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 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 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 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 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 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 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 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 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 223 profile_free_buffer(profile_t profile, char *buf) 224 { 225 free(buf); 226 } 227 228 void KRB5_CALLCONV 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 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*/ 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 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 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 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*/ 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 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 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