import less(1)
[unleashed/tickless.git] / usr / src / lib / libc / port / nsl / nis_sec_mechs.c
blob6828c8c9b24a0c3a9052348ffd5e75c130f30bdc
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
23 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
28 * This module contains the interfaces for the NIS+ security mechanisms.
31 #include "mt.h"
32 #include <ctype.h>
33 #include <stdlib.h>
34 #include <stdio.h>
35 #include <strings.h>
36 #include <rpc/rpc.h>
37 #include <netconfig.h>
38 #include <sys/types.h>
39 #include <sys/stat.h>
40 #include <sys/file.h>
41 #include <thread.h>
42 #include <synch.h>
43 #include <dlfcn.h>
44 #include <rpcsvc/nis_dhext.h>
48 * NIS+ security file
51 #define NIS_SEC_CF_MAX_LINELEN 512
53 /* the min number of fields allowable per line */
54 #define NIS_SEC_CF_MIN_FIELDS 5
55 /* the max number of fields processed per line */
56 #define NIS_SEC_CF_MAX_FIELDS 7
58 /* field "Not Applicable" char */
59 #define NIS_SEC_CF_NA_CHAR '-'
60 #define NIS_SEC_CF_NA_CMP(a) ((a)[0] == NIS_SEC_CF_NA_CHAR && (a)[1] == '\0')
63 static const char *cf_entry_type_mech_str = "mech";
64 static const char *cf_mech_des_str = NIS_SEC_CF_DES_ALIAS;
65 static const char *cf_mech_dh1920_str = "dh192-0";
67 static const char *cf_secserv_default_str = "default";
68 static const char *cf_secserv_none_str = "none";
69 static const char *cf_secserv_integrity_str = "integrity";
70 static const char *cf_secserv_privacy_str = "privacy";
72 static mutex_t nis_sec_cf_lock = DEFAULTMUTEX;
76 * GSS mechanisms file
78 * This is currently a private NIS+ interface but at some point in the future
79 * can be broken out and made available to other apps that need to access
80 * GSS backends.
83 #define MF_MAX_LINELEN 256
84 #define MF_MAX_FLDLEN MAXDHNAME
86 /* mech file entry type */
87 typedef struct {
88 char *mechname;
89 char *oid;
90 char *libname;
91 /* the 4th field is not used by user land apps */
92 } mfent_t;
94 static const char mech_file[] = "/etc/gss/mech";
95 static const int mech_file_flds_max = 3;
96 static const int mech_file_flds_min = 3;
97 static mutex_t mech_file_lock = DEFAULTMUTEX;
98 static const char dh_str[] = "diffie_hellman";
101 #define MECH_LIB_PREFIX1 "/usr/lib/"
103 #ifdef _LP64
105 #define MECH_LIB_PREFIX2 "64/"
107 #else /* _LP64 */
109 #define MECH_LIB_PREFIX2 ""
111 #endif /* _LP64 */
113 #define MECH_LIB_DIR "gss/"
115 #define MECH_LIB_PREFIX MECH_LIB_PREFIX1 MECH_LIB_PREFIX2 MECH_LIB_DIR
118 static void
119 list_free_all(void (*free_ent)(), void **mpp)
121 void **tpp = mpp;
123 if (tpp) {
124 for (; *tpp; tpp++)
125 (*free_ent)(*tpp);
126 free(mpp);
130 static void **
131 list_append_ent(void *ent, void **list, uint_t cnt, void (*free_ent)())
133 void **new_l;
135 if (!(new_l = reallocarray(list, cnt + 1, sizeof (*list)))) {
136 list_free_all(free_ent, list);
137 return (NULL);
139 *(new_l + cnt - 1) = ent;
140 *(new_l + cnt) = NULL;
142 return (new_l);
145 static void **
146 list_copy(void *(*cp_ent)(), void **mpp)
148 void **tpp_h;
149 void **tpp;
150 void *tp;
151 int diff;
153 if (!mpp)
154 return (NULL);
156 for (tpp = mpp; *tpp; tpp++)
159 diff = tpp - mpp;
161 if (!(tpp_h = calloc(diff + 1, sizeof (*mpp))))
162 return (NULL);
164 for (tpp = tpp_h; *mpp; mpp++) {
165 if (!(tp = (*cp_ent)(*mpp))) {
166 free(tpp_h);
167 return (NULL);
169 *tpp++ = tp;
172 return (tpp_h);
175 static char *
176 nextline(fd, line)
177 FILE *fd;
178 char *line;
180 char *cp;
182 if (fgets(line, NIS_SEC_CF_MAX_LINELEN, fd) == NULL)
183 return (NULL);
184 cp = index(line, '\n');
185 if (cp)
186 *cp = '\0';
187 return (line);
190 static int
191 nextfield(char **cpp, char *op, int n)
194 intptr_t max;
195 char *dst = op;
196 char *cp = *cpp;
198 while (*cp == ' ' || *cp == '\t')
199 cp++;
200 if (*cp == '\0' || *cp == '#')
201 return (0);
203 max = (intptr_t)op + n;
204 while (*cp && *cp != ' ' && *cp != '\t' && *cp != '#' &&
205 (intptr_t)dst < max)
206 *dst++ = *cp++;
207 *dst = '\0';
209 if ((intptr_t)dst >= max)
210 /* not much else to do but move past current field */
211 while (*cp && *cp != ' ' && *cp != '\t' && *cp != '#')
212 cp++;
214 *cpp = cp;
216 return (1);
220 static rpc_gss_service_t
221 str_to_secserv_t(const char *s)
224 if (s) {
225 if (strncmp(cf_secserv_none_str, s,
226 strlen(cf_secserv_none_str)) == 0)
227 return (rpc_gss_svc_none);
228 if (strncmp(cf_secserv_integrity_str, s,
229 strlen(cf_secserv_integrity_str)) == 0)
230 return (rpc_gss_svc_integrity);
231 if (strncmp(cf_secserv_privacy_str, s,
232 strlen(cf_secserv_privacy_str)) == 0)
233 return (rpc_gss_svc_privacy);
236 return (rpc_gss_svc_default);
240 * Return TRUE if all the chars up to the NUL are of the digit type.
241 * Else return FALSE.
243 static bool_t
244 isnumberstr(const char *s)
247 for (; *s; s++)
248 if (!isdigit(*s))
249 return (FALSE);
251 return (TRUE);
255 * Free security file mechanism entry.
257 static void
258 sf_free_mech_ent(mechanism_t *mp)
260 if (mp) {
261 free(mp->mechname);
262 free(mp->alias);
263 free(mp->qop);
264 free(mp);
268 static void
269 free_fields(char **cpp, int cnt)
271 char **tpp = cpp;
273 if (cpp) {
274 if (cnt)
275 for (; cnt > 0; cnt--, tpp++)
276 if (*tpp)
277 free(*tpp);
278 else
279 break;
280 free(cpp);
285 * Generic parse-linestr-of-config-file routine. Arg linep is ptr
286 * (which will be modified) to the input string . Arg minflds is the
287 * minimum number of fields expected. Arg maxflds is the max number
288 * of fields that will be parsed. Arg bufsiz is the max len of each
289 * field that will be copied to the return area.
291 * If there are less fields in the entry than the max number,
292 * the remainding ptrs will be 0.
294 * Returns a ptr to an array of ptrs to strings on success else
295 * NULL on failure.
297 * The caller must free the storage (of a successful return only).
299 static char **
300 parse_line(char *linep, int minflds, int maxflds, int bufsiz)
302 char **fpp = calloc(maxflds, sizeof (linep));
303 char **tpp = fpp;
304 char *cp;
305 int i;
307 if (!fpp)
308 return (NULL);
310 if (!(cp = malloc(bufsiz))) {
311 free(fpp);
312 return (NULL);
315 for (i = 0; i < maxflds; i++, tpp++) {
316 char *tp;
317 if (!nextfield(&linep, cp, bufsiz)) {
318 free(cp);
319 if (i < minflds) {
320 free_fields(fpp, i);
321 return (NULL);
322 } else
323 return (fpp);
325 if (!(tp = strdup(cp))) {
326 free_fields(fpp, i);
327 free(cp);
328 return (NULL);
330 *tpp = tp;
333 free(cp);
334 return (fpp);
338 * Return a ptr to a mechanism entry read from a line of the sec conf file.
339 * Return NULL on EOF or error.
341 * An alias field of "des" (case not sig) will override any settings
342 * in the keylen or algtype fields like so:
343 * keylen = 192
344 * algtype = 0
347 static mechanism_t *
348 get_secfile_ent(FILE *fptr)
350 mechanism_t *m;
351 char *cp;
352 char **flds; /* line fields */
353 const int num_flds_min = NIS_SEC_CF_MIN_FIELDS;
354 const int num_flds_max = NIS_SEC_CF_MAX_FIELDS;
355 char line[NIS_SEC_CF_MAX_LINELEN + 1 ] = {0};
356 const int line_len = NIS_SEC_CF_MAX_LINELEN + 1;
359 * NIS+ security conf file layout
360 * <Entry_type>
361 * mech <GSS_mechanism_name> <Mech_bit_size> <Mech_alg_type>
362 * <Alias> <GSS_quality_of_protection> <GSS_sec_svc>
364 * QOP and sec_svc are optional.
366 const int mn_offset = 1; /* mechname */
367 const int kl_offset = 2; /* key length */
368 const int at_offset = 3; /* alg type */
369 const int al_offset = 4; /* mech alias */
370 const int qp_offset = 5; /* qop */
371 const int ss_offset = 6; /* security svc */
373 cont:
374 while (((cp = nextline(fptr, line)) != NULL) &&
375 (*cp == '#' || *cp == '\0'))
377 if (cp == NULL)
378 return (NULL);
380 if (!(flds = parse_line(cp, num_flds_min, num_flds_max,
381 line_len)))
382 goto cont;
384 if (strncmp(cf_entry_type_mech_str, *flds,
385 strlen(cf_entry_type_mech_str))) {
386 free_fields(flds, num_flds_max);
387 goto cont;
390 if (!(m = malloc(sizeof (mechanism_t)))) {
391 free_fields(flds, num_flds_max);
392 return (NULL);
395 /* mechanism name */
396 m->mechname = NIS_SEC_CF_NA_CMP(*(flds + mn_offset)) ? NULL
397 : strdup(*(flds + mn_offset));
399 /* mechanism alias */
400 m->alias = NIS_SEC_CF_NA_CMP(*(flds + al_offset)) ? NULL
401 : strdup(*(flds + al_offset));
404 * qop: optional field
405 * Make qop NULL if the field was empty or was "default" or
406 * was '-'.
408 if (!*(flds + qp_offset) ||
409 (strncasecmp(*(flds + qp_offset), cf_secserv_default_str,
410 strlen(cf_secserv_default_str)) == 0) ||
411 NIS_SEC_CF_NA_CMP(*(flds + qp_offset)))
412 m->qop = NULL;
413 else
414 m->qop = strdup(*(flds + qp_offset));
416 /* security service: optional field */
417 m->secserv = str_to_secserv_t(*(flds + ss_offset));
419 /* mech alias */
420 if (*(flds + al_offset) &&
421 (strncasecmp(*(flds + al_offset), cf_mech_des_str,
422 strlen(cf_mech_des_str)) == 0)) {
423 /* we've got the AUTH_DES compat line */
424 m->keylen = 192;
425 m->algtype = 0;
426 } else {
427 /* key length (bits) */
428 if (NIS_SEC_CF_NA_CMP(*(flds + kl_offset)))
429 m->keylen = NIS_SEC_CF_NA_KA;
430 else if (!isnumberstr(*(flds + kl_offset))) {
431 free_fields(flds, num_flds_max);
432 sf_free_mech_ent(m);
433 goto cont;
434 } else
435 m->keylen = atoi(*(flds + kl_offset));
437 /* algorithm type */
438 if (NIS_SEC_CF_NA_CMP(*(flds + at_offset)))
439 m->algtype = NIS_SEC_CF_NA_KA;
440 else if (!isnumberstr(*(flds + at_offset))) {
441 free_fields(flds, num_flds_max);
442 sf_free_mech_ent(m);
443 goto cont;
444 } else
445 m->algtype = atoi(*(flds + at_offset));
448 free_fields(flds, num_flds_max);
450 return (m);
454 * Return TRUE if both entries have the same
455 * mechname/alias/keylen/algotype combo. Else return FALSE.
457 static bool_t
458 equal_entries(const mechanism_t *mp, const mechanism_t *tp)
460 if (mp && tp) {
461 if (mp->keylen != tp->keylen)
462 return (FALSE);
463 if (mp->algtype != tp->algtype)
464 return (FALSE);
466 /* both NULL, the 2 are equal */
467 if (!mp->mechname && !tp->mechname)
468 return (TRUE);
469 /* only one NULL, not equal */
470 if (!mp->mechname || !tp->mechname)
471 return (FALSE);
472 if (strcmp(mp->mechname, tp->mechname) != 0)
473 return (FALSE);
475 if (!mp->alias && !tp->alias)
476 return (TRUE);
477 if (!mp->alias || !tp->alias)
478 return (FALSE);
479 if (strcmp(mp->alias, tp->alias) != 0)
480 return (FALSE);
483 return (TRUE);
486 static mechanism_t *
487 sf_copy_mech_ent(mechanism_t *mp)
489 mechanism_t *tp = calloc(1, sizeof (*mp));
491 if (!mp || !tp)
492 return (NULL);
494 tp->mechname = mp->mechname ? strdup(mp->mechname) : NULL;
495 tp->alias = mp->alias ? strdup(mp->alias) : NULL;
496 tp->qop = mp->qop ? strdup(mp->qop) : NULL;
497 tp->keylen = mp->keylen;
498 tp->algtype = mp->algtype;
499 tp->secserv = mp->secserv;
501 return (tp);
505 * Return TRUE if the mechname/alias/keylen/algtype combo
506 * already exists in the no dups array. Else return FALSE.
508 static bool_t
509 member_of_dups(mechanism_t **t, const mechanism_t *mp)
512 if (t)
513 for (; *t; t++)
514 if (equal_entries(mp, *t))
515 return (TRUE);
517 return (FALSE);
521 * Return a list of valid mechanisms ranked by sequence in the NIS+
522 * security conf file. Return NULL if there are no valid entries.
523 * On success, the last pointer of the array of pointers will be NULL.
525 * If input arg 'qop_secserv' is TRUE, include duplicate
526 * mechname/alias/keylen/algtype entries that differ only in the QOP
527 * and security service. Else, duplicates are omitted.
529 * The list of mechanisms are gauranteed to be valid ones installed
530 * on the system.
532 * This implementation returns copies of the "master" list. The "master"
533 * list will updated if the file is modified.
536 mechanism_t **
537 __nis_get_mechanisms(bool_t qop_secserv)
540 * 'mechs' is the "master" list of valid mechanisms from
541 * the NIS+ security conf file.
542 * 'mechs_no_dups' is the "master" list of valid mechanisms
543 * that differ only in QOP/SecuritySvc fields.
545 static mechanism_t **mechs = NULL;
546 static mechanism_t **mechs_no_dups = NULL;
548 mechanism_t *mp;
549 mechanism_t **tmechs = NULL; /* temp mechs */
550 mechanism_t **tmechs_no_dups = NULL; /* temp mechs sans dups */
551 int ent_cnt = 0; /* valid cf file entry count */
552 int ent_cnt_no_dups = 0; /* valid cf count, no dups */
553 static uint_t last = 0;
554 struct stat sbuf;
555 FILE *fptr;
557 if (stat(NIS_SEC_CF_PATHNAME, &sbuf) != 0)
558 return (NULL);
560 (void) mutex_lock(&nis_sec_cf_lock);
561 if (sbuf.st_mtime > last) {
562 last = sbuf.st_mtime;
564 if (mechs) {
565 /* free old master lists */
566 __nis_release_mechanisms(mechs);
567 free(mechs_no_dups);
569 mechs = mechs_no_dups = NULL;
571 if (!(fptr = fopen(NIS_SEC_CF_PATHNAME, "rF"))) {
572 (void) mutex_unlock(&nis_sec_cf_lock);
573 return (NULL);
576 while (mp = get_secfile_ent(fptr)) {
578 * Make sure entry is either the AUTH_DES compat
579 * one or a valid GSS one that is installed.
581 if (!(AUTH_DES_COMPAT_CHK(mp) ||
582 (NIS_SEC_CF_GSS_MECH(mp) &&
583 rpc_gss_is_installed(mp->mechname)))) {
584 continue;
587 ent_cnt++;
588 tmechs = (mechanism_t **)
589 list_append_ent((void *)mp, (void **)tmechs,
590 ent_cnt, (void (*)())sf_free_mech_ent);
591 if (tmechs == NULL) {
592 (void) fclose(fptr);
593 (void) mutex_unlock(&nis_sec_cf_lock);
594 return (NULL);
597 if (member_of_dups(tmechs_no_dups, mp))
598 continue;
600 ent_cnt_no_dups++;
601 tmechs_no_dups = (mechanism_t **)
602 list_append_ent((void *)mp, (void **)tmechs_no_dups,
603 ent_cnt_no_dups, (void (*)())sf_free_mech_ent);
604 if (tmechs_no_dups == NULL) {
605 (void) fclose(fptr);
606 (void) mutex_unlock(&nis_sec_cf_lock);
607 return (NULL);
610 (void) fclose(fptr);
612 /* set master lists to point to new built ones */
613 mechs = tmechs;
614 mechs_no_dups = tmechs_no_dups;
616 (void) mutex_unlock(&nis_sec_cf_lock);
618 if (qop_secserv)
619 /* return a copy of the list with possible dups */
620 return (mechs ?
621 (mechanism_t **)list_copy(
622 (void *(*)()) sf_copy_mech_ent,
623 (void **)mechs) :
624 NULL);
626 /* return a copy of the list without dups */
627 return (mechs_no_dups ?
628 (mechanism_t **)list_copy((void *(*)()) sf_copy_mech_ent,
629 (void **)mechs_no_dups) :
630 NULL);
634 * Search the mechs (no dups array) for an entry (mechname or alias)
635 * that matches (case not sig) the given mechname. On target match,
636 * load the given memory locations pointed to by args keylen and
637 * algtype with values from the matched entry.
639 * The AUTH_DES "compat" line (alias == "des") will return 192-0
640 * (overriding the fields in the conf file).
642 * For any other entry, a conf file field of '-' (not applicable),
643 * in the keylen or algtype field will result in the locations for
644 * keylen and algtype being set to -1. (this is actually done in
645 * __nis_get_mechanisms()).
647 * Returns 0 on success and -1 on failure.
650 __nis_translate_mechanism(const char *mechname, int *keylen, int *algtype)
652 mechanism_t **mpp;
653 mechanism_t **mpp_h;
655 if (!mechname || !keylen || !algtype)
656 return (-1);
658 /* AUTH_DES */
659 if (strcmp(mechname, NIS_SEC_CF_DES_ALIAS) == 0) {
660 *keylen = AUTH_DES_KEYLEN;
661 *algtype = AUTH_DES_ALGTYPE;
662 return (0);
665 if (!(mpp = __nis_get_mechanisms(FALSE)))
666 return (-1);
668 mpp_h = mpp;
669 for (; *mpp; mpp++) {
670 mechanism_t *mp = *mpp;
671 if (mp->mechname &&
672 (!strcasecmp(mechname, mp->mechname))) {
673 *keylen = mp->keylen;
674 *algtype = mp->algtype;
675 __nis_release_mechanisms(mpp_h);
676 return (0);
678 if (mp->alias &&
679 (!strcasecmp(mechname, mp->alias))) {
680 *keylen = mp->keylen;
681 *algtype = mp->algtype;
682 __nis_release_mechanisms(mpp_h);
683 return (0);
687 __nis_release_mechanisms(mpp_h);
688 return (-1);
693 * Translate a mechname to an alias name.
695 * Returns alias on success or NULL on failure.
697 * Note alias will be the nullstring CSTYLE(on success) if cf
698 * alias field was "Not Applicable".
700 char *
701 __nis_mechname2alias(const char *mechname, /* in */
702 char *alias, /* out */
703 size_t bufsize) /* in */
705 mechanism_t **mpp;
706 mechanism_t **mpp_h;
708 if (!mechname || !alias)
709 return (NULL);
711 if (!(mpp = __nis_get_mechanisms(FALSE)))
712 return (NULL);
714 mpp_h = mpp;
715 for (; *mpp; mpp++) {
716 mechanism_t *mp = *mpp;
717 int len;
719 if (mp->mechname &&
720 (strcasecmp(mechname, mp->mechname) == 0)) {
721 if (mp->alias) {
722 if ((len = strlen(mp->alias)) < bufsize) {
723 (void) strncpy(alias, mp->alias,
724 len + 1);
725 __nis_release_mechanisms(mpp_h);
726 return (alias);
728 } else { /* cf file entry alias field was NA */
729 alias[0] = '\0';
730 __nis_release_mechanisms(mpp_h);
731 return (alias);
737 __nis_release_mechanisms(mpp_h);
738 return (NULL);
741 void
742 __nis_release_mechanisms(mechanism_t **mpp)
744 list_free_all(sf_free_mech_ent, (void **)mpp);
748 * Convert an authtype (ie. DH640-0) to mechanism alias (ie. dh640-0).
749 * Input the authtype ptr, the mechalis ptr and the size of the mechalias
750 * buf.
752 * If mechalias buf is not large enough, truncate and don't indicate failure.
754 * Return the mechalias ptr on success or NULL on failure CSTYLE(any of
755 * the input args are NULL/0).
757 char *
758 __nis_authtype2mechalias(
759 const char *authtype, /* in */
760 char *mechalias, /* out */
761 size_t mechaliaslen) /* in */
763 char *dst = mechalias;
764 const char *src = authtype;
765 const char *max = src + mechaliaslen;
767 if (!src || !dst || mechaliaslen == 0)
768 return (NULL);
770 while (*src && src < max - 1)
771 *dst++ = tolower(*src++);
773 *dst = '\0';
775 return (mechalias);
779 * Convert an mechalias (ie. dh640-0) to authtype (ie. DH640-0).
780 * Input the authtype ptr, the mechalis ptr and the size of the mechalias
781 * buf.
783 * A special mechalias of "dh192-0" will get converted to "DES".
785 * If authtype buf is not large enough, truncate and don't indicate failure.
787 * Return the authtype ptr on success or NULL on failure (any of
788 * the input args are NULL/0.
790 char *
791 __nis_mechalias2authtype(
792 const char *mechalias, /* in */
793 char *authtype, /* out */
794 size_t authtypelen) /* in */
797 const char *src = mechalias;
798 char *dst = authtype;
799 const char *max = src + authtypelen;
800 const int slen = strlen(cf_mech_dh1920_str);
802 if (!src || !dst || !authtypelen)
803 return (NULL);
805 if (strncasecmp(src, cf_mech_dh1920_str, slen + 1)
806 == 0) {
807 if (slen >= authtypelen)
808 return (NULL);
809 (void) strcpy(authtype, AUTH_DES_AUTH_TYPE);
810 return (authtype);
813 while (*src && src < max - 1)
814 *dst++ = toupper(*src++);
816 *dst = '\0';
818 return (authtype);
822 * Given a DH key length and algorithm type, return the mech
823 * alias string. If the keyalg is not the classic AUTH_DES,
824 * then search the NIS+ security cf.
826 * On success return the mech alias string address. Return
827 * NULL on failure. Failure occurs if keylen or algtype is
828 * not found or the length of the input buf is too small
829 * or input args are bogus. Alias buf will not be
830 * changed on failure.
832 char *
833 __nis_keyalg2mechalias(
834 keylen_t keylen, /* in */
835 algtype_t algtype, /* in */
836 char *alias, /* out */
837 size_t alias_len) /* in */
839 mechanism_t **mechs; /* array of mechanisms */
841 if (!alias)
842 return (NULL);
844 if (AUTH_DES_KEY(keylen, algtype)) {
845 if (alias_len > strlen(NIS_SEC_CF_DES_ALIAS)) {
846 (void) strcpy(alias, NIS_SEC_CF_DES_ALIAS);
847 return (alias);
849 else
850 return (NULL);
851 } else
852 if (mechs = __nis_get_mechanisms(FALSE)) {
853 mechanism_t **mpp;
855 for (mpp = mechs; *mpp; mpp++) {
856 mechanism_t *mp = *mpp;
858 if (!VALID_MECH_ENTRY(mp) ||
859 AUTH_DES_COMPAT_CHK(mp))
860 continue;
862 if (keylen == mp->keylen &&
863 algtype == mp->algtype && mp->alias) {
864 int al_len = strlen(mp->alias);
866 if (alias_len > al_len) {
867 (void) strncpy(alias, mp->alias,
868 al_len + 1);
869 return (alias);
870 } else {
871 __nis_release_mechanisms(mechs);
872 return (NULL);
876 __nis_release_mechanisms(mechs);
879 return (NULL);
883 * Given the key length and algorithm type, return the auth type
884 * string suitable for the cred table.
886 * Return the authtype on success and NULL on failure.
888 char *
889 __nis_keyalg2authtype(
890 keylen_t keylen, /* in */
891 algtype_t algtype, /* in */
892 char *authtype, /* out */
893 size_t authtype_len) /* in */
895 char alias[MECH_MAXALIASNAME+1] = {0};
898 if (!authtype || authtype_len == 0)
899 return (NULL);
901 if (!__nis_keyalg2mechalias(keylen, algtype, alias, sizeof (alias)))
902 return (NULL);
904 if (!__nis_mechalias2authtype(alias, authtype, authtype_len))
905 return (NULL);
907 return (authtype);
911 * Return a ptr to the next mech file entry or NULL on EOF.
912 * The caller should free the storage of a successful return.
914 static mfent_t *
915 get_mechfile_ent(FILE *fptr)
917 mfent_t *m;
918 char *cp;
919 char **flds;
920 char line[MF_MAX_LINELEN] = {0};
923 cont:
924 while (((cp = nextline(fptr, line)) != NULL) &&
925 (*cp == '#' || *cp == '\0'))
927 if (cp == NULL)
928 return (NULL);
930 if (!(flds = parse_line(cp, mech_file_flds_min,
931 mech_file_flds_max, MF_MAX_FLDLEN)))
932 goto cont;
934 if (!(m = malloc(sizeof (mfent_t)))) {
935 free_fields(flds, mech_file_flds_max);
936 return (NULL);
939 m->mechname = strdup(*flds);
940 m->oid = strdup(*(flds + 1));
941 m->libname = strdup(*(flds + 2));
943 free_fields(flds, mech_file_flds_max);
945 return (m);
948 static mfent_t *
949 mf_copy_ent(mfent_t *mp)
951 mfent_t *tp = calloc(1, sizeof (*mp));
953 if (!mp || !tp)
954 return (NULL);
956 tp->mechname = mp->mechname ? strdup(mp->mechname) : NULL;
957 tp->oid = mp->oid ? strdup(mp->oid) : NULL;
958 tp->libname = mp->libname ? strdup(mp->libname) : NULL;
960 return (tp);
964 static void
965 mf_free_ent(mfent_t *mp)
967 if (mp) {
968 free(mp->mechname);
969 free(mp->oid);
970 free(mp->libname);
971 free(mp);
976 static void
977 mf_free_mechs(mfent_t **mpp)
979 list_free_all(mf_free_ent, (void **)mpp);
983 * Return a copy of the list of the mech file entries. The ptr to the last
984 * entry will be NULL on success. The master list will be updated when
985 * the mechs file is modified.
987 * Return NULL if the file does not exist or no valid mechs exist in the
988 * file.
990 static mfent_t **
991 mf_get_mechs()
993 static mfent_t **mechs = NULL; /* master mechs list */
994 mfent_t *mp; /* a mech entry */
995 mfent_t **tmechs = NULL; /* temp mechs list */
996 uint_t ent_cnt = 0; /* valid cf file entry count */
997 static uint_t last = 0; /* file last modified date */
998 struct stat sbuf;
999 FILE *fptr;
1001 if (stat(mech_file, &sbuf) != 0)
1002 return (NULL);
1004 (void) mutex_lock(&mech_file_lock);
1005 if (sbuf.st_mtime > last) {
1006 last = sbuf.st_mtime;
1008 if (mechs) {
1009 /* free old master list */
1010 mf_free_mechs(mechs);
1011 mechs = NULL;
1014 if (!(fptr = fopen(mech_file, "rF"))) {
1015 (void) mutex_unlock(&mech_file_lock);
1016 return (NULL);
1019 while (mp = get_mechfile_ent(fptr)) {
1020 ent_cnt++;
1021 tmechs = (mfent_t **)list_append_ent((void *)mp,
1022 (void **)tmechs, ent_cnt, (void (*)()) mf_free_ent);
1023 if (tmechs == NULL) {
1024 (void) fclose(fptr);
1025 (void) mutex_unlock(&mech_file_lock);
1026 return (NULL);
1029 (void) fclose(fptr);
1031 mechs = tmechs; /* set master list to pt to newly built one */
1033 (void) mutex_unlock(&mech_file_lock);
1035 /* return a copy of the master list */
1036 return (mechs ? (mfent_t **)list_copy((void *(*)()) mf_copy_ent,
1037 (void **)mechs) : NULL);
1041 * Translate a full mechname to it's corresponding library name
1042 * as specified in the mech file.
1044 char *
1045 mechfile_name2lib(const char *mechname, char *libname, int len)
1047 mfent_t **mechs = mf_get_mechs();
1048 mfent_t **mpp;
1050 if (!mechs || !mechname || !libname || !len)
1051 return (NULL);
1053 for (mpp = mechs; *mpp; mpp++) {
1054 mfent_t *mp = *mpp;
1056 if (mp->mechname && strcasecmp(mechname, mp->mechname) == 0) {
1057 if (strlen(mp->libname) < len) {
1058 (void) strcpy(libname, mp->libname);
1059 mf_free_mechs(mechs);
1060 return (libname);
1064 mf_free_mechs(mechs);
1066 return (NULL);
1070 * Given a key length and algo type, return the appro DH mech library
1071 * name.
1073 char *
1074 __nis_get_mechanism_library(keylen_t keylen, algtype_t algtype,
1075 char *buffer, size_t buflen)
1077 char mechname[MAXDHNAME + 1];
1079 if (keylen == 0 || !buffer || buflen == 0)
1080 return (NULL);
1082 (void) snprintf(mechname, sizeof (mechname),
1083 "%s_%d_%d", dh_str, keylen, algtype);
1085 if (!mechfile_name2lib(mechname, buffer, buflen))
1086 return (NULL);
1088 return (buffer);
1092 * Input key length, algorithm type, and a string identifying a symbol
1093 * (example: "__gen_dhkeys").
1095 * Returns a function pointer to the specified symbol in the appropriate
1096 * key length/algorithm type library, or NULL if the symbol isn't found.
1098 void *
1099 __nis_get_mechanism_symbol(keylen_t keylen,
1100 algtype_t algtype,
1101 const char *symname)
1104 void *handle;
1105 char libname[MAXDHNAME+1];
1106 char libpath[MAXPATHLEN+1];
1108 if (!__nis_get_mechanism_library(keylen, algtype, libname, MAXDHNAME))
1109 return (NULL);
1111 if (strlen(MECH_LIB_PREFIX) + strlen(libname) + 1 > sizeof (libpath))
1112 return (NULL);
1114 (void) snprintf(libpath, sizeof (libpath),
1115 "%s%s", MECH_LIB_PREFIX, libname);
1117 if (!(handle = dlopen(libpath, RTLD_LAZY)))
1118 return (NULL);
1120 return (dlsym(handle, symname));