xref: /freebsd/lib/libpam/modules/pam_unix/pam_unix.c (revision 1642eb1a52563643a9e0b3b69b82c8f1e45541db)
19a10bb17SJohn Polstra /*-
29a10bb17SJohn Polstra  * Copyright 1998 Juniper Networks, Inc.
39a10bb17SJohn Polstra  * All rights reserved.
49a10bb17SJohn Polstra  *
59a10bb17SJohn Polstra  * Redistribution and use in source and binary forms, with or without
69a10bb17SJohn Polstra  * modification, are permitted provided that the following conditions
79a10bb17SJohn Polstra  * are met:
89a10bb17SJohn Polstra  * 1. Redistributions of source code must retain the above copyright
99a10bb17SJohn Polstra  *    notice, this list of conditions and the following disclaimer.
109a10bb17SJohn Polstra  * 2. Redistributions in binary form must reproduce the above copyright
119a10bb17SJohn Polstra  *    notice, this list of conditions and the following disclaimer in the
129a10bb17SJohn Polstra  *    documentation and/or other materials provided with the distribution.
139a10bb17SJohn Polstra  *
149a10bb17SJohn Polstra  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
159a10bb17SJohn Polstra  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
169a10bb17SJohn Polstra  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
179a10bb17SJohn Polstra  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
189a10bb17SJohn Polstra  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
199a10bb17SJohn Polstra  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
209a10bb17SJohn Polstra  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
219a10bb17SJohn Polstra  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
229a10bb17SJohn Polstra  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
239a10bb17SJohn Polstra  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
249a10bb17SJohn Polstra  * SUCH DAMAGE.
259a10bb17SJohn Polstra  *
269a10bb17SJohn Polstra  *	$FreeBSD$
279a10bb17SJohn Polstra  */
289a10bb17SJohn Polstra 
299a10bb17SJohn Polstra #include <sys/types.h>
30d65b34dbSJohn Polstra #include <sys/time.h>
31d65b34dbSJohn Polstra #include <login_cap.h>
329a10bb17SJohn Polstra #include <pwd.h>
339a10bb17SJohn Polstra #include <stdlib.h>
349a10bb17SJohn Polstra #include <string.h>
35d65b34dbSJohn Polstra #include <stdio.h>
369a10bb17SJohn Polstra #include <unistd.h>
379a10bb17SJohn Polstra 
389a10bb17SJohn Polstra #define PAM_SM_AUTH
39d65b34dbSJohn Polstra #define PAM_SM_ACCOUNT
409a10bb17SJohn Polstra #include <security/pam_modules.h>
419a10bb17SJohn Polstra 
429a10bb17SJohn Polstra #include "pam_mod_misc.h"
439a10bb17SJohn Polstra 
449a10bb17SJohn Polstra #define PASSWORD_PROMPT	"Password:"
451642eb1aSMark Murray #define DEFAULT_WARN  (2L * 7L * 86400L)  /* Two weeks */
461642eb1aSMark Murray 
471642eb1aSMark Murray enum { PAM_OPT_AUTH_AS_SELF=PAM_OPT_STD_MAX, PAM_OPT_NULLOK };
481642eb1aSMark Murray 
491642eb1aSMark Murray static struct opttab other_options[] = {
501642eb1aSMark Murray 	{ "auth_as_self",	PAM_OPT_AUTH_AS_SELF },
511642eb1aSMark Murray 	{ "nullok",		PAM_OPT_NULLOK },
521642eb1aSMark Murray 	{ NULL, 0 }
531642eb1aSMark Murray };
549a10bb17SJohn Polstra 
55d65b34dbSJohn Polstra /*
56d65b34dbSJohn Polstra  * authentication management
57d65b34dbSJohn Polstra  */
58d65b34dbSJohn Polstra 
599a10bb17SJohn Polstra PAM_EXTERN int
601642eb1aSMark Murray pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv)
619a10bb17SJohn Polstra {
621642eb1aSMark Murray 	struct options options;
639a10bb17SJohn Polstra 	struct passwd *pwd;
641642eb1aSMark Murray 	int retval;
651642eb1aSMark Murray 	const char *password, *user;
669a10bb17SJohn Polstra 	char *encrypted;
679a10bb17SJohn Polstra 
681642eb1aSMark Murray 	pam_std_option(&options, other_options, argc, argv);
691642eb1aSMark Murray 
701642eb1aSMark Murray 	PAM_LOG("Options processed");
711642eb1aSMark Murray 
721642eb1aSMark Murray 	if (pam_test_option(&options, PAM_OPT_AUTH_AS_SELF, NULL))
734448b21cSMark Murray 		pwd = getpwuid(getuid());
744448b21cSMark Murray 	else {
751642eb1aSMark Murray 		retval = pam_get_user(pamh, &user, NULL);
761642eb1aSMark Murray 		if (retval != PAM_SUCCESS)
771642eb1aSMark Murray 			PAM_RETURN(retval);
784448b21cSMark Murray 		pwd = getpwnam(user);
794448b21cSMark Murray 	}
801642eb1aSMark Murray 
811642eb1aSMark Murray 	PAM_LOG("Got user: %s", user);
821642eb1aSMark Murray 
834448b21cSMark Murray 	if (pwd != NULL) {
841642eb1aSMark Murray 
851642eb1aSMark Murray 		PAM_LOG("Doing real authentication");
861642eb1aSMark Murray 
871642eb1aSMark Murray 		if (pwd->pw_passwd[0] == '\0'
881642eb1aSMark Murray 		    && pam_test_option(&options, PAM_OPT_NULLOK, NULL)) {
8946efbac2SMark Murray 			/*
9046efbac2SMark Murray 			 * No password case. XXX Are we giving too much away
9146efbac2SMark Murray 			 * by not prompting for a password?
9246efbac2SMark Murray 			 */
931642eb1aSMark Murray 			PAM_LOG("No password, and null password OK");
941642eb1aSMark Murray 			PAM_RETURN(PAM_SUCCESS);
951642eb1aSMark Murray 		}
9646efbac2SMark Murray 		else {
971642eb1aSMark Murray 			retval = pam_get_pass(pamh, &password, PASSWORD_PROMPT,
981642eb1aSMark Murray 			    &options);
991642eb1aSMark Murray 			if (retval != PAM_SUCCESS)
1001642eb1aSMark Murray 				PAM_RETURN(retval);
1011642eb1aSMark Murray 			PAM_LOG("Got password");
10246efbac2SMark Murray 		}
1039a10bb17SJohn Polstra 		encrypted = crypt(password, pwd->pw_passwd);
104ce9f8663SJohn Polstra 		if (password[0] == '\0' && pwd->pw_passwd[0] != '\0')
1059a10bb17SJohn Polstra 			encrypted = ":";
1069a10bb17SJohn Polstra 
1071642eb1aSMark Murray 		PAM_LOG("Encrypted passwords are: %s & %s", encrypted,
1081642eb1aSMark Murray 		    pwd->pw_passwd);
1091642eb1aSMark Murray 
1109a10bb17SJohn Polstra 		retval = strcmp(encrypted, pwd->pw_passwd) == 0 ?
1119a10bb17SJohn Polstra 		    PAM_SUCCESS : PAM_AUTH_ERR;
1121642eb1aSMark Murray 	}
1131642eb1aSMark Murray 	else {
1141642eb1aSMark Murray 
1151642eb1aSMark Murray 		PAM_LOG("Doing dummy authentication");
1161642eb1aSMark Murray 
1179a10bb17SJohn Polstra 		/*
1181642eb1aSMark Murray 		 * User unknown.
1191642eb1aSMark Murray 		 * Encrypt a dummy password so as to not give away too much.
1209a10bb17SJohn Polstra 		 */
1211642eb1aSMark Murray 		retval = pam_get_pass(pamh, &password, PASSWORD_PROMPT,
1221642eb1aSMark Murray 		    &options);
1231642eb1aSMark Murray 		if (retval != PAM_SUCCESS)
1241642eb1aSMark Murray 			PAM_RETURN(retval);
1251642eb1aSMark Murray 		PAM_LOG("Got password");
1269a10bb17SJohn Polstra 		crypt(password, "xx");
1279a10bb17SJohn Polstra 		retval = PAM_AUTH_ERR;
1289a10bb17SJohn Polstra 	}
1291642eb1aSMark Murray 
1309a10bb17SJohn Polstra 	/*
1319a10bb17SJohn Polstra 	 * The PAM infrastructure will obliterate the cleartext
1329a10bb17SJohn Polstra 	 * password before returning to the application.
1339a10bb17SJohn Polstra 	 */
1341642eb1aSMark Murray 	PAM_RETURN(retval);
1359a10bb17SJohn Polstra }
1369a10bb17SJohn Polstra 
1379a10bb17SJohn Polstra PAM_EXTERN int
1389a10bb17SJohn Polstra pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv)
1399a10bb17SJohn Polstra {
1409a10bb17SJohn Polstra 	return PAM_SUCCESS;
1419a10bb17SJohn Polstra }
1429294327dSJohn Polstra 
143d65b34dbSJohn Polstra /*
144d65b34dbSJohn Polstra  * account management
145d65b34dbSJohn Polstra  *
146d65b34dbSJohn Polstra  * check pw_change and pw_expire fields
147d65b34dbSJohn Polstra  */
148d65b34dbSJohn Polstra PAM_EXTERN
1491642eb1aSMark Murray int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int argc, const char **argv)
150d65b34dbSJohn Polstra {
1511642eb1aSMark Murray 	struct options options;
152d65b34dbSJohn Polstra 	struct passwd *pw;
153d65b34dbSJohn Polstra 	struct timeval tp;
1541642eb1aSMark Murray 	login_cap_t *lc;
155d65b34dbSJohn Polstra 	time_t warntime;
156d65b34dbSJohn Polstra 	int retval;
1571642eb1aSMark Murray 	const char *user;
1581642eb1aSMark Murray 	char buf[128];
1591642eb1aSMark Murray 
1601642eb1aSMark Murray 	pam_std_option(&options, other_options, argc, argv);
1611642eb1aSMark Murray 
1621642eb1aSMark Murray 	PAM_LOG("Options processed");
163d65b34dbSJohn Polstra 
164d65b34dbSJohn Polstra 	retval = pam_get_item(pamh, PAM_USER, (const void **)&user);
165d65b34dbSJohn Polstra 	if (retval != PAM_SUCCESS || user == NULL)
166d65b34dbSJohn Polstra 		/* some implementations return PAM_SUCCESS here */
1671642eb1aSMark Murray 		PAM_RETURN(PAM_USER_UNKNOWN);
168d65b34dbSJohn Polstra 
1691642eb1aSMark Murray 	pw = getpwnam(user);
1701642eb1aSMark Murray 	if (pw == NULL)
1711642eb1aSMark Murray 		PAM_RETURN(PAM_USER_UNKNOWN);
1721642eb1aSMark Murray 
1731642eb1aSMark Murray 	PAM_LOG("Got user: %s", user);
174d65b34dbSJohn Polstra 
175d65b34dbSJohn Polstra 	retval = PAM_SUCCESS;
176d65b34dbSJohn Polstra 	lc = login_getpwclass(pw);
177d65b34dbSJohn Polstra 
178d65b34dbSJohn Polstra 	if (pw->pw_change || pw->pw_expire)
179d65b34dbSJohn Polstra 		gettimeofday(&tp, NULL);
180d65b34dbSJohn Polstra 
181d65b34dbSJohn Polstra 	warntime = login_getcaptime(lc, "warnpassword", DEFAULT_WARN,
182d65b34dbSJohn Polstra 	    DEFAULT_WARN);
183d65b34dbSJohn Polstra 
1841642eb1aSMark Murray 	PAM_LOG("Got login_cap");
1851642eb1aSMark Murray 
186d65b34dbSJohn Polstra 	if (pw->pw_change) {
187d65b34dbSJohn Polstra 		if (tp.tv_sec >= pw->pw_change)
188d65b34dbSJohn Polstra 			/* some implementations return PAM_AUTHTOK_EXPIRED */
189d65b34dbSJohn Polstra 			retval = PAM_NEW_AUTHTOK_REQD;
190d65b34dbSJohn Polstra 		else if (pw->pw_change - tp.tv_sec < warntime) {
191d65b34dbSJohn Polstra 			snprintf(buf, sizeof(buf),
192d65b34dbSJohn Polstra 			    "Warning: your password expires on %s",
193d65b34dbSJohn Polstra 			    ctime(&pw->pw_change));
194d65b34dbSJohn Polstra 			pam_prompt(pamh, PAM_ERROR_MSG, buf, NULL);
195d65b34dbSJohn Polstra 		}
196d65b34dbSJohn Polstra 	}
197d65b34dbSJohn Polstra 
198d65b34dbSJohn Polstra 	warntime = login_getcaptime(lc, "warnexpire", DEFAULT_WARN,
199d65b34dbSJohn Polstra 	    DEFAULT_WARN);
200d65b34dbSJohn Polstra 
201d65b34dbSJohn Polstra 	if (pw->pw_expire) {
202d65b34dbSJohn Polstra 		if (tp.tv_sec >= pw->pw_expire)
203d65b34dbSJohn Polstra 			retval = PAM_ACCT_EXPIRED;
204d65b34dbSJohn Polstra 		else if (pw->pw_expire - tp.tv_sec < warntime) {
205d65b34dbSJohn Polstra 			snprintf(buf, sizeof(buf),
206d65b34dbSJohn Polstra 			    "Warning: your account expires on %s",
207d65b34dbSJohn Polstra 			    ctime(&pw->pw_expire));
208d65b34dbSJohn Polstra 			pam_prompt(pamh, PAM_ERROR_MSG, buf, NULL);
209d65b34dbSJohn Polstra 		}
210d65b34dbSJohn Polstra 	}
211d65b34dbSJohn Polstra 
212d65b34dbSJohn Polstra 	login_close(lc);
2131642eb1aSMark Murray 
2141642eb1aSMark Murray 	PAM_RETURN(retval);
215d65b34dbSJohn Polstra }
216d65b34dbSJohn Polstra 
2179294327dSJohn Polstra PAM_MODULE_ENTRY("pam_unix");
218