OpenSolaris_b135/lib/libnsl/rpc/netname.c

Compare this file to the similar file:
Show the results in this format:

/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (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 2009 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */
/* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
/*
 * Portions of this source code were derived from Berkeley
 * 4.3 BSD under license from the Regents of the University of
 * California.
 */
/*
 * ==== hack-attack:  possibly MT-safe but definitely not MT-hot.
 * ==== turn this into a real switch frontend and backends
 *
 * Well, at least the API doesn't involve pointers-to-static.
 */

/*
 * netname utility routines (getnetname, user2netname, host2netname).
 *
 * Convert from unix names (uid, gid) to network wide names.
 * This module is operating system dependent!
 * What we define here will work with any unix system that has adopted
 * the Sun NIS domain architecture.
 */

#undef NIS

#include "mt.h"
#include "rpc_mt.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <ctype.h>
#include <string.h>
#include <syslog.h>
#include <sys/param.h>
#include <rpc/rpc.h>
#include <rpcsvc/nis.h>
#include <rpcsvc/nis_dhext.h>
#include <nsswitch.h>
#include <syslog.h>
#include <errno.h>

#ifndef MAXHOSTNAMELEN
#define	MAXHOSTNAMELEN 256
#endif
#ifndef NGROUPS
#define	NGROUPS 16
#endif

/*
 * the value for NOBODY_UID is set by the SVID. The following define also
 * appears in netnamer.c
 */

#define	NOBODY_UID 60001

extern int getdomainname();
extern int key_call();
#define	OPSYS_LEN 4
static const char *OPSYS = "unix";

/*
 * default publickey policy:
 *	publickey: nis [NOTFOUND = return] files
 */


/*	NSW_NOTSUCCESS  NSW_NOTFOUND   NSW_UNAVAIL    NSW_TRYAGAIN */
#define	DEF_ACTION {__NSW_RETURN, __NSW_RETURN, __NSW_CONTINUE, __NSW_CONTINUE}

static struct __nsw_lookup lookup_files = {"files", DEF_ACTION, NULL, NULL},
		lookup_nis = {"nis", DEF_ACTION, NULL, &lookup_files};
static struct __nsw_switchconfig publickey_default =
			{0, "publickey", 2, &lookup_nis};

static mutex_t serialize_netname = ERRORCHECKMUTEX;


#define	MAXIPRINT	(11)	/* max length of printed integer */

/*
 * Convert unix cred to network-name by concatenating the
 * 3 pieces of information <opsys type> <uid> <domain>.
 */

static int
user2netname_nis(int *err, char netname[MAXNETNAMELEN + 1], uid_t uid,
								char *domain)
{
	int i;
	char *dfltdom;
	if (domain == NULL) {
		if (__rpc_get_default_domain(&dfltdom) != 0) {
			*err = __NSW_UNAVAIL;
			return (0);
		}
		domain = dfltdom;
	}
	if ((strlen(domain) + OPSYS_LEN + 3 + MAXIPRINT) >
	    (size_t)MAXNETNAMELEN) {
		*err = __NSW_UNAVAIL;
		return (0);
	}
	(void) snprintf(netname, MAXNETNAMELEN + 1,
	    "%s.%d@%s", OPSYS, (int)uid, domain);
	i = strlen(netname);
	if (netname[i-1] == '.')
		netname[i-1] = '\0';
	*err = __NSW_SUCCESS;
	return (1);
}

/*
 * Figure out my fully qualified network name
 */
int
getnetname(char name[MAXNETNAMELEN + 1])
{
	uid_t uid;

	uid = geteuid();
	if (uid == 0)
		return (host2netname(name, NULL, NULL));
	return (user2netname(name, uid, NULL));
}


/*
 * Figure out the fully qualified network name for the given uid.
 * This is a private interface.
 */
int
__getnetnamebyuid(char name[MAXNETNAMELEN + 1], uid_t uid)
{
	if (uid == 0)
		return (host2netname(name, NULL, NULL));
	return (user2netname(name, uid, NULL));
}

/*
 * Convert unix cred to network-name
 *
 * It uses the publickey policy in the /etc/nsswitch.conf file
 * (Unless the netname is "nobody", which is special cased).
 * If there is no publickey policy in /etc/nsswitch.conf,
 * the default publickey policy is used, which is
 *	publickey: nis [NOTFOUND=return] files
 * Note that for the non-nisplus case, there is no failover
 * so only the first entry would be relevant for those cases.
 */
int
user2netname(char netname[MAXNETNAMELEN + 1], const uid_t uid,
							const char *domain)
{
	struct __nsw_switchconfig *conf;
	struct __nsw_lookup *look;
	int needfree = 1, res = 0;
	enum __nsw_parse_err perr;
	int err;

	/*
	 * Take care of the special case of "nobody". If the uid is
	 * the value assigned by the SVID for nobody, return the string
	 * "nobody".
	 */

	if (uid == NOBODY_UID) {
		(void) strlcpy(netname, "nobody", sizeof (netname));
		return (1);
	}

	netname[0] = '\0';  /* make null first (no need for memset) */

	if (mutex_lock(&serialize_netname) == EDEADLK) {
		/*
		 * This thread already holds this lock. This scenario
		 * occurs when a process requires a netname which
		 * itself requires a netname to look up. As we clearly
		 * can't continue like this we return 'nobody'.
		 */
		(void) strlcpy(netname, "nobody", sizeof (netname));
		return (1);
	}

	conf = __nsw_getconfig("publickey", &perr);
	if (!conf) {
		conf = &publickey_default;
		needfree = 0;
	}

	for (look = conf->lookups; look; look = look->next) {
		/* ldap, nis, and files all do the same thing. */
		if (strcmp(look->service_name, "ldap") == 0 ||
		    strcmp(look->service_name, "nis") == 0 ||
		    strcmp(look->service_name, "files") == 0)
			res = user2netname_nis(&err,
			    netname, uid, (char *)domain);
		else {
			syslog(LOG_INFO,
			    "user2netname: unknown nameservice \
					for publickey info '%s'\n",
			    look->service_name);
			err = __NSW_UNAVAIL;
		}
		switch (look->actions[err]) {
			case __NSW_CONTINUE :
				break;
			case __NSW_RETURN :
				if (needfree)
					(void) __nsw_freeconfig(conf);
				(void) mutex_unlock(&serialize_netname);
				return (res);
			default :
				syslog(LOG_ERR,
			"user2netname: Unknown action for nameservice '%s'",
				    look->service_name);
			}
	}
	if (needfree)
		(void) __nsw_freeconfig(conf);
	(void) mutex_unlock(&serialize_netname);
	return (0);
}


/*
 * Convert host to network-name
 * This routine returns following netnames given the host and domain
 * arguments defined below: (domainname=y.z)
 *	  Arguments
 *	host	domain		netname
 *	----	------		-------
 *	-	-		unix.m@y.z (hostname=m)
 *	-	a.b		unix.m@a.b (hostname=m)
 *	-	-		unix.m@y.z (hostname=m.w.x)
 *	-	a.b		unix.m@a.b (hostname=m.w.x)
 *	h	-		unix.h@y.z
 *	h	a.b		unix.h@a.b
 *	h.w.x	-		unix.h@w.x
 *	h.w.x	a.b		unix.h@a.b
 */
int
host2netname(char netname[MAXNETNAMELEN + 1], const char *host,
							const char *domain)
{
	char *p;
	char hostname[MAXHOSTNAMELEN + 1];
	char domainname[MAXHOSTNAMELEN + 1];
	char *dot_in_host;
	int i;
	size_t len;

	netname[0] = '\0';  /* make null first (no need for memset) */

	if (host == NULL) {
		(void) strncpy(hostname, nis_local_host(), sizeof (hostname));
		p = (char *)strchr(hostname, '.');
		if (p) {
			*p++ = '\0';
			/* if no domain passed, use tail of nis_local_host() */
			if (domain == NULL) {
				domain = p;
			}
		}
	} else {
		len = strlen(host);
		if (len >= sizeof (hostname)) {
			return (0);
		}
		(void) strcpy(hostname, host);
	}

	dot_in_host = (char *)strchr(hostname, '.');
	if (domain == NULL) {
		p = dot_in_host;
		if (p) {
			p = (char *)nis_domain_of(hostname);
			len = strlen(p);
			if (len >= sizeof (domainname)) {
				return (0);
			}
			(void) strcpy(domainname, p);
		} else {
			domainname[0] = NULL;
			if (getdomainname(domainname, MAXHOSTNAMELEN) < 0)
				return (0);
		}
	} else {
		len = strlen(domain);
		if (len >= sizeof (domainname)) {
			return (0);
		}
		(void) strcpy(domainname, domain);
	}

	i = strlen(domainname);
	if (i == 0)
		/* No domainname */
		return (0);
	if (domainname[i - 1] == '.')
		domainname[i - 1] = 0;

	if (dot_in_host) {  /* strip off rest of name */
		*dot_in_host = '\0';
	}

	if ((strlen(domainname) + strlen(hostname) + OPSYS_LEN + 3)
	    > (size_t)MAXNETNAMELEN) {
		return (0);
	}

	(void) snprintf(netname, MAXNETNAMELEN + 1,
	    "%s.%s@%s", OPSYS, hostname, domainname);
	return (1);
}