/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" /* * This module contains the interfaces for the NIS+ security mechanisms. */ #include "mt.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "nsl_stdio_prv.h" /* * NIS+ security file */ #define NIS_SEC_CF_MAX_LINELEN 512 /* the min number of fields allowable per line */ #define NIS_SEC_CF_MIN_FIELDS 5 /* the max number of fields processed per line */ #define NIS_SEC_CF_MAX_FIELDS 7 /* field "Not Applicable" char */ #define NIS_SEC_CF_NA_CHAR '-' #define NIS_SEC_CF_NA_CMP(a) ((a)[0] == NIS_SEC_CF_NA_CHAR && (a)[1] == '\0') static const char *cf_entry_type_mech_str = "mech"; static const char *cf_mech_des_str = NIS_SEC_CF_DES_ALIAS; static const char *cf_mech_dh1920_str = "dh192-0"; static const char *cf_secserv_default_str = "default"; static const char *cf_secserv_none_str = "none"; static const char *cf_secserv_integrity_str = "integrity"; static const char *cf_secserv_privacy_str = "privacy"; static mutex_t nis_sec_cf_lock = DEFAULTMUTEX; /* * GSS mechanisms file * * This is currently a private NIS+ interface but at some point in the future * can be broken out and made available to other apps that need to access * GSS backends. */ #define MF_MAX_LINELEN 256 #define MF_MAX_FLDLEN MAXDHNAME /* mech file entry type */ typedef struct { char *mechname; char *oid; char *libname; /* the 4th field is not used by user land apps */ } mfent_t; static const char mech_file[] = "/etc/gss/mech"; static const int mech_file_flds_max = 3; static const int mech_file_flds_min = 3; static mutex_t mech_file_lock = DEFAULTMUTEX; static const char dh_str[] = "diffie_hellman"; #define MECH_LIB_PREFIX1 "/usr/lib/" #ifdef _LP64 #define MECH_LIB_PREFIX2 "64/" #else /* _LP64 */ #define MECH_LIB_PREFIX2 "" #endif /* _LP64 */ #define MECH_LIB_DIR "gss/" #define MECH_LIB_PREFIX MECH_LIB_PREFIX1 MECH_LIB_PREFIX2 MECH_LIB_DIR static void list_free_all(void (*free_ent)(), void **mpp) { void **tpp = mpp; if (tpp) { for (; *tpp; tpp++) (*free_ent)(*tpp); free(mpp); } } static void ** list_append_ent(void *ent, void **list, uint_t cnt, void (*free_ent)()) { void **new_l; if (!(new_l = realloc(list, sizeof (*list) * (cnt + 1)))) { list_free_all(free_ent, list); return (NULL); } *(new_l + cnt - 1) = ent; *(new_l + cnt) = NULL; return (new_l); } static void ** list_copy(void *(*cp_ent)(), void **mpp) { void **tpp_h; void **tpp; void *tp; int diff; if (!mpp) return (NULL); for (tpp = mpp; *tpp; tpp++) ; diff = tpp - mpp; if (!(tpp_h = calloc(diff + 1, sizeof (*mpp)))) return (NULL); for (tpp = tpp_h; *mpp; mpp++) { if (!(tp = (*cp_ent)(*mpp))) { free(tpp_h); return (NULL); } *tpp++ = tp; } return (tpp_h); } static char * nextline(fd, line) __NSL_FILE *fd; char *line; { char *cp; if (__nsl_fgets(line, NIS_SEC_CF_MAX_LINELEN, fd) == NULL) return (NULL); cp = index(line, '\n'); if (cp) *cp = '\0'; return (line); } static int nextfield(char **cpp, char *op, int n) { intptr_t max; char *dst = op; char *cp = *cpp; while (*cp == ' ' || *cp == '\t') cp++; if (*cp == '\0' || *cp == '#') return (0); max = (intptr_t)op + n; while (*cp && *cp != ' ' && *cp != '\t' && *cp != '#' && (intptr_t)dst < max) *dst++ = *cp++; *dst = '\0'; if ((intptr_t)dst >= max) /* not much else to do but move past current field */ while (*cp && *cp != ' ' && *cp != '\t' && *cp != '#') cp++; *cpp = cp; return (1); } static rpc_gss_service_t str_to_secserv_t(const char *s) { if (s) { if (strncmp(cf_secserv_none_str, s, strlen(cf_secserv_none_str)) == 0) return (rpc_gss_svc_none); if (strncmp(cf_secserv_integrity_str, s, strlen(cf_secserv_integrity_str)) == 0) return (rpc_gss_svc_integrity); if (strncmp(cf_secserv_privacy_str, s, strlen(cf_secserv_privacy_str)) == 0) return (rpc_gss_svc_privacy); } return (rpc_gss_svc_default); } /* * Return TRUE if all the chars up to the NUL are of the digit type. * Else return FALSE. */ static bool_t isnumberstr(const char *s) { for (; *s; s++) if (!isdigit(*s)) return (FALSE); return (TRUE); } /* * Free security file mechanism entry. */ static void sf_free_mech_ent(mechanism_t *mp) { if (mp) { if (mp->mechname) free(mp->mechname); if (mp->alias) free(mp->alias); if (mp->qop) free(mp->qop); free(mp); } } static void free_fields(char **cpp, int cnt) { char **tpp = cpp; if (cpp) { if (cnt) for (; cnt > 0; cnt--, tpp++) if (*tpp) free(*tpp); else break; free(cpp); } } /* * Generic parse-linestr-of-config-file routine. Arg linep is ptr * (which will be modified) to the input string . Arg minflds is the * minimum number of fields expected. Arg maxflds is the max number * of fields that will be parsed. Arg bufsiz is the max len of each * field that will be copied to the return area. * * If there are less fields in the entry than the max number, * the remainding ptrs will be 0. * * Returns a ptr to an array of ptrs to strings on success else * NULL on failure. * * The caller must free the storage (of a successful return only). */ static char ** parse_line(char *linep, int minflds, int maxflds, int bufsiz) { char **fpp = calloc(maxflds, sizeof (linep)); char **tpp = fpp; char *cp; int i; if (!fpp) return (NULL); if (!(cp = malloc(bufsiz))) { free(fpp); return (NULL); } for (i = 0; i < maxflds; i++, tpp++) { char *tp; if (!nextfield(&linep, cp, bufsiz)) { free(cp); if (i < minflds) { free_fields(fpp, i); return (NULL); } else return (fpp); } if (!(tp = strdup(cp))) { free_fields(fpp, i); free(cp); return (NULL); } *tpp = tp; } free(cp); return (fpp); } /* * Return a ptr to a mechanism entry read from a line of the sec conf file. * Return NULL on EOF or error. * * An alias field of "des" (case not sig) will override any settings * in the keylen or algtype fields like so: * keylen = 192 * algtype = 0 */ static mechanism_t * get_secfile_ent(__NSL_FILE *fptr) { mechanism_t *m; char *cp; char **flds; /* line fields */ const int num_flds_min = NIS_SEC_CF_MIN_FIELDS; const int num_flds_max = NIS_SEC_CF_MAX_FIELDS; char line[NIS_SEC_CF_MAX_LINELEN + 1 ] = {0}; const int line_len = NIS_SEC_CF_MAX_LINELEN + 1; /* * NIS+ security conf file layout * * mech * * * QOP and sec_svc are optional. */ const int mn_offset = 1; /* mechname */ const int kl_offset = 2; /* key length */ const int at_offset = 3; /* alg type */ const int al_offset = 4; /* mech alias */ const int qp_offset = 5; /* qop */ const int ss_offset = 6; /* security svc */ cont: while (((cp = nextline(fptr, line)) != NULL) && (*cp == '#' || *cp == '\0')) ; if (cp == NULL) return (NULL); if (!(flds = parse_line(cp, num_flds_min, num_flds_max, line_len))) goto cont; if (strncmp(cf_entry_type_mech_str, *flds, strlen(cf_entry_type_mech_str))) { free_fields(flds, num_flds_max); goto cont; } if (!(m = malloc(sizeof (mechanism_t)))) { free_fields(flds, num_flds_max); return (NULL); } /* mechanism name */ m->mechname = NIS_SEC_CF_NA_CMP(*(flds + mn_offset)) ? NULL : strdup(*(flds + mn_offset)); /* mechanism alias */ m->alias = NIS_SEC_CF_NA_CMP(*(flds + al_offset)) ? NULL : strdup(*(flds + al_offset)); /* * qop: optional field * Make qop NULL if the field was empty or was "default" or * was '-'. */ if (!*(flds + qp_offset) || (strncasecmp(*(flds + qp_offset), cf_secserv_default_str, strlen(cf_secserv_default_str)) == 0) || NIS_SEC_CF_NA_CMP(*(flds + qp_offset))) m->qop = NULL; else m->qop = strdup(*(flds + qp_offset)); /* security service: optional field */ m->secserv = str_to_secserv_t(*(flds + ss_offset)); /* mech alias */ if (*(flds + al_offset) && (strncasecmp(*(flds + al_offset), cf_mech_des_str, strlen(cf_mech_des_str)) == 0)) { /* we've got the AUTH_DES compat line */ m->keylen = 192; m->algtype = 0; } else { /* key length (bits) */ if (NIS_SEC_CF_NA_CMP(*(flds + kl_offset))) m->keylen = NIS_SEC_CF_NA_KA; else if (!isnumberstr(*(flds + kl_offset))) { free_fields(flds, num_flds_max); sf_free_mech_ent(m); goto cont; } else m->keylen = atoi(*(flds + kl_offset)); /* algorithm type */ if (NIS_SEC_CF_NA_CMP(*(flds + at_offset))) m->algtype = NIS_SEC_CF_NA_KA; else if (!isnumberstr(*(flds + at_offset))) { free_fields(flds, num_flds_max); sf_free_mech_ent(m); goto cont; } else m->algtype = atoi(*(flds + at_offset)); } free_fields(flds, num_flds_max); return (m); } /* * Return TRUE if both entries have the same * mechname/alias/keylen/algotype combo. Else return FALSE. */ static bool_t equal_entries(const mechanism_t *mp, const mechanism_t *tp) { if (mp && tp) { if (mp->keylen != tp->keylen) return (FALSE); if (mp->algtype != tp->algtype) return (FALSE); /* both NULL, the 2 are equal */ if (!mp->mechname && !tp->mechname) return (TRUE); /* only one NULL, not equal */ if (!mp->mechname || !tp->mechname) return (FALSE); if (strcmp(mp->mechname, tp->mechname) != 0) return (FALSE); if (!mp->alias && !tp->alias) return (TRUE); if (!mp->alias || !tp->alias) return (FALSE); if (strcmp(mp->alias, tp->alias) != 0) return (FALSE); } return (TRUE); } static mechanism_t * sf_copy_mech_ent(mechanism_t *mp) { mechanism_t *tp = calloc(1, sizeof (*mp)); if (!mp || !tp) return (NULL); tp->mechname = mp->mechname ? strdup(mp->mechname) : NULL; tp->alias = mp->alias ? strdup(mp->alias) : NULL; tp->qop = mp->qop ? strdup(mp->qop) : NULL; tp->keylen = mp->keylen; tp->algtype = mp->algtype; tp->secserv = mp->secserv; return (tp); } /* * Return TRUE if the mechname/alias/keylen/algtype combo * already exists in the no dups array. Else return FALSE. */ static bool_t member_of_dups(mechanism_t **t, const mechanism_t *mp) { if (t) for (; *t; t++) if (equal_entries(mp, *t)) return (TRUE); return (FALSE); } /* * Return a list of valid mechanisms ranked by sequence in the NIS+ * security conf file. Return NULL if there are no valid entries. * On success, the last pointer of the array of pointers will be NULL. * * If input arg 'qop_secserv' is TRUE, include duplicate * mechname/alias/keylen/algtype entries that differ only in the QOP * and security service. Else, duplicates are omitted. * * The list of mechanisms are gauranteed to be valid ones installed * on the system. * * This implementation returns copies of the "master" list. The "master" * list will updated if the file is modified. */ mechanism_t ** __nis_get_mechanisms(bool_t qop_secserv) { /* * 'mechs' is the "master" list of valid mechanisms from * the NIS+ security conf file. * 'mechs_no_dups' is the "master" list of valid mechanisms * that differ only in QOP/SecuritySvc fields. */ static mechanism_t **mechs = NULL; static mechanism_t **mechs_no_dups = NULL; mechanism_t *mp; mechanism_t **tmechs = NULL; /* temp mechs */ mechanism_t **tmechs_no_dups = NULL; /* temp mechs sans dups */ int ent_cnt = 0; /* valid cf file entry count */ int ent_cnt_no_dups = 0; /* valid cf count, no dups */ static uint_t last = 0; struct stat sbuf; __NSL_FILE *fptr; if (stat(NIS_SEC_CF_PATHNAME, &sbuf) != 0) return (NULL); (void) mutex_lock(&nis_sec_cf_lock); if (sbuf.st_mtime > last) { last = sbuf.st_mtime; if (mechs) { /* free old master lists */ __nis_release_mechanisms(mechs); if (mechs_no_dups) free(mechs_no_dups); } mechs = mechs_no_dups = NULL; if (!(fptr = __nsl_fopen(NIS_SEC_CF_PATHNAME, "r"))) { (void) mutex_unlock(&nis_sec_cf_lock); return (NULL); } while (mp = get_secfile_ent(fptr)) { /* * Make sure entry is either the AUTH_DES compat * one or a valid GSS one that is installed. */ if (!(AUTH_DES_COMPAT_CHK(mp) || (NIS_SEC_CF_GSS_MECH(mp) && rpc_gss_is_installed(mp->mechname)))) { continue; } ent_cnt++; tmechs = (mechanism_t **) list_append_ent((void *)mp, (void **)tmechs, ent_cnt, (void (*)())sf_free_mech_ent); if (tmechs == NULL) { (void) __nsl_fclose(fptr); (void) mutex_unlock(&nis_sec_cf_lock); return (NULL); } if (member_of_dups(tmechs_no_dups, mp)) continue; ent_cnt_no_dups++; tmechs_no_dups = (mechanism_t **) list_append_ent((void *)mp, (void **)tmechs_no_dups, ent_cnt_no_dups, (void (*)())sf_free_mech_ent); if (tmechs_no_dups == NULL) { (void) __nsl_fclose(fptr); (void) mutex_unlock(&nis_sec_cf_lock); return (NULL); } } (void) __nsl_fclose(fptr); /* set master lists to point to new built ones */ mechs = tmechs; mechs_no_dups = tmechs_no_dups; } (void) mutex_unlock(&nis_sec_cf_lock); if (qop_secserv) /* return a copy of the list with possible dups */ return (mechs ? (mechanism_t **)list_copy( (void *(*)()) sf_copy_mech_ent, (void **)mechs) : NULL); /* return a copy of the list without dups */ return (mechs_no_dups ? (mechanism_t **)list_copy((void *(*)()) sf_copy_mech_ent, (void **)mechs_no_dups) : NULL); } /* * Search the mechs (no dups array) for an entry (mechname or alias) * that matches (case not sig) the given mechname. On target match, * load the given memory locations pointed to by args keylen and * algtype with values from the matched entry. * * The AUTH_DES "compat" line (alias == "des") will return 192-0 * (overriding the fields in the conf file). * * For any other entry, a conf file field of '-' (not applicable), * in the keylen or algtype field will result in the locations for * keylen and algtype being set to -1. (this is actually done in * __nis_get_mechanisms()). * * Returns 0 on success and -1 on failure. */ int __nis_translate_mechanism(const char *mechname, int *keylen, int *algtype) { mechanism_t **mpp; mechanism_t **mpp_h; if (!mechname || !keylen || !algtype) return (-1); /* AUTH_DES */ if (strcmp(mechname, NIS_SEC_CF_DES_ALIAS) == 0) { *keylen = AUTH_DES_KEYLEN; *algtype = AUTH_DES_ALGTYPE; return (0); } if (!(mpp = __nis_get_mechanisms(FALSE))) return (-1); mpp_h = mpp; for (; *mpp; mpp++) { mechanism_t *mp = *mpp; if (mp->mechname && (!strcasecmp(mechname, mp->mechname))) { *keylen = mp->keylen; *algtype = mp->algtype; __nis_release_mechanisms(mpp_h); return (0); } if (mp->alias && (!strcasecmp(mechname, mp->alias))) { *keylen = mp->keylen; *algtype = mp->algtype; __nis_release_mechanisms(mpp_h); return (0); } } __nis_release_mechanisms(mpp_h); return (-1); } /* * Translate a mechname to an alias name. * * Returns alias on success or NULL on failure. * * Note alias will be the nullstring CSTYLE(on success) if cf * alias field was "Not Applicable". */ char * __nis_mechname2alias(const char *mechname, /* in */ char *alias, /* out */ size_t bufsize) /* in */ { mechanism_t **mpp; mechanism_t **mpp_h; if (!mechname || !alias) return (NULL); if (!(mpp = __nis_get_mechanisms(FALSE))) return (NULL); mpp_h = mpp; for (; *mpp; mpp++) { mechanism_t *mp = *mpp; int len; if (mp->mechname && (strcasecmp(mechname, mp->mechname) == 0)) { if (mp->alias) { if ((len = strlen(mp->alias)) < bufsize) { (void) strncpy(alias, mp->alias, len + 1); __nis_release_mechanisms(mpp_h); return (alias); } } else { /* cf file entry alias field was NA */ alias[0] = '\0'; __nis_release_mechanisms(mpp_h); return (alias); } } } __nis_release_mechanisms(mpp_h); return (NULL); } void __nis_release_mechanisms(mechanism_t **mpp) { list_free_all(sf_free_mech_ent, (void **)mpp); } /* * Convert an authtype (ie. DH640-0) to mechanism alias (ie. dh640-0). * Input the authtype ptr, the mechalis ptr and the size of the mechalias * buf. * * If mechalias buf is not large enough, truncate and don't indicate failure. * * Return the mechalias ptr on success or NULL on failure CSTYLE(any of * the input args are NULL/0). */ char * __nis_authtype2mechalias( const char *authtype, /* in */ char *mechalias, /* out */ size_t mechaliaslen) /* in */ { char *dst = mechalias; const char *src = authtype; const char *max = src + mechaliaslen; if (!src || !dst || mechaliaslen == 0) return (NULL); while (*src && src < max - 1) *dst++ = tolower(*src++); *dst = '\0'; return (mechalias); } /* * Convert an mechalias (ie. dh640-0) to authtype (ie. DH640-0). * Input the authtype ptr, the mechalis ptr and the size of the mechalias * buf. * * A special mechalias of "dh192-0" will get converted to "DES". * * If authtype buf is not large enough, truncate and don't indicate failure. * * Return the authtype ptr on success or NULL on failure (any of * the input args are NULL/0. */ char * __nis_mechalias2authtype( const char *mechalias, /* in */ char *authtype, /* out */ size_t authtypelen) /* in */ { const char *src = mechalias; char *dst = authtype; const char *max = src + authtypelen; const int slen = strlen(cf_mech_dh1920_str); if (!src || !dst || !authtypelen) return (NULL); if (strncasecmp(src, cf_mech_dh1920_str, slen + 1) == 0) { if (slen >= authtypelen) return (NULL); (void) strcpy(authtype, AUTH_DES_AUTH_TYPE); return (authtype); } while (*src && src < max - 1) *dst++ = toupper(*src++); *dst = '\0'; return (authtype); } /* * Given a DH key length and algorithm type, return the mech * alias string. If the keyalg is not the classic AUTH_DES, * then search the NIS+ security cf. * * On success return the mech alias string address. Return * NULL on failure. Failure occurs if keylen or algtype is * not found or the length of the input buf is too small * or input args are bogus. Alias buf will not be * changed on failure. */ char * __nis_keyalg2mechalias( keylen_t keylen, /* in */ algtype_t algtype, /* in */ char *alias, /* out */ size_t alias_len) /* in */ { mechanism_t **mechs; /* array of mechanisms */ if (!alias) return (NULL); if (AUTH_DES_KEY(keylen, algtype)) { if (alias_len > strlen(NIS_SEC_CF_DES_ALIAS)) { (void) strcpy(alias, NIS_SEC_CF_DES_ALIAS); return (alias); } else return (NULL); } else if (mechs = __nis_get_mechanisms(FALSE)) { mechanism_t **mpp; for (mpp = mechs; *mpp; mpp++) { mechanism_t *mp = *mpp; if (!VALID_MECH_ENTRY(mp) || AUTH_DES_COMPAT_CHK(mp)) continue; if (keylen == mp->keylen && algtype == mp->algtype && mp->alias) { int al_len = strlen(mp->alias); if (alias_len > al_len) { (void) strncpy(alias, mp->alias, al_len + 1); return (alias); } else { __nis_release_mechanisms(mechs); return (NULL); } } } __nis_release_mechanisms(mechs); } return (NULL); } /* * Given the key length and algorithm type, return the auth type * string suitable for the cred table. * * Return the authtype on success and NULL on failure. */ char * __nis_keyalg2authtype( keylen_t keylen, /* in */ algtype_t algtype, /* in */ char *authtype, /* out */ size_t authtype_len) /* in */ { char alias[MECH_MAXALIASNAME+1] = {0}; if (!authtype || authtype_len == 0) return (NULL); if (!__nis_keyalg2mechalias(keylen, algtype, alias, sizeof (alias))) return (NULL); if (!__nis_mechalias2authtype(alias, authtype, authtype_len)) return (NULL); return (authtype); } /* * Return a ptr to the next mech file entry or NULL on EOF. * The caller should free the storage of a successful return. */ static mfent_t * get_mechfile_ent(__NSL_FILE *fptr) { mfent_t *m; char *cp; char **flds; char line[MF_MAX_LINELEN] = {0}; cont: while (((cp = nextline(fptr, line)) != NULL) && (*cp == '#' || *cp == '\0')) ; if (cp == NULL) return (NULL); if (!(flds = parse_line(cp, mech_file_flds_min, mech_file_flds_max, MF_MAX_FLDLEN))) goto cont; if (!(m = malloc(sizeof (mfent_t)))) { free_fields(flds, mech_file_flds_max); return (NULL); } m->mechname = strdup(*flds); m->oid = strdup(*(flds + 1)); m->libname = strdup(*(flds + 2)); free_fields(flds, mech_file_flds_max); return (m); } static mfent_t * mf_copy_ent(mfent_t *mp) { mfent_t *tp = calloc(1, sizeof (*mp)); if (!mp || !tp) return (NULL); tp->mechname = mp->mechname ? strdup(mp->mechname) : NULL; tp->oid = mp->oid ? strdup(mp->oid) : NULL; tp->libname = mp->libname ? strdup(mp->libname) : NULL; return (tp); } static void mf_free_ent(mfent_t *mp) { if (mp) { if (mp->mechname) free(mp->mechname); if (mp->oid) free(mp->oid); if (mp->libname) free(mp->libname); free(mp); } } static void mf_free_mechs(mfent_t **mpp) { list_free_all(mf_free_ent, (void **)mpp); } /* * Return a copy of the list of the mech file entries. The ptr to the last * entry will be NULL on success. The master list will be updated when * the mechs file is modified. * * Return NULL if the file does not exist or no valid mechs exist in the * file. */ static mfent_t ** mf_get_mechs() { static mfent_t **mechs = NULL; /* master mechs list */ mfent_t *mp; /* a mech entry */ mfent_t **tmechs = NULL; /* temp mechs list */ uint_t ent_cnt = 0; /* valid cf file entry count */ static uint_t last = 0; /* file last modified date */ struct stat sbuf; __NSL_FILE *fptr; if (stat(mech_file, &sbuf) != 0) return (NULL); (void) mutex_lock(&mech_file_lock); if (sbuf.st_mtime > last) { last = sbuf.st_mtime; if (mechs) { /* free old master list */ mf_free_mechs(mechs); mechs = NULL; } if (!(fptr = __nsl_fopen(mech_file, "r"))) { (void) mutex_unlock(&mech_file_lock); return (NULL); } while (mp = get_mechfile_ent(fptr)) { ent_cnt++; tmechs = (mfent_t **)list_append_ent((void *)mp, (void **)tmechs, ent_cnt, (void (*)()) mf_free_ent); if (tmechs == NULL) { (void) __nsl_fclose(fptr); (void) mutex_unlock(&mech_file_lock); return (NULL); } } (void) __nsl_fclose(fptr); mechs = tmechs; /* set master list to pt to newly built one */ } (void) mutex_unlock(&mech_file_lock); /* return a copy of the master list */ return (mechs ? (mfent_t **)list_copy((void *(*)()) mf_copy_ent, (void **)mechs) : NULL); } /* * Translate a full mechname to it's corresponding library name * as specified in the mech file. */ char * mechfile_name2lib(const char *mechname, char *libname, int len) { mfent_t **mechs = mf_get_mechs(); mfent_t **mpp; if (!mechs || !mechname || !libname || !len) return (NULL); for (mpp = mechs; *mpp; mpp++) { mfent_t *mp = *mpp; if (mp->mechname && strcasecmp(mechname, mp->mechname) == 0) { if (strlen(mp->libname) < len) { (void) strcpy(libname, mp->libname); mf_free_mechs(mechs); return (libname); } } } mf_free_mechs(mechs); return (NULL); } /* * Given a key length and algo type, return the appro DH mech library * name. */ char * __nis_get_mechanism_library(keylen_t keylen, algtype_t algtype, char *buffer, size_t buflen) { char mechname[MAXDHNAME + 1]; if (keylen == 0 || !buffer || buflen == 0) return (NULL); (void) snprintf(mechname, sizeof (mechname), "%s_%d_%d", dh_str, keylen, algtype); if (!mechfile_name2lib(mechname, buffer, buflen)) return (NULL); return (buffer); } /* * Input key length, algorithm type, and a string identifying a symbol * (example: "__gen_dhkeys"). * * Returns a function pointer to the specified symbol in the appropriate * key length/algorithm type library, or NULL if the symbol isn't found. */ void * __nis_get_mechanism_symbol(keylen_t keylen, algtype_t algtype, const char *symname) { void *handle; char libname[MAXDHNAME+1]; char libpath[MAXPATHLEN+1]; if (!__nis_get_mechanism_library(keylen, algtype, libname, MAXDHNAME)) return (NULL); if (strlen(MECH_LIB_PREFIX) + strlen(libname) + 1 > sizeof (libpath)) return (NULL); (void) snprintf(libpath, sizeof (libpath), "%s%s", MECH_LIB_PREFIX, libname); if (!(handle = dlopen(libpath, RTLD_LAZY))) return (NULL); return (dlsym(handle, symname)); }