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