pam_unix.c revision 77718
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 77718 2001-06-04 19:16:57Z 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 (pwd != NULL) {
73		if (pwd->pw_passwd[0] == '\0' && (options & PAM_OPT_NULLOK))
74			/*
75			 * No password case. XXX Are we giving too much away
76			 * by not prompting for a password?
77			 */
78			return PAM_SUCCESS;
79		else {
80			if ((retval = pam_get_pass(pamh, &password,
81			    PASSWORD_PROMPT, options)) != PAM_SUCCESS)
82				return retval;
83		}
84		encrypted = crypt(password, pwd->pw_passwd);
85		if (password[0] == '\0' && pwd->pw_passwd[0] != '\0')
86			encrypted = ":";
87
88		retval = strcmp(encrypted, pwd->pw_passwd) == 0 ?
89		    PAM_SUCCESS : PAM_AUTH_ERR;
90	} else {
91		/*
92		 * User unknown.  Encrypt anyway so that it takes the
93		 * same amount of time.
94		 */
95		crypt(password, "xx");
96		retval = PAM_AUTH_ERR;
97	}
98	/*
99	 * The PAM infrastructure will obliterate the cleartext
100	 * password before returning to the application.
101	 */
102	return retval;
103}
104
105PAM_EXTERN int
106pam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv)
107{
108	return PAM_SUCCESS;
109}
110
111/*
112 * account management
113 *
114 * check pw_change and pw_expire fields
115 */
116PAM_EXTERN
117int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags,
118		     int argc, const char **argv)
119{
120	const char *user;
121	struct passwd *pw;
122	struct timeval tp;
123	time_t warntime;
124	login_cap_t *lc = NULL;
125	char buf[128];
126	int retval;
127
128	retval = pam_get_item(pamh, PAM_USER, (const void **)&user);
129	if (retval != PAM_SUCCESS || user == NULL)
130		/* some implementations return PAM_SUCCESS here */
131		return PAM_USER_UNKNOWN;
132
133	if ((pw = getpwnam(user)) == NULL)
134		return PAM_USER_UNKNOWN;
135
136	retval = PAM_SUCCESS;
137	lc = login_getpwclass(pw);
138
139	if (pw->pw_change || pw->pw_expire)
140		gettimeofday(&tp, NULL);
141
142#define DEFAULT_WARN  (2L * 7L * 86400L)  /* Two weeks */
143
144	warntime = login_getcaptime(lc, "warnpassword", DEFAULT_WARN,
145	    DEFAULT_WARN);
146
147	if (pw->pw_change) {
148		if (tp.tv_sec >= pw->pw_change)
149			/* some implementations return PAM_AUTHTOK_EXPIRED */
150			retval = PAM_NEW_AUTHTOK_REQD;
151		else if (pw->pw_change - tp.tv_sec < warntime) {
152			snprintf(buf, sizeof(buf),
153			    "Warning: your password expires on %s",
154			    ctime(&pw->pw_change));
155			pam_prompt(pamh, PAM_ERROR_MSG, buf, NULL);
156		}
157	}
158
159	warntime = login_getcaptime(lc, "warnexpire", DEFAULT_WARN,
160	    DEFAULT_WARN);
161
162	if (pw->pw_expire) {
163		if (tp.tv_sec >= pw->pw_expire)
164			retval = PAM_ACCT_EXPIRED;
165		else if (pw->pw_expire - tp.tv_sec < warntime) {
166			snprintf(buf, sizeof(buf),
167			    "Warning: your account expires on %s",
168			    ctime(&pw->pw_expire));
169			pam_prompt(pamh, PAM_ERROR_MSG, buf, NULL);
170		}
171	}
172
173	login_close(lc);
174	return retval;
175}
176
177PAM_MODULE_ENTRY("pam_unix");
178