17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
227c478bd9Sstevel@tonic-gate /*
23*a506a34cSth  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate #include <stdio.h>
287c478bd9Sstevel@tonic-gate #include <stdlib.h>
297c478bd9Sstevel@tonic-gate #include <unistd.h>
307c478bd9Sstevel@tonic-gate #include <signal.h>
317c478bd9Sstevel@tonic-gate #include <fcntl.h>
327c478bd9Sstevel@tonic-gate #include <ctype.h>
337c478bd9Sstevel@tonic-gate #include <string.h>
347c478bd9Sstevel@tonic-gate #include <syslog.h>
357c478bd9Sstevel@tonic-gate #include <crypt.h>
367c478bd9Sstevel@tonic-gate #include <errno.h>
377c478bd9Sstevel@tonic-gate #include <tiuser.h>
387c478bd9Sstevel@tonic-gate #include <netdir.h>
397c478bd9Sstevel@tonic-gate #include <pwd.h>
407c478bd9Sstevel@tonic-gate #include <shadow.h>
417c478bd9Sstevel@tonic-gate #include <sys/types.h>
427c478bd9Sstevel@tonic-gate #include <sys/stat.h>
437c478bd9Sstevel@tonic-gate #include <sys/wait.h>
447c478bd9Sstevel@tonic-gate #include <sys/resource.h>
457c478bd9Sstevel@tonic-gate #include <rpc/rpc.h>
467c478bd9Sstevel@tonic-gate #include <rpc/pmap_clnt.h>
477c478bd9Sstevel@tonic-gate #include <rpcsvc/yppasswd.h>
487c478bd9Sstevel@tonic-gate #include <netconfig.h>
497c478bd9Sstevel@tonic-gate #include <deflt.h>
507c478bd9Sstevel@tonic-gate 
517c478bd9Sstevel@tonic-gate /* N2L includes */
527c478bd9Sstevel@tonic-gate #include <ndbm.h>
537c478bd9Sstevel@tonic-gate #include "shim.h"
547c478bd9Sstevel@tonic-gate #include "yptol.h"
557c478bd9Sstevel@tonic-gate 
567c478bd9Sstevel@tonic-gate /* must match sizes in passwd */
577c478bd9Sstevel@tonic-gate #define	STRSIZE 100
587c478bd9Sstevel@tonic-gate 
597c478bd9Sstevel@tonic-gate #define	DEFDIR "/etc/"
607c478bd9Sstevel@tonic-gate #define	MYPASSWD "passwd"
617c478bd9Sstevel@tonic-gate #define	MYSHADOW "shadow"
627c478bd9Sstevel@tonic-gate #define	DEFAULT_YPPASSWDD "/etc/default/yppasswdd"
637c478bd9Sstevel@tonic-gate #define	YPPASSWDD_STR "check_restricted_shell_name=1"
647c478bd9Sstevel@tonic-gate 
657c478bd9Sstevel@tonic-gate /* The guts are in there */
66*a506a34cSth extern void changepasswd(SVCXPRT *);
677c478bd9Sstevel@tonic-gate 
687c478bd9Sstevel@tonic-gate static void	boilerplate(struct svc_req *rqstp, SVCXPRT *transp);
697c478bd9Sstevel@tonic-gate static void	unlimit(int lim);
707c478bd9Sstevel@tonic-gate bool_t		validloginshell(char *sh, char *arg, int);
717c478bd9Sstevel@tonic-gate int		validstr(char *str, size_t size);
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate extern char  *getusershell(void);
747c478bd9Sstevel@tonic-gate extern void   setusershell(void);
757c478bd9Sstevel@tonic-gate extern void   endusershell(void);
767c478bd9Sstevel@tonic-gate 
777c478bd9Sstevel@tonic-gate int  Argc;
787c478bd9Sstevel@tonic-gate char **Argv;
797c478bd9Sstevel@tonic-gate int  mflag;			/* do a make */
807c478bd9Sstevel@tonic-gate int Mstart;
817c478bd9Sstevel@tonic-gate int single = 0;
827c478bd9Sstevel@tonic-gate int nogecos = 0;
837c478bd9Sstevel@tonic-gate int noshell = 0;
847c478bd9Sstevel@tonic-gate int nopw = 0;
857c478bd9Sstevel@tonic-gate int useadjunct = 0;
867c478bd9Sstevel@tonic-gate int useshadow = 0;
877c478bd9Sstevel@tonic-gate 
887c478bd9Sstevel@tonic-gate static char *defshell = "/bin/sh";
897c478bd9Sstevel@tonic-gate 
907c478bd9Sstevel@tonic-gate /* These are the various reasons we might exit. */
917c478bd9Sstevel@tonic-gate enum exitstat {
927c478bd9Sstevel@tonic-gate     Esuccess,
937c478bd9Sstevel@tonic-gate     EminusDandfiles,
947c478bd9Sstevel@tonic-gate     Emissingdir,
957c478bd9Sstevel@tonic-gate     Emissingadjunct,
967c478bd9Sstevel@tonic-gate     Eaccesspasswd,
977c478bd9Sstevel@tonic-gate     Eaccessshadow,
987c478bd9Sstevel@tonic-gate     Echdir,
997c478bd9Sstevel@tonic-gate     Egetnetconfigent,
1007c478bd9Sstevel@tonic-gate     Et_open,
1017c478bd9Sstevel@tonic-gate     Enetdir_rsvdport,
1027c478bd9Sstevel@tonic-gate     Et_sync,
1037c478bd9Sstevel@tonic-gate     Et_info,
1047c478bd9Sstevel@tonic-gate     Esvc_create,
1057c478bd9Sstevel@tonic-gate     Esvc_reg,
1067c478bd9Sstevel@tonic-gate     Esvcrun_ret,
1077c478bd9Sstevel@tonic-gate     ElockFail,
1087c478bd9Sstevel@tonic-gate     EparseFail
1097c478bd9Sstevel@tonic-gate };
1107c478bd9Sstevel@tonic-gate 
1117c478bd9Sstevel@tonic-gate static char err_usage[] =
1127c478bd9Sstevel@tonic-gate "Usage:\n"
1137c478bd9Sstevel@tonic-gate "        rpc.yppasswdd [-D directory | passwd [passwd.adjunct]]\n"
1147c478bd9Sstevel@tonic-gate "                      [-nopw] [-nogecos]\n"
1157c478bd9Sstevel@tonic-gate "                      [-noshell] [-m arg1 arg2 ...]\n"
1167c478bd9Sstevel@tonic-gate "where\n"
1177c478bd9Sstevel@tonic-gate "        directory is the directory where the passwd, shadow and/or\n"
1187c478bd9Sstevel@tonic-gate "        passwd.adjunct files are found (/etc by default)\n"
1197c478bd9Sstevel@tonic-gate "        It should match the setting of PWDIR in /var/yp/Makefile\n\n"
1207c478bd9Sstevel@tonic-gate "        Alternatively, the old 4.1.x syntax is supported where\n"
1217c478bd9Sstevel@tonic-gate "        passwd is the path to the passwd file\n"
1227c478bd9Sstevel@tonic-gate "        passwd.adjunct is the patch to the passwd.adjunct file\n"
1237c478bd9Sstevel@tonic-gate "        NOTES:\n"
1247c478bd9Sstevel@tonic-gate "         1. The -D option and the passwd/passwd.adjunct arguments are\n"
1257c478bd9Sstevel@tonic-gate "            mutually exclusive\n"
1267c478bd9Sstevel@tonic-gate "         2. The old syntax deprecated and will be removed in a future\n"
1277c478bd9Sstevel@tonic-gate "            release\n"
1287c478bd9Sstevel@tonic-gate "         3. A shadow file found in the same directory as the passwd\n"
1297c478bd9Sstevel@tonic-gate "            will be assumed to contain the password information\n\n"
1307c478bd9Sstevel@tonic-gate "        arguments after -m are passed to make(1S) after password changes\n"
1317c478bd9Sstevel@tonic-gate "        -nopw passwords may not be changed remotely using passwd\n"
1327c478bd9Sstevel@tonic-gate "        -nogecos full name may not be changed remotely using passwd or chfn\n"
1337c478bd9Sstevel@tonic-gate "        -noshell shell may not be changed remotely using passwd or chsh\n";
1347c478bd9Sstevel@tonic-gate 
1357c478bd9Sstevel@tonic-gate char passwd_file[FILENAME_MAX], shadow_file[FILENAME_MAX];
1367c478bd9Sstevel@tonic-gate char lockfile[FILENAME_MAX], adjunct_file[FILENAME_MAX];
1377c478bd9Sstevel@tonic-gate 
1387c478bd9Sstevel@tonic-gate int
main(int argc,char ** argv)1397c478bd9Sstevel@tonic-gate main(int argc, char **argv)
1407c478bd9Sstevel@tonic-gate {
1417c478bd9Sstevel@tonic-gate 	SVCXPRT *transp4, *transp6, *transpl;
1427c478bd9Sstevel@tonic-gate 	struct netconfig *nconf4, *nconf6, *nconfl;
1437c478bd9Sstevel@tonic-gate 	int i, tli4, tli6, stat;
1447c478bd9Sstevel@tonic-gate 	int errorflag;
1457c478bd9Sstevel@tonic-gate 	int dfexcl; /* -D or files, not both flag */
1467c478bd9Sstevel@tonic-gate 	enum exitstat exitstatus = Esuccess;
1477c478bd9Sstevel@tonic-gate 	int connmaxrec = RPC_MAXDATASIZE;
1487c478bd9Sstevel@tonic-gate 
1497c478bd9Sstevel@tonic-gate 	strcpy(passwd_file, DEFDIR MYPASSWD);
1507c478bd9Sstevel@tonic-gate 	strcpy(shadow_file, DEFDIR MYSHADOW);
1517c478bd9Sstevel@tonic-gate 	strcpy(lockfile, DEFDIR ".pwd.lock");
1527c478bd9Sstevel@tonic-gate 	strcpy(adjunct_file, DEFDIR "security/passwd.adjunct");
1537c478bd9Sstevel@tonic-gate 
1547c478bd9Sstevel@tonic-gate 	Argc = argc;
1557c478bd9Sstevel@tonic-gate 	Argv = argv;
1567c478bd9Sstevel@tonic-gate 
1577c478bd9Sstevel@tonic-gate 	for (i = 1, errorflag = 0, dfexcl = 0; i < argc; i++) {
1587c478bd9Sstevel@tonic-gate 		if (argv[i][0] == '-' && argv[i][1] == 'm') {
1597c478bd9Sstevel@tonic-gate 		    if (access("/usr/ccs/bin/make", X_OK) < 0)
1607c478bd9Sstevel@tonic-gate 			fprintf(stderr,
1617c478bd9Sstevel@tonic-gate 				"%s: /usr/ccs/bin/make is not available, "
1627c478bd9Sstevel@tonic-gate 				"ignoring -m option",
1637c478bd9Sstevel@tonic-gate 				argv[0]);
1647c478bd9Sstevel@tonic-gate 		    else {
1657c478bd9Sstevel@tonic-gate 			mflag++;
1667c478bd9Sstevel@tonic-gate 			Mstart = i;
1677c478bd9Sstevel@tonic-gate 			break;
1687c478bd9Sstevel@tonic-gate 		    }
1697c478bd9Sstevel@tonic-gate 		} else if (argv[i][0] == '-' && argv[i][1] == 'D') {
1707c478bd9Sstevel@tonic-gate 		    switch (dfexcl) {
1717c478bd9Sstevel@tonic-gate 		    case 0:
1727c478bd9Sstevel@tonic-gate 			if (++i < argc) {
1737c478bd9Sstevel@tonic-gate 			    strcpy(passwd_file, argv[i]);
1747c478bd9Sstevel@tonic-gate 			    strcpy(shadow_file, argv[i]);
1757c478bd9Sstevel@tonic-gate 			    strcpy(adjunct_file, argv[i]);
1767c478bd9Sstevel@tonic-gate 			    strcpy(lockfile, argv[i]);
1777c478bd9Sstevel@tonic-gate 			    if (argv[i][strlen(argv[i]) - 1] == '/') {
1787c478bd9Sstevel@tonic-gate 				strcat(passwd_file, MYPASSWD);
1797c478bd9Sstevel@tonic-gate 				strcat(shadow_file, MYSHADOW);
1807c478bd9Sstevel@tonic-gate 				strcat(lockfile, ".pwd.lock");
1817c478bd9Sstevel@tonic-gate 				strcat(adjunct_file, "security/passwd.adjunct");
1827c478bd9Sstevel@tonic-gate 			    } else {
1837c478bd9Sstevel@tonic-gate 				strcat(passwd_file, "/" MYPASSWD);
1847c478bd9Sstevel@tonic-gate 				strcat(shadow_file, "/" MYSHADOW);
1857c478bd9Sstevel@tonic-gate 				strcat(lockfile, "/.pwd.lock");
1867c478bd9Sstevel@tonic-gate 				strcat(adjunct_file,
1877c478bd9Sstevel@tonic-gate 					"/security/passwd.adjunct");
1887c478bd9Sstevel@tonic-gate 			    }
1897c478bd9Sstevel@tonic-gate 			    dfexcl++;
1907c478bd9Sstevel@tonic-gate 			} else {
1917c478bd9Sstevel@tonic-gate 			    fprintf(stderr,
1927c478bd9Sstevel@tonic-gate 				"rpc.yppasswdd: -D option requires a "
1937c478bd9Sstevel@tonic-gate 				"directory argument\n");
1947c478bd9Sstevel@tonic-gate 			    errorflag++;
1957c478bd9Sstevel@tonic-gate 			    exitstatus = Emissingdir;
1967c478bd9Sstevel@tonic-gate 			}
1977c478bd9Sstevel@tonic-gate 			break;
1987c478bd9Sstevel@tonic-gate 		    case 1:
1997c478bd9Sstevel@tonic-gate 			fprintf(stderr,
2007c478bd9Sstevel@tonic-gate 				"rpc.yppasswdd: cannot specify passwd/"
2017c478bd9Sstevel@tonic-gate 				"passwd.adjunct pathnames AND use -D\n");
2027c478bd9Sstevel@tonic-gate 			errorflag++;
2037c478bd9Sstevel@tonic-gate 			dfexcl++;
2047c478bd9Sstevel@tonic-gate 			exitstatus = EminusDandfiles;
2057c478bd9Sstevel@tonic-gate 			break;
2067c478bd9Sstevel@tonic-gate 		    default:
2077c478bd9Sstevel@tonic-gate 			break;
2087c478bd9Sstevel@tonic-gate 		    }
2097c478bd9Sstevel@tonic-gate 	/* -single: Allow user to change only one of password,  */
2107c478bd9Sstevel@tonic-gate 	/*		shell, or full name at a time.  (WHY?)	*/
2117c478bd9Sstevel@tonic-gate 	/*	else if (strcmp(argv[i], "-single") == 0)	*/
2127c478bd9Sstevel@tonic-gate 	/*	    single = 1;					*/
2137c478bd9Sstevel@tonic-gate 	/*	else if (strcmp(argv[i], "-nosingle") == 0)	*/
2147c478bd9Sstevel@tonic-gate 	/*	    single = 0;					*/
2157c478bd9Sstevel@tonic-gate 		} else if (strcmp(argv[i], "-nogecos") == 0)
2167c478bd9Sstevel@tonic-gate 		    nogecos = 1;
2177c478bd9Sstevel@tonic-gate 		else if (strcmp(argv[i], "-nopw") == 0)
2187c478bd9Sstevel@tonic-gate 		    nopw = 1;
2197c478bd9Sstevel@tonic-gate 		else if (strcmp(argv[i], "-noshell") == 0)
2207c478bd9Sstevel@tonic-gate 		    noshell = 1;
2217c478bd9Sstevel@tonic-gate 		else if (argv[i][0] != '-') {
2227c478bd9Sstevel@tonic-gate 			/*
2237c478bd9Sstevel@tonic-gate 			 * If we find a shadow file, we warn that we're
2247c478bd9Sstevel@tonic-gate 			 * using it in addition to warning that the user
2257c478bd9Sstevel@tonic-gate 			 * it using a deprecated syntax.
2267c478bd9Sstevel@tonic-gate 			 */
2277c478bd9Sstevel@tonic-gate 		    errorflag++;
2287c478bd9Sstevel@tonic-gate 		    switch (dfexcl) {
2297c478bd9Sstevel@tonic-gate 		    case 0:
2307c478bd9Sstevel@tonic-gate 			strcpy(passwd_file, argv[i]);
2317c478bd9Sstevel@tonic-gate 			memset(shadow_file, 0, sizeof (shadow_file));
2327c478bd9Sstevel@tonic-gate 			strncpy(shadow_file, argv[i],
2337c478bd9Sstevel@tonic-gate 				strrchr(argv[i], '/') - argv[i] + 1);
2347c478bd9Sstevel@tonic-gate 			strcat(shadow_file, MYSHADOW);
2357c478bd9Sstevel@tonic-gate 			fprintf(stderr,
2367c478bd9Sstevel@tonic-gate 				"rpc.yppasswdd: specifying the password file"
2377c478bd9Sstevel@tonic-gate 				" on the command line is \n"
2387c478bd9Sstevel@tonic-gate 				"               obsolete, "
2397c478bd9Sstevel@tonic-gate 				"consider using the -D option instead.\n");
2407c478bd9Sstevel@tonic-gate 			if (access(shadow_file, F_OK) == 0) {
2417c478bd9Sstevel@tonic-gate 			    fprintf(stderr,
2427c478bd9Sstevel@tonic-gate 				    "rpc.yppasswdd: found a shadow file in "
2437c478bd9Sstevel@tonic-gate 				    "the same directory as %s\n"
2447c478bd9Sstevel@tonic-gate 				    "               It will be used.\n",
2457c478bd9Sstevel@tonic-gate 				    passwd_file);
2467c478bd9Sstevel@tonic-gate 			}
2477c478bd9Sstevel@tonic-gate 			if (i + 1 < argc && argv[i+1][0] != '-') {
2487c478bd9Sstevel@tonic-gate 			    strcpy(adjunct_file, argv[++i]);
2497c478bd9Sstevel@tonic-gate 			    if (access(adjunct_file, F_OK) != 0) {
2507c478bd9Sstevel@tonic-gate 				fprintf(stderr,
2517c478bd9Sstevel@tonic-gate 					"rpc.yppasswdd: adjunct file %s "
2527c478bd9Sstevel@tonic-gate 					"not found\n",
2537c478bd9Sstevel@tonic-gate 					adjunct_file);
2547c478bd9Sstevel@tonic-gate 				exitstatus = Emissingadjunct;
2557c478bd9Sstevel@tonic-gate 			    }
2567c478bd9Sstevel@tonic-gate 			}
2577c478bd9Sstevel@tonic-gate 			dfexcl++;
2587c478bd9Sstevel@tonic-gate 			break;
2597c478bd9Sstevel@tonic-gate 		    case 1:
2607c478bd9Sstevel@tonic-gate 			fprintf(stderr,
2617c478bd9Sstevel@tonic-gate 				"rpc.yppasswdd: cannot specify passwd/"
2627c478bd9Sstevel@tonic-gate 				"passwd.adjunct pathnames AND use -D\n");
2637c478bd9Sstevel@tonic-gate 			dfexcl++;
2647c478bd9Sstevel@tonic-gate 			exitstatus = EminusDandfiles;
2657c478bd9Sstevel@tonic-gate 			break;
2667c478bd9Sstevel@tonic-gate 		    default:
2677c478bd9Sstevel@tonic-gate 			break;
2687c478bd9Sstevel@tonic-gate 		    }
2697c478bd9Sstevel@tonic-gate 		} else {
2707c478bd9Sstevel@tonic-gate 		    errorflag++;
2717c478bd9Sstevel@tonic-gate 		    fprintf(stderr,
2727c478bd9Sstevel@tonic-gate 			    "rpc.yppasswdd: unrecognized option %s ignored\n",
2737c478bd9Sstevel@tonic-gate 			    argv[i]);
2747c478bd9Sstevel@tonic-gate 		}
2757c478bd9Sstevel@tonic-gate 	}
2767c478bd9Sstevel@tonic-gate 
2777c478bd9Sstevel@tonic-gate 	if (errorflag)
2787c478bd9Sstevel@tonic-gate 		fprintf(stderr, err_usage);
2797c478bd9Sstevel@tonic-gate 
2807c478bd9Sstevel@tonic-gate 	if (exitstatus)
2817c478bd9Sstevel@tonic-gate 		exit(exitstatus);
2827c478bd9Sstevel@tonic-gate 
2837c478bd9Sstevel@tonic-gate 	if (access(passwd_file, W_OK) < 0) {
2847c478bd9Sstevel@tonic-gate 		fprintf(stderr, "rpc.yppasswdd: can't access %s\n",
2857c478bd9Sstevel@tonic-gate 			passwd_file);
2867c478bd9Sstevel@tonic-gate 		exitstatus = Eaccesspasswd;
2877c478bd9Sstevel@tonic-gate 	}
2887c478bd9Sstevel@tonic-gate 	if (access(shadow_file, W_OK) == 0) {
2897c478bd9Sstevel@tonic-gate 		useshadow = 1;
2907c478bd9Sstevel@tonic-gate 	} else {
2917c478bd9Sstevel@tonic-gate 		/* We don't demand a shadow file unless we're looking at /etc */
2927c478bd9Sstevel@tonic-gate 		if (strcmp(DEFDIR MYSHADOW, shadow_file) == 0) {
2937c478bd9Sstevel@tonic-gate 		    fprintf(stderr, "rpc.yppasswdd: can't access %s\n",
2947c478bd9Sstevel@tonic-gate 				shadow_file);
2957c478bd9Sstevel@tonic-gate 		    exitstatus = Eaccessshadow;
2967c478bd9Sstevel@tonic-gate 		}
2977c478bd9Sstevel@tonic-gate 	}
2987c478bd9Sstevel@tonic-gate 	if (access(adjunct_file, W_OK) == 0) {
2997c478bd9Sstevel@tonic-gate 		/* using an adjunct file */
3007c478bd9Sstevel@tonic-gate 		useadjunct = 1;
3017c478bd9Sstevel@tonic-gate 	}
3027c478bd9Sstevel@tonic-gate 
3037c478bd9Sstevel@tonic-gate 	if (chdir("/var/yp") < 0) {
3047c478bd9Sstevel@tonic-gate 		fprintf(stderr, "rpc.yppasswdd: can't chdir to /var/yp\n");
3057c478bd9Sstevel@tonic-gate 		exitstatus = Echdir;
3067c478bd9Sstevel@tonic-gate 	}
3077c478bd9Sstevel@tonic-gate 
3087c478bd9Sstevel@tonic-gate 	if (exitstatus)
3097c478bd9Sstevel@tonic-gate 		exit(exitstatus);
3107c478bd9Sstevel@tonic-gate 
3117c478bd9Sstevel@tonic-gate 	if (errorflag)
3127c478bd9Sstevel@tonic-gate 		fprintf(stderr, "\nProceeding.\n");
3137c478bd9Sstevel@tonic-gate 
3147c478bd9Sstevel@tonic-gate 
3157c478bd9Sstevel@tonic-gate 	/*
3167c478bd9Sstevel@tonic-gate 	 * Initialize locking system.
3177c478bd9Sstevel@tonic-gate 	 * This is required for N2L version which accesses the DBM files.
3187c478bd9Sstevel@tonic-gate 	 * For the non N2L version this sets up some locking which, since non
3197c478bd9Sstevel@tonic-gate 	 * N2L mode does not access the DBM files, will be unused.
3207c478bd9Sstevel@tonic-gate 	 *
3217c478bd9Sstevel@tonic-gate 	 * This also sets up yptol_mode.
3227c478bd9Sstevel@tonic-gate 	 */
3237c478bd9Sstevel@tonic-gate 	if (!init_lock_system(TRUE)) {
3247c478bd9Sstevel@tonic-gate 		fprintf(stderr,
3257c478bd9Sstevel@tonic-gate 			"rpc.yppasswdd: Cant initialize locking system\n");
3267c478bd9Sstevel@tonic-gate 		exit(ElockFail);
3277c478bd9Sstevel@tonic-gate 	}
3287c478bd9Sstevel@tonic-gate 
3297c478bd9Sstevel@tonic-gate #ifndef	DEBUG
3307c478bd9Sstevel@tonic-gate 	/* Close everything, but stdin/stdout/stderr */
3317c478bd9Sstevel@tonic-gate 	closefrom(3);
3327c478bd9Sstevel@tonic-gate #endif
3337c478bd9Sstevel@tonic-gate 
3347c478bd9Sstevel@tonic-gate 	if (yptol_mode) {
3357c478bd9Sstevel@tonic-gate 		stat = parseConfig(NULL, NTOL_MAP_FILE);
3367c478bd9Sstevel@tonic-gate 		if (stat == 1) {
3377c478bd9Sstevel@tonic-gate 			fprintf(stderr, "yppasswdd : NIS to LDAP mapping"
3387c478bd9Sstevel@tonic-gate 							" inactive.\n");
3397c478bd9Sstevel@tonic-gate 		} else if (stat != 0) {
3407c478bd9Sstevel@tonic-gate 			fprintf(stderr, "yppasswdd : Aborting after NIS to LDAP"
3417c478bd9Sstevel@tonic-gate 							" mapping error.\n");
3427c478bd9Sstevel@tonic-gate 			exit(EparseFail);
3437c478bd9Sstevel@tonic-gate 		}
3447c478bd9Sstevel@tonic-gate 	}
3457c478bd9Sstevel@tonic-gate 
3467c478bd9Sstevel@tonic-gate #ifndef	DEBUG
3477c478bd9Sstevel@tonic-gate 	/* Wack umask that we inherited from parent */
3487c478bd9Sstevel@tonic-gate 	umask(0);
3497c478bd9Sstevel@tonic-gate 
3507c478bd9Sstevel@tonic-gate 	/* Be a midwife to ourselves */
3517c478bd9Sstevel@tonic-gate 	if (fork())
3527c478bd9Sstevel@tonic-gate 		exit(Esuccess);
3537c478bd9Sstevel@tonic-gate 
3547c478bd9Sstevel@tonic-gate 	/* Disassociation is hard to do, la la la */
3557c478bd9Sstevel@tonic-gate 	setpgrp();
3567c478bd9Sstevel@tonic-gate 	setsid();
3577c478bd9Sstevel@tonic-gate 
3587c478bd9Sstevel@tonic-gate 	/* Ignore stuff */
3597c478bd9Sstevel@tonic-gate 	signal(SIGHUP, SIG_IGN);
3607c478bd9Sstevel@tonic-gate 	signal(SIGINT, SIG_IGN);
3617c478bd9Sstevel@tonic-gate 	signal(SIGWINCH, SIG_IGN);
3627c478bd9Sstevel@tonic-gate 	signal(SIGTSTP, SIG_IGN);
3637c478bd9Sstevel@tonic-gate 	signal(SIGTTIN, SIG_IGN);
3647c478bd9Sstevel@tonic-gate 	signal(SIGTTOU, SIG_IGN);
3657c478bd9Sstevel@tonic-gate 	signal(SIGCHLD, SIG_IGN);
3667c478bd9Sstevel@tonic-gate 
3677c478bd9Sstevel@tonic-gate 	/*
3687c478bd9Sstevel@tonic-gate 	 * Just in case that wasn't enough, let's fork
3697c478bd9Sstevel@tonic-gate 	 * again.  (per Stevens).
3707c478bd9Sstevel@tonic-gate 	 */
3717c478bd9Sstevel@tonic-gate 	if (fork())
3727c478bd9Sstevel@tonic-gate 		exit(Esuccess);
3737c478bd9Sstevel@tonic-gate 
3747c478bd9Sstevel@tonic-gate 	/*
3757c478bd9Sstevel@tonic-gate 	 * We need stdin, stdout, and stderr later when we
3767c478bd9Sstevel@tonic-gate 	 * fork a make(1).
3777c478bd9Sstevel@tonic-gate 	 */
3787c478bd9Sstevel@tonic-gate 	freopen("/dev/null", "r+", stdin);
3797c478bd9Sstevel@tonic-gate 	freopen("/dev/null", "r+", stdout);
3807c478bd9Sstevel@tonic-gate 	freopen("/dev/null", "r+", stderr);
3817c478bd9Sstevel@tonic-gate #endif
3827c478bd9Sstevel@tonic-gate 
3837c478bd9Sstevel@tonic-gate 	openlog("yppasswdd", LOG_CONS | LOG_PID, LOG_AUTH);
3847c478bd9Sstevel@tonic-gate 	unlimit(RLIMIT_CPU);
3857c478bd9Sstevel@tonic-gate 	unlimit(RLIMIT_FSIZE);
3867c478bd9Sstevel@tonic-gate 
3877c478bd9Sstevel@tonic-gate 	/*
3887c478bd9Sstevel@tonic-gate 	 * Set non-blocking mode and maximum record size for
3897c478bd9Sstevel@tonic-gate 	 * connection oriented RPC transports.
3907c478bd9Sstevel@tonic-gate 	 */
3917c478bd9Sstevel@tonic-gate 	if (!rpc_control(RPC_SVC_CONNMAXREC_SET, &connmaxrec)) {
3927c478bd9Sstevel@tonic-gate 		syslog(LOG_INFO, "unable to set maximum RPC record size");
3937c478bd9Sstevel@tonic-gate 	}
3947c478bd9Sstevel@tonic-gate 
3957c478bd9Sstevel@tonic-gate 	nconf4 = getnetconfigent("udp");
3967c478bd9Sstevel@tonic-gate 	nconf6 = getnetconfigent("udp6");
3977c478bd9Sstevel@tonic-gate 	if (nconf4 == 0 && nconf6 == 0) {
3987c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "udp/udp6 transport not supported\n");
3997c478bd9Sstevel@tonic-gate 		exit(Egetnetconfigent);
4007c478bd9Sstevel@tonic-gate 	}
4017c478bd9Sstevel@tonic-gate 
4027c478bd9Sstevel@tonic-gate 	tli4 = (nconf4 != 0) ? t_open(nconf4->nc_device, O_RDWR, NULL) : -1;
4037c478bd9Sstevel@tonic-gate 	tli6 = (nconf6 != 0) ? t_open(nconf6->nc_device, O_RDWR, NULL) : -1;
4047c478bd9Sstevel@tonic-gate 
4057c478bd9Sstevel@tonic-gate 	if (tli4 == -1 && tli6 == -1) {
4067c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "can\'t open TLI endpoint(s)\n");
4077c478bd9Sstevel@tonic-gate 		exit(Et_open);
4087c478bd9Sstevel@tonic-gate 	}
4097c478bd9Sstevel@tonic-gate 
4107c478bd9Sstevel@tonic-gate 	if (tli4 != -1) {
4117c478bd9Sstevel@tonic-gate 		if (netdir_options(nconf4, ND_SET_RESERVEDPORT, tli4, NULL)) {
4127c478bd9Sstevel@tonic-gate 			syslog(LOG_ERR, "could not set reserved port: %s\n",
4137c478bd9Sstevel@tonic-gate 				netdir_sperror());
4147c478bd9Sstevel@tonic-gate 			exit(Enetdir_rsvdport);
4157c478bd9Sstevel@tonic-gate 		}
4167c478bd9Sstevel@tonic-gate 	}
4177c478bd9Sstevel@tonic-gate 	if (tli6 != -1) {
4187c478bd9Sstevel@tonic-gate 		if (netdir_options(nconf6, ND_SET_RESERVEDPORT, tli6, NULL)) {
4197c478bd9Sstevel@tonic-gate 			syslog(LOG_ERR, "could not set reserved port: %s\n",
4207c478bd9Sstevel@tonic-gate 				netdir_sperror());
4217c478bd9Sstevel@tonic-gate 			exit(Enetdir_rsvdport);
4227c478bd9Sstevel@tonic-gate 		}
4237c478bd9Sstevel@tonic-gate 	}
4247c478bd9Sstevel@tonic-gate #ifdef	DEBUG
4257c478bd9Sstevel@tonic-gate 	{
4267c478bd9Sstevel@tonic-gate 		int i, tli[2];
4277c478bd9Sstevel@tonic-gate 		char *label[2] = {"udp", "udp6"};
4287c478bd9Sstevel@tonic-gate 		int state;
4297c478bd9Sstevel@tonic-gate 		struct t_info tinfo;
4307c478bd9Sstevel@tonic-gate 
4317c478bd9Sstevel@tonic-gate 		tli[0] = tli4;
4327c478bd9Sstevel@tonic-gate 		tli[1] = tli6;
4337c478bd9Sstevel@tonic-gate 
4347c478bd9Sstevel@tonic-gate 		for (i = 0; i < sizeof (tli)/sizeof (tli[0]); i++) {
4357c478bd9Sstevel@tonic-gate 			fprintf(stderr, "transport %s, fd = %d\n",
4367c478bd9Sstevel@tonic-gate 				tli[i], label[i]);
4377c478bd9Sstevel@tonic-gate 			if ((state = t_sync(tli[i])) < 0) {
4387c478bd9Sstevel@tonic-gate 				fprintf(stderr, "t_sync failed: %s\n",
4397c478bd9Sstevel@tonic-gate 					t_errlist[t_errno]);
4407c478bd9Sstevel@tonic-gate 				exit(Et_sync);
4417c478bd9Sstevel@tonic-gate 			}
4427c478bd9Sstevel@tonic-gate 			if (t_getinfo(tli[i], &tinfo) < 0) {
4437c478bd9Sstevel@tonic-gate 				fprintf(stderr, "t_getinfo failed: %s\n",
4447c478bd9Sstevel@tonic-gate 					t_errlist[t_errno]);
4457c478bd9Sstevel@tonic-gate 				exit(Et_info);
4467c478bd9Sstevel@tonic-gate 			}
4477c478bd9Sstevel@tonic-gate 
4487c478bd9Sstevel@tonic-gate 			switch (state) {
4497c478bd9Sstevel@tonic-gate 			case T_UNBND:
4507c478bd9Sstevel@tonic-gate 				fprintf(stderr, "TLI is unbound\n");
4517c478bd9Sstevel@tonic-gate 				break;
4527c478bd9Sstevel@tonic-gate 			case T_IDLE:
4537c478bd9Sstevel@tonic-gate 				fprintf(stderr, "TLI is idle\n");
4547c478bd9Sstevel@tonic-gate 				break;
4557c478bd9Sstevel@tonic-gate 			case T_INREL:
4567c478bd9Sstevel@tonic-gate 				fprintf(stderr,
4577c478bd9Sstevel@tonic-gate 					"other side wants to release\n");
4587c478bd9Sstevel@tonic-gate 				break;
4597c478bd9Sstevel@tonic-gate 			case T_INCON:
4607c478bd9Sstevel@tonic-gate 				fprintf(stderr, "T_INCON\n");
4617c478bd9Sstevel@tonic-gate 				break;
4627c478bd9Sstevel@tonic-gate 			case T_DATAXFER:
4637c478bd9Sstevel@tonic-gate 				fprintf(stderr, "T_DATAXFER\n");
4647c478bd9Sstevel@tonic-gate 				break;
4657c478bd9Sstevel@tonic-gate 			default:
4667c478bd9Sstevel@tonic-gate 				fprintf(stderr, "no state info, state = %d\n",
4677c478bd9Sstevel@tonic-gate 					state);
4687c478bd9Sstevel@tonic-gate 			}
4697c478bd9Sstevel@tonic-gate 		}
4707c478bd9Sstevel@tonic-gate 	}
4717c478bd9Sstevel@tonic-gate #endif
4727c478bd9Sstevel@tonic-gate 	if (tli4 != -1) {
4737c478bd9Sstevel@tonic-gate 		rpcb_unset((ulong_t)YPPASSWDPROG, (ulong_t)YPPASSWDVERS,
4747c478bd9Sstevel@tonic-gate 			nconf4);
4757c478bd9Sstevel@tonic-gate 		transp4 = svc_tli_create(tli4, nconf4, NULL, 0, 0);
4767c478bd9Sstevel@tonic-gate 	} else {
4777c478bd9Sstevel@tonic-gate 		transp4 = 0;
4787c478bd9Sstevel@tonic-gate 	}
4797c478bd9Sstevel@tonic-gate 	if (tli6 != -1) {
4807c478bd9Sstevel@tonic-gate 		rpcb_unset((ulong_t)YPPASSWDPROG, (ulong_t)YPPASSWDVERS,
4817c478bd9Sstevel@tonic-gate 			nconf6);
4827c478bd9Sstevel@tonic-gate 		transp6 = svc_tli_create(tli6, nconf6, NULL, 0, 0);
4837c478bd9Sstevel@tonic-gate 	} else {
4847c478bd9Sstevel@tonic-gate 		transp6 = 0;
4857c478bd9Sstevel@tonic-gate 	}
4867c478bd9Sstevel@tonic-gate 	if (transp4 == 0 && transp6 == 0) {
4877c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "yppasswdd: couldn't create an RPC server\n");
4887c478bd9Sstevel@tonic-gate 		exit(Esvc_create);
4897c478bd9Sstevel@tonic-gate 	}
4907c478bd9Sstevel@tonic-gate 	if (transp4 && !svc_reg(transp4, (ulong_t)YPPASSWDPROG,
4917c478bd9Sstevel@tonic-gate 			(ulong_t)YPPASSWDVERS, boilerplate, nconf4)) {
4927c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "yppasswdd: couldn't register yppasswdd\n");
4937c478bd9Sstevel@tonic-gate 		exit(Esvc_reg);
4947c478bd9Sstevel@tonic-gate 	}
4957c478bd9Sstevel@tonic-gate 	if (transp6 && !svc_reg(transp6, (ulong_t)YPPASSWDPROG,
4967c478bd9Sstevel@tonic-gate 			(ulong_t)YPPASSWDVERS, boilerplate, nconf6)) {
4977c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "yppasswdd: couldn't register yppasswdd\n");
4987c478bd9Sstevel@tonic-gate 		exit(Esvc_reg);
4997c478bd9Sstevel@tonic-gate 	}
5007c478bd9Sstevel@tonic-gate 
5017c478bd9Sstevel@tonic-gate 	/*
5027c478bd9Sstevel@tonic-gate 	 * Create a loopback RPC service for secure authentication of local
5037c478bd9Sstevel@tonic-gate 	 * principals -- we need this for accepting passwd updates from
5047c478bd9Sstevel@tonic-gate 	 * root on the master server.
5057c478bd9Sstevel@tonic-gate 	 */
5067c478bd9Sstevel@tonic-gate 	if ((nconfl = getnetconfigent("ticlts")) == NULL) {
5077c478bd9Sstevel@tonic-gate 	    syslog(LOG_ERR, "transport ticlts not supported\n");
5087c478bd9Sstevel@tonic-gate 	    exit(Egetnetconfigent);
5097c478bd9Sstevel@tonic-gate 	}
5107c478bd9Sstevel@tonic-gate 	rpcb_unset((ulong_t)YPPASSWDPROG, (ulong_t)YPPASSWDVERS, nconfl);
5117c478bd9Sstevel@tonic-gate 	transpl = svc_tli_create(RPC_ANYFD, nconfl, NULL, 0, 0);
5127c478bd9Sstevel@tonic-gate 	if (transpl == NULL) {
5137c478bd9Sstevel@tonic-gate 	    syslog(LOG_ERR,
5147c478bd9Sstevel@tonic-gate 		"yppasswdd: couldn't create an loopback RPC server\n");
5157c478bd9Sstevel@tonic-gate 	    exit(Esvc_create);
5167c478bd9Sstevel@tonic-gate 	}
5177c478bd9Sstevel@tonic-gate 	if (!svc_reg(transpl, (ulong_t)YPPASSWDPROG, (ulong_t)YPPASSWDVERS,
5187c478bd9Sstevel@tonic-gate 			boilerplate, nconfl)) {
5197c478bd9Sstevel@tonic-gate 	    syslog(LOG_ERR, "yppasswdd: couldn't register yppasswdd\n");
5207c478bd9Sstevel@tonic-gate 	    exit(Esvc_reg);
5217c478bd9Sstevel@tonic-gate 	}
5227c478bd9Sstevel@tonic-gate 	__rpc_negotiate_uid(transpl->xp_fd);
5237c478bd9Sstevel@tonic-gate 	freenetconfigent(nconf4);
5247c478bd9Sstevel@tonic-gate 	freenetconfigent(nconf6);
5257c478bd9Sstevel@tonic-gate 	freenetconfigent(nconfl);
5267c478bd9Sstevel@tonic-gate 	svc_run();
5277c478bd9Sstevel@tonic-gate 	syslog(LOG_ERR, "yppasswdd: svc_run shouldn't have returned\n");
5287c478bd9Sstevel@tonic-gate 
5297c478bd9Sstevel@tonic-gate 	return (Esvcrun_ret);
5307c478bd9Sstevel@tonic-gate 	/* NOTREACHED */
5317c478bd9Sstevel@tonic-gate }
5327c478bd9Sstevel@tonic-gate 
5337c478bd9Sstevel@tonic-gate static void
boilerplate(struct svc_req * rqstp,SVCXPRT * transp)5347c478bd9Sstevel@tonic-gate boilerplate(struct svc_req *rqstp, SVCXPRT *transp)
5357c478bd9Sstevel@tonic-gate {
5367c478bd9Sstevel@tonic-gate 	switch (rqstp->rq_proc) {
5377c478bd9Sstevel@tonic-gate 	case NULLPROC:
5387c478bd9Sstevel@tonic-gate 		if (!svc_sendreply(transp, xdr_void, (char *)0))
5397c478bd9Sstevel@tonic-gate 		    syslog(LOG_WARNING,
5407c478bd9Sstevel@tonic-gate 			"yppasswdd: couldn't reply to RPC call\n");
5417c478bd9Sstevel@tonic-gate 		break;
5427c478bd9Sstevel@tonic-gate 	case YPPASSWDPROC_UPDATE:
5437c478bd9Sstevel@tonic-gate 		if (yptol_mode)
5447c478bd9Sstevel@tonic-gate 			shim_changepasswd(transp);
5457c478bd9Sstevel@tonic-gate 		else
5467c478bd9Sstevel@tonic-gate 			changepasswd(transp);
5477c478bd9Sstevel@tonic-gate 		break;
5487c478bd9Sstevel@tonic-gate 	}
5497c478bd9Sstevel@tonic-gate }
5507c478bd9Sstevel@tonic-gate 
5517c478bd9Sstevel@tonic-gate int
validstr(char * str,size_t size)5527c478bd9Sstevel@tonic-gate validstr(char *str, size_t size)
5537c478bd9Sstevel@tonic-gate {
5547c478bd9Sstevel@tonic-gate 	char c;
5557c478bd9Sstevel@tonic-gate 
5567c478bd9Sstevel@tonic-gate 	if (str == NULL || strlen(str) > size || strchr(str, ':'))
5577c478bd9Sstevel@tonic-gate 		return (0);
5587c478bd9Sstevel@tonic-gate 	while (c = *str++) {
5597c478bd9Sstevel@tonic-gate 		if (iscntrl(c))
5607c478bd9Sstevel@tonic-gate 		    return (0);
5617c478bd9Sstevel@tonic-gate 	}
5627c478bd9Sstevel@tonic-gate 	return (1);
5637c478bd9Sstevel@tonic-gate }
5647c478bd9Sstevel@tonic-gate 
5657c478bd9Sstevel@tonic-gate bool_t
validloginshell(char * pw_shell,char * arg,int privileged)5667c478bd9Sstevel@tonic-gate validloginshell(char *pw_shell, char *arg, int privileged)
5677c478bd9Sstevel@tonic-gate {
5687c478bd9Sstevel@tonic-gate 	static char newshell[STRSIZE];
5697c478bd9Sstevel@tonic-gate 	char *cp, *valid;
5707c478bd9Sstevel@tonic-gate 
5717c478bd9Sstevel@tonic-gate 	if (pw_shell == 0 || *pw_shell == '\0')
5727c478bd9Sstevel@tonic-gate 		pw_shell = defshell;
5737c478bd9Sstevel@tonic-gate 
5747c478bd9Sstevel@tonic-gate 	if ((defopen(DEFAULT_YPPASSWDD)) == 0) {
5757c478bd9Sstevel@tonic-gate 		if ((defread(YPPASSWDD_STR)) != NULL) {
5767c478bd9Sstevel@tonic-gate 			cp = strrchr(pw_shell, '/');
5777c478bd9Sstevel@tonic-gate 			if (cp)
5787c478bd9Sstevel@tonic-gate 				cp++;
5797c478bd9Sstevel@tonic-gate 			else
5807c478bd9Sstevel@tonic-gate 				cp = pw_shell;
5817c478bd9Sstevel@tonic-gate 
5827c478bd9Sstevel@tonic-gate 			if (*cp == 'r') {
5837c478bd9Sstevel@tonic-gate 				syslog(LOG_ERR,
5847c478bd9Sstevel@tonic-gate 					"yppasswdd: cannot change "
5857c478bd9Sstevel@tonic-gate 					"from restricted shell %s\n",
5867c478bd9Sstevel@tonic-gate 					pw_shell);
5877c478bd9Sstevel@tonic-gate 				return (0);
5887c478bd9Sstevel@tonic-gate 			}
5897c478bd9Sstevel@tonic-gate 		}
5907c478bd9Sstevel@tonic-gate 		(void) defopen((char *)NULL);
5917c478bd9Sstevel@tonic-gate 	}
5927c478bd9Sstevel@tonic-gate 
5937c478bd9Sstevel@tonic-gate 	for (valid = getusershell(); valid; valid = getusershell())
5947c478bd9Sstevel@tonic-gate 		if (strcmp(pw_shell, valid) == 0)
5957c478bd9Sstevel@tonic-gate 		    break;
5967c478bd9Sstevel@tonic-gate 
5977c478bd9Sstevel@tonic-gate 	if (valid == NULL && !privileged) {
5987c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, "yppasswdd: Current shell is not valid: %s\n",
5997c478bd9Sstevel@tonic-gate 			pw_shell);
6007c478bd9Sstevel@tonic-gate 		endusershell();
6017c478bd9Sstevel@tonic-gate 		return (0);
6027c478bd9Sstevel@tonic-gate 	}
6037c478bd9Sstevel@tonic-gate 
6047c478bd9Sstevel@tonic-gate 	if (arg != 0) {
6057c478bd9Sstevel@tonic-gate 		strncpy(newshell, arg, sizeof (newshell) - 1);
6067c478bd9Sstevel@tonic-gate 		newshell[sizeof (newshell) - 1] = 0;
6077c478bd9Sstevel@tonic-gate 	} else {
6087c478bd9Sstevel@tonic-gate 		endusershell();
6097c478bd9Sstevel@tonic-gate 		return (0);
6107c478bd9Sstevel@tonic-gate 	}
6117c478bd9Sstevel@tonic-gate 
6127c478bd9Sstevel@tonic-gate 	/*
6137c478bd9Sstevel@tonic-gate 	 * Allow user to give shell name w/o preceding pathname.
6147c478bd9Sstevel@tonic-gate 	 */
6157c478bd9Sstevel@tonic-gate 	setusershell();
6167c478bd9Sstevel@tonic-gate 	for (valid = getusershell(); valid; valid = getusershell()) {
6177c478bd9Sstevel@tonic-gate 		if (newshell[0] == '/') {
6187c478bd9Sstevel@tonic-gate 		    cp = valid;
6197c478bd9Sstevel@tonic-gate 		} else {
6207c478bd9Sstevel@tonic-gate 		    cp = strrchr(valid, '/');
6217c478bd9Sstevel@tonic-gate 		    if (cp == 0)
6227c478bd9Sstevel@tonic-gate 			cp = valid;
6237c478bd9Sstevel@tonic-gate 		    else
6247c478bd9Sstevel@tonic-gate 			cp++;
6257c478bd9Sstevel@tonic-gate 		}
6267c478bd9Sstevel@tonic-gate 		if (strcmp(newshell, cp) == 0)
6277c478bd9Sstevel@tonic-gate 		    break;
6287c478bd9Sstevel@tonic-gate 	}
6297c478bd9Sstevel@tonic-gate 
6307c478bd9Sstevel@tonic-gate 	if (valid == 0) {
6317c478bd9Sstevel@tonic-gate 		if (!privileged || newshell[0] != '/') {
6327c478bd9Sstevel@tonic-gate 			syslog(LOG_WARNING,
6337c478bd9Sstevel@tonic-gate 				"%s is unacceptable as a new shell.\n",
6347c478bd9Sstevel@tonic-gate 				newshell);
6357c478bd9Sstevel@tonic-gate 			endusershell();
6367c478bd9Sstevel@tonic-gate 			return (0);
6377c478bd9Sstevel@tonic-gate 		}
6387c478bd9Sstevel@tonic-gate 		valid = newshell;
6397c478bd9Sstevel@tonic-gate 	}
6407c478bd9Sstevel@tonic-gate 
6417c478bd9Sstevel@tonic-gate 	if (access(valid, X_OK) < 0) {
6427c478bd9Sstevel@tonic-gate 		syslog(LOG_WARNING, "%s is unavailable.\n", valid);
6437c478bd9Sstevel@tonic-gate 		endusershell();
6447c478bd9Sstevel@tonic-gate 		return (0);
6457c478bd9Sstevel@tonic-gate 	}
6467c478bd9Sstevel@tonic-gate 
6477c478bd9Sstevel@tonic-gate 	strncpy(newshell, valid, sizeof (newshell));
6487c478bd9Sstevel@tonic-gate 	pw_shell =  newshell;
6497c478bd9Sstevel@tonic-gate 	endusershell();
6507c478bd9Sstevel@tonic-gate 	return (1);
6517c478bd9Sstevel@tonic-gate }
6527c478bd9Sstevel@tonic-gate 
6537c478bd9Sstevel@tonic-gate static void
unlimit(int lim)6547c478bd9Sstevel@tonic-gate unlimit(int lim)
6557c478bd9Sstevel@tonic-gate {
6567c478bd9Sstevel@tonic-gate 	struct rlimit rlim;
6577c478bd9Sstevel@tonic-gate 	rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY;
6587c478bd9Sstevel@tonic-gate 	setrlimit(lim, &rlim);
6597c478bd9Sstevel@tonic-gate }
660