1 /* 2 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 #pragma ident "%Z%%M% %I% %E% SMI" 7 8 /* 9 * prof_init.c --- routines that manipulate the user-visible profile_t 10 * object. 11 */ 12 13 #include "prof_int.h" 14 15 #include <stdio.h> 16 #include <string.h> 17 #ifdef HAVE_STDLIB_H 18 #include <stdlib.h> 19 #endif 20 #include <errno.h> 21 22 /* Find a 4-byte integer type */ 23 #if (SIZEOF_SHORT == 4) 24 typedef short prof_int32; 25 #elif (SIZEOF_INT == 4) 26 typedef int prof_int32; 27 #elif (SIZEOF_LONG == 4) 28 typedef long prof_int32; 29 #else /* SIZEOF_LONG == 4 */ 30 error(do not have a 4-byte integer type) 31 #endif /* SIZEOF_LONG == 4 */ 32 33 errcode_t KRB5_CALLCONV 34 profile_init(const_profile_filespec_t *files, profile_t *ret_profile) 35 { 36 const_profile_filespec_t *fs; 37 profile_t profile; 38 prf_file_t new_file, last = 0; 39 errcode_t retval = 0; 40 41 profile = malloc(sizeof(struct _profile_t)); 42 if (!profile) 43 return ENOMEM; 44 memset(profile, 0, sizeof(struct _profile_t)); 45 profile->magic = PROF_MAGIC_PROFILE; 46 47 /* if the filenames list is not specified return an empty profile */ 48 if ( files ) { 49 for (fs = files; !PROFILE_LAST_FILESPEC(*fs); fs++) { 50 retval = profile_open_file(*fs, &new_file); 51 /* if this file is missing, skip to the next */ 52 if (retval == ENOENT || retval == EACCES) { 53 continue; 54 } 55 if (retval) { 56 profile_release(profile); 57 return retval; 58 } 59 if (last) 60 last->next = new_file; 61 else 62 profile->first_file = new_file; 63 last = new_file; 64 } 65 /* 66 * If last is still null after the loop, then all the files were 67 * missing, so return the appropriate error. 68 */ 69 if (!last) { 70 profile_release(profile); 71 return ENOENT; 72 } 73 } 74 75 *ret_profile = profile; 76 return 0; 77 } 78 79 errcode_t KRB5_CALLCONV 80 profile_init_path(const_profile_filespec_list_t filepath, 81 profile_t *ret_profile) 82 { 83 int n_entries, i; 84 unsigned int ent_len; 85 const char *s, *t; 86 profile_filespec_t *filenames; 87 errcode_t retval; 88 89 /* count the distinct filename components */ 90 for(s = filepath, n_entries = 1; *s; s++) { 91 if (*s == ':') 92 n_entries++; 93 } 94 95 /* the array is NULL terminated */ 96 filenames = (profile_filespec_t*) malloc((n_entries+1) * sizeof(char*)); 97 if (filenames == 0) 98 return ENOMEM; 99 100 /* measure, copy, and skip each one */ 101 for(s = filepath, i=0; ((t = strchr(s, ':')) != NULL) || 102 ((t=s+strlen(s)) != NULL); s=t+1, i++) { 103 ent_len = t-s; 104 filenames[i] = (char*) malloc(ent_len + 1); 105 if (filenames[i] == 0) { 106 /* if malloc fails, free the ones that worked */ 107 while(--i >= 0) free(filenames[i]); 108 free(filenames); 109 return ENOMEM; 110 } 111 strncpy(filenames[i], s, ent_len); 112 filenames[i][ent_len] = 0; 113 if (*t == 0) { 114 i++; 115 break; 116 } 117 } 118 /* cap the array */ 119 filenames[i] = 0; 120 121 retval = profile_init((const_profile_filespec_t *) filenames, 122 ret_profile); 123 124 /* count back down and free the entries */ 125 while(--i >= 0) free(filenames[i]); 126 free(filenames); 127 128 return retval; 129 } 130 131 errcode_t KRB5_CALLCONV 132 profile_is_writable(profile_t profile, int *writable) 133 { 134 if (!profile || profile->magic != PROF_MAGIC_PROFILE) 135 return PROF_MAGIC_PROFILE; 136 137 if (!writable) 138 return EINVAL; 139 140 if (profile->first_file) 141 *writable = (profile->first_file->data->flags & PROFILE_FILE_RW); 142 143 return 0; 144 } 145 146 errcode_t KRB5_CALLCONV 147 profile_is_modified(profile_t profile, int *modified) 148 { 149 if (!profile || profile->magic != PROF_MAGIC_PROFILE) 150 return PROF_MAGIC_PROFILE; 151 152 if (!modified) 153 return EINVAL; 154 155 if (profile->first_file) 156 *modified = (profile->first_file->data->flags & PROFILE_FILE_DIRTY); 157 158 return 0; 159 } 160 161 errcode_t KRB5_CALLCONV 162 profile_flush(profile_t profile) 163 { 164 if (!profile || profile->magic != PROF_MAGIC_PROFILE) 165 return PROF_MAGIC_PROFILE; 166 167 if (profile->first_file) 168 return profile_flush_file(profile->first_file); 169 170 return 0; 171 } 172 173 errcode_t KRB5_CALLCONV 174 profile_flush_to_file(profile_t profile, const_profile_filespec_t outfile) 175 { 176 if (!profile || profile->magic != PROF_MAGIC_PROFILE) 177 return PROF_MAGIC_PROFILE; 178 179 if (profile->first_file) 180 return profile_flush_file_to_file(profile->first_file, 181 outfile); 182 183 return 0; 184 } 185 186 errcode_t KRB5_CALLCONV 187 profile_flush_to_buffer(profile_t profile, char **buf) 188 { 189 return profile_flush_file_data_to_buffer(profile->first_file->data, buf); 190 } 191 192 void KRB5_CALLCONV 193 profile_free_buffer(profile_t profile, char *buf) 194 { 195 free(buf); 196 } 197 198 void KRB5_CALLCONV 199 profile_abandon(profile_t profile) 200 { 201 prf_file_t p, next; 202 203 if (!profile || profile->magic != PROF_MAGIC_PROFILE) 204 return; 205 206 for (p = profile->first_file; p; p = next) { 207 next = p->next; 208 profile_free_file(p); 209 } 210 profile->magic = 0; 211 free(profile); 212 } 213 214 void KRB5_CALLCONV 215 profile_release(profile_t profile) 216 { 217 prf_file_t p, next; 218 219 if (!profile || profile->magic != PROF_MAGIC_PROFILE) 220 return; 221 222 for (p = profile->first_file; p; p = next) { 223 next = p->next; 224 profile_close_file(p); 225 } 226 profile->magic = 0; 227 free(profile); 228 } 229 230 /* 231 * Here begins the profile serialization functions. 232 */ 233 /*ARGSUSED*/ 234 errcode_t profile_ser_size(const char *unused, profile_t profile, 235 size_t *sizep) 236 { 237 size_t required; 238 prf_file_t pfp; 239 240 required = 3*sizeof(prof_int32); 241 for (pfp = profile->first_file; pfp; pfp = pfp->next) { 242 required += sizeof(prof_int32); 243 required += strlen(pfp->data->filespec); 244 } 245 *sizep += required; 246 return 0; 247 } 248 249 static void pack_int32(prof_int32 oval, unsigned char **bufpp, size_t *remainp) 250 { 251 (*bufpp)[0] = (unsigned char) ((oval >> 24) & 0xff); 252 (*bufpp)[1] = (unsigned char) ((oval >> 16) & 0xff); 253 (*bufpp)[2] = (unsigned char) ((oval >> 8) & 0xff); 254 (*bufpp)[3] = (unsigned char) (oval & 0xff); 255 *bufpp += sizeof(prof_int32); 256 *remainp -= sizeof(prof_int32); 257 } 258 259 errcode_t profile_ser_externalize(const char *unused, profile_t profile, 260 unsigned char **bufpp, size_t *remainp) 261 { 262 errcode_t retval; 263 size_t required; 264 unsigned char *bp; 265 size_t remain; 266 prf_file_t pfp; 267 prof_int32 fcount, slen; 268 269 required = 0; 270 bp = *bufpp; 271 remain = *remainp; 272 retval = EINVAL; 273 if (profile) { 274 retval = ENOMEM; 275 (void) profile_ser_size(unused, profile, &required); 276 if (required <= remain) { 277 fcount = 0; 278 for (pfp = profile->first_file; pfp; pfp = pfp->next) 279 fcount++; 280 pack_int32((prof_int32)PROF_MAGIC_PROFILE, &bp, &remain); 281 pack_int32(fcount, &bp, &remain); 282 for (pfp = profile->first_file; pfp; pfp = pfp->next) { 283 slen = (prof_int32) strlen(pfp->data->filespec); 284 pack_int32(slen, &bp, &remain); 285 if (slen) { 286 memcpy(bp, pfp->data->filespec, (size_t) slen); 287 bp += slen; 288 remain -= (size_t) slen; 289 } 290 } 291 pack_int32((prof_int32)PROF_MAGIC_PROFILE, &bp, &remain); 292 retval = 0; 293 *bufpp = bp; 294 *remainp = remain; 295 } 296 } 297 return(retval); 298 } 299 300 static int unpack_int32(prof_int32 *intp, unsigned char **bufpp, 301 size_t *remainp) 302 { 303 if (*remainp >= sizeof(prof_int32)) { 304 *intp = (((prof_int32) (*bufpp)[0] << 24) | 305 ((prof_int32) (*bufpp)[1] << 16) | 306 ((prof_int32) (*bufpp)[2] << 8) | 307 ((prof_int32) (*bufpp)[3])); 308 *bufpp += sizeof(prof_int32); 309 *remainp -= sizeof(prof_int32); 310 return 0; 311 } 312 else 313 return 1; 314 } 315 316 /*ARGSUSED*/ 317 errcode_t profile_ser_internalize(const char *unused, profile_t *profilep, 318 unsigned char **bufpp, size_t *remainp) 319 { 320 errcode_t retval; 321 unsigned char *bp; 322 size_t remain; 323 int i; 324 prof_int32 fcount, tmp; 325 profile_filespec_t *flist = 0; 326 327 bp = *bufpp; 328 remain = *remainp; 329 330 if (remain >= 12) 331 (void) unpack_int32(&tmp, &bp, &remain); 332 else 333 tmp = 0; 334 335 if (tmp != PROF_MAGIC_PROFILE) { 336 retval = EINVAL; 337 goto cleanup; 338 } 339 340 (void) unpack_int32(&fcount, &bp, &remain); 341 retval = ENOMEM; 342 343 flist = (profile_filespec_t *) malloc(sizeof(profile_filespec_t) * (fcount + 1)); 344 if (!flist) 345 goto cleanup; 346 347 memset(flist, 0, sizeof(char *) * (fcount+1)); 348 for (i=0; i<fcount; i++) { 349 if (!unpack_int32(&tmp, &bp, &remain)) { 350 flist[i] = (char *) malloc((size_t) (tmp+1)); 351 if (!flist[i]) 352 goto cleanup; 353 memcpy(flist[i], bp, (size_t) tmp); 354 flist[i][tmp] = '\0'; 355 bp += tmp; 356 remain -= (size_t) tmp; 357 } 358 } 359 360 if (unpack_int32(&tmp, &bp, &remain) || 361 (tmp != PROF_MAGIC_PROFILE)) { 362 retval = EINVAL; 363 goto cleanup; 364 } 365 366 if ((retval = profile_init((const_profile_filespec_t *) flist, 367 profilep))) 368 goto cleanup; 369 370 *bufpp = bp; 371 *remainp = remain; 372 373 cleanup: 374 if (flist) { 375 for (i=0; i<fcount; i++) { 376 if (flist[i]) 377 free(flist[i]); 378 } 379 free(flist); 380 } 381 return(retval); 382 } 383 384 385 errcode_t 386 profile_get_options_boolean(profile, section, options) 387 profile_t profile; 388 char ** section; 389 profile_options_boolean *options; 390 { 391 char ** actual_section; 392 char * value = NULL; 393 errcode_t retval = 0; 394 int i, max_i; 395 396 for (max_i = 0; section[max_i]; max_i++); 397 if (actual_section = (char **)malloc((max_i + 2) * sizeof(char *))) { 398 for (actual_section[max_i + 1] = NULL, i = 0; section[i]; i++) 399 actual_section[i] = section[i]; 400 401 for (i = 0; options[i].name; i++) { 402 if (options[i].found) continue; 403 actual_section[max_i] = options[i].name; 404 retval = profile_get_value(profile, (const char **) actual_section, 405 (const char **)&value); 406 if (retval && (retval != PROF_NO_RELATION) && 407 (retval != PROF_NO_SECTION)) { 408 free(actual_section); 409 return(retval); 410 } 411 if ((retval == 0) && value) { 412 /* 413 * Any string other than true will turn off the 414 *option 415 */ 416 if (strncmp(value,"true",4) == 0) 417 *(options[i].value) = 1; 418 else 419 *(options[i].value) = 0; 420 options[i].found = 1; 421 422 } 423 } 424 free(actual_section); 425 } else { 426 retval = ENOMEM; 427 } 428 return(retval); 429 } 430 431 errcode_t 432 profile_get_options_string(profile, section, options) 433 profile_t profile; 434 char ** section; 435 profile_option_strings *options; 436 { 437 char ** actual_section; 438 char * value = NULL; 439 errcode_t retval = 0; 440 int i, max_i; 441 442 for (max_i = 0; section[max_i]; max_i++); 443 if (actual_section = (char **)malloc((max_i + 2) * sizeof(char *))) { 444 for (actual_section[max_i + 1] = NULL, i = 0; section[i]; i++) 445 actual_section[i] = section[i]; 446 447 for (i = 0; options[i].name; i++) { 448 if (options[i].found) continue; 449 actual_section[max_i] = options[i].name; 450 retval = profile_get_value(profile, (const char **) actual_section, 451 (const char **)&value); 452 if (retval && (retval != PROF_NO_RELATION) && 453 (retval != PROF_NO_SECTION)) { 454 free(actual_section); 455 return(retval); 456 } 457 if ((retval == 0) && value) { 458 *options[i].value = malloc(strlen(value)+1); 459 if (*options[i].value == 0) 460 retval = ENOMEM; 461 strcpy(*options[i].value, value); 462 options[i].found = 1; 463 } else 464 *options[i].value = 0; 465 } 466 free(actual_section); 467 } else { 468 retval = ENOMEM; 469 } 470 return(retval); 471 } 472