1 #pragma ident "%Z%%M% %I% %E% SMI" 2 /* 3 * prof_get.c --- routines that expose the public interfaces for 4 * querying items from the profile. 5 * 6 */ 7 8 #include "prof_int.h" 9 #include <stdio.h> 10 #include <string.h> 11 #ifdef HAVE_STDLIB_H 12 #include <stdlib.h> 13 #endif 14 #include <errno.h> 15 #include <limits.h> 16 17 /* 18 * These functions --- init_list(), end_list(), and add_to_list() are 19 * internal functions used to build up a null-terminated char ** list 20 * of strings to be returned by functions like profile_get_values. 21 * 22 * The profile_string_list structure is used for internal booking 23 * purposes to build up the list, which is returned in *ret_list by 24 * the end_list() function. 25 * 26 * The publicly exported interface for freeing char** list is 27 * profile_free_list(). 28 */ 29 30 struct profile_string_list { 31 char **list; 32 int num; 33 int max; 34 }; 35 36 /* 37 * Initialize the string list abstraction. 38 */ 39 static errcode_t init_list(struct profile_string_list *list) 40 { 41 list->num = 0; 42 list->max = 10; 43 list->list = (char **) malloc(list->max * sizeof(char *)); 44 if (list->list == 0) 45 return ENOMEM; 46 list->list[0] = 0; 47 return 0; 48 } 49 50 /* 51 * Free any memory left over in the string abstraction, returning the 52 * built up list in *ret_list if it is non-null. 53 */ 54 static void end_list(struct profile_string_list *list, char ***ret_list) 55 { 56 char **cp; 57 58 if (list == 0) 59 return; 60 61 if (ret_list) { 62 *ret_list = list->list; 63 return; 64 } else { 65 for (cp = list->list; *cp; cp++) 66 free(*cp); 67 free(list->list); 68 } 69 list->num = list->max = 0; 70 list->list = 0; 71 } 72 73 /* 74 * Add a string to the list. 75 */ 76 static errcode_t add_to_list(struct profile_string_list *list, const char *str) 77 { 78 char *newstr, **newlist; 79 int newmax; 80 81 if (list->num+1 >= list->max) { 82 newmax = list->max + 10; 83 newlist = (char **) realloc(list->list, newmax * sizeof(char *)); 84 if (newlist == 0) 85 return ENOMEM; 86 list->max = newmax; 87 list->list = newlist; 88 } 89 newstr = (char *) malloc(strlen(str)+1); 90 if (newstr == 0) 91 return ENOMEM; 92 strcpy(newstr, str); 93 94 list->list[list->num++] = newstr; 95 list->list[list->num] = 0; 96 return 0; 97 } 98 99 /* 100 * Return TRUE if the string is already a member of the list. 101 */ 102 static int is_list_member(struct profile_string_list *list, const char *str) 103 { 104 char **cpp; 105 106 if (!list->list) 107 return 0; 108 109 for (cpp = list->list; *cpp; cpp++) { 110 if (!strcmp(*cpp, str)) 111 return 1; 112 } 113 return 0; 114 } 115 116 /* 117 * This function frees a null-terminated list as returned by 118 * profile_get_values. 119 */ 120 void KRB5_CALLCONV profile_free_list(char **list) 121 { 122 char **cp; 123 124 if (list == 0) 125 return; 126 127 for (cp = list; *cp; cp++) 128 free(*cp); 129 free(list); 130 } 131 132 errcode_t KRB5_CALLCONV 133 profile_get_values(profile_t profile, const char *const *names, 134 char ***ret_values) 135 { 136 errcode_t retval; 137 void *state; 138 char *value; 139 struct profile_string_list values; 140 141 if ((retval = profile_node_iterator_create(profile, names, 142 PROFILE_ITER_RELATIONS_ONLY, 143 &state))) 144 return retval; 145 146 if ((retval = init_list(&values))) 147 return retval; 148 149 do { 150 if ((retval = profile_node_iterator(&state, 0, 0, &value))) 151 goto cleanup; 152 if (value) 153 add_to_list(&values, value); 154 } while (state); 155 156 if (values.num == 0) { 157 retval = PROF_NO_RELATION; 158 goto cleanup; 159 } 160 161 end_list(&values, ret_values); 162 return 0; 163 164 cleanup: 165 end_list(&values, (char ***)NULL); 166 return retval; 167 } 168 169 /* 170 * This function only gets the first value from the file; it is a 171 * helper function for profile_get_string, profile_get_integer, etc. 172 */ 173 errcode_t profile_get_value(profile_t profile, const char **names, 174 const char **ret_value) 175 { 176 errcode_t retval; 177 void *state; 178 char *value; 179 180 if ((retval = profile_node_iterator_create(profile, names, 181 PROFILE_ITER_RELATIONS_ONLY, 182 &state))) 183 return retval; 184 185 if ((retval = profile_node_iterator(&state, 0, 0, &value))) 186 goto cleanup; 187 188 if (value) 189 *ret_value = value; 190 else 191 retval = PROF_NO_RELATION; 192 193 cleanup: 194 profile_node_iterator_free(&state); 195 return retval; 196 } 197 198 errcode_t KRB5_CALLCONV 199 profile_get_string(profile_t profile, const char *name, const char *subname, 200 const char *subsubname, const char *def_val, 201 char **ret_string) 202 { 203 const char *value; 204 errcode_t retval; 205 const char *names[4]; 206 207 if (profile) { 208 names[0] = name; 209 names[1] = subname; 210 names[2] = subsubname; 211 names[3] = 0; 212 retval = profile_get_value(profile, names, &value); 213 if (retval == PROF_NO_SECTION || retval == PROF_NO_RELATION) 214 value = def_val; 215 else if (retval) 216 return retval; 217 } else 218 value = def_val; 219 220 if (value) { 221 *ret_string = (char *) malloc(strlen(value)+1); 222 if (*ret_string == 0) 223 return ENOMEM; 224 strcpy(*ret_string, value); 225 } else 226 *ret_string = 0; 227 return 0; 228 } 229 230 errcode_t KRB5_CALLCONV 231 profile_get_integer(profile_t profile, const char *name, const char *subname, 232 const char *subsubname, int def_val, int *ret_int) 233 { 234 const char *value; 235 errcode_t retval; 236 const char *names[4]; 237 char *end_value; 238 long ret_long; 239 240 *ret_int = def_val; 241 if (profile == 0) 242 return 0; 243 244 names[0] = name; 245 names[1] = subname; 246 names[2] = subsubname; 247 names[3] = 0; 248 retval = profile_get_value(profile, names, &value); 249 if (retval == PROF_NO_SECTION || retval == PROF_NO_RELATION) { 250 *ret_int = def_val; 251 return 0; 252 } else if (retval) 253 return retval; 254 255 if (value[0] == 0) 256 /* Empty string is no good. */ 257 return PROF_BAD_INTEGER; 258 errno = 0; 259 ret_long = strtol (value, &end_value, 10); 260 261 /* Overflow or underflow. */ 262 if ((ret_long == LONG_MIN || ret_long == LONG_MAX) && errno != 0) 263 return PROF_BAD_INTEGER; 264 /* Value outside "int" range. */ 265 if ((long) (int) ret_long != ret_long) 266 return PROF_BAD_INTEGER; 267 /* Garbage in string. */ 268 if (end_value != value + strlen (value)) 269 return PROF_BAD_INTEGER; 270 271 272 *ret_int = ret_long; 273 return 0; 274 } 275 276 static const char *const conf_yes[] = { 277 "y", "yes", "true", "t", "1", "on", 278 0, 279 }; 280 281 static const char *const conf_no[] = { 282 "n", "no", "false", "nil", "0", "off", 283 0, 284 }; 285 286 static errcode_t 287 profile_parse_boolean(const char *s, int *ret_boolean) 288 { 289 const char *const *p; 290 291 if (ret_boolean == NULL) 292 return PROF_EINVAL; 293 294 for(p=conf_yes; *p; p++) { 295 if (!strcasecmp(*p,s)) { 296 *ret_boolean = 1; 297 return 0; 298 } 299 } 300 301 for(p=conf_no; *p; p++) { 302 if (!strcasecmp(*p,s)) { 303 *ret_boolean = 0; 304 return 0; 305 } 306 } 307 308 return PROF_BAD_BOOLEAN; 309 } 310 311 errcode_t KRB5_CALLCONV 312 profile_get_boolean(profile_t profile, const char *name, const char *subname, 313 const char *subsubname, int def_val, int *ret_boolean) 314 { 315 const char *value; 316 errcode_t retval; 317 const char *names[4]; 318 319 if (profile == 0) { 320 *ret_boolean = def_val; 321 return 0; 322 } 323 324 names[0] = name; 325 names[1] = subname; 326 names[2] = subsubname; 327 names[3] = 0; 328 retval = profile_get_value(profile, names, &value); 329 if (retval == PROF_NO_SECTION || retval == PROF_NO_RELATION) { 330 *ret_boolean = def_val; 331 return 0; 332 } else if (retval) 333 return retval; 334 335 return profile_parse_boolean (value, ret_boolean); 336 } 337 338 /* 339 * This function will return the list of the names of subections in the 340 * under the specified section name. 341 */ 342 errcode_t KRB5_CALLCONV 343 profile_get_subsection_names(profile_t profile, const char **names, 344 char ***ret_names) 345 { 346 errcode_t retval; 347 void *state; 348 char *name; 349 struct profile_string_list values; 350 351 if ((retval = profile_node_iterator_create(profile, names, 352 PROFILE_ITER_LIST_SECTION | PROFILE_ITER_SECTIONS_ONLY, 353 &state))) 354 return retval; 355 356 if ((retval = init_list(&values))) 357 return retval; 358 359 do { 360 if ((retval = profile_node_iterator(&state, 0, &name, 0))) 361 goto cleanup; 362 if (name) 363 add_to_list(&values, name); 364 } while (state); 365 366 end_list(&values, ret_names); 367 return 0; 368 369 cleanup: 370 end_list(&values, (char ***)NULL); 371 return retval; 372 } 373 374 /* 375 * This function will return the list of the names of relations in the 376 * under the specified section name. 377 */ 378 errcode_t KRB5_CALLCONV 379 profile_get_relation_names(profile_t profile, const char **names, 380 char ***ret_names) 381 { 382 errcode_t retval; 383 void *state; 384 char *name; 385 struct profile_string_list values; 386 387 if ((retval = profile_node_iterator_create(profile, names, 388 PROFILE_ITER_LIST_SECTION | PROFILE_ITER_RELATIONS_ONLY, 389 &state))) 390 return retval; 391 392 if ((retval = init_list(&values))) 393 return retval; 394 395 do { 396 if ((retval = profile_node_iterator(&state, 0, &name, 0))) 397 goto cleanup; 398 if (name && !is_list_member(&values, name)) 399 add_to_list(&values, name); 400 } while (state); 401 402 end_list(&values, ret_names); 403 return 0; 404 405 cleanup: 406 end_list(&values, (char ***)NULL); 407 return retval; 408 } 409 410 errcode_t KRB5_CALLCONV 411 profile_iterator_create(profile_t profile, const char *const *names, int flags, 412 void **ret_iter) 413 { 414 return profile_node_iterator_create(profile, names, flags, ret_iter); 415 } 416 417 void KRB5_CALLCONV 418 profile_iterator_free(void **iter_p) 419 { 420 profile_node_iterator_free(iter_p); 421 } 422 423 errcode_t KRB5_CALLCONV 424 profile_iterator(void **iter_p, char **ret_name, char **ret_value) 425 { 426 char *name, *value; 427 errcode_t retval; 428 429 retval = profile_node_iterator(iter_p, 0, &name, &value); 430 if (retval) 431 return retval; 432 433 if (ret_name) { 434 if (name) { 435 *ret_name = (char *) malloc(strlen(name)+1); 436 if (!*ret_name) 437 return ENOMEM; 438 strcpy(*ret_name, name); 439 } else 440 *ret_name = 0; 441 } 442 if (ret_value) { 443 if (value) { 444 *ret_value = (char *) malloc(strlen(value)+1); 445 if (!*ret_value) { 446 if (ret_name) { 447 free(*ret_name); 448 *ret_name = 0; 449 } 450 return ENOMEM; 451 } 452 strcpy(*ret_value, value); 453 } else 454 *ret_value = 0; 455 } 456 return 0; 457 } 458 459 void KRB5_CALLCONV 460 profile_release_string(char *str) 461 { 462 free(str); 463 } 464