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