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