xref: /freebsd/lib/libpam/modules/pam_unix/pam_unix.c (revision d0b8d0fdfc8ba4e214cda2b7d4c5598aad3d1f6c)
1 /*-
2  * Copyright 1998 Juniper Networks, Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26 
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29 
30 #include <sys/types.h>
31 #include <sys/time.h>
32 #ifdef YP
33 #include <rpc/rpc.h>
34 #include <rpcsvc/yp_prot.h>
35 #include <rpcsvc/ypclnt.h>
36 #include <rpcsvc/yppasswd.h>
37 #endif
38 #include <login_cap.h>
39 #include <pwd.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <stdio.h>
43 #include <unistd.h>
44 
45 #include <pw_copy.h>
46 #include <pw_util.h>
47 
48 #ifdef YP
49 #include <pw_yp.h>
50 #include "yppasswd_private.h"
51 #endif
52 
53 #define PAM_SM_AUTH
54 #define PAM_SM_ACCOUNT
55 #define	PAM_SM_SESSION
56 #define	PAM_SM_PASSWORD
57 
58 #include <security/pam_modules.h>
59 
60 #include "pam_mod_misc.h"
61 
62 #define USER_PROMPT		"Username: "
63 #define PASSWORD_PROMPT		"Password:"
64 #define PASSWORD_PROMPT_EXPIRED	"\nPassword expired\nOld Password:"
65 #define NEW_PASSWORD_PROMPT_1	"New Password:"
66 #define NEW_PASSWORD_PROMPT_2	"New Password (again):"
67 #define PASSWORD_HASH		"md5"
68 #define DEFAULT_WARN		(2L * 7L * 86400L)  /* Two weeks */
69 #define	MAX_TRIES		3
70 
71 enum { PAM_OPT_AUTH_AS_SELF=PAM_OPT_STD_MAX, PAM_OPT_NULLOK, PAM_OPT_LOCAL_PASS, PAM_OPT_NIS_PASS };
72 
73 static struct opttab other_options[] = {
74 	{ "auth_as_self",	PAM_OPT_AUTH_AS_SELF },
75 	{ "nullok",		PAM_OPT_NULLOK },
76 	{ "local_pass",		PAM_OPT_LOCAL_PASS },
77 	{ "nis_pass",		PAM_OPT_NIS_PASS },
78 	{ NULL, 0 }
79 };
80 
81 #ifdef YP
82 int pam_use_yp = 0;
83 int yp_errno = YP_TRUE;
84 #endif
85 
86 char *tempname = NULL;
87 static int local_passwd(const char *user, const char *pass);
88 #ifdef YP
89 static int yp_passwd(const char *user, const char *pass);
90 #endif
91 
92 /*
93  * authentication management
94  */
95 PAM_EXTERN int
96 pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv)
97 {
98 	login_cap_t *lc;
99 	struct options options;
100 	struct passwd *pwd;
101 	int retval;
102 	const char *pass, *user;
103 	char *encrypted, *password_prompt;
104 
105 	pam_std_option(&options, other_options, argc, argv);
106 
107 	PAM_LOG("Options processed");
108 
109 	if (pam_test_option(&options, PAM_OPT_AUTH_AS_SELF, NULL))
110 		pwd = getpwnam(getlogin());
111 	else {
112 		retval = pam_get_user(pamh, &user, NULL);
113 		if (retval != PAM_SUCCESS)
114 			PAM_RETURN(retval);
115 		pwd = getpwnam(user);
116 	}
117 
118 	PAM_LOG("Got user: %s", user);
119 
120 	lc = login_getclass(NULL);
121 	password_prompt = login_getcapstr(lc, "passwd_prompt",
122 	    PASSWORD_PROMPT, PASSWORD_PROMPT);
123 	login_close(lc);
124 	lc = NULL;
125 
126 	if (pwd != NULL) {
127 
128 		PAM_LOG("Doing real authentication");
129 
130 		if (pwd->pw_passwd[0] == '\0'
131 		    && pam_test_option(&options, PAM_OPT_NULLOK, NULL)) {
132 			/*
133 			 * No password case. XXX Are we giving too much away
134 			 * by not prompting for a password?
135 			 */
136 			PAM_LOG("No password, and null password OK");
137 			PAM_RETURN(PAM_SUCCESS);
138 		}
139 		else {
140 			retval = pam_get_pass(pamh, &pass, password_prompt,
141 			    &options);
142 			if (retval != PAM_SUCCESS)
143 				PAM_RETURN(retval);
144 			PAM_LOG("Got password");
145 		}
146 		encrypted = crypt(pass, pwd->pw_passwd);
147 		if (pass[0] == '\0' && pwd->pw_passwd[0] != '\0')
148 			encrypted = ":";
149 
150 		PAM_LOG("Encrypted password 1 is: %s", encrypted);
151 		PAM_LOG("Encrypted password 2 is: %s", pwd->pw_passwd);
152 
153 		retval = strcmp(encrypted, pwd->pw_passwd) == 0 ?
154 		    PAM_SUCCESS : PAM_AUTH_ERR;
155 	}
156 	else {
157 
158 		PAM_LOG("Doing dummy authentication");
159 
160 		/*
161 		 * User unknown.
162 		 * Encrypt a dummy password so as to not give away too much.
163 		 */
164 		retval = pam_get_pass(pamh, &pass, password_prompt,
165 		    &options);
166 		if (retval != PAM_SUCCESS)
167 			PAM_RETURN(retval);
168 		PAM_LOG("Got password");
169 		crypt(pass, "xx");
170 		retval = PAM_AUTH_ERR;
171 	}
172 
173 	/*
174 	 * The PAM infrastructure will obliterate the cleartext
175 	 * password before returning to the application.
176 	 */
177 	if (retval != PAM_SUCCESS)
178 		PAM_VERBOSE_ERROR("UNIX authentication refused");
179 
180 	PAM_RETURN(retval);
181 }
182 
183 PAM_EXTERN int
184 pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv)
185 {
186 	struct options options;
187 
188 	pam_std_option(&options, other_options, argc, argv);
189 
190 	PAM_LOG("Options processed");
191 
192 	PAM_RETURN(PAM_SUCCESS);
193 }
194 
195 /*
196  * account management
197  */
198 PAM_EXTERN int
199 pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int argc, const char **argv)
200 {
201 	struct options options;
202 	struct passwd *pw;
203 	struct timeval tp;
204 	login_cap_t *lc;
205 	time_t warntime;
206 	int retval;
207 	const char *user;
208 	char buf[128];
209 
210 	pam_std_option(&options, other_options, argc, argv);
211 
212 	PAM_LOG("Options processed");
213 
214 	retval = pam_get_item(pamh, PAM_USER, (const void **)&user);
215 	if (retval != PAM_SUCCESS || user == NULL)
216 		/* some implementations return PAM_SUCCESS here */
217 		PAM_RETURN(PAM_USER_UNKNOWN);
218 
219 	pw = getpwnam(user);
220 	if (pw == NULL)
221 		PAM_RETURN(PAM_USER_UNKNOWN);
222 
223 	PAM_LOG("Got user: %s", user);
224 
225 	retval = PAM_SUCCESS;
226 	lc = login_getpwclass(pw);
227 
228 	if (pw->pw_change || pw->pw_expire)
229 		gettimeofday(&tp, NULL);
230 
231 	warntime = login_getcaptime(lc, "warnpassword", DEFAULT_WARN,
232 	    DEFAULT_WARN);
233 
234 	PAM_LOG("Got login_cap");
235 
236 	if (pw->pw_change) {
237 		if (tp.tv_sec >= pw->pw_change)
238 			/* some implementations return PAM_AUTHTOK_EXPIRED */
239 			retval = PAM_NEW_AUTHTOK_REQD;
240 		else if (pw->pw_change - tp.tv_sec < warntime) {
241 			snprintf(buf, sizeof(buf),
242 			    "Warning: your password expires on %s",
243 			    ctime(&pw->pw_change));
244 			pam_prompt(pamh, PAM_ERROR_MSG, buf, NULL);
245 		}
246 	}
247 
248 	warntime = login_getcaptime(lc, "warnexpire", DEFAULT_WARN,
249 	    DEFAULT_WARN);
250 
251 	if (pw->pw_expire) {
252 		if (tp.tv_sec >= pw->pw_expire)
253 			retval = PAM_ACCT_EXPIRED;
254 		else if (pw->pw_expire - tp.tv_sec < warntime) {
255 			snprintf(buf, sizeof(buf),
256 			    "Warning: your account expires on %s",
257 			    ctime(&pw->pw_expire));
258 			pam_prompt(pamh, PAM_ERROR_MSG, buf, NULL);
259 		}
260 	}
261 
262 	login_close(lc);
263 
264 	PAM_RETURN(retval);
265 }
266 
267 /*
268  * session management
269  *
270  * logging only
271  */
272 PAM_EXTERN int
273 pam_sm_open_session(pam_handle_t *pamh, int flags, int argc, const char **argv)
274 {
275 	struct options options;
276 
277 	pam_std_option(&options, other_options, argc, argv);
278 
279 	PAM_LOG("Options processed");
280 
281 	PAM_RETURN(PAM_SUCCESS);
282 }
283 
284 PAM_EXTERN int
285 pam_sm_close_session(pam_handle_t *pamh, int flags, int argc, const char **argv)
286 {
287 	struct options options;
288 
289 	pam_std_option(&options, other_options, argc, argv);
290 
291 	PAM_LOG("Options processed");
292 
293 	PAM_RETURN(PAM_SUCCESS);
294 }
295 
296 /*
297  * password management
298  *
299  * standard Unix and NIS password changing
300  */
301 PAM_EXTERN int
302 pam_sm_chauthtok(pam_handle_t *pamh, int flags, int argc, const char **argv)
303 {
304 	struct options options;
305 	struct passwd *pwd;
306 	int retval, retry, res, got;
307 	const char *user, *pass;
308 	char *new_pass, *new_pass_, *encrypted;
309 
310 	pam_std_option(&options, other_options, argc, argv);
311 
312 	PAM_LOG("Options processed");
313 
314 	if (pam_test_option(&options, PAM_OPT_AUTH_AS_SELF, NULL))
315 		pwd = getpwnam(getlogin());
316 	else {
317 		retval = pam_get_user(pamh, &user, NULL);
318 		if (retval != PAM_SUCCESS)
319 			PAM_RETURN(retval);
320 		pwd = getpwnam(user);
321 	}
322 
323 	PAM_LOG("Got user: %s", user);
324 
325 	if (flags & PAM_PRELIM_CHECK) {
326 
327 		PAM_LOG("PRELIM round; checking user password");
328 
329 		if (pwd->pw_passwd[0] == '\0'
330 		    && pam_test_option(&options, PAM_OPT_NULLOK, NULL)) {
331 			/*
332 			 * No password case. XXX Are we giving too much away
333 			 * by not prompting for a password?
334 			 */
335 			PAM_LOG("No password, and null password OK");
336 			PAM_RETURN(PAM_SUCCESS);
337 		}
338 		else {
339 			retval = pam_get_pass(pamh, &pass,
340 			    PASSWORD_PROMPT_EXPIRED, &options);
341 			if (retval != PAM_SUCCESS)
342 				PAM_RETURN(retval);
343 			PAM_LOG("Got password: %s", pass);
344 		}
345 		encrypted = crypt(pass, pwd->pw_passwd);
346 		if (pass[0] == '\0' && pwd->pw_passwd[0] != '\0')
347 			encrypted = ":";
348 
349 		PAM_LOG("Encrypted password 1 is: %s", encrypted);
350 		PAM_LOG("Encrypted password 2 is: %s", pwd->pw_passwd);
351 
352 		if (strcmp(encrypted, pwd->pw_passwd) != 0)
353 			PAM_RETURN(PAM_AUTH_ERR);
354 
355 		retval = pam_set_item(pamh, PAM_OLDAUTHTOK, (const void *)pass);
356 		pass = NULL;
357 		if (retval != PAM_SUCCESS)
358 			PAM_RETURN(retval);
359 
360 		PAM_LOG("Stashed old password");
361 
362 		retval = pam_set_item(pamh, PAM_AUTHTOK, (const void *)pass);
363 		if (retval != PAM_SUCCESS)
364 			PAM_RETURN(retval);
365 
366 		PAM_LOG("Voided old password");
367 
368 		PAM_RETURN(PAM_SUCCESS);
369 	}
370 	else if (flags & PAM_UPDATE_AUTHTOK) {
371 		PAM_LOG("UPDATE round; checking user password");
372 
373 		retval = pam_get_item(pamh, PAM_OLDAUTHTOK,
374 		    (const void **)&pass);
375 		if (retval != PAM_SUCCESS)
376 			PAM_RETURN(retval);
377 
378 		PAM_LOG("Got old password: %s", pass);
379 
380 		got = 0;
381 		retry = 0;
382 		while (retry++ < MAX_TRIES) {
383 			new_pass = NULL;
384 			retval = pam_prompt(pamh, PAM_PROMPT_ECHO_OFF,
385 			    NEW_PASSWORD_PROMPT_1, &new_pass);
386 
387 			if (new_pass == NULL)
388 				new_pass = "";
389 
390 			if (retval == PAM_SUCCESS) {
391 				new_pass_ = NULL;
392 				retval = pam_prompt(pamh, PAM_PROMPT_ECHO_OFF,
393 				    NEW_PASSWORD_PROMPT_2, &new_pass_);
394 
395 				if (new_pass_ == NULL)
396 					new_pass_ = "";
397 
398 				if (retval == PAM_SUCCESS) {
399 					if (strcmp(new_pass, new_pass_) == 0) {
400 						got = 1;
401 						break;
402 					}
403 					else
404 						PAM_VERBOSE_ERROR("Password mismatch");
405 				}
406 			}
407 		}
408 
409 		if (!got) {
410 			PAM_VERBOSE_ERROR("Unable to get valid password");
411 			PAM_RETURN(PAM_PERM_DENIED);
412 		}
413 
414 		PAM_LOG("Got new password: %s", new_pass);
415 
416 #ifdef YP
417 		/* If NIS is set in the passwd database, use it */
418 		res = use_yp((char *)user, 0, 0);
419 		if (res == USER_YP_ONLY) {
420 			if (!pam_test_option(&options, PAM_OPT_LOCAL_PASS,
421 			    NULL))
422 				retval = yp_passwd(user, new_pass);
423 			else {
424 				/* Reject 'local' flag if NIS is on and the user
425 				 * is not local
426 				 */
427 				retval = PAM_PERM_DENIED;
428 				PAM_LOG("Unknown local user: %s", user);
429 			}
430 		}
431 		else if (res == USER_LOCAL_ONLY) {
432 			if (!pam_test_option(&options, PAM_OPT_NIS_PASS, NULL))
433 				retval = local_passwd(user, new_pass);
434 			else {
435 				/* Reject 'nis' flag if user is only local */
436 				retval = PAM_PERM_DENIED;
437 				PAM_LOG("Unknown NIS user: %s", user);
438 			}
439 		}
440 		else if (res == USER_YP_AND_LOCAL) {
441 			if (pam_test_option(&options, PAM_OPT_NIS_PASS, NULL))
442 				retval = yp_passwd(user, new_pass);
443 			else
444 				retval = local_passwd(user, new_pass);
445 		}
446 		else
447 			retval = PAM_ABORT; /* Bad juju */
448 #else
449 		retval = local_passwd(user, new_pass);
450 #endif
451 
452 		/* XXX wipe the mem as well */
453 		pass = NULL;
454 		new_pass = NULL;
455 	}
456 	else {
457 		/* Very bad juju */
458 		retval = PAM_ABORT;
459 		PAM_LOG("Illegal 'flags'");
460 	}
461 
462 	PAM_RETURN(retval);
463 }
464 
465 /* Mostly stolen from passwd(1)'s local_passwd.c - markm */
466 
467 static unsigned char itoa64[] =		/* 0 ... 63 => ascii - 64 */
468 	"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
469 
470 static void
471 to64(char *s, long v, int n)
472 {
473 	while (--n >= 0) {
474 		*s++ = itoa64[v&0x3f];
475 		v >>= 6;
476 	}
477 }
478 
479 static int
480 local_passwd(const char *user, const char *pass)
481 {
482 	login_cap_t * lc;
483 	struct passwd *pwd;
484 	struct timeval tv;
485 	int pfd, tfd;
486 	char *crypt_type, salt[32];
487 
488 	pwd = getpwnam(user);
489 	if (pwd == NULL)
490 		return(PAM_ABORT); /* Really bad things */
491 
492 #ifdef YP
493 	pwd = (struct passwd *)&local_password;
494 #endif
495 	pw_init();
496 
497 	pwd->pw_change = 0;
498 	lc = login_getclass(NULL);
499 	crypt_type = login_getcapstr(lc, "passwd_format",
500 		PASSWORD_HASH, PASSWORD_HASH);
501 	if (login_setcryptfmt(lc, crypt_type, NULL) == NULL)
502 		syslog(LOG_ERR, "cannot set password cipher");
503 	login_close(lc);
504 	/* Salt suitable for anything */
505 	srandomdev();
506 	gettimeofday(&tv, 0);
507 	to64(&salt[0], random(), 3);
508 	to64(&salt[3], tv.tv_usec, 3);
509 	to64(&salt[6], tv.tv_sec, 2);
510 	to64(&salt[8], random(), 5);
511 	to64(&salt[13], random(), 5);
512 	to64(&salt[17], random(), 5);
513 	to64(&salt[22], random(), 5);
514 	salt[27] = '\0';
515 
516 	pwd->pw_passwd = crypt(pass, salt);
517 
518 	pfd = pw_lock();
519 	tfd = pw_tmp();
520 	pw_copy(pfd, tfd, pwd);
521 
522 	if (!pw_mkdb((char *)user))
523 		pw_error((char *)NULL, 0, 1);
524 
525 	return PAM_SUCCESS;
526 }
527 
528 #ifdef YP
529 /* Stolen from src/usr.bin/passwd/yp_passwd.c, carrying copyrights of:
530  * Copyright (c) 1992/3 Theo de Raadt <deraadt@fsa.ca>
531  * Copyright (c) 1994 Olaf Kirch <okir@monad.swb.de>
532  * Copyright (c) 1995 Bill Paul <wpaul@ctr.columbia.edu>
533  */
534 int
535 yp_passwd(const char *user, const char *pass)
536 {
537 	struct master_yppasswd master_yppasswd;
538 	struct passwd *pwd;
539 	struct rpc_err err;
540 	struct timeval tv;
541 	struct yppasswd yppasswd;
542 	CLIENT *clnt;
543 	login_cap_t *lc;
544 	int    *status;
545 	uid_t	uid;
546 	char   *master, *sockname = YP_SOCKNAME, salt[32];
547 
548 	_use_yp = 1;
549 
550 	uid = getuid();
551 
552 	master = get_yp_master(1);
553 	if (master == NULL)
554 		return PAM_ABORT; /* Major disaster */
555 
556 	/*
557 	 * It is presumed that by the time we get here, use_yp()
558 	 * has been called and that we have verified that the user
559 	 * actually exists. This being the case, the yp_password
560 	 * stucture has already been filled in for us.
561 	 */
562 
563 	/* Use the correct password */
564 	pwd = (struct passwd *)&yp_password;
565 
566 	pwd->pw_change = 0;
567 
568 	/* Initialize password information */
569 	if (suser_override) {
570 		master_yppasswd.newpw.pw_passwd = strdup(pwd->pw_passwd);
571 		master_yppasswd.newpw.pw_name = strdup(pwd->pw_name);
572 		master_yppasswd.newpw.pw_uid = pwd->pw_uid;
573 		master_yppasswd.newpw.pw_gid = pwd->pw_gid;
574 		master_yppasswd.newpw.pw_expire = pwd->pw_expire;
575 		master_yppasswd.newpw.pw_change = pwd->pw_change;
576 		master_yppasswd.newpw.pw_fields = pwd->pw_fields;
577 		master_yppasswd.newpw.pw_gecos = strdup(pwd->pw_gecos);
578 		master_yppasswd.newpw.pw_dir = strdup(pwd->pw_dir);
579 		master_yppasswd.newpw.pw_shell = strdup(pwd->pw_shell);
580 		master_yppasswd.newpw.pw_class = pwd->pw_class != NULL ?
581 					strdup(pwd->pw_class) : "";
582 		master_yppasswd.oldpass = "";
583 		master_yppasswd.domain = yp_domain;
584 	} else {
585 		yppasswd.newpw.pw_passwd = strdup(pwd->pw_passwd);
586 		yppasswd.newpw.pw_name = strdup(pwd->pw_name);
587 		yppasswd.newpw.pw_uid = pwd->pw_uid;
588 		yppasswd.newpw.pw_gid = pwd->pw_gid;
589 		yppasswd.newpw.pw_gecos = strdup(pwd->pw_gecos);
590 		yppasswd.newpw.pw_dir = strdup(pwd->pw_dir);
591 		yppasswd.newpw.pw_shell = strdup(pwd->pw_shell);
592 		yppasswd.oldpass = "";
593 	}
594 
595 	if (login_setcryptfmt(lc, "md5", NULL) == NULL)
596 		syslog(LOG_ERR, "cannot set password cipher");
597 	login_close(lc);
598 	/* Salt suitable for anything */
599 	srandomdev();
600 	gettimeofday(&tv, 0);
601 	to64(&salt[0], random(), 3);
602 	to64(&salt[3], tv.tv_usec, 3);
603 	to64(&salt[6], tv.tv_sec, 2);
604 	to64(&salt[8], random(), 5);
605 	to64(&salt[13], random(), 5);
606 	to64(&salt[17], random(), 5);
607 	to64(&salt[22], random(), 5);
608 	salt[27] = '\0';
609 
610 	if (suser_override)
611 		master_yppasswd.newpw.pw_passwd = crypt(pass, salt);
612 	else
613 		yppasswd.newpw.pw_passwd = crypt(pass, salt);
614 
615 	if (suser_override) {
616 		if ((clnt = clnt_create(sockname, MASTER_YPPASSWDPROG,
617 		    MASTER_YPPASSWDVERS, "unix")) == NULL) {
618 			syslog(LOG_ERR,
619 			    "Cannot contact rpc.yppasswdd on host %s: %s",
620 			    master, clnt_spcreateerror(""));
621 			return PAM_ABORT;
622 		}
623 	}
624 	else {
625 		if ((clnt = clnt_create(master, YPPASSWDPROG,
626 		    YPPASSWDVERS, "udp")) == NULL) {
627 			syslog(LOG_ERR,
628 			    "Cannot contact rpc.yppasswdd on host %s: %s",
629 			    master, clnt_spcreateerror(""));
630 			return PAM_ABORT;
631 		}
632 	}
633 	/*
634 	 * The yppasswd.x file said `unix authentication required',
635 	 * so I added it. This is the only reason it is in here.
636 	 * My yppasswdd doesn't use it, but maybe some others out there
637 	 * do. 					--okir
638 	 */
639 	clnt->cl_auth = authunix_create_default();
640 
641 	if (suser_override)
642 		status = yppasswdproc_update_master_1(&master_yppasswd, clnt);
643 	else
644 		status = yppasswdproc_update_1(&yppasswd, clnt);
645 
646 	clnt_geterr(clnt, &err);
647 
648 	auth_destroy(clnt->cl_auth);
649 	clnt_destroy(clnt);
650 
651 	if (err.re_status != RPC_SUCCESS || status == NULL || *status)
652 		return PAM_ABORT;
653 
654 	return (err.re_status || status == NULL || *status)
655 	    ? PAM_ABORT : PAM_SUCCESS;
656 }
657 #endif /* YP */
658 
659 PAM_MODULE_ENTRY("pam_unix");
660