nis_misc_proc.c revision 61961e0f20c7637a3846bb39786bb9dffa91dfb9
/*
* 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 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* This contains miscellaneous functions moved from commands to the library.
*/
#include "mt.h"
#include <stdlib.h>
#include <stdio.h>
#include <syslog.h>
#include <string.h>
#include <unistd.h>
#include <rpcsvc/nis_dhext.h>
#include <rpc/auth_sys.h>
#include <rpc/auth_des.h>
#include <rpc/key_prot.h>
#include <netdir.h>
#include <netconfig.h>
#include <netdb.h>
#include <dlfcn.h>
#include "nis_local.h"
/*
* Returns the NIS principal name of the person making the request
* XXX This is set up to use Secure RPC only at the moment, it should
* be possible for any authentication scheme to be incorporated if it
* has a "full name" that we can return as the principal name.
*/
static NIS_HASH_TABLE credtbl;
struct creditem {
char pname[1024];
};
static void
{
"add_cred_item: principal name too long '%s'",
pname);
return;
}
return;
return;
return;
}
}
static bool_t
{
return (FALSE);
return (FALSE);
return (TRUE);
}
static bool_t
delete_cred_item(char *netname)
{
&credtbl)) {
return (TRUE);
} else
return (FALSE);
}
void
char *name,
int flavor,
int verbose)
{
struct authsys_parms *au;
struct authdes_cred *ad;
char *rmtdomain;
srch[0] = '\0';
if (verbose) {
"__nis_auth2princ: flavor = NONE: returning '%s'", nobody);
}
return;
/* LINTED pointer cast */
if (!rmtdomain)
if (verbose) {
"__nis_auth2princ: flavor = SYS: returning '%s'", name);
}
return;
}
sizeof (srch) - 1,
"[auth_name=\"%d\", auth_type=LOCAL], cred.org_dir.%s",
(char *)nis_local_directory() : rmtdomain);
}
/* LINTED pointer cast */
if (refresh)
else
if (verbose)
"__nis_auth2princ: flavor = DES: returning from cache '%s'",
name);
return;
}
if (rmtdomain) {
rmtdomain++;
sizeof (srch) - 1,
"[auth_name=%s, auth_type=DES], cred.org_dir.%s",
}
} else {
if (verbose) {
"__nis_auth2princ: flavor = DES: returning '%s'",
nobody);
}
return;
}
} else {
"__nis_auth2princ: flavor = %d(unknown): returning '%s'",
return;
}
if (verbose)
"__nis_auth2princ: calling list with name '%s'",
name);
if (verbose)
"__nis_auth2princ: error doing nis_list: %s",
} else {
1024);
}
if (verbose)
"__nis_auth2princ: flavor = %s: returning : '%s'",
}
#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 gss_OID_desc __dh_gss_c_nt_netname = {
9, "\053\006\004\001\052\002\032\001\001"
};
static gss_OID GSS_EXPORT_NAME = 0;
OM_uint32 (*g_import_name)();
OM_uint32 (*g_display_name)();
OM_uint32 (*g_release_name)();
OM_uint32 (*g_release_buffer)();
OM_uint32 (*g_release_oid)();
/*
* gss_OID_load()
*
* This routine is called by __nis_gssprin2netname to define values for
* the gss-api-export-name OID, the Diffie-Hellman netname OID, and
* the gss support routines that it needs.
* The reason for this support routine is that libnsl cannot have an
* explicit dependency on libgss. Callers of __nisgssprin2netname are
* expected to have loaded libgss through the rpcsec layer. The work around
* is to dlopen the needed shared objects and grab the symbols with dlsym.
* This routine opens libgss RTLD_NOLOAD. If this fails then libgss.so.1
* is not loaded and we return error. Otherwise it uses dlsym to
* defines GSS_EXPORT_NAME to have the value of GSS_C_NT_EXPORT_NAME and
* to assign the above fuction pointers.
* If this succeeds then the routine will attempt to load mech_dh.so.1
* and over ride DH_NETNAME with the value of __DH_GSS_C_NT_NETNAME from
* that shared object. We don't consider it an error if this fails because
* its conceivable that another mechanism backend will support the netname
* name type and mech_dh.so.1 not be available.
*
* Return 0 on failer, 1 on success.
*/
static int
{
void *dh;
int stat = 0;
(void) mutex_lock(&gss_load_lock);
if (GSS_EXPORT_NAME) {
(void) mutex_unlock(&gss_load_lock);
return (0);
}
/* if LIBGSS is not loaded return an error */
(void) mutex_unlock(&gss_load_lock);
return (0);
}
if (OIDptr)
else
goto Done;
if (g_import_name == 0)
goto Done;
if (g_display_name == 0)
goto Done;
if (g_release_name == 0)
goto Done;
if (g_release_buffer == 0)
goto Done;
if (g_release_oid == 0)
goto Done;
stat = 1;
/*
* Try and get the official netname oid from mech_dh.so.
* If this fails will just keep our default from above.
*/
if (OIDptr)
DH_NETNAME = *OIDptr;
}
Done:
(void) mutex_unlock(&gss_load_lock);
if (stat == 0)
GSS_EXPORT_NAME = 0;
return (stat);
}
/*
* int
* __nis_gssprin2netname(rpc_gss_principal_t prin,
* char netname[MAXNETNAMELEN+1])
*
* This routine attempts to extract the netname from an rpc_gss_principal_t
* which is in { gss-api-exorted-name } format. Return 0 if a netname was
* found, else return -1.
*/
/*
* This routine has a dependency on libgss.so. So we will pragma weak
* the interfaces that we need. When this routine is called libgss
* should have been loaded by the rpcsec layer. We will call gss_OID_load
* to get the value for GSS_EXPORT_NAME. If gss_OID_load failes return -1.
*/
int
{
int stat = -1;
/* See if we already got the OID */
if (GSS_EXPORT_NAME == 0) {
/* Nope. See if GSS is loaded and get the OIDs */
if (!gss_OID_load())
return (-1); /* if libgss.so.1 isn't loaded */
}
if (major == GSS_S_COMPLETE) {
&display_name, &name_type);
/* We're done with the gss_internal name */
if (major == GSS_S_COMPLETE) {
/*
* Check if we've got a netname. If we do we copy it
* and make sure that its null terminated.
*/
(char *)display_name.value,
stat = 0;
}
/*
* If there are other display formats that can
* be converted to netnames easily, insert here.
*
* else if (OID_IS_EQUAL(OTHER_NT_OID, name_type)) {
* convert2netname(display_name.value, netname);
* } ...
*/
/* Release temporty storage */
}
}
if (stat == 0)
return (stat);
/*
* If we got here then prin is not a gss netname type. Currently
* other types are not supported. To support the general case the
* prin type needs to be looked up in a table that will map an
* gss-api-export-name to a netname. The guts of the routine to do
* this, would look like this:
*
* char xport[NIS_MAXNAMELEN];
* char query[NIS_MAXNAMELEN];
* stat = -1;
* nis_result *r;
*
* bin2hex(expName.length, expName.value, xport);
* sprintf(query, "[gssprincipal=%s],gssprin.org_dir.%s", xport,
* nis_local_directory());
* r = nis_list(query, 0, 0, 0);
* if (r->status == NIS_SUCCESS) {
* stat = 0;
* strcpy(netname, ENTRY_VAL(r->objects.object_val, 1);
* }
* nis_freeresult(r);
* return (stat);
*
* Here it is assumed that the gssprin table containes two columns.
* The first, gssprincipal, contains the exported gss principal name
* in hex format. And the second, netname, that contains the secure
* rpc netname.
*/
return (stat);
}
static char *
flavor2str(int flavor)
{
switch (flavor) {
case AUTH_NONE:
return ("NONE");
case AUTH_SYS:
return ("SYS");
case AUTH_DES:
return ("DES");
case RPCSEC_GSS:
return ("GSS");
default:
return ("unknown");
}
}
/*
* Based on __nis_auth2princ but this one has RPCSEC_GSS support.
*/
void
char *name, /* out */
int verbose) /* in */
{
struct authsys_parms *au;
struct authdes_cred *ad;
char *rmtdomain;
int flavor; /* secure RPC flavor */
srch[0] = '\0';
if (req) {
} else {
if (verbose)
"_auth2princ_rpcgss: req = NULL: returning '%s'",
nobody);
return;
}
if (verbose) {
"__nis_auth2princ_rpcgss: flavor = NONE: returning '%s'",
nobody);
}
return;
/* LINTED pointer cast */
if (!rmtdomain)
if (verbose) {
"__nis_auth2princ_rpcgss: flavor = SYS: returning '%s'", name);
}
return;
}
sizeof (srch) - 1,
"[auth_name=\"%ld\", auth_type=LOCAL], cred.org_dir.%s",
(char *)nis_local_directory() : rmtdomain);
}
/* LINTED pointer cast */
if (refresh)
else
if (verbose)
"__nis_auth2princ_rpcgss: flavor = DES: returning from cache '%s'",
name);
return;
}
if (rmtdomain) {
rmtdomain++;
sizeof (srch) - 1,
"[auth_name=%s, auth_type=DES], cred.org_dir.%s",
sizeof (netname));
}
} else {
if (verbose) {
"__nis_auth2princ_rpcgss: flavor = DES: returning '%s'",
nobody);
}
return;
}
} else if (flavor == RPCSEC_GSS) {
void *cookie;
if (verbose) {
"__nis_auth2princ_rpcgss: GSS getcred failure: returning '%s'",
nobody);
}
return;
}
< 0) {
"__nis_auth2princ_rpcgss: can't extract netname from gss cred: returning '%s'",
nobody);
return;
}
if (refresh)
(void) delete_cred_item(netname);
else
if (verbose)
"__nis_auth2princ_rpcgss: flavor = RPCSEC_GSS: returning from cache '%s'",
name);
return;
}
if (rmtdomain) {
rmtdomain++;
sizeof (alias))) {
"__nis_auth2princ_rpcgss: mechname '%s' not found: returning 'nobody'",
return;
}
if (alias[0] != '\0') {
(void) __nis_mechalias2authtype(alias,
"[auth_name=%s, auth_type=%s], cred.org_dir.%s",
}
} else {
"__nis_auth2princ_rpcgss: no alias found for mechname '%s': returning 'nobody'",
return;
}
} else {
if (verbose) {
"__nis_auth2princ_rpcgss: flavor = RPCSEC_GSS: returning '%s'",
nobody);
}
return;
}
} else {
"__nis_auth2princ_rpcgss: flavor = %d(unknown): returning '%s'",
return;
}
if (verbose)
"__nis_auth2princ_rpcgss: calling list with name '%s' and type '%s'",
else /* AUTH_SYS */
"__nis_auth2princ_rpcgss: calling list with uid (LOCAL) '%d'",
if (verbose)
"__nis_auth2princ_rpcgss: error doing nis_list: %s",
} else {
1024);
if (verbose)
"__nis_auth2princ_rpcgss: caching '%s'/'%s'\n",
}
}
if (verbose)
"__nis_auth2princ_rpcgss: flavor = %s: returning : '%s'",
}
/*
* This function returns true if the given principal has the right to
* do the requested function on the given object. It could be a define
* if that would save time. At the moment it is a function.
* NOTE: It recursively calls NIS by doing the lookup on the group if
* the conditional gets that far.
*
* N.B. If the principal passed is 'null' then we're recursing and don't
* need to check it. (we always let ourselves look at the data)
*/
unsigned int right, /* The Access right we desire */
int level) /* security level server is running at */
{
return (TRUE);
}
/*
* is 'host' the master server for "org_dir."'domain' ?
*/
{
char buf[NIS_MAXNAMELEN];
return (FALSE);
}
/* strlen(".org_dir") + null + "." = 10 */
return (FALSE);
/* can't find any of the servers that serve this domain */
/* something is very wrong ! */
"cannot get a list of servers that serve '%s'",
buf);
return (FALSE);
}
else
/* done with server list */
return (res);
}
/*
* check if this principal is the owner of the table
* or is a member of the table group owner
*/
{
char buf[NIS_MAXNAMELEN];
struct nis_result *res;
struct nis_object *obj;
return (FALSE);
/* strlen(".org_dir.") + null + "." = 11 */
(size_t)NIS_MAXNAMELEN) {
return (FALSE);
}
/* get the table object */
"__nis_isadmin: could not lookup '%s' table",
table);
return (FALSE);
}
return (FALSE);
}
return (ans);
}
#define NIS_NOHOSTNAME 48
#define NIS_NOHOSTADDR 49
char *host, /* host name */
int *errcode) /* error code */
{
errcode));
}
static void
{
int i;
for (i = 0; i < n; i++) {
}
}
}
void
{
}
}
/*
* This function constructs a server description of the host
* given (or the local host) and returns it as a nis_server
* structure.
* Returns NULL on error, and sets the errcode.
*/
__nis_host2nis_server_g(const char *host,
int *errcode)
{
#define INC_SIZE 512
int addr_size = 0;
int num_ep = 0, i;
void *nch;
struct nd_hostserv hs;
struct nd_addrlist *addrlist;
char hostnetname[NIS_MAXPATH];
char netname[MAXNETNAMELEN];
if (host) {
if (!he) {
if (errcode)
*errcode = NIS_BADNAME;
return (NULL);
}
if (errcode)
*errcode = NIS_BADNAME;
return (NULL);
}
/*
* Make attempt to fully qualify hostname. If hostname
* contains a dot, then assume it is already fully
* qualified and just add a trailing dot. Otherwise,
* append local domain name.
*/
char *localDir = nis_local_directory();
if (*localDir != '.') {
reqlen += 1;
}
if (reqlen >= sizeof (hostnetname)) {
if (errcode)
*errcode = NIS_BADNAME;
return (NULL);
}
}
} else {
if (errcode)
return (NULL);
}
}
if (!(nch = setnetconfig()))
return (NULL);
continue;
continue;
if (errcode)
*errcode = NIS_NOMEMORY;
(void) endnetconfig(nch);
return (NULL);
}
}
if (errcode)
*errcode = NIS_NOMEMORY;
(void) endnetconfig(nch);
return (NULL);
}
}
}
(void) endnetconfig(nch);
if (errcode)
*errcode = NIS_NOMEMORY;
return (NULL);
}
if (errcode)
*errcode = NIS_NOMEMORY;
return (NULL);
}
if (addpubkey) {
goto nocred;
if (mechlist = __nis_get_mechanisms(0)) {
size_t keylistsize = 0;
int i;
for (i = 0; mechlist[i]; i++) {
char *hexkey, *entryoffset;
if (errcode)
*errcode = NIS_NOMEMORY;
return (NULL);
}
hexkeylen) == 0) {
continue;
} else {
if (keylen == 192)
else
}
keylistsize))) {
if (errcode)
*errcode = NIS_NOMEMORY;
return (NULL);
}
/* LINTED pointer cast */
}
/*
* If there is only keys for DH192, then we pretend
* that DHEXT doesn't exist.
*
* If no keys are returned, then we no nuthin'.
*/
if (!gotothers) {
if (got192)
goto only192;
else
goto nocred;
}
} else {
if (errcode)
*errcode = NIS_NOMEMORY;
return (NULL);
}
} else {
}
}
} else
goto nocred;
return (hostinfo);
}
/*
* Extract a public key given a key length and alg. type from a packed
* netobj containing extended Diffie-Hellman keys.
*/
char *
{
char *hexkey;
/* LINTED pointer cast */
/* LINTED pointer cast */
char *keyoffset;
return (NULL);
return (hexkey);
}
/* LINTED pointer cast */
}
return (NULL);
}
/*
* Returns a list of key lengths and alg. types for a given nis_server
* structure.
*/
int
{
int count = 0;
/* LINTED pointer cast */
case NIS_PK_DH:
return (0);
keyinfolist[0].algtype = 0;
*retdat = keyinfolist;
return (1);
case NIS_PK_DHEXT:
/* LINTED pointer cast */
char *keyoffset;
(count + 1) *
sizeof (extdhkey_t)))) {
return (0);
}
/* LINTED pointer cast */
count++;
}
*retdat = keyinfolist;
return (count);
default:
return (0);
}
}