2 * $Id: unix_chkpwd.c,v 1.3 2001/02/11 06:33:53 agmorgan Exp $
3 * $FreeBSD: src/contrib/libpam/modules/pam_unix/unix_chkpwd.c,v 1.1.1.1.2.2 2001/06/11 15:28:30 markm Exp $
5 * This program is designed to run setuid(root) or with sufficient
6 * privilege to read all of the unix password databases. It is designed
7 * to provide a mechanism for the current user (defined by this
8 * process' uid) to verify their own password.
10 * The password is read from the standard input. The exit status of
11 * this program indicates whether the user is authenticated or not.
13 * Copyright information is located at the end of the file.
17 #include <security/_pam_aconf.h>
25 #include <sys/types.h>
30 #define MAXPASS 200 /* the maximum length of a password */
32 #include <security/_pam_macros.h>
36 extern char *crypt(const char *key, const char *salt);
37 extern char *bigcrypt(const char *key, const char *salt);
42 /* syslogging function for errors and other information */
44 static void _log_err(int err, const char *format,...)
48 va_start(args, format);
49 openlog("unix_chkpwd", LOG_CONS | LOG_PID, LOG_AUTH);
50 vsyslog(err, format, args);
55 static void su_sighandler(int sig)
58 _log_err(LOG_NOTICE, "caught signal %d.", sig);
63 static void setup_signals(void)
65 struct sigaction action; /* posix signal structure */
68 * Setup signal handlers
70 (void) memset((void *) &action, 0, sizeof(action));
71 action.sa_handler = su_sighandler;
72 action.sa_flags = SA_RESETHAND;
73 (void) sigaction(SIGILL, &action, NULL);
74 (void) sigaction(SIGTRAP, &action, NULL);
75 (void) sigaction(SIGBUS, &action, NULL);
76 (void) sigaction(SIGSEGV, &action, NULL);
77 action.sa_handler = SIG_IGN;
79 (void) sigaction(SIGTERM, &action, NULL);
80 (void) sigaction(SIGHUP, &action, NULL);
81 (void) sigaction(SIGINT, &action, NULL);
82 (void) sigaction(SIGQUIT, &action, NULL);
85 static int _unix_verify_password(const char *name, const char *p, int opt)
87 struct passwd *pwd = NULL;
88 struct spwd *spwdent = NULL;
91 int retval = UNIX_FAILED;
93 /* UNIX passwords area */
95 pwd = getpwnam(name); /* Get password file entry... */
98 if (strcmp(pwd->pw_passwd, "x") == 0) {
100 * ...and shadow password file entry for this user,
101 * if shadowing is enabled
104 spwdent = getspnam(name);
107 salt = x_strdup(spwdent->sp_pwdp);
111 if (strcmp(pwd->pw_passwd, "*NP*") == 0) { /* NIS+ */
114 save_uid = geteuid();
115 seteuid(pwd->pw_uid);
116 spwdent = getspnam(name);
119 salt = x_strdup(spwdent->sp_pwdp);
121 salt = x_strdup(pwd->pw_passwd);
125 if (pwd == NULL || salt == NULL) {
126 _log_err(LOG_ALERT, "check pass; user unknown");
131 if (strlen(salt) == 0)
132 return (opt == 0) ? UNIX_FAILED : UNIX_PASSED;
134 /* the moment of truth -- do we agree with the password? */
135 retval = UNIX_FAILED;
136 if (!strncmp(salt, "$1$", 3)) {
137 pp = Goodcrypt_md5(p, salt);
138 if (strcmp(pp, salt) == 0) {
139 retval = UNIX_PASSED;
141 pp = Brokencrypt_md5(p, salt);
142 if (strcmp(pp, salt) == 0)
143 retval = UNIX_PASSED;
146 pp = bigcrypt(p, salt);
147 if (strcmp(pp, salt) == 0) {
148 retval = UNIX_PASSED;
151 p = NULL; /* no longer needed here */
166 static char *getuidname(uid_t uid)
169 static char username[32];
175 memset(username, 0, 32);
176 strncpy(username, pw->pw_name, 32);
182 int main(int argc, char *argv[])
184 char pass[MAXPASS + 1];
187 int force_failure = 0;
188 int retval = UNIX_FAILED;
192 * Catch or ignore as many signal as possible.
197 * we establish that this program is running with non-tty stdin.
198 * this is to discourage casual use. It does *NOT* prevent an
199 * intruder from repeatadly running this program to determine the
200 * password of the current user (brute force attack, but one for
201 * which the attacker must already have gained access to the user's
205 if (isatty(STDIN_FILENO)) {
208 ,"inappropriate use of Unix helper binary [UID=%d]"
211 ,"This binary is not designed for running in this way\n"
212 "-- the system administrator has been informed\n");
213 sleep(10); /* this should discourage/annoy the user */
218 * determine the current user's name is
220 user = getuidname(getuid());
222 /* if the caller specifies the username, verify that user
224 if (strcmp(user, argv[1])) {
229 /* read the nollok/nonull option */
231 npass = read(STDIN_FILENO, option, 8);
234 _log_err(LOG_DEBUG, "no option supplied");
238 if (strncmp(option, "nullok", 8) == 0)
244 /* read the password from stdin (a pipe from the pam_unix module) */
246 npass = read(STDIN_FILENO, pass, MAXPASS);
248 if (npass < 0) { /* is it a valid password? */
250 _log_err(LOG_DEBUG, "no password supplied");
252 } else if (npass >= MAXPASS) {
254 _log_err(LOG_DEBUG, "password too long");
258 /* the password is NULL */
260 retval = _unix_verify_password(user, NULL, opt);
263 /* does pass agree with the official one? */
265 pass[npass] = '\0'; /* NUL terminate */
266 retval = _unix_verify_password(user, pass, opt);
271 memset(pass, '\0', MAXPASS); /* clear memory of the password */
273 /* return pass or fail */
275 if ((retval != UNIX_PASSED) || force_failure) {
283 * Copyright (c) Andrew G. Morgan, 1996. All rights reserved
285 * Redistribution and use in source and binary forms, with or without
286 * modification, are permitted provided that the following conditions
288 * 1. Redistributions of source code must retain the above copyright
289 * notice, and the entire permission notice in its entirety,
290 * including the disclaimer of warranties.
291 * 2. Redistributions in binary form must reproduce the above copyright
292 * notice, this list of conditions and the following disclaimer in the
293 * documentation and/or other materials provided with the distribution.
294 * 3. The name of the author may not be used to endorse or promote
295 * products derived from this software without specific prior
296 * written permission.
298 * ALTERNATIVELY, this product may be distributed under the terms of
299 * the GNU Public License, in which case the provisions of the GPL are
300 * required INSTEAD OF the above restrictions. (This clause is
301 * necessary due to a potential bad interaction between the GPL and
302 * the restrictions contained in a BSD-style copyright.)
304 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
305 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
306 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
307 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
308 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
309 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
310 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
311 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
312 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
313 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
314 * OF THE POSSIBILITY OF SUCH DAMAGE.