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