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