diff options
Diffstat (limited to 'chpass/pw_yp.c')
-rw-r--r-- | chpass/pw_yp.c | 530 |
1 files changed, 0 insertions, 530 deletions
diff --git a/chpass/pw_yp.c b/chpass/pw_yp.c deleted file mode 100644 index df8a082..0000000 --- a/chpass/pw_yp.c +++ /dev/null @@ -1,530 +0,0 @@ -/* - * Copyright (c) 1995 - * Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Bill Paul. - * 4. Neither the name of the author nor the names of any co-contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * NIS interface routines for chpass - * - * Written by Bill Paul <wpaul@ctr.columbia.edu> - * Center for Telecommunications Research - * Columbia University, New York City - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#ifdef YP -#include <sys/param.h> -#include <sys/stat.h> -#include <sys/stat.h> -#include <sys/types.h> - -#include <rpc/rpc.h> -#include <rpcsvc/yp.h> -#include <rpcsvc/ypclnt.h> -#include <rpcsvc/yppasswd.h> - -#include <db.h> -#include <err.h> -#include <errno.h> -#include <fcntl.h> -#include <limits.h> -#include <netdb.h> -#include <pw_util.h> -#include <pwd.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <time.h> -#include <unistd.h> -#include <utmp.h> - -#include "pw_yp.h" -#include "ypxfr_extern.h" -#include "yppasswd_private.h" - -#define PERM_SECURE (S_IRUSR|S_IWUSR) -static HASHINFO openinfo = { - 4096, /* bsize */ - 32, /* ffactor */ - 256, /* nelem */ - 2048 * 1024, /* cachesize */ - NULL, /* hash */ - 0, /* lorder */ -}; - -static char passwdbyname[] = "passwd.byname"; -static char localhost[] = "localhost"; - -int force_old = 0; -int _use_yp = 0; -int suser_override = 0; -int yp_in_pw_file = 0; -char *yp_domain = NULL; -char *yp_server = NULL; - -extern char *tempname; - -/* Save the local and NIS password information */ -struct passwd local_password; -struct passwd yp_password; - -void -copy_yp_pass(char *p, int x, int m) -{ - register char *t, *s = p; - static char *buf; - - yp_password.pw_fields = 0; - - buf = (char *)realloc(buf, m + 10); - bzero(buf, m + 10); - - /* Turn all colons into NULLs */ - while (strchr(s, ':')) { - s = (strchr(s, ':') + 1); - *(s - 1)= '\0'; - } - - t = buf; -#define EXPAND(e) e = t; while ((*t++ = *p++)); - EXPAND(yp_password.pw_name); - yp_password.pw_fields |= _PWF_NAME; - EXPAND(yp_password.pw_passwd); - yp_password.pw_fields |= _PWF_PASSWD; - yp_password.pw_uid = atoi(p); - p += (strlen(p) + 1); - yp_password.pw_fields |= _PWF_UID; - yp_password.pw_gid = atoi(p); - p += (strlen(p) + 1); - yp_password.pw_fields |= _PWF_GID; - if (x) { - EXPAND(yp_password.pw_class); - yp_password.pw_fields |= _PWF_CLASS; - yp_password.pw_change = atol(p); - p += (strlen(p) + 1); - yp_password.pw_fields |= _PWF_CHANGE; - yp_password.pw_expire = atol(p); - p += (strlen(p) + 1); - yp_password.pw_fields |= _PWF_EXPIRE; - } - EXPAND(yp_password.pw_gecos); - yp_password.pw_fields |= _PWF_GECOS; - EXPAND(yp_password.pw_dir); - yp_password.pw_fields |= _PWF_DIR; - EXPAND(yp_password.pw_shell); - yp_password.pw_fields |= _PWF_SHELL; - - return; -} - -static void -copy_local_pass(char *p, int m) -{ - register char *t; - static char *buf; - - buf = (char *)realloc(buf, m + 10); - bzero(buf, m + 10); - - t = buf; - EXPAND(local_password.pw_name); - EXPAND(local_password.pw_passwd); - bcopy(p, (char *)&local_password.pw_uid, sizeof(int)); - p += sizeof(int); - bcopy(p, (char *)&local_password.pw_gid, sizeof(int)); - p += sizeof(int); - bcopy(p, (char *)&local_password.pw_change, sizeof(time_t)); - p += sizeof(time_t); - EXPAND(local_password.pw_class); - EXPAND(local_password.pw_gecos); - EXPAND(local_password.pw_dir); - EXPAND(local_password.pw_shell); - bcopy(p, (char *)&local_password.pw_expire, sizeof(time_t)); - p += sizeof(time_t); - bcopy(p, (char *)&local_password.pw_fields, sizeof local_password.pw_fields); - p += sizeof local_password.pw_fields; - - return; -} - -/* - * It is not mandatory that an NIS master server also be a client. - * However, if the NIS master is not configured as a client, then the - * domain name will not be set and ypbind will not be running, so we - * will be unable to use the ypclnt routines inside libc. We therefore - * need our own magic version of yp_match() which we can use in any - * environment. - */ -static int -my_yp_match(char *server, char *domain, const char *map, char *key, - unsigned long keylen, char **result, unsigned long *resultlen) -{ - ypreq_key ypkey; - ypresp_val *ypval; - CLIENT *clnt; - static char buf[YPMAXRECORD + 2]; - - bzero((char *)buf, sizeof(buf)); - - /* - * Don't make this a fatal error. The inability to contact - * a server is, for our purposes, equivalent to not finding - * the record we were looking for. Letting use_yp() know - * that the lookup failed is sufficient. - */ - if ((clnt = clnt_create(server, YPPROG,YPVERS,"udp")) == NULL) - return(1); - - ypkey.domain = domain; - ypkey.map = strdup(map); - ypkey.key.keydat_len = keylen; - ypkey.key.keydat_val = key; - - if ((ypval = ypproc_match_2(&ypkey, clnt)) == NULL) { - clnt_destroy(clnt); - return(1); - } - - clnt_destroy(clnt); - - if (ypval->stat != YP_TRUE) { - xdr_free(xdr_ypresp_val, (char *)ypval); - return(1); - } - - - strncpy((char *)&buf, ypval->val.valdat_val, ypval->val.valdat_len); - - *result = (char *)&buf; - *resultlen = ypval->val.valdat_len; - - xdr_free(xdr_ypresp_val, (char *)ypval); - - return(0); -} - -/* - * Check if the user we're working with is local or in NIS. - */ -int -use_yp(char *user, uid_t uid, int which /* 0 = use username, 1 = use uid */) -{ - int user_local = 0, user_yp = 0, user_exists = 0; - DB *dbp; - DBT key,data; - char bf[UT_NAMESIZE + 2]; - char *result; - char *server; - long resultlen; - char ubuf[UT_NAMESIZE + 2]; - - if (which) { - snprintf(ubuf, sizeof(ubuf), "%lu", (unsigned long)uid); - user = (char *)&ubuf; - } - - /* Grope around for the user in the usual way */ - if (which) { - if (getpwuid(uid) != NULL) - user_exists = 1; - } else { - if (getpwnam(user) != NULL) - user_exists = 1; - } - - /* Now grope directly through the user database */ - if ((dbp = dbopen(_PATH_SMP_DB, O_RDONLY, PERM_SECURE, - DB_HASH, &openinfo)) == NULL) { - warn("error opening database: %s.", _PATH_MP_DB); - pw_error(tempname, 0, 1); - } - - /* Is NIS turned on */ - bf[0] = _PW_KEYYPENABLED; - key.data = (u_char *)bf; - key.size = 1; - yp_in_pw_file = !(dbp->get)(dbp,&key,&data,0); - if (_yp_check(NULL) || (yp_domain && yp_server)) { - server = get_yp_master(0); - - /* Is the user in the NIS passwd map */ - if (!my_yp_match(server, yp_domain, which ? "passwd.byuid" : - "passwd.byname", user, strlen(user), - &result, &resultlen)) { - user_yp = user_exists = 1; - *(char *)(result + resultlen) = '\0'; - copy_yp_pass(result, 0, resultlen); - } - /* Is the user in the NIS master.passwd map */ - if (user_yp && !my_yp_match(server, yp_domain, which ? - "master.passwd.byuid" : "master.passwd.byname", - user, strlen(user), - &result, &resultlen)) { - *(char *)(result + resultlen) = '\0'; - copy_yp_pass(result, 1, resultlen); - } - } - - /* Is the user in the local password database */ - - bf[0] = which ? _PW_KEYBYUID : _PW_KEYBYNAME; - if (which) - bcopy((char *)&uid, bf + 1, sizeof(uid)); - else - bcopy((char *)user, bf + 1, MIN(strlen(user), UT_NAMESIZE)); - key.data = (u_char *)bf; - key.size = which ? sizeof(uid) + 1 : strlen(user) + 1; - if (!(dbp->get)(dbp,&key,&data,0)) { - user_local = 1; - copy_local_pass(data.data, data.size); - } - - (dbp->close)(dbp); - - if (user_local && user_yp && user_exists) - return(USER_YP_AND_LOCAL); - else if (!user_local && user_yp && user_exists) - return(USER_YP_ONLY); - else if (user_local && !user_yp && user_exists) - return(USER_LOCAL_ONLY); - else if (!user_exists) - return(USER_UNKNOWN); - - return(-1); -} - -/* - * Find the name of the NIS master server for this domain - * and make sure it's running yppasswdd. - */ -char * -get_yp_master(int getserver) -{ - char *mastername; - int rval, localport; - - /* - * Sometimes we are called just to probe for rpc.yppasswdd and - * set the suser_override flag. Just return NULL and leave - * suser_override at 0 if _use_yp doesn't indicate that NIS is - * in use and we weren't called from use_yp() itself. - * Without this check, we might try probing and fail with an NIS - * error in non-NIS environments. - */ - if ((_use_yp == USER_UNKNOWN || _use_yp == USER_LOCAL_ONLY) && - getserver) - return(NULL); - - /* Get default NIS domain. */ - - if (yp_domain == NULL && (rval = yp_get_default_domain(&yp_domain))) { - warnx("can't get local NIS domain name: %s",yperr_string(rval)); - pw_error(tempname, 0, 1); - } - - /* Get master server of passwd map. */ - - if ((mastername = ypxfr_get_master(yp_domain, passwdbyname, - yp_server, yp_server ? 0 : 1)) == NULL) { - warnx("can't get name of master NIS server"); - pw_error(tempname, 0, 1); - } - - if (!getserver) - return(mastername); - - /* Check if yppasswdd is out there. */ - - if ((rval = getrpcport(mastername, YPPASSWDPROG, YPPASSWDPROC_UPDATE, - IPPROTO_UDP)) == 0) { - warnx("rpc.yppasswdd is not running on the NIS master server"); - pw_error(tempname, 0, 1); - } - - /* - * Make sure it's on a reserved port. - * XXX Might break with yppasswdd servers running on Solaris 2.x. - */ - - if (rval >= IPPORT_RESERVED) { - warnx("rpc.yppasswdd server not running on reserved port"); - pw_error(tempname, 0, 1); - } - - /* See if _we_ are the master server. */ - if (!force_old && !getuid() && (localport = getrpcport(localhost, - YPPASSWDPROG, YPPASSWDPROC_UPDATE, IPPROTO_UDP)) != 0) { - if (localport == rval) { - suser_override = 1; - mastername = localhost; - } - } - - /* Everything checks out: return the name of the server. */ - - return (mastername); -} - -/* - * Ask the user for his NIS password and submit the new information - * to yppasswdd. Note that rpc.yppasswdd requires password authentication - * and only allows changes to existing records rather than the addition - * of new records. (To do actual updates we would need something like - * secure RPC and ypupdated, which FreeBSD doesn't have yet.) The FreeBSD - * rpc.yppasswdd has some special hooks to allow the superuser update - * information without specifying a password, however this only works - * for the superuser on the NIS master server. - */ -void -yp_submit(struct passwd *pw) -{ - struct yppasswd yppwd; - struct master_yppasswd master_yppwd; - struct netconfig *nconf; - void *localhandle; - CLIENT *clnt; - char *master, *password; - int *status = NULL; - struct rpc_err lerr; - - nconf = NULL; - _use_yp = 1; - - /* Get NIS master server name */ - - master = get_yp_master(1); - - /* Populate the yppasswd structure that gets handed to yppasswdd. */ - - if (suser_override) { - master_yppwd.newpw.pw_passwd = strdup(pw->pw_passwd); - master_yppwd.newpw.pw_name = strdup(pw->pw_name); - master_yppwd.newpw.pw_uid = pw->pw_uid; - master_yppwd.newpw.pw_gid = pw->pw_gid; - master_yppwd.newpw.pw_expire = pw->pw_expire; - master_yppwd.newpw.pw_change = pw->pw_change; - master_yppwd.newpw.pw_fields = pw->pw_fields; - master_yppwd.newpw.pw_gecos = strdup(pw->pw_gecos); - master_yppwd.newpw.pw_dir = strdup(pw->pw_dir); - master_yppwd.newpw.pw_shell = strdup(pw->pw_shell); - master_yppwd.newpw.pw_class = pw->pw_class != NULL - ? strdup(pw->pw_class) - : strdup(""); - master_yppwd.oldpass = strdup(""); /* not really needed */ - master_yppwd.domain = yp_domain; - } else { - yppwd.newpw.pw_passwd = strdup(pw->pw_passwd); - yppwd.newpw.pw_name = strdup(pw->pw_name); - yppwd.newpw.pw_uid = pw->pw_uid; - yppwd.newpw.pw_gid = pw->pw_gid; - yppwd.newpw.pw_gecos = strdup(pw->pw_gecos); - yppwd.newpw.pw_dir = strdup(pw->pw_dir); - yppwd.newpw.pw_shell = strdup(pw->pw_shell); - yppwd.oldpass = strdup(""); - } - - /* Get the user's password for authentication purposes. */ - - printf ("Changing NIS information for %s on %s\n", - pw->pw_name, master); - - if (pw->pw_passwd[0] && !suser_override) { - password = getpass("Please enter password: "); - if (strncmp(crypt(password,pw->pw_passwd), - pw->pw_passwd,strlen(pw->pw_passwd))) { - warnx("Password incorrect."); - pw_error(tempname, 0, 1); - } - yppwd.oldpass = password; /* XXX */ - } - - if (suser_override) { - /* Talk to server via AF_UNIX socket. */ - localhandle = setnetconfig(); - while ((nconf = getnetconfig(localhandle)) != NULL) { - if (nconf->nc_protofmly != NULL && - strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) - break; - } - if (nconf == NULL) { - warnx("getnetconfig: %s", nc_sperror()); - pw_error(tempname, 0, 1); - } - - clnt = clnt_tp_create(NULL, MASTER_YPPASSWDPROG, - MASTER_YPPASSWDVERS, nconf); - if (clnt == NULL) { - warnx("failed to contact rpc.yppasswdd: %s", - clnt_spcreateerror(master)); - endnetconfig(localhandle); - pw_error(tempname, 0, 1); - } - endnetconfig(localhandle); - } else { - /* Create a handle to yppasswdd. */ - - if ((clnt = clnt_create(master, YPPASSWDPROG, - YPPASSWDVERS, "udp")) == NULL) { - warnx("failed to contact rpc.yppasswdd: %s", - clnt_spcreateerror(master)); - pw_error(tempname, 0, 1); - } - } - - clnt->cl_auth = authunix_create_default(); - - if (suser_override) - status = yppasswdproc_update_master_1(&master_yppwd, clnt); - else - status = yppasswdproc_update_1(&yppwd, clnt); - - clnt_geterr(clnt, &lerr); - - auth_destroy(clnt->cl_auth); - clnt_destroy(clnt); - - /* Call failed: signal the error. */ - - if (lerr.re_status != RPC_SUCCESS || status == NULL || *status) { - warnx("NIS update failed: %s", clnt_sperrno(lerr.re_status)); - pw_error(NULL, 0, 1); - } - - /* Success. */ - - if (suser_override) - warnx("NIS information changed on host %s, domain %s", - master, yp_domain); - else - warnx("NIS information changed on host %s", master); - - return; -} -#endif /* YP */ |