Home | History | Annotate | Download | only in profile
      1 /*
      2  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
      3  * Use is subject to license terms.
      4  */
      5 
      6 
      7 /*
      8  * prof_init.c --- routines that manipulate the user-visible profile_t
      9  * 	object.
     10  */
     11 
     12 #include "prof_int.h"
     13 
     14 #include <stdio.h>
     15 #include <string.h>
     16 #ifdef HAVE_STDLIB_H
     17 #include <stdlib.h>
     18 #endif
     19 #include <errno.h>
     20 
     21 #ifdef HAVE_STDINT_H
     22 # include <stdint.h>
     23 #endif
     24 #ifdef HAVE_INTTYPES_H
     25 # include <inttypes.h>
     26 #endif
     27 typedef int32_t prof_int32;
     28 
     29 errcode_t KRB5_CALLCONV
     30 profile_init(const_profile_filespec_t *files, profile_t *ret_profile)
     31 {
     32 	const_profile_filespec_t *fs;
     33 	profile_t profile;
     34 	prf_file_t  new_file, last = 0;
     35 	errcode_t retval = 0;
     36 
     37 	profile = malloc(sizeof(struct _profile_t));
     38 	if (!profile)
     39 		return ENOMEM;
     40 	memset(profile, 0, sizeof(struct _profile_t));
     41 	profile->magic = PROF_MAGIC_PROFILE;
     42 
     43         /* if the filenames list is not specified return an empty profile */
     44         if ( files ) {
     45 	    for (fs = files; !PROFILE_LAST_FILESPEC(*fs); fs++) {
     46 		retval = profile_open_file(*fs, &new_file);
     47 		/* if this file is missing, skip to the next */
     48 		if (retval == ENOENT || retval == EACCES) {
     49 			continue;
     50 		}
     51 		if (retval) {
     52 			profile_release(profile);
     53 			return retval;
     54 		}
     55 		if (last)
     56 			last->next = new_file;
     57 		else
     58 			profile->first_file = new_file;
     59 		last = new_file;
     60 	    }
     61 	    /*
     62 	     * If last is still null after the loop, then all the files were
     63 	     * missing, so return the appropriate error.
     64 	     */
     65 	    if (!last) {
     66 		profile_release(profile);
     67 		return ENOENT;
     68 	    }
     69 	}
     70 
     71         *ret_profile = profile;
     72         return 0;
     73 }
     74 
     75 #define COUNT_LINKED_LIST(COUNT, PTYPE, START, FIELD)	\
     76 	{						\
     77 	    int cll_counter = 0;			\
     78 	    PTYPE cll_ptr = (START);			\
     79 	    while (cll_ptr != NULL) {			\
     80 		cll_counter++;				\
     81 		cll_ptr = cll_ptr->FIELD;		\
     82 	    }						\
     83 	    (COUNT) = cll_counter;			\
     84 	}
     85 
     86 errcode_t KRB5_CALLCONV
     87 profile_copy(profile_t old_profile, profile_t *new_profile)
     88 {
     89     size_t size, i;
     90     const_profile_filespec_t *files;
     91     prf_file_t file;
     92     errcode_t err;
     93 
     94     /* The fields we care about are read-only after creation, so
     95        no locking is needed.  */
     96     COUNT_LINKED_LIST (size, prf_file_t, old_profile->first_file, next);
     97     files = malloc ((size+1) * sizeof(*files));
     98     if (files == NULL)
     99 	return errno;
    100     for (i = 0, file = old_profile->first_file; i < size; i++, file = file->next)
    101 	files[i] = file->data->filespec;
    102     files[size] = NULL;
    103     err = profile_init (files, new_profile);
    104     free (files);
    105     return err;
    106 }
    107 
    108 errcode_t KRB5_CALLCONV
    109 profile_init_path(const_profile_filespec_list_t filepath,
    110 		  profile_t *ret_profile)
    111 {
    112 	int n_entries, i;
    113 	unsigned int ent_len;
    114 	const char *s, *t;
    115 	profile_filespec_t *filenames;
    116 	errcode_t retval;
    117 
    118 	/* count the distinct filename components */
    119 	for(s = filepath, n_entries = 1; *s; s++) {
    120 		if (*s == ':')
    121 			n_entries++;
    122 	}
    123 
    124 	/* the array is NULL terminated */
    125 	filenames = (profile_filespec_t*) malloc((n_entries+1) * sizeof(char*));
    126 	if (filenames == 0)
    127 		return ENOMEM;
    128 
    129 	/* measure, copy, and skip each one */
    130 	/* Solaris Kerberos */
    131 	for(s = filepath, i=0; ((t = strchr(s, ':')) != NULL) ||
    132 			((t=s+strlen(s)) != NULL); s=t+1, i++) {
    133 		ent_len = t-s;
    134 		filenames[i] = (char*) malloc(ent_len + 1);
    135 		if (filenames[i] == 0) {
    136 			/* if malloc fails, free the ones that worked */
    137 			while(--i >= 0) free(filenames[i]);
    138                         free(filenames);
    139 			return ENOMEM;
    140 		}
    141 		strncpy(filenames[i], s, ent_len);
    142 		filenames[i][ent_len] = 0;
    143 		if (*t == 0) {
    144 			i++;
    145 			break;
    146 		}
    147 	}
    148 	/* cap the array */
    149 	filenames[i] = 0;
    150 
    151 	retval = profile_init((const_profile_filespec_t *) filenames,
    152 			      ret_profile);
    153 
    154 	/* count back down and free the entries */
    155 	while(--i >= 0) free(filenames[i]);
    156 	free(filenames);
    157 
    158 	return retval;
    159 }
    160 
    161 errcode_t KRB5_CALLCONV
    162 profile_is_writable(profile_t profile, int *writable)
    163 {
    164     if (!profile || profile->magic != PROF_MAGIC_PROFILE)
    165         return PROF_MAGIC_PROFILE;
    166 
    167     if (!writable)
    168         return EINVAL;
    169 
    170     if (profile->first_file)
    171         *writable = (profile->first_file->data->flags & PROFILE_FILE_RW);
    172 
    173     return 0;
    174 }
    175 
    176 errcode_t KRB5_CALLCONV
    177 profile_is_modified(profile_t profile, int *modified)
    178 {
    179     if (!profile || profile->magic != PROF_MAGIC_PROFILE)
    180         return PROF_MAGIC_PROFILE;
    181 
    182     if (!modified)
    183         return EINVAL;
    184 
    185     if (profile->first_file)
    186         *modified = (profile->first_file->data->flags & PROFILE_FILE_DIRTY);
    187 
    188     return 0;
    189 }
    190 
    191 errcode_t KRB5_CALLCONV
    192 profile_flush(profile_t profile)
    193 {
    194 	if (!profile || profile->magic != PROF_MAGIC_PROFILE)
    195 		return PROF_MAGIC_PROFILE;
    196 
    197 	if (profile->first_file)
    198 		return profile_flush_file(profile->first_file);
    199 
    200 	return 0;
    201 }
    202 
    203 errcode_t KRB5_CALLCONV
    204 profile_flush_to_file(profile_t profile, const_profile_filespec_t outfile)
    205 {
    206 	if (!profile || profile->magic != PROF_MAGIC_PROFILE)
    207 		return PROF_MAGIC_PROFILE;
    208 
    209 	if (profile->first_file)
    210 		return profile_flush_file_to_file(profile->first_file,
    211 						  outfile);
    212 
    213 	return 0;
    214 }
    215 
    216 errcode_t KRB5_CALLCONV
    217 profile_flush_to_buffer(profile_t profile, char **buf)
    218 {
    219     return profile_flush_file_data_to_buffer(profile->first_file->data, buf);
    220 }
    221 
    222 void KRB5_CALLCONV
    223 profile_free_buffer(profile_t profile, char *buf)
    224 {
    225     free(buf);
    226 }
    227 
    228 void KRB5_CALLCONV
    229 profile_abandon(profile_t profile)
    230 {
    231 	prf_file_t	p, next;
    232 
    233 	if (!profile || profile->magic != PROF_MAGIC_PROFILE)
    234 		return;
    235 
    236 	for (p = profile->first_file; p; p = next) {
    237 		next = p->next;
    238 		profile_free_file(p);
    239 	}
    240 	profile->magic = 0;
    241 	free(profile);
    242 }
    243 
    244 void KRB5_CALLCONV
    245 profile_release(profile_t profile)
    246 {
    247 	prf_file_t	p, next;
    248 
    249 	if (!profile || profile->magic != PROF_MAGIC_PROFILE)
    250 		return;
    251 
    252 	for (p = profile->first_file; p; p = next) {
    253 		next = p->next;
    254 		profile_close_file(p);
    255 	}
    256 	profile->magic = 0;
    257 	free(profile);
    258 }
    259 
    260 /*
    261  * Here begins the profile serialization functions.
    262  */
    263 /*ARGSUSED*/
    264 errcode_t profile_ser_size(const char *unused, profile_t profile,
    265 			   size_t *sizep)
    266 {
    267     size_t	required;
    268     prf_file_t	pfp;
    269 
    270     required = 3*sizeof(prof_int32);
    271     for (pfp = profile->first_file; pfp; pfp = pfp->next) {
    272 	required += sizeof(prof_int32);
    273 	required += strlen(pfp->data->filespec);
    274     }
    275     *sizep += required;
    276     return 0;
    277 }
    278 
    279 static void pack_int32(prof_int32 oval, unsigned char **bufpp, size_t *remainp)
    280 {
    281     (*bufpp)[0] = (unsigned char) ((oval >> 24) & 0xff);
    282     (*bufpp)[1] = (unsigned char) ((oval >> 16) & 0xff);
    283     (*bufpp)[2] = (unsigned char) ((oval >> 8) & 0xff);
    284     (*bufpp)[3] = (unsigned char) (oval & 0xff);
    285     *bufpp += sizeof(prof_int32);
    286     *remainp -= sizeof(prof_int32);
    287 }
    288 
    289 errcode_t profile_ser_externalize(const char *unused, profile_t profile,
    290 				  unsigned char **bufpp, size_t *remainp)
    291 {
    292     errcode_t		retval;
    293     size_t		required;
    294     unsigned char	*bp;
    295     size_t		remain;
    296     prf_file_t		pfp;
    297     prof_int32		fcount, slen;
    298 
    299     required = 0;
    300     bp = *bufpp;
    301     remain = *remainp;
    302     retval = EINVAL;
    303     if (profile) {
    304 	retval = ENOMEM;
    305 	(void) profile_ser_size(unused, profile, &required);
    306 	if (required <= remain) {
    307 	    fcount = 0;
    308 	    for (pfp = profile->first_file; pfp; pfp = pfp->next)
    309 		fcount++;
    310 	    pack_int32(PROF_MAGIC_PROFILE, &bp, &remain);
    311 	    pack_int32(fcount, &bp, &remain);
    312 	    for (pfp = profile->first_file; pfp; pfp = pfp->next) {
    313 		slen = (prof_int32) strlen(pfp->data->filespec);
    314 		pack_int32(slen, &bp, &remain);
    315 		if (slen) {
    316 		    memcpy(bp, pfp->data->filespec, (size_t) slen);
    317 		    bp += slen;
    318 		    remain -= (size_t) slen;
    319 		}
    320 	    }
    321 	    pack_int32(PROF_MAGIC_PROFILE, &bp, &remain);
    322 	    retval = 0;
    323 	    *bufpp = bp;
    324 	    *remainp = remain;
    325 	}
    326     }
    327     return(retval);
    328 }
    329 
    330 static int unpack_int32(prof_int32 *intp, unsigned char **bufpp,
    331 			size_t *remainp)
    332 {
    333     if (*remainp >= sizeof(prof_int32)) {
    334 	*intp = (((prof_int32) (*bufpp)[0] << 24) |
    335 		 ((prof_int32) (*bufpp)[1] << 16) |
    336 		 ((prof_int32) (*bufpp)[2] << 8) |
    337 		 ((prof_int32) (*bufpp)[3]));
    338 	*bufpp += sizeof(prof_int32);
    339 	*remainp -= sizeof(prof_int32);
    340 	return 0;
    341     }
    342     else
    343 	return 1;
    344 }
    345 
    346 /*ARGSUSED*/
    347 errcode_t profile_ser_internalize(const char *unused, profile_t *profilep,
    348 				  unsigned char **bufpp, size_t *remainp)
    349 {
    350 	errcode_t		retval;
    351 	unsigned char	*bp;
    352 	size_t		remain;
    353 	int			i;
    354 	prof_int32		fcount, tmp;
    355 	profile_filespec_t		*flist = 0;
    356 
    357 	bp = *bufpp;
    358 	remain = *remainp;
    359 
    360 	if (remain >= 12)
    361 		(void) unpack_int32(&tmp, &bp, &remain);
    362 	else
    363 		tmp = 0;
    364 
    365 	if (tmp != PROF_MAGIC_PROFILE) {
    366 		retval = EINVAL;
    367 		goto cleanup;
    368 	}
    369 
    370 	(void) unpack_int32(&fcount, &bp, &remain);
    371 	retval = ENOMEM;
    372 
    373 	flist = (profile_filespec_t *) malloc(sizeof(profile_filespec_t) * (fcount + 1));
    374 	if (!flist)
    375 		goto cleanup;
    376 
    377 	memset(flist, 0, sizeof(char *) * (fcount+1));
    378 	for (i=0; i<fcount; i++) {
    379 		if (!unpack_int32(&tmp, &bp, &remain)) {
    380 			flist[i] = (char *) malloc((size_t) (tmp+1));
    381 			if (!flist[i])
    382 				goto cleanup;
    383 			memcpy(flist[i], bp, (size_t) tmp);
    384 			flist[i][tmp] = '\0';
    385 			bp += tmp;
    386 			remain -= (size_t) tmp;
    387 		}
    388 	}
    389 
    390 	if (unpack_int32(&tmp, &bp, &remain) ||
    391 	    (tmp != PROF_MAGIC_PROFILE)) {
    392 		retval = EINVAL;
    393 		goto cleanup;
    394 	}
    395 
    396 	if ((retval = profile_init((const_profile_filespec_t *) flist,
    397 				   profilep)))
    398 		goto cleanup;
    399 
    400 	*bufpp = bp;
    401 	*remainp = remain;
    402 
    403 cleanup:
    404 	if (flist) {
    405 		for (i=0; i<fcount; i++) {
    406 			if (flist[i])
    407 				free(flist[i]);
    408 		}
    409 		free(flist);
    410 	}
    411 	return(retval);
    412 }
    413 
    414 
    415 errcode_t
    416 profile_get_options_boolean(profile, section, options)
    417     profile_t		profile;
    418     char **		section;
    419     profile_options_boolean *options;
    420 {
    421     char ** actual_section;
    422     char * value = NULL;
    423     errcode_t retval = 0;
    424     int i, max_i;
    425 
    426     for (max_i = 0; section[max_i]; max_i++);
    427     if (actual_section = (char **)malloc((max_i + 2) * sizeof(char *))) {
    428         for (actual_section[max_i + 1] = NULL, i = 0; section[i]; i++)
    429 	    actual_section[i] = section[i];
    430 
    431 	for (i = 0; options[i].name; i++) {
    432 	    if (options[i].found) continue;
    433 	    actual_section[max_i] = options[i].name;
    434 	    retval = profile_get_value(profile, (const char **) actual_section,
    435                                        (const char **)&value);
    436 	    if (retval && (retval != PROF_NO_RELATION) &&
    437 	       (retval != PROF_NO_SECTION)) {
    438 		free(actual_section);
    439 		return(retval);
    440 	    }
    441 	    if ((retval == 0) && value) {
    442 		/*
    443 		 * Any string other than true will turn off the
    444 		 *option
    445 		 */
    446 		if (strncmp(value,"true",4) == 0)
    447 		    *(options[i].value) = 1;
    448 		else
    449 		    *(options[i].value) = 0;
    450 		options[i].found = 1;
    451 
    452 		}
    453 	}
    454 	free(actual_section);
    455     } else {
    456 	retval = ENOMEM;
    457     }
    458     return(retval);
    459 }
    460 
    461 errcode_t
    462 profile_get_options_string(profile, section, options)
    463     profile_t		profile;
    464     char **		section;
    465     profile_option_strings *options;
    466 {
    467     char ** actual_section;
    468     char * value = NULL;
    469     errcode_t retval = 0;
    470     int i, max_i;
    471 
    472     for (max_i = 0; section[max_i]; max_i++);
    473     if (actual_section = (char **)malloc((max_i + 2) * sizeof(char *))) {
    474         for (actual_section[max_i + 1] = NULL, i = 0; section[i]; i++)
    475 	    actual_section[i] = section[i];
    476 
    477 	for (i = 0; options[i].name; i++) {
    478 	    if (options[i].found) continue;
    479 	    actual_section[max_i] = options[i].name;
    480 	    retval = profile_get_value(profile, (const char **) actual_section,
    481                                        (const char **)&value);
    482 	    if (retval && (retval != PROF_NO_RELATION) &&
    483 	       (retval != PROF_NO_SECTION)) {
    484 		free(actual_section);
    485 		return(retval);
    486 	    }
    487 	    if ((retval == 0) && value) {
    488 		*options[i].value = malloc(strlen(value)+1);
    489 		if (*options[i].value == 0)
    490 			retval = ENOMEM;
    491 		strcpy(*options[i].value, value);
    492 	        options[i].found = 1;
    493     	    } else
    494 		*options[i].value = 0;
    495 	}
    496 	free(actual_section);
    497     } else {
    498 	retval = ENOMEM;
    499     }
    500     return(retval);
    501 }
    502