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