login_chpass.c revision 1.2
1/*	$OpenBSD: login_chpass.c,v 1.2 2001/10/24 13:06:35 mpech Exp $	*/
2
3/*-
4 * Copyright (c) 1995,1996 Berkeley Software Design, Inc. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 *    must display the following acknowledgement:
16 *      This product includes software developed by Berkeley Software Design,
17 *      Inc.
18 * 4. The name of Berkeley Software Design, Inc.  may not be used to endorse
19 *    or promote products derived from this software without specific prior
20 *    written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY BERKELEY SOFTWARE DESIGN, INC. ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED.  IN NO EVENT SHALL BERKELEY SOFTWARE DESIGN, INC. BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 *
34 *	BSDI $From: login_chpass.c,v 1.3 1996/08/21 21:01:48 prb Exp $
35 */
36#include <sys/param.h>
37#include <sys/stat.h>
38#include <sys/time.h>
39#include <sys/resource.h>
40#include <sys/file.h>
41#include <sys/wait.h>
42
43#include <err.h>
44#include <errno.h>
45#include <pwd.h>
46#include <signal.h>
47#include <stdio.h>
48#include <stdlib.h>
49#include <string.h>
50#include <syslog.h>
51#include <unistd.h>
52#include <login_cap.h>
53
54#ifdef YP
55# include <netdb.h>
56# include <rpc/rpc.h>
57# include <rpcsvc/yp_prot.h>
58# include <rpcsvc/ypclnt.h>
59# define passwd yp_passwd_rec
60# include <rpcsvc/yppasswd.h>
61# undef passwd
62#endif
63
64#ifdef KERBEROS
65# include <netinet/in.h>
66# include <kerberosIV/krb.h>
67# include <kerberosIV/kadm.h>
68# include <kerberosIV/kadm_err.h>
69#endif
70
71#define	_PATH_LOGIN_LCHPASS	"/usr/libexec/auth/login_lchpass"
72
73#ifdef  YP
74int	_yp_check __P((char **));
75char	*ypgetnewpasswd __P((struct passwd *, char **));
76struct passwd *ypgetpwnam __P((char *));
77#endif
78
79#ifdef KERBEROS
80int	get_pw_new_pwd __P((char *, int, krb_principal *, int));
81char	realm[REALM_SZ];
82#endif
83
84void	local_chpass __P((char **));
85void	krb_chpass __P((char *, char *, char **));
86void	yp_chpass __P((char *));
87
88int
89main(argc, argv)
90	int argc;
91	char *argv[];
92{
93    	struct rlimit rl;
94    	char *username;
95    	char *instance;
96    	int c;
97
98	rl.rlim_cur = 0;
99	rl.rlim_max = 0;
100	(void)setrlimit(RLIMIT_CORE, &rl);
101
102	(void)signal(SIGQUIT, SIG_IGN);
103	(void)signal(SIGINT, SIG_IGN);
104	(void)setpriority(PRIO_PROCESS, 0, 0);
105
106	openlog("login", LOG_ODELAY, LOG_AUTH);
107
108    	while ((c = getopt(argc, argv, "s:v:")) != -1)
109		switch(c) {
110		case 'v':
111			break;
112		case 's':	/* service */
113			if (strcmp(optarg, "login") != 0) {
114				syslog(LOG_ERR, "%s: invalid service", optarg);
115				exit(1);
116			}
117			break;
118		default:
119			syslog(LOG_ERR, "usage error");
120			exit(1);
121		}
122
123	switch(argc - optind) {
124	case 2:
125		/* class is not used */
126	case 1:
127		username = argv[optind];
128		break;
129	default:
130		syslog(LOG_ERR, "usage error");
131		exit(1);
132	}
133
134	/* Instance ignored for all but Kerberos. */
135	instance = strchr(username, '.');
136	if (instance)
137		*instance++ = '\0';
138	else
139		instance = "";
140
141#ifdef KERBEROS
142	if (krb_get_lrealm(realm, 0) == KSUCCESS)
143		krb_chpass(username, instance, argv);
144#endif
145#ifdef  YP
146	if (_yp_check(NULL))
147		yp_chpass(username);
148#endif
149	local_chpass(argv);
150	/* NOTREACHED */
151	exit(0);
152}
153
154void
155local_chpass(argv)
156	char *argv[];
157{
158
159	/* login_lchpass doesn't check instance so don't bother restoring it */
160	argv[0] = strrchr(_PATH_LOGIN_LCHPASS, '/') + 1;
161	execv(_PATH_LOGIN_LCHPASS, argv);
162	syslog(LOG_ERR, "%s: %m", _PATH_LOGIN_LCHPASS);
163	exit(1);
164}
165
166#ifdef YP
167void
168yp_chpass(username)
169	char *username;
170{
171	FILE *back;
172	char *master;
173	int r, rpcport, status;
174	struct yppasswd yppasswd;
175	struct passwd *pw;
176	struct timeval tv;
177	CLIENT *client;
178	extern char *domain;
179
180	if (!(back = fdopen(3, "a")))  {
181		syslog(LOG_ERR, "reopening back channel: %m");
182		exit(1);
183	}
184
185	if ((r = yp_get_default_domain(&domain)) != 0) {
186		warnx("can't get local YP domain. Reason: %s", yperr_string(r));
187		exit(1);
188	}
189
190	/*
191	 * Find the host for the passwd map; it should be running
192	 * the daemon.
193	 */
194	if ((r = yp_master(domain, "passwd.byname", &master)) != 0) {
195		warnx("can't find the master YP server. Reason: %s",
196		    yperr_string(r));
197		exit(1);
198	}
199
200	/* Ask the portmapper for the port of the daemon. */
201	if ((rpcport = getrpcport(master, YPPASSWDPROG,
202	    YPPASSWDPROC_UPDATE, IPPROTO_UDP)) == 0) {
203		warnx("master YP server not running yppasswd daemon.");
204		warnx("Can't change password.");
205		exit(1);
206	}
207
208	if (rpcport >= IPPORT_RESERVED) {
209		warnx("yppasswd daemon is on an invalid port.");
210		exit(1);
211	}
212
213	/* If user doesn't exist, just prompt for old password and exit. */
214	if ((pw = ypgetpwnam(username)) == NULL) {
215		char *p = getpass("Old password:");
216		crypt(p, "xx");
217		memset(p, 0, strlen(p));
218		warnx("YP passwd database unchanged.");
219		exit(1);
220	}
221
222	if (*pw->pw_passwd == '\0') {
223		syslog(LOG_ERR, "%s attempting to add password", username);
224		fprintf(back, BI_SILENT "\n");
225		exit(0);
226	}
227
228	/* prompt for new password */
229	yppasswd.newpw.pw_passwd = ypgetnewpasswd(pw, &yppasswd.oldpass);
230
231	/* tell rpc.yppasswdd */
232	yppasswd.newpw.pw_name	= pw->pw_name;
233	yppasswd.newpw.pw_uid 	= pw->pw_uid;
234	yppasswd.newpw.pw_gid	= pw->pw_gid;
235	yppasswd.newpw.pw_gecos = pw->pw_gecos;
236	yppasswd.newpw.pw_dir	= pw->pw_dir;
237	yppasswd.newpw.pw_shell	= pw->pw_shell;
238
239	client = clnt_create(master, YPPASSWDPROG, YPPASSWDVERS, "udp");
240	if (client == NULL) {
241		warnx("cannot contact yppasswdd on %s: Reason: %s",
242		    master, yperr_string(YPERR_YPBIND));
243		free(yppasswd.newpw.pw_passwd);
244		exit(1);
245	}
246	client->cl_auth = authunix_create_default();
247	tv.tv_sec = 2;
248	tv.tv_usec = 0;
249	r = clnt_call(client, YPPASSWDPROC_UPDATE,
250	    xdr_yppasswd, &yppasswd, xdr_int, &status, tv);
251	if (r)
252		warnx("rpc to yppasswdd failed.");
253	else if (status) {
254		printf("Couldn't change YP password.\n");
255		free(yppasswd.newpw.pw_passwd);
256		exit(1);
257	}
258	printf("The YP password has been changed on %s, the master YP passwd server.\n",
259	    master);
260	free(yppasswd.newpw.pw_passwd);
261	fprintf(back, BI_SILENT "\n");
262	exit(0);
263}
264#endif
265
266#ifdef KERBEROS
267void
268krb_chpass(username, instance, argv)
269	char *username;
270	char *instance;
271	char *argv[];
272{
273	FILE *back;
274	int rval;
275	char pword[MAX_KPW_LEN];
276	char tktstring[MAXPATHLEN];
277	krb_principal principal;
278
279	if (!(back = fdopen(3, "a")))  {
280		syslog(LOG_ERR, "reopening back channel: %m");
281		exit(1);
282	}
283
284	memset(&principal, 0, sizeof(principal));
285	krb_get_default_principal(principal.name,
286	    principal.instance, principal.realm);
287
288	snprintf(tktstring, sizeof(tktstring), "%s.chpass.%s.%d",
289	    TKT_ROOT, username, getpid());
290	krb_set_tkt_string(tktstring);
291
292	(void)setpriority(PRIO_PROCESS, 0, -4);
293
294	if (get_pw_new_pwd(pword, sizeof(pword), &principal, 0)) {
295		dest_tkt();
296		exit(1);
297	}
298
299	rval = kadm_init_link (PWSERV_NAME, KRB_MASTER, principal.realm);
300	if (rval != KADM_SUCCESS)
301		com_err(argv[0], rval, "while initializing");
302	else {
303		des_cblock newkey;
304		char *pw_msg; /* message from server */
305
306		des_string_to_key(pword, &newkey);
307		rval = kadm_change_pw_plain((u_char *)&newkey, pword, &pw_msg);
308		memset(newkey, 0, sizeof(newkey));
309
310		if (rval == KADM_INSECURE_PW)
311			warnx("Insecure password: %s", pw_msg);
312		else if (rval != KADM_SUCCESS)
313			com_err(argv[0], rval, "attempting to change password.");
314	}
315	memset(pword, 0, sizeof(pword));
316
317	if (rval != KADM_SUCCESS)
318		fprintf(stderr, "Password NOT changed.\n");
319	else
320		printf("Password changed.\n");
321
322	dest_tkt();
323
324	if (rval == 0)
325		fprintf(back, BI_SILENT "\n");
326    	exit(rval);
327}
328#endif
329