yp_passwd.c revision 1.29 1 /* $NetBSD: yp_passwd.c,v 1.29 2005/01/11 22:42:30 christos Exp $ */
2
3 /*
4 * Copyright (c) 1988, 1990, 1993, 1994
5 * The Regents of the University of California. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32 #include <sys/cdefs.h>
33 #ifndef lint
34 #if 0
35 static char sccsid[] = "from: @(#)local_passwd.c 8.3 (Berkeley) 4/2/94";
36 #else
37 __RCSID("$NetBSD: yp_passwd.c,v 1.29 2005/01/11 22:42:30 christos Exp $");
38 #endif
39 #endif /* not lint */
40
41 #ifdef YP
42
43 #include <ctype.h>
44 #include <err.h>
45 #include <errno.h>
46 #include <netdb.h>
47 #include <pwd.h>
48 #include <stdio.h>
49 #include <stdlib.h>
50 #include <string.h>
51 #include <time.h>
52 #include <unistd.h>
53
54 #include <rpc/rpc.h>
55 #include <rpcsvc/yp_prot.h>
56 #include <rpcsvc/ypclnt.h>
57
58 #include "extern.h"
59
60 #define passwd yp_passwd_rec
61 #include <rpcsvc/yppasswd.h>
62 #undef passwd
63
64 #ifndef _PASSWORD_LEN
65 #define _PASSWORD_LEN PASS_MAX
66 #endif
67
68 static int yflag;
69
70 static char *getnewpasswd __P((struct passwd *, char **));
71 static int ypgetpwnam __P((const char *));
72 static void pw_error __P((char *, int, int));
73
74 static uid_t uid;
75 char *domain;
76
77 static void
78 pw_error(name, err, eval)
79 char *name;
80 int err, eval;
81 {
82
83 if (err)
84 warn("%s", name);
85 errx(eval, "YP passwd database unchanged");
86 }
87
88 int
89 yp_init(progname)
90 const char *progname;
91 {
92 int yppwd;
93
94 if (strcmp(progname, "yppasswd") == 0) {
95 yppwd = 1;
96 } else
97 yppwd = 0;
98 yflag = 0;
99 if (_yp_check(NULL) == 0) {
100 /* can't use YP. */
101 if (yppwd)
102 errx(1, "YP not in use.");
103 return(-1);
104 }
105 return (0);
106 }
107
108 int
109 yp_arg(ch, arg)
110 char ch;
111 const char *arg;
112 {
113 switch (ch) {
114 case 'y':
115 yflag = 1;
116 break;
117 default:
118 return(0);
119 }
120 return(1);
121 }
122
123 int
124 yp_arg_end()
125 {
126 if (yflag)
127 return (PW_USE_FORCE);
128 return (PW_USE);
129 }
130
131 void
132 yp_end()
133 {
134 /* NOOP */
135 }
136
137 int
138 yp_chpw(username)
139 const char *username;
140 {
141 char *master;
142 int r, rpcport, status;
143 struct yppasswd yppasswd;
144 struct passwd *pw;
145 struct timeval tv;
146 CLIENT *client;
147
148 uid = getuid();
149
150 /*
151 * Get local domain
152 */
153 if ((r = yp_get_default_domain(&domain)) != 0)
154 errx(1, "can't get local YP domain. Reason: %s",
155 yperr_string(r));
156
157 /*
158 * Find the host for the passwd map; it should be running
159 * the daemon.
160 */
161 if ((r = yp_master(domain, "passwd.byname", &master)) != 0) {
162 warnx("can't find the master YP server. Reason: %s",
163 yperr_string(r));
164 /* continuation */
165 return(-1);
166 }
167
168 /*
169 * Ask the portmapper for the port of the daemon.
170 */
171 if ((rpcport = getrpcport(master, YPPASSWDPROG,
172 YPPASSWDPROC_UPDATE, IPPROTO_UDP)) == 0) {
173 warnx("master YP server not running yppasswd daemon.\n\t%s\n",
174 "Can't change YP password.");
175 /* continuation */
176 return(-1);
177 }
178
179 /*
180 * Be sure the port is privileged
181 */
182 if (rpcport >= IPPORT_RESERVED)
183 errx(1, "yppasswd daemon is on an invalid port.");
184
185 /* Bail out if this is a local (non-yp) user, */
186 /* then get user's login identity */
187 if (!ypgetpwnam(username) ||
188 !(pw = getpwnam(username))) {
189 warnx("YP unknown user %s", username);
190 /* continuation */
191 return(-1);
192 }
193
194 if (uid && uid != pw->pw_uid)
195 errx(1, "you may only change your own password: %s",
196 strerror(EACCES));
197
198 /* prompt for new password */
199 yppasswd.newpw.pw_passwd = getnewpasswd(pw, &yppasswd.oldpass);
200
201 /* tell rpc.yppasswdd */
202 yppasswd.newpw.pw_name = strdup(pw->pw_name);
203 if (!yppasswd.newpw.pw_name) {
204 err(1, "strdup");
205 /*NOTREACHED*/
206 }
207 yppasswd.newpw.pw_uid = pw->pw_uid;
208 yppasswd.newpw.pw_gid = pw->pw_gid;
209 yppasswd.newpw.pw_gecos = strdup(pw->pw_gecos);
210 if (!yppasswd.newpw.pw_gecos) {
211 err(1, "strdup");
212 /*NOTREACHED*/
213 }
214 yppasswd.newpw.pw_dir = strdup(pw->pw_dir);
215 if (!yppasswd.newpw.pw_dir) {
216 err(1, "strdup");
217 /*NOTREACHED*/
218 }
219 yppasswd.newpw.pw_shell = strdup(pw->pw_shell);
220 if (!yppasswd.newpw.pw_shell) {
221 err(1, "strdup");
222 /*NOTREACHED*/
223 }
224
225 client = clnt_create(master, YPPASSWDPROG, YPPASSWDVERS, "udp");
226 if (client == NULL) {
227 warnx("cannot contact yppasswdd on %s: Reason: %s",
228 master, yperr_string(YPERR_YPBIND));
229 return (YPERR_YPBIND);
230 }
231
232 client->cl_auth = authunix_create_default();
233 tv.tv_sec = 2;
234 tv.tv_usec = 0;
235 r = clnt_call(client, YPPASSWDPROC_UPDATE,
236 xdr_yppasswd, &yppasswd, xdr_int, &status, tv);
237 if (r)
238 errx(1, "rpc to yppasswdd failed.");
239 else if (status)
240 printf("Couldn't change YP password.\n");
241 else
242 printf("The YP password has been changed on %s, %s\n",
243 master, "the master YP passwd server.");
244 return(0);
245 }
246
247 static char *
248 getnewpasswd(pw, old_pass)
249 struct passwd *pw;
250 char **old_pass;
251 {
252 int tries;
253 char *p, *t;
254 static char buf[_PASSWORD_LEN+1];
255 char salt[_PASSWORD_LEN+1];
256
257 (void)printf("Changing YP password for %s.\n", pw->pw_name);
258
259 if (old_pass) {
260 *old_pass = NULL;
261
262 if (pw->pw_passwd[0]) {
263 if (strcmp(crypt(p = getpass("Old password:"),
264 pw->pw_passwd), pw->pw_passwd)) {
265 (void)printf("Sorry.\n");
266 pw_error(NULL, 0, 1);
267 }
268 } else {
269 p = "";
270 }
271
272 *old_pass = strdup(p);
273 if (!*old_pass) {
274 (void)printf("not enough core.\n");
275 pw_error(NULL, 0, 1);
276 }
277 }
278 for (buf[0] = '\0', tries = 0;;) {
279 p = getpass("New password:");
280 if (!*p) {
281 (void)printf("Password unchanged.\n");
282 pw_error(NULL, 0, 0);
283 }
284 if (strlen(p) <= 5 && ++tries < 2) {
285 (void)printf("Please enter a longer password.\n");
286 continue;
287 }
288 for (t = p; *t && islower((unsigned char)*t); ++t);
289 if (!*t && ++tries < 2) {
290 (void)printf("Please don't use an all-lower case "
291 "password.\nUnusual capitalization, "
292 "control characters or digits are "
293 "suggested.\n");
294 continue;
295 }
296 (void)strlcpy(buf, p, sizeof(buf));
297 if (!strcmp(buf, getpass("Retype new password:")))
298 break;
299 (void)printf("Mismatch; try again, EOF to quit.\n");
300 }
301
302 if (pw_gensalt(salt, _PASSWORD_LEN, pw, 'y' ) == -1) {
303 warn("Couldn't generate salt");
304 pw_error(NULL, 0, 0);
305 }
306 p = strdup(crypt(buf, salt));
307 if (!p) {
308 (void)printf("not enough core.\n");
309 pw_error(NULL, 0, 0);
310 }
311 return (p);
312 }
313
314 static int
315 ypgetpwnam(nam)
316 const char *nam;
317 {
318 char *val;
319 int reason, vallen;
320
321 val = NULL;
322 reason = yp_match(domain, "passwd.byname", nam, strlen(nam),
323 &val, &vallen);
324 if (reason != 0) {
325 if (val != NULL)
326 free(val);
327 return 0;
328 }
329 free(val);
330 return 1;
331 }
332
333 #endif /* YP */
334