nis_sec_mechs.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* 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
* 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 2004 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 <ctype.h>
#include <stdlib.h>
#include <stdio.h>
#include <strings.h>
#include <netconfig.h>
#include <thread.h>
#include <synch.h>
#include <dlfcn.h>
#include <rpcsvc/nis_dhext.h>
#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 '-'
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";
/*
* 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 int mech_file_flds_max = 3;
static const int mech_file_flds_min = 3;
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/"
static void
{
if (tpp) {
}
}
static void **
{
void **new_l;
return (NULL);
}
return (new_l);
}
static void **
{
void **tpp_h;
void **tpp;
void *tp;
int diff;
if (! mpp)
return (NULL);
;
return (NULL);
return (NULL);
}
}
return (tpp_h);
}
static char *
__NSL_FILE *fd;
char *line;
{
char *cp;
return (NULL);
if (cp)
*cp = '\0';
return (line);
}
static int
{
cp++;
return (0);
*dst = '\0';
/* not much else to do but move past current field */
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
{
if (mp) {
}
}
static void
{
if (cpp) {
if (cnt)
if (*tpp)
else
break;
}
}
/*
* 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 **
{
char *cp;
int i;
if (! fpp)
return (NULL);
return (NULL);
}
char *tp;
if (i < minflds) {
free_fields(fpp, i);
return (NULL);
} else
return (fpp);
}
free_fields(fpp, i);
return (NULL);
}
}
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 *
{
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;
/*
* NIS+ security conf file layout
* <Entry_type>
* mech <GSS_mechanism_name> <Mech_bit_size> <Mech_alg_type>
* <Alias> <GSS_quality_of_protection> <GSS_sec_svc>
*
* QOP and sec_svc are optional.
*/
cont:
;
return (NULL);
line_len)))
goto cont;
goto cont;
}
if (! (m = malloc(sizeof (mechanism_t)))) {
return (NULL);
}
/* mechanism name */
/* mechanism alias */
/*
* qop: optional field
* Make qop NULL if the field was empty or was "default" or
* was '-'.
*/
strlen(cf_secserv_default_str)) == 0) ||
else
/* security service: optional field */
/* mech alias */
strlen(cf_mech_des_str)) == 0)) {
/* we've got the AUTH_DES compat line */
m->keylen = 192;
m->algtype = 0;
} else {
/* key length (bits) */
m->keylen = NIS_SEC_CF_NA_KA;
sf_free_mech_ent(m);
goto cont;
} else
/* algorithm type */
m->algtype = NIS_SEC_CF_NA_KA;
sf_free_mech_ent(m);
goto cont;
} else
}
return (m);
}
/*
* Return TRUE if both entries have the same
*/
static bool_t
{
return (FALSE);
return (FALSE);
/* both NULL, the 2 are equal */
return (TRUE);
/* only one NULL, not equal */
return (FALSE);
return (FALSE);
return (TRUE);
return (FALSE);
return (FALSE);
}
return (TRUE);
}
static mechanism_t *
{
return (NULL);
return (tp);
}
/*
* already exists in the no dups array. Else return FALSE.
*/
static bool_t
{
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
* 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 **
{
/*
* '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.
*/
int ent_cnt = 0; /* valid cf file entry count */
int ent_cnt_no_dups = 0; /* valid cf count, no dups */
return (NULL);
(void) mutex_lock(&nis_sec_cf_lock);
if (mechs) {
/* free old master lists */
if (mechs_no_dups)
}
(void) mutex_unlock(&nis_sec_cf_lock);
return (NULL);
}
/*
* 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) &&
continue;
}
ent_cnt++;
tmechs = (mechanism_t **)
ent_cnt, (void (*)())sf_free_mech_ent);
(void) __nsl_fclose(fptr);
(void) mutex_unlock(&nis_sec_cf_lock);
return (NULL);
}
continue;
tmechs_no_dups = (mechanism_t **)
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 */
}
(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 ?
(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
{
mechanism_t **mpp;
mechanism_t **mpp_h;
return (-1);
/* AUTH_DES */
return (0);
}
return (-1);
return (0);
}
return (0);
}
}
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 *
char *alias, /* out */
{
mechanism_t **mpp;
mechanism_t **mpp_h;
return (NULL);
return (NULL);
int len;
len + 1);
return (alias);
}
} else { /* cf file entry alias field was NA */
alias[0] = '\0';
return (alias);
}
}
}
return (NULL);
}
void
{
}
/*
* 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 *
const char *authtype, /* in */
char *mechalias, /* out */
{
return (NULL);
*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 *
const char *mechalias, /* in */
char *authtype, /* out */
{
return (NULL);
== 0) {
if (slen >= authtypelen)
return (NULL);
return (authtype);
}
*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 *
char *alias, /* out */
{
if (! alias)
return (NULL);
return (alias);
}
else
return (NULL);
} else
mechanism_t **mpp;
if (! VALID_MECH_ENTRY(mp) ||
continue;
al_len + 1);
return (alias);
} else {
return (NULL);
}
}
}
}
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 *
char *authtype, /* out */
{
if (! authtype || authtype_len == 0)
return (NULL);
return (NULL);
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 *
{
mfent_t *m;
char *cp;
char **flds;
char line[MF_MAX_LINELEN] = {0};
cont:
;
return (NULL);
goto cont;
return (NULL);
}
return (m);
}
static mfent_t *
{
return (NULL);
return (tp);
}
static void
{
if (mp) {
}
}
static void
{
}
/*
* 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 **
{
return (NULL);
(void) mutex_lock(&mech_file_lock);
if (mechs) {
/* free old master list */
}
(void) mutex_unlock(&mech_file_lock);
return (NULL);
}
ent_cnt++;
(void) __nsl_fclose(fptr);
(void) mutex_unlock(&mech_file_lock);
return (NULL);
}
}
(void) __nsl_fclose(fptr);
}
(void) mutex_unlock(&mech_file_lock);
/* return a copy of the master list */
}
/*
* Translate a full mechname to it's corresponding library name
* as specified in the mech file.
*/
char *
{
return (NULL);
return (libname);
}
}
}
return (NULL);
}
/*
* Given a key length and algo type, return the appro DH mech library
* name.
*/
char *
{
return (NULL);
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
*/
void *
const char *symname)
{
void *handle;
return (NULL);
return (NULL);
return (NULL);
}