/* * prof_init.c --- routines that manipulate the user-visible profile_t * object. */ #include #include #include #include #include "prof_int.h" /* Find a 4-byte integer type */ #if (SIZEOF_SHORT == 4) typedef short prof_int32; #elif (SIZEOF_INT == 4) typedef int prof_int32; #elif (SIZEOF_LONG == 4) typedef int prof_int32; #else /* SIZEOF_LONG == 4 */ error(do not have a 4-byte integer type) #endif /* SIZEOF_LONG == 4 */ errcode_t profile_init(filenames, ret_profile) const char **filenames; profile_t *ret_profile; { const char **fn; profile_t profile; prf_file_t new_file, last = 0; errcode_t retval; initialize_prof_error_table(); profile = malloc(sizeof(struct _profile_t)); if (!profile) return ENOMEM; memset(profile, 0, sizeof(struct _profile_t)); profile->magic = PROF_MAGIC_PROFILE; for (fn = filenames; *fn; fn++) { retval = profile_open_file(*fn, &new_file); /* if this file is missing, skip to the next */ if (retval == ENOENT) { continue; } if (retval) { profile_release(profile); return retval; } if (last) last->next = new_file; else profile->first_file = new_file; last = new_file; /* since we actually got something, don't loop again */ /* (at least until we understand what multiple files mean) */ break; } /* if the last file was missing, they all were, so report such */ if (retval == ENOENT) { profile_release(profile); return retval; } *ret_profile = profile; return 0; } errcode_t profile_init_path(filepath, ret_profile) const char *filepath; profile_t *ret_profile; { int n_entries, i; int ent_len; const char *s, *t; char **filenames; errcode_t retval; /* count the distinct filename components */ for(s = filepath, n_entries = 1; *s; s++) { if (*s == ':') n_entries++; } /* the array is NULL terminated */ filenames = (char**) malloc((n_entries+1) * sizeof(char*)); if (filenames == 0) return ENOMEM; /* measure, copy, and skip each one */ for(s = filepath, i=0; (t = strchr(s, ':')) || (t=s+strlen(s)); s=t+1, i++) { ent_len = t-s; filenames[i] = (char*) malloc(ent_len + 1); if (filenames[i] == 0) { /* if malloc fails, free the ones that worked */ while(--i >= 0) free(filenames[i]); return ENOMEM; } strncpy(filenames[i], s, ent_len); filenames[i][ent_len] = 0; if (*t == 0) { i++; break; } } /* cap the array */ filenames[i] = 0; retval = profile_init((const char **)filenames, ret_profile); /* count back down and free the entries */ while(--i >= 0) free(filenames[i]); free(filenames); return retval; } void profile_release(profile) profile_t profile; { prf_file_t p, next; for (p = profile->first_file; p; p = next) { next = p->next; profile_close_file(p); } profile->magic = 0; free(profile); } struct string_list { char **list; int num; int max; }; static errcode_t init_list(list) struct string_list *list; { list->num = 0; list->max = 10; list->list = malloc(list->max * sizeof(char *)); if (list->list == 0) return ENOMEM; list->list[0] = 0; return 0; } static void free_list(list) struct string_list *list; { char **cp; for (cp = list->list; *cp; cp++) free(*cp); free(list->list); list->num = list->max = 0; list->list = 0; } static errcode_t add_to_list(list, str) struct string_list *list; const char *str; { char *newstr; if (list->num+1 >= list->max) { list->max += 5; list->list = realloc(list->list, list->max * sizeof(char *)); if (list->list == 0) return ENOMEM; } newstr = malloc(strlen(str)+1); if (newstr == 0) return ENOMEM; strcpy(newstr, str); list->list[list->num++] = newstr; list->list[list->num] = 0; return 0; } /* * XXX this version only works to get values from the first file. * To do more than that means we have to implement some "interesting" * code to do the section searching. */ errcode_t profile_get_values(profile, names, ret_values) profile_t profile; const char **names; char ***ret_values; { prf_file_t file; errcode_t retval; struct profile_node *section; void *state; char *value; struct string_list values; const char **cpp; if (profile == 0) return PROF_NO_PROFILE; if (names == 0 || names[0] == 0 || names[1] == 0) return PROF_BAD_NAMESET; init_list(&values); file = profile->first_file; retval = profile_update_file(file); if (retval) goto cleanup; section = file->root; for (cpp = names; cpp[1]; cpp++) { state = 0; retval = profile_find_node_subsection(section, *cpp, &state, 0, §ion); if (retval) goto cleanup; } state = 0; do { retval = profile_find_node_relation(section, *cpp, &state, 0, &value); if (retval) goto cleanup; add_to_list(&values, value); } while (state); *ret_values = values.list; return 0; cleanup: free_list(&values); return retval; } /* * XXX this version only works to get values from the first file. * To do more than that means we have to implement some "interesting" * code to do the section searching. */ errcode_t profile_get_first_values(profile, names, ret_values) profile_t profile; const char **names; char ***ret_values; { prf_file_t file; errcode_t retval; struct profile_node *section; void *state; char *value; struct string_list values; char *secname; if (profile == 0) return PROF_NO_PROFILE; if (names == 0 || names[0] == 0) return PROF_BAD_NAMESET; init_list(&values); file = profile->first_file; retval = profile_update_file(file); if (retval) goto cleanup; section = file->root; state = 0; retval = profile_find_node_subsection(section, *names, &state, &secname, §ion); do { retval = profile_find_node_name(section, &state, &value); if (retval) goto cleanup; add_to_list(&values, value); } while (state); *ret_values = values.list; return 0; cleanup: free_list(&values); return retval; } /* * XXX this version only works to get values from the first file. */ static errcode_t profile_get_value(profile, names, ret_value) profile_t profile; const char **names; char **ret_value; { prf_file_t file; errcode_t retval; struct profile_node *section; void *state; char *value; const char **cpp; if (names == 0 || names[0] == 0 || names[1] == 0) return PROF_BAD_NAMESET; file = profile->first_file; retval = profile_update_file(file); if (retval) goto cleanup; section = file->root; for (cpp = names; cpp[1]; cpp++) { state = 0; retval = profile_find_node_subsection(section, *cpp, &state, 0, §ion); if (retval) goto cleanup; } state = 0; retval = profile_find_node_relation(section, *cpp, &state, 0, &value); if (retval) goto cleanup; *ret_value = value; return 0; cleanup: return retval; } errcode_t profile_get_string(profile, name, subname, subsubname, def_val, ret_string) profile_t profile; const char *name, *subname, *subsubname; const char *def_val; char **ret_string; { const char *value; errcode_t retval; const char *names[4]; if (profile) { names[0] = name; names[1] = subname; names[2] = subsubname; names[3] = 0; retval = profile_get_value(profile, names, &value); if (retval == PROF_NO_SECTION || retval == PROF_NO_RELATION) value = def_val; else if (retval) return retval; } else value = def_val; if (value) { *ret_string = malloc(strlen(value)+1); if (*ret_string == 0) return ENOMEM; strcpy(*ret_string, value); } else *ret_string = 0; return 0; } errcode_t profile_get_integer(profile, name, subname, subsubname, def_val, ret_int) profile_t profile; const char *name, *subname, *subsubname; int def_val; int *ret_int; { char *value; errcode_t retval; const char *names[4]; if (profile == 0) { *ret_int = def_val; return 0; } names[0] = name; names[1] = subname; names[2] = subsubname; names[3] = 0; retval = profile_get_value(profile, names, &value); if (retval == PROF_NO_SECTION || retval == PROF_NO_RELATION) { *ret_int = def_val; return 0; } else if (retval) return retval; *ret_int = atoi(value); return 0; } errcode_t profile_ser_size(unused, profile, sizep) const char *unused; profile_t profile; size_t *sizep; { size_t required; prf_file_t pfp; /* * ARGH - We want to avoid having to include k5-int.h. We ASSuME that * krb5_int32 is 4 bytes in length. * * krb5_int32 for header * krb5_int32 for number of files. * krb5_int32 for trailer */ required = 3*sizeof(prof_int32); for (pfp = profile->first_file; pfp; pfp = pfp->next) { required += sizeof(prof_int32); if (pfp->filename) required += strlen(pfp->filename); } *sizep += required; return 0; } static void pack_int32(oval, bufpp, remainp) prof_int32 oval; unsigned char **bufpp; size_t *remainp; { (*bufpp)[0] = (unsigned char) ((oval >> 24) & 0xff); (*bufpp)[1] = (unsigned char) ((oval >> 16) & 0xff); (*bufpp)[2] = (unsigned char) ((oval >> 8) & 0xff); (*bufpp)[3] = (unsigned char) (oval & 0xff); *bufpp += sizeof(prof_int32); *remainp -= sizeof(prof_int32); } errcode_t profile_ser_externalize(unused, profile, bufpp, remainp) const char *unused; profile_t profile; unsigned char **bufpp; size_t *remainp; { errcode_t retval; size_t required; unsigned char *bp; size_t remain; prf_file_t pfp; prof_int32 fcount, slen; required = 0; bp = *bufpp; remain = *remainp; retval = EINVAL; if (profile) { retval = ENOMEM; (void) profile_ser_size(unused, profile, &required); if (required <= remain) { fcount = 0; for (pfp = profile->first_file; pfp; pfp = pfp->next) fcount++; pack_int32(PROF_MAGIC_PROFILE, &bp, &remain); pack_int32(fcount, &bp, &remain); for (pfp = profile->first_file; pfp; pfp = pfp->next) { slen = (pfp->filename) ? (prof_int32) strlen(pfp->filename) : 0; pack_int32(slen, &bp, &remain); if (slen) { memcpy(bp, pfp->filename, (size_t) slen); bp += slen; remain -= (size_t) slen; } } pack_int32(PROF_MAGIC_PROFILE, &bp, &remain); retval = 0; *bufpp = bp; *remainp = remain; } } return(retval); } static int unpack_int32(intp, bufpp, remainp) prof_int32 *intp; unsigned char **bufpp; size_t *remainp; { if (*remainp >= sizeof(prof_int32)) { *intp = (((prof_int32) (*bufpp)[0] << 24) | ((prof_int32) (*bufpp)[1] << 16) | ((prof_int32) (*bufpp)[2] << 8) | ((prof_int32) (*bufpp)[3])); *bufpp += sizeof(prof_int32); *remainp -= sizeof(prof_int32); return 0; } else return 1; } errcode_t profile_ser_internalize(unused, profilep, bufpp, remainp) const char *unused; profile_t *profilep; unsigned char **bufpp; size_t *remainp; { errcode_t retval; unsigned char *bp; size_t remain; int i; prof_int32 fcount, tmp; char **flist; bp = *bufpp; remain = *remainp; retval = EINVAL; if (remain >= 12) (void) unpack_int32(&tmp, &bp, &remain); else tmp = 0; if (tmp == PROF_MAGIC_PROFILE) { (void) unpack_int32(&fcount, &bp, &remain); retval = ENOMEM; if (!fcount || (flist = (char **) malloc(sizeof(char *) * (fcount + 1)))) { memset(flist, 0, sizeof(char *) * (fcount+1)); for (i=0; i