1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
24 */
25
26 /*
27 * prof_solaris.c:
28 * Abstracted contract private interfaces for configuring krb5.conf(5).
29 */
30
31 #include <ctype.h>
32 #include "prof_int.h"
33 #include "k5-int.h"
34
35 errcode_t
__profile_iter_name_value(profile_t profile,char * section,char * key,char *** retvals)36 __profile_iter_name_value(profile_t profile, char *section, char *key,
37 char ***retvals)
38 {
39 const char *hierarchy[4];
40 errcode_t code, code2;
41 char *name = NULL, *value = NULL, **ret_values = NULL;
42 void *state = NULL;
43 struct profile_string_list values;
44 boolean_t found = FALSE;
45
46 hierarchy[0] = section;
47 hierarchy[1] = NULL;
48
49 if (code = init_list(&values))
50 return (code);
51
52 code = profile_iterator_create(profile, hierarchy,
53 PROFILE_ITER_LIST_SECTION, &state);
54 while (code == 0) {
55 code = profile_iterator(&state, &name, &value);
56 if (code == 0 && name != NULL) {
57 if ((key == NULL) || (strcmp(value, key) == 0)) {
58 code2 = add_to_list(&values, name);
59 if (code2 != 0) {
60 end_list(&values, &ret_values);
61 profile_free_list(ret_values);
62 code2 = code;
63 goto cleanup;
64 }
65 found = TRUE;
66 }
67 }
68 if (name != NULL) {
69 profile_release_string(name);
70 name = NULL;
71 }
72 if (value != NULL) {
73 profile_release_string(value);
74 value = NULL;
75 }
76 }
77 code = 0;
78 if (found == TRUE)
79 end_list(&values, &ret_values);
80
81 cleanup:
82
83 if (state != NULL)
84 profile_iterator_free(&state);
85 if (name != NULL)
86 profile_release_string(name);
87 if (value != NULL)
88 profile_release_string(value);
89
90 *retvals = ret_values;
91
92 return (code);
93 }
94
95 errcode_t
__profile_get_domain_realm(profile_t profile,char * realm,char *** domains)96 __profile_get_domain_realm(profile_t profile, char *realm, char ***domains)
97 {
98 if (profile == NULL || realm == NULL || domains == NULL)
99 return (EINVAL);
100
101 return (__profile_iter_name_value(profile, "domain_realm", realm,
102 domains));
103 }
104
105 errcode_t
__profile_set_appdefaults(profile_t profile)106 __profile_set_appdefaults(profile_t profile)
107 {
108 const char *hierarchy[4];
109 errcode_t code;
110
111 if (profile == NULL)
112 return (EINVAL);
113
114 hierarchy[0] = "appdefaults";
115 hierarchy[1] = "kinit";
116 hierarchy[3] = NULL;
117
118 hierarchy[2] = "renewable";
119
120 /*
121 * Not fatal if this fails, continue on.
122 */
123 (void) profile_clear_relation(profile, hierarchy);
124
125 code = profile_add_relation(profile, hierarchy, "true");
126 if (code != 0)
127 return (code);
128
129 hierarchy[2] = "forwardable";
130
131 (void) profile_clear_relation(profile, hierarchy);
132
133 code = profile_add_relation(profile, hierarchy, "true");
134
135 return (code);
136 }
137
138 errcode_t
__profile_set_logging(profile_t profile)139 __profile_set_logging(profile_t profile)
140 {
141 const char *hierarchy[4];
142 errcode_t code;
143
144 if (profile == NULL)
145 return (EINVAL);
146
147 hierarchy[0] = "logging";
148 hierarchy[2] = NULL;
149 hierarchy[3] = NULL;
150
151 hierarchy[1] = "default";
152
153 /*
154 * Not fatal if this fails, continue on.
155 */
156 (void) profile_clear_relation(profile, hierarchy);
157
158 code = profile_add_relation(profile, hierarchy,
159 "FILE:/var/krb5/kdc.log");
160 if (code != 0)
161 return (code);
162
163 hierarchy[1] = "kdc";
164
165 (void) profile_clear_relation(profile, hierarchy);
166
167 code = profile_add_relation(profile, hierarchy,
168 "FILE:/var/krb5/kdc.log");
169 if (code != 0)
170 return (code);
171
172 hierarchy[1] = "kdc_rotate";
173
174 hierarchy[2] = "period";
175
176 (void) profile_clear_relation(profile, hierarchy);
177
178 code = profile_add_relation(profile, hierarchy, "1d");
179 if (code != 0)
180 return (code);
181
182 hierarchy[2] = "versions";
183
184 (void) profile_clear_relation(profile, hierarchy);
185
186 code = profile_add_relation(profile, hierarchy, "10");
187
188 return (code);
189 }
190
191 errcode_t
__profile_set_libdefaults(profile_t profile,char * realm)192 __profile_set_libdefaults(profile_t profile, char *realm)
193 {
194 const char *hierarchy[4];
195 errcode_t code;
196
197 if (profile == NULL || realm == NULL)
198 return (EINVAL);
199
200 hierarchy[0] = "libdefaults";
201 hierarchy[1] = "default_realm";
202 hierarchy[2] = NULL;
203
204 /*
205 * Not fatal if this fails, continue on.
206 */
207 (void) profile_clear_relation(profile, hierarchy);
208
209 code = profile_add_relation(profile, hierarchy, realm);
210
211 return (code);
212 }
213
214 errcode_t
__profile_set_kdc(profile_t profile,char * realm,char * kdc,boolean_t overwrite)215 __profile_set_kdc(profile_t profile, char *realm, char *kdc,
216 boolean_t overwrite)
217 {
218 const char *hierarchy[4];
219 errcode_t code;
220
221 if (profile == NULL || realm == NULL || kdc == NULL)
222 return (EINVAL);
223
224 hierarchy[0] = "realms";
225 hierarchy[1] = realm;
226 hierarchy[3] = NULL;
227
228 hierarchy[2] = "kdc";
229
230 if (overwrite == TRUE) {
231 /*
232 * Not fatal if this fails, continue on.
233 */
234 (void) profile_clear_relation(profile, hierarchy);
235 }
236
237 code = profile_add_relation(profile, hierarchy, kdc);
238
239 return (code);
240 }
241
242 /*
243 * errcode_t __profile_release(profile_t profile)
244 *
245 * where profile was the pointer passed back by __profile_init
246 * Note: used to commit the associated profile to the backing store
247 * (e.g. file) and free profile memory
248 * Note: that this function returns an error code which profile_release
249 * does not. With the error code, the application can determine if they
250 * need to free the resulting profile information in memory
251 */
252 errcode_t
__profile_release(profile_t profile)253 __profile_release(profile_t profile)
254 {
255 prf_file_t p, next;
256 errcode_t code;
257
258 if (profile == NULL || profile->magic != PROF_MAGIC_PROFILE)
259 return (EINVAL);
260
261 for (p = profile->first_file; p; p = next) {
262 next = p->next;
263 if ((code = profile_close_file(p)) != 0)
264 return (code);
265 }
266 profile->magic = 0;
267 free(profile);
268
269 return (0);
270 }
271
272 /*
273 * void __profile_abandon(profile_t profile)
274 *
275 * where profile was the pointer passed back by __profile_init
276 * Note: used to free any profile information in memory. Typically can
277 * be used in conjunction with __profile_release upon error
278 */
279 void
__profile_abandon(profile_t profile)280 __profile_abandon(profile_t profile)
281 {
282 profile_abandon(profile);
283 }
284
285 /*
286 * errcode_t __profile_add_domain_mapping(profile_t profile, char *domain,
287 * char *realm)
288 *
289 * where profile was the pointer passed back by __profile_init
290 * where domain is the domain name of the associated realm name
291 * where realm is the corresponding realm name for the domain
292 */
293 errcode_t
__profile_add_domain_mapping(profile_t profile,char * domain,char * realm)294 __profile_add_domain_mapping(profile_t profile, char *domain, char *realm)
295 {
296 const char *hierarchy[4];
297 errcode_t code = 0;
298
299 if (profile == NULL || domain == NULL || realm == NULL)
300 return (EINVAL);
301
302 hierarchy[0] = "domain_realm";
303 hierarchy[1] = domain;
304 hierarchy[2] = NULL;
305
306 /*
307 * Not fatal if relation can't be cleared, continue on.
308 */
309 (void) profile_clear_relation(profile, hierarchy);
310
311 code = profile_add_relation(profile, hierarchy, realm);
312
313 return (code);
314 }
315
316 /*
317 * errcode_t __profile_remove_domain_mapping(profile_t profile, char *realm)
318 *
319 * where profile was the pointer passed back by __profile_init
320 * where domain is the domain name of the associated realm name
321 * where realm is the corresponding realm name for the domain
322 * Note: for the remove function, all matching domain - realm mappings
323 * will be removed for realm
324 */
325 errcode_t
__profile_remove_domain_mapping(profile_t profile,char * realm)326 __profile_remove_domain_mapping(profile_t profile, char *realm)
327 {
328 const char *hierarchy[4];
329 errcode_t code;
330 char **domains = NULL, **domain = NULL;
331
332 if (profile == NULL || realm == NULL)
333 return (EINVAL);
334
335 hierarchy[0] = "domain_realm";
336 hierarchy[1] = NULL;
337 hierarchy[2] = NULL;
338
339 code = __profile_get_domain_realm(profile, realm, &domains);
340 if (code == 0 && domains != NULL) {
341 for (domain = domains; *domain; domain++) {
342 hierarchy[1] = *domain;
343 code = profile_clear_relation(profile, hierarchy);
344 if (code != 0)
345 goto error;
346 }
347 }
348
349 error:
350 if (domains != NULL)
351 profile_free_list(domains);
352
353 return (code);
354 }
355
356 /*
357 * errcode_t __profile_get_realm_entry(profile_t profile, char *realm,
358 * char *name, char ***ret_value)
359 *
360 * where profile was the pointer passed back by __profile_init
361 * where realm is the target realm for lookup
362 * where name is the name in the realm section requested
363 * where value is a string array of any matching values assigned to name.
364 * The array is terminated with a NULL pointer.
365 * Note: if no name has been configured and a profile does exist
366 * then value is set to NULL
367 */
368 errcode_t
__profile_get_realm_entry(profile_t profile,char * realm,char * name,char *** ret_value)369 __profile_get_realm_entry(profile_t profile, char *realm, char *name,
370 char ***ret_value)
371 {
372 const char *hierarchy[4];
373 errcode_t code;
374 char **values = NULL;
375
376 if (profile == NULL || realm == NULL || name == NULL ||
377 ret_value == NULL)
378 return (EINVAL);
379
380 hierarchy[0] = "realms";
381 hierarchy[1] = realm;
382 hierarchy[2] = name;
383 hierarchy[3] = NULL;
384
385 code = profile_get_values(profile, hierarchy, &values);
386 if (code == 0 && values != NULL)
387 *ret_value = values;
388
389 if (code == PROF_NO_RELATION)
390 code = 0;
391
392 return (code);
393 }
394
395 /*
396 * errcode_t __profile_add_realm_entry(profile_t profile, char *realm,
397 * char *name, char **value)
398 *
399 * where profile was the pointer passed back by __profile_init
400 * where realm is the target realm for the name-value pair
401 * where name is the name in the realm subsection to add
402 * where value is a string array values to assigned to name. The array is
403 * terminated with a NULL pointer.
404 * Note: if the realm subsection does no exist then an error is returned
405 * Note: if the name already exists the set is overwritten with the values
406 * passed
407 */
408 errcode_t
__profile_add_realm_entry(profile_t profile,char * realm,char * name,char ** values)409 __profile_add_realm_entry(profile_t profile, char *realm, char *name,
410 char **values)
411 {
412 const char *hierarchy[4];
413 errcode_t code;
414 char **tvalue = NULL;
415
416 if (profile == NULL || realm == NULL || name == NULL || values == NULL)
417 return (EINVAL);
418
419 hierarchy[0] = "realms";
420 hierarchy[1] = realm;
421 hierarchy[2] = name;
422 hierarchy[3] = NULL;
423
424 /*
425 * Not fatal if this fails, continue on.
426 */
427 (void) profile_clear_relation(profile, hierarchy);
428
429 for (tvalue = values; *tvalue; tvalue++) {
430
431 code = profile_add_relation(profile, hierarchy, *tvalue);
432 if (code != 0)
433 return (code);
434 }
435
436 return (0);
437 }
438
439 /*
440 * errcode_t __profile_get_default_realm(profile_t profile, char **realm)
441 *
442 * where profile was the pointer passed back by __profile_init
443 * where realm is the default_realm configured for the system
444 * Note: if no default_realm has been configured and a profile does exist
445 * then realm is set to NULL
446 */
447 errcode_t
__profile_get_default_realm(profile_t profile,char ** realm)448 __profile_get_default_realm(profile_t profile, char **realm)
449 {
450 errcode_t code;
451 char *value = NULL;
452
453 if (profile == NULL || realm == NULL)
454 return (EINVAL);
455
456 code = profile_get_string(profile, "libdefaults", "default_realm", 0, 0,
457 &value);
458 if (code == 0 && value != NULL)
459 *realm = value;
460
461 if (code == PROF_NO_RELATION)
462 code = 0;
463
464 return (code);
465 }
466
467 /*
468 * errcode_t __profile_get_realms(profile_t profile, char ***realms)
469 *
470 * where profile was the pointer passed back by __profile_init
471 * where realms is a string array of realm names currently configured.
472 * The array is terminated with a NULL pointer.
473 * Note: if no realms have been configured and a profile does exist then
474 * realms is set to NULL
475 */
476 errcode_t
__profile_get_realms(profile_t profile,char *** realms)477 __profile_get_realms(profile_t profile, char ***realms)
478 {
479
480 if (profile == NULL || realms == NULL)
481 return (EINVAL);
482
483 return (__profile_iter_name_value(profile, "realms", NULL, realms));
484 }
485
486 /*
487 * errcode_t __profile_add_realm(profile_t profile, char *realm,
488 * char *master, char **kdcs, boolean_t set_change, boolean_t
489 * default_realm)
490 *
491 * where profile was the pointer passed back by __profile_init
492 * where realm is the realm name associated with the configuration
493 * where master is the server that is assigned to admin_server
494 * where kdcs is a string array of KDCs used to populate the kdc set.
495 * The array is terminated with a NULL pointer.
496 * where set_change, if set, will use the SET_CHANGE protocol for password
497 * modifications. RPCSEC_GSS is set by default
498 * where default_realm, if set, will assign the realm to default_realm
499 * Note: the ordering of kdcs is determined by the server's position in the
500 * array
501 * Note: kdcs must be assigned a value, even if it is the same value as the
502 * master.
503 */
504 errcode_t
__profile_add_realm(profile_t profile,char * realm,char * master,char ** kdcs,boolean_t set_change,boolean_t default_realm)505 __profile_add_realm(profile_t profile, char *realm, char *master, char **kdcs,
506 boolean_t set_change, boolean_t default_realm)
507 {
508 const char *hierarchy[4];
509 errcode_t code;
510 boolean_t ow = TRUE;
511 char **tkdcs;
512
513 if (profile == NULL || realm == NULL || master == NULL || kdcs == NULL)
514 return (EINVAL);
515
516 /*
517 * Sets the default realm to realm if default_realm flag is set.
518 */
519 if (default_realm == TRUE) {
520 if (code = __profile_set_libdefaults(profile, realm))
521 return (code);
522 }
523
524 hierarchy[0] = "realms";
525 hierarchy[1] = realm;
526 hierarchy[3] = NULL;
527
528 hierarchy[2] = "admin_server";
529
530 /*
531 * Not fatal if this fails, therefore return code is not checked.
532 */
533 (void) profile_clear_relation(profile, hierarchy);
534
535 if (code = profile_add_relation(profile, hierarchy, master))
536 return (code);
537
538 /*
539 * If not set then defaults to undefined, which defaults to RPCSEC_GSS.
540 */
541 if (set_change == TRUE) {
542 hierarchy[2] = "kpasswd_protocol";
543
544 (void) profile_clear_relation(profile, hierarchy);
545
546 code = profile_add_relation(profile, hierarchy, "SET_CHANGE");
547 if (code != 0)
548 return (code);
549 }
550
551 for (tkdcs = kdcs; *tkdcs; tkdcs++) {
552 if (code = __profile_set_kdc(profile, realm, *tkdcs, ow))
553 return (code);
554 ow = FALSE;
555 }
556
557 code = __profile_set_logging(profile);
558 if (code != 0)
559 return (code);
560
561 code = __profile_set_appdefaults(profile);
562
563 return (code);
564 }
565
566 /*
567 * errcode_t __profile_remove_xrealm_mapping(profile_t profile, char *realm)
568 *
569 * where profile was the pointer passed back by __profile_init
570 * where source is the source realm for the capath
571 * where target is the target realm for the capath
572 * where inter is the intermediate realm between the source and target
573 * realms. If the source and target share x-realm keys then this set to "."
574 * Note: for the remove function, all associated source, target, and
575 * intermediate entries will be removed matching the realm name
576 */
577 errcode_t
__profile_remove_xrealm_mapping(profile_t profile,char * realm)578 __profile_remove_xrealm_mapping(profile_t profile, char *realm)
579 {
580 const char *hierarchy[4];
581 errcode_t code, code2, code3;
582 void *state = NULL, *state2 = NULL;
583 char *source = NULL, *dummy_val = NULL, *target = NULL;
584 char *inter = NULL;
585
586 if (profile == NULL || realm == NULL)
587 return (EINVAL);
588
589 hierarchy[0] = "capaths";
590 hierarchy[1] = realm;
591 hierarchy[2] = NULL;
592 hierarchy[3] = NULL;
593
594 /*
595 * Not fatal if this fails, continue on.
596 */
597 code = profile_rename_section(profile, hierarchy, NULL);
598
599 hierarchy[1] = NULL;
600 code = profile_iterator_create(profile, hierarchy,
601 PROFILE_ITER_LIST_SECTION, &state);
602 while (code == 0) {
603 code = profile_iterator(&state, &source, &dummy_val);
604 if (code == 0 && source != NULL) {
605 hierarchy[1] = source;
606 code2 = profile_iterator_create(profile, hierarchy,
607 PROFILE_ITER_LIST_SECTION, &state2);
608 while (code2 == 0) {
609 code2 = profile_iterator(&state2, &target,
610 &inter);
611 if (code2 == 0 && target != NULL &&
612 inter != NULL) {
613 if (strcmp(realm, target) == 0 ||
614 strcmp(realm, inter) == 0) {
615 hierarchy[2] = target;
616 code3 =
617 profile_clear_relation(
618 profile, hierarchy);
619 if (code3 != 0) {
620 code = code3;
621 goto error;
622 }
623 }
624 }
625 if (target != NULL) {
626 profile_release_string(target);
627 target = NULL;
628 }
629 if (inter != NULL) {
630 profile_release_string(inter);
631 inter = NULL;
632 }
633 }
634 }
635 if (source != NULL) {
636 profile_release_string(source);
637 source = NULL;
638 }
639 if (dummy_val != NULL) {
640 profile_release_string(dummy_val);
641 dummy_val = NULL;
642 }
643 }
644 code = 0;
645
646 error:
647 if (state != NULL)
648 profile_iterator_free(&state);
649 if (state2 != NULL)
650 profile_iterator_free(&state2);
651 if (target != NULL)
652 profile_release_string(target);
653 if (inter != NULL)
654 profile_release_string(inter);
655 if (source != NULL)
656 profile_release_string(source);
657 if (dummy_val != NULL)
658 profile_release_string(dummy_val);
659
660 return (code);
661 }
662
663 /*
664 * errcode_t __profile_remove_realm(profile_t profile, char *realm)
665 *
666 * where profile was the pointer passed back by __profile_init
667 * where realm is the target realm for removal
668 * Note: the function removes the matching realm in the realms section,
669 * the default_realm, relevant domain_realm mappings with the realm name,
670 * and matching capaths source realm subsection.
671 */
672 errcode_t
__profile_remove_realm(profile_t profile,char * realm)673 __profile_remove_realm(profile_t profile, char *realm)
674 {
675 const char *hierarchy[4];
676 errcode_t code;
677 char *drealm = NULL;
678
679 if (profile == NULL || realm == NULL)
680 return (EINVAL);
681
682 /*
683 * Remove the default realm.
684 */
685 hierarchy[0] = "libdefaults";
686 hierarchy[1] = "default_realm";
687 hierarchy[2] = NULL;
688
689 code = __profile_get_default_realm(profile, &drealm);
690 if (code != 0)
691 return (code);
692 else if (drealm != NULL) {
693 if (strcmp(drealm, realm) == 0) {
694 code = profile_clear_relation(profile, hierarchy);
695 if (code != 0) {
696 free(drealm);
697 return (code);
698 }
699 }
700 free(drealm);
701 }
702
703 hierarchy[0] = "realms";
704 hierarchy[1] = realm;
705 hierarchy[2] = NULL;
706
707 code = profile_rename_section(profile, hierarchy, NULL);
708 if (code != 0)
709 return (code);
710
711 code = __profile_remove_domain_mapping(profile, realm);
712 if (code != 0)
713 return (code);
714
715 code = __profile_remove_xrealm_mapping(profile, realm);
716 if (code != 0)
717 return (code);
718
719 /*
720 * Not fatal even if realm wasn't available to remove.
721 */
722 return (0);
723 }
724
725 /*
726 * errcode_t __profile_add_xrealm_mapping(profile_t profile, char *source,
727 * char *target, char *inter)
728 *
729 * where profile was the pointer passed back by __profile_init
730 * where source is the source realm for the capath
731 * where target is the target realm for the capath
732 * where inter is the intermediate realm between the source and target
733 * realms. If the source and target share x-realm keys then this set to "."
734 * Note: if the section does not exist one will be created
735 */
736 errcode_t
__profile_add_xrealm_mapping(profile_t profile,char * source,char * target,char * inter)737 __profile_add_xrealm_mapping(profile_t profile, char *source, char *target,
738 char *inter)
739 {
740 const char *hierarchy[4];
741 errcode_t code;
742
743 if (profile == NULL || source == NULL || target == NULL ||
744 inter == NULL)
745 return (EINVAL);
746
747 hierarchy[0] = "capaths";
748 hierarchy[1] = source;
749 hierarchy[2] = target;
750 hierarchy[3] = NULL;
751
752 /*
753 * Not fatal if this fails, continue on.
754 */
755 (void) profile_clear_relation(profile, hierarchy);
756
757 code = profile_add_relation(profile, hierarchy, inter);
758
759 return (code);
760 }
761
762 /*
763 * errcode_t __profile_validate(profile_t profile, int *val_err, char **val)
764 *
765 * where profile was the pointer passed back by __profile_init
766 * where val_err is a function specific error code of the following values:
767 * 0 No errors detected in profile
768 * 1 default realm is in lower-case (val returns realm)
769 * 2 realm in realms section is in lower-case (val returns realm)
770 * 3 default realm is not found in realms section
771 * (val returns realm not found)
772 * 4 default realm does not exist
773 * 5 no realm found in realms section
774 * 6 no domain realm mapping entry found corresponding to a realm
775 * in the realms section (val returns realm name)
776 * 7 kdc relation-value does not exist in realm
777 * (val returns realm name)
778 * 8 admin_server relation-value does not exist in realm
779 * (val returns realm name)
780 * where val is the associated errant value, associated with val_err. This
781 * value is returned as is from the profile
782 * Note: function infers the following:
783 * 1. REALM should be in upper-case
784 * 2. all required entries are present
785 * 3. all relations are defined between default realm, realm, and
786 * domain - realm mappings
787 *
788 * Note: The return value of this function is based on the error code returned
789 * by the framework/mechanism. The function could return zero with the
790 * validation error code set to non-zero if the profile is invalid in any way.
791 *
792 * Caution: This function could return false positives on valid
793 * configurations and should only be used by the CIFS team for
794 * specific purposes.
795 */
796 errcode_t
__profile_validate(profile_t profile,int * val_err,char ** val)797 __profile_validate(profile_t profile, int *val_err, char **val)
798 {
799 errcode_t code;
800 int c;
801 boolean_t found = FALSE;
802 char *default_realm = NULL, **realms = NULL, *tr = NULL;
803 char **trealms = NULL, **domains = NULL, **ret_vals = NULL;
804
805 if (profile == NULL || val_err == NULL || val == NULL)
806 return (EINVAL);
807
808 *val_err = 0;
809 *val = NULL;
810
811 code = __profile_get_default_realm(profile, &default_realm);
812 if (code == 0 && default_realm != NULL) {
813 tr = default_realm;
814
815 while ((c = *tr++) != 0) {
816 if (islower(c)) {
817 *val_err = 1;
818 *val = strdup(default_realm);
819 if (*val == NULL)
820 code = ENOMEM;
821 goto cleanup;
822 }
823 }
824 } else if (code == 0 && default_realm == NULL) {
825 *val_err = 4;
826 goto cleanup;
827 } else
828 goto cleanup;
829
830 code = __profile_get_realms(profile, &realms);
831 if (code == 0 && realms != NULL) {
832 for (trealms = realms; *trealms; trealms++) {
833
834 tr = *trealms;
835 while ((c = *tr++) != 0) {
836 if (islower(c)) {
837 *val_err = 2;
838 *val = strdup(*trealms);
839 if (*val == NULL)
840 code = ENOMEM;
841 goto cleanup;
842 }
843 }
844
845 if (strcmp(default_realm, *trealms) == 0)
846 found = TRUE;
847
848 code = __profile_get_domain_realm(profile, *trealms,
849 &domains);
850 if (code == 0 && domains != NULL) {
851 profile_free_list(domains);
852 domains = NULL;
853 } else if (code == 0 && domains == NULL) {
854 *val_err = 6;
855 *val = strdup(*trealms);
856 if (*val == NULL)
857 code = ENOMEM;
858 goto cleanup;
859 } else
860 goto cleanup;
861
862 code = __profile_get_realm_entry(profile, *trealms,
863 "kdc", &ret_vals);
864 if (code == 0 && ret_vals != NULL) {
865 profile_free_list(ret_vals);
866 ret_vals = NULL;
867 } else if (code == 0 && ret_vals == NULL) {
868 *val_err = 7;
869 *val = strdup(*trealms);
870 if (*val == NULL)
871 code = ENOMEM;
872 goto cleanup;
873 } else
874 goto cleanup;
875
876 code = __profile_get_realm_entry(profile, *trealms,
877 "admin_server", &ret_vals);
878 if (code == 0 && ret_vals != NULL) {
879 profile_free_list(ret_vals);
880 ret_vals = NULL;
881 } else if (code == 0 && ret_vals == NULL) {
882 *val_err = 8;
883 *val = strdup(*trealms);
884 if (*val == NULL)
885 code = ENOMEM;
886 goto cleanup;
887 } else
888 goto cleanup;
889 }
890
891 if (found == FALSE) {
892 *val_err = 3;
893 *val = strdup(default_realm);
894 if (*val == NULL)
895 code = ENOMEM;
896 goto cleanup;
897 }
898 } else if (code == 0 && realms == NULL)
899 *val_err = 5;
900
901 cleanup:
902
903 if (realms != NULL)
904 profile_free_list(realms);
905 if (ret_vals != NULL)
906 profile_free_list(ret_vals);
907 if (default_realm != NULL)
908 profile_release_string(default_realm);
909 if (domains != NULL)
910 profile_free_list(domains);
911
912 return (code);
913 }
914
915 /*
916 * errcode_t __profile_init(char *filename, profile_t *profile)
917 *
918 * where filename is the specified profile location. If filename is NULL
919 * then function uses the system default name, /etc/krb5/krb5.conf
920 * where profile is pointer passed to caller upon success
921 * Note: if the file does not exist then one will be created
922 * Note: if the file does exist then any existing profile information will
923 * be in profile
924 * Note: profile_release() should be used by the caller to free profile
925 */
926 errcode_t
__profile_init(char * filename,profile_t * profile)927 __profile_init(char *filename, profile_t *profile)
928 {
929 profile_filespec_t *filenames = NULL;
930 krb5_error_code ret = 0;
931 errcode_t code = 0;
932 int err = 0, fd;
933 mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
934
935 if (profile == NULL)
936 return (EINVAL);
937
938 if (filename != NULL) {
939 filenames = malloc(2 * sizeof (char *));
940 if (filenames == NULL)
941 return (ENOMEM);
942 filenames[0] = strdup(filename);
943 if (filenames[0] == NULL) {
944 free(filenames);
945 return (ENOMEM);
946 }
947 filenames[1] = NULL;
948 } else {
949 ret = krb5_get_default_config_files(&filenames);
950 if (ret != 0)
951 return (ret);
952 }
953
954 /*
955 * If file does not exist then create said file.
956 */
957 fd = open(*filenames, O_RDWR|O_CREAT|O_NOFOLLOW|O_NOLINKS, mode);
958 if (fd < 0) {
959 err = errno;
960 krb5_free_config_files(filenames);
961 return (err);
962 } else
963 close(fd);
964
965 /*
966 * Specify non-null for specific file (to load any existing profile)
967 */
968 code = profile_init((const_profile_filespec_t *)filenames, profile);
969
970 krb5_free_config_files(filenames);
971
972 return (code);
973 }
974