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