pam_unix.c revision 77142
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: head/lib/libpam/modules/pam_unix/pam_unix.c 77142 2001-05-24 18:35:52Z markm $
27 */
28
29#include <sys/types.h>
30#include <sys/time.h>
31#include <login_cap.h>
32#include <pwd.h>
33#include <stdlib.h>
34#include <string.h>
35#include <stdio.h>
36#include <unistd.h>
37
38#define PAM_SM_AUTH
39#define PAM_SM_ACCOUNT
40#include <security/pam_modules.h>
41
42#include "pam_mod_misc.h"
43
44#define PASSWORD_PROMPT	"Password:"
45
46/*
47 * authentication management
48 */
49
50PAM_EXTERN int
51pam_sm_authenticate(pam_handle_t *pamh, int flags, int argc,
52    const char **argv)
53{
54	int retval;
55	const char *user;
56	const char *password;
57	struct passwd *pwd;
58	char *encrypted;
59	int options;
60	int i;
61
62	options = 0;
63	for (i = 0;  i < argc;  i++)
64		pam_std_option(&options, argv[i]);
65	if (options & PAM_OPT_AUTH_AS_SELF)
66		pwd = getpwuid(getuid());
67	else {
68		if ((retval = pam_get_user(pamh, &user, NULL)) != PAM_SUCCESS)
69			return retval;
70		pwd = getpwnam(user);
71	}
72	if ((retval = pam_get_pass(pamh, &password, PASSWORD_PROMPT,
73	    options)) != PAM_SUCCESS)
74		return retval;
75	if (pwd != NULL) {
76		encrypted = crypt(password, pwd->pw_passwd);
77		if (password[0] == '\0' && pwd->pw_passwd[0] != '\0')
78			encrypted = ":";
79
80		retval = strcmp(encrypted, pwd->pw_passwd) == 0 ?
81		    PAM_SUCCESS : PAM_AUTH_ERR;
82	} else {
83		/*
84		 * User unknown.  Encrypt anyway so that it takes the
85		 * same amount of time.
86		 */
87		crypt(password, "xx");
88		retval = PAM_AUTH_ERR;
89	}
90	/*
91	 * The PAM infrastructure will obliterate the cleartext
92	 * password before returning to the application.
93	 */
94	return retval;
95}
96
97PAM_EXTERN int
98pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv)
99{
100	return PAM_SUCCESS;
101}
102
103/*
104 * account management
105 *
106 * check pw_change and pw_expire fields
107 */
108PAM_EXTERN
109int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags,
110		     int argc, const char **argv)
111{
112	const char *user;
113	struct passwd *pw;
114	struct timeval tp;
115	time_t warntime;
116	login_cap_t *lc = NULL;
117	char buf[128];
118	int retval;
119
120	retval = pam_get_item(pamh, PAM_USER, (const void **)&user);
121	if (retval != PAM_SUCCESS || user == NULL)
122		/* some implementations return PAM_SUCCESS here */
123		return PAM_USER_UNKNOWN;
124
125	if ((pw = getpwnam(user)) == NULL)
126		return PAM_USER_UNKNOWN;
127
128	retval = PAM_SUCCESS;
129	lc = login_getpwclass(pw);
130
131	if (pw->pw_change || pw->pw_expire)
132		gettimeofday(&tp, NULL);
133
134#define DEFAULT_WARN  (2L * 7L * 86400L)  /* Two weeks */
135
136	warntime = login_getcaptime(lc, "warnpassword", DEFAULT_WARN,
137	    DEFAULT_WARN);
138
139	if (pw->pw_change) {
140		if (tp.tv_sec >= pw->pw_change)
141			/* some implementations return PAM_AUTHTOK_EXPIRED */
142			retval = PAM_NEW_AUTHTOK_REQD;
143		else if (pw->pw_change - tp.tv_sec < warntime) {
144			snprintf(buf, sizeof(buf),
145			    "Warning: your password expires on %s",
146			    ctime(&pw->pw_change));
147			pam_prompt(pamh, PAM_ERROR_MSG, buf, NULL);
148		}
149	}
150
151	warntime = login_getcaptime(lc, "warnexpire", DEFAULT_WARN,
152	    DEFAULT_WARN);
153
154	if (pw->pw_expire) {
155		if (tp.tv_sec >= pw->pw_expire)
156			retval = PAM_ACCT_EXPIRED;
157		else if (pw->pw_expire - tp.tv_sec < warntime) {
158			snprintf(buf, sizeof(buf),
159			    "Warning: your account expires on %s",
160			    ctime(&pw->pw_expire));
161			pam_prompt(pamh, PAM_ERROR_MSG, buf, NULL);
162		}
163	}
164
165	login_close(lc);
166	return retval;
167}
168
169PAM_MODULE_ENTRY("pam_unix");
170