prof_init.c revision 7934:6aeeafc994de
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
27typedef int32_t prof_int32;
28
29errcode_t KRB5_CALLCONV
30profile_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
86errcode_t KRB5_CALLCONV
87profile_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
108errcode_t KRB5_CALLCONV
109profile_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
161errcode_t KRB5_CALLCONV
162profile_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
176errcode_t KRB5_CALLCONV
177profile_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
191errcode_t KRB5_CALLCONV
192profile_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
203errcode_t KRB5_CALLCONV
204profile_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
216errcode_t KRB5_CALLCONV
217profile_flush_to_buffer(profile_t profile, char **buf)
218{
219    return profile_flush_file_data_to_buffer(profile->first_file->data, buf);
220}
221
222void KRB5_CALLCONV
223profile_free_buffer(profile_t profile, char *buf)
224{
225    free(buf);
226}
227
228void KRB5_CALLCONV
229profile_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
244void KRB5_CALLCONV
245profile_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*/
264errcode_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
279static 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
289errcode_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
330static 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*/
347errcode_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
403cleanup:
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
415errcode_t
416profile_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
461errcode_t
462profile_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