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
profile_init(const_profile_filespec_t * files,profile_t * ret_profile)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
profile_copy(profile_t old_profile,profile_t * new_profile)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
profile_init_path(const_profile_filespec_list_t filepath,profile_t * ret_profile)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
profile_is_writable(profile_t profile,int * writable)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
profile_is_modified(profile_t profile,int * modified)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
profile_flush(profile_t profile)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
profile_flush_to_file(profile_t profile,const_profile_filespec_t outfile)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
profile_flush_to_buffer(profile_t profile,char ** buf)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
profile_free_buffer(profile_t profile,char * buf)223 profile_free_buffer(profile_t profile, char *buf)
224 {
225     free(buf);
226 }
227 
228 void KRB5_CALLCONV
profile_abandon(profile_t profile)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
profile_release(profile_t profile)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*/
profile_ser_size(const char * unused,profile_t profile,size_t * sizep)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 
pack_int32(prof_int32 oval,unsigned char ** bufpp,size_t * remainp)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 
profile_ser_externalize(const char * unused,profile_t profile,unsigned char ** bufpp,size_t * remainp)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 
unpack_int32(prof_int32 * intp,unsigned char ** bufpp,size_t * remainp)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*/
profile_ser_internalize(const char * unused,profile_t * profilep,unsigned char ** bufpp,size_t * remainp)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
profile_get_options_boolean(profile,section,options)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
profile_get_options_string(profile,section,options)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