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