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