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 $
4 * $DragonFly: src/contrib/libpam/modules/pam_unix/Attic/unix_chkpwd.c,v 1.2 2003/06/17 04:24:03 dillon Exp $
6 * This program is designed to run setuid(root) or with sufficient
7 * privilege to read all of the unix password databases. It is designed
8 * to provide a mechanism for the current user (defined by this
9 * process' uid) to verify their own password.
11 * The password is read from the standard input. The exit status of
12 * this program indicates whether the user is authenticated or not.
14 * Copyright information is located at the end of the file.
18 #include <security/_pam_aconf.h>
26 #include <sys/types.h>
31 #define MAXPASS 200 /* the maximum length of a password */
33 #include <security/_pam_macros.h>
37 extern char *crypt(const char *key, const char *salt);
38 extern char *bigcrypt(const char *key, const char *salt);
43 /* syslogging function for errors and other information */
45 static void _log_err(int err, const char *format,...)
49 va_start(args, format);
50 openlog("unix_chkpwd", LOG_CONS | LOG_PID, LOG_AUTH);
51 vsyslog(err, format, args);
56 static void su_sighandler(int sig)
59 _log_err(LOG_NOTICE, "caught signal %d.", sig);
64 static void setup_signals(void)
66 struct sigaction action; /* posix signal structure */
69 * Setup signal handlers
71 (void) memset((void *) &action, 0, sizeof(action));
72 action.sa_handler = su_sighandler;
73 action.sa_flags = SA_RESETHAND;
74 (void) sigaction(SIGILL, &action, NULL);
75 (void) sigaction(SIGTRAP, &action, NULL);
76 (void) sigaction(SIGBUS, &action, NULL);
77 (void) sigaction(SIGSEGV, &action, NULL);
78 action.sa_handler = SIG_IGN;
80 (void) sigaction(SIGTERM, &action, NULL);
81 (void) sigaction(SIGHUP, &action, NULL);
82 (void) sigaction(SIGINT, &action, NULL);
83 (void) sigaction(SIGQUIT, &action, NULL);
86 static int _unix_verify_password(const char *name, const char *p, int opt)
88 struct passwd *pwd = NULL;
89 struct spwd *spwdent = NULL;
92 int retval = UNIX_FAILED;
94 /* UNIX passwords area */
96 pwd = getpwnam(name); /* Get password file entry... */
99 if (strcmp(pwd->pw_passwd, "x") == 0) {
101 * ...and shadow password file entry for this user,
102 * if shadowing is enabled
105 spwdent = getspnam(name);
108 salt = x_strdup(spwdent->sp_pwdp);
112 if (strcmp(pwd->pw_passwd, "*NP*") == 0) { /* NIS+ */
115 save_uid = geteuid();
116 seteuid(pwd->pw_uid);
117 spwdent = getspnam(name);
120 salt = x_strdup(spwdent->sp_pwdp);
122 salt = x_strdup(pwd->pw_passwd);
126 if (pwd == NULL || salt == NULL) {
127 _log_err(LOG_ALERT, "check pass; user unknown");
132 if (strlen(salt) == 0)
133 return (opt == 0) ? UNIX_FAILED : UNIX_PASSED;
135 /* the moment of truth -- do we agree with the password? */
136 retval = UNIX_FAILED;
137 if (!strncmp(salt, "$1$", 3)) {
138 pp = Goodcrypt_md5(p, salt);
139 if (strcmp(pp, salt) == 0) {
140 retval = UNIX_PASSED;
142 pp = Brokencrypt_md5(p, salt);
143 if (strcmp(pp, salt) == 0)
144 retval = UNIX_PASSED;
147 pp = bigcrypt(p, salt);
148 if (strcmp(pp, salt) == 0) {
149 retval = UNIX_PASSED;
152 p = NULL; /* no longer needed here */
167 static char *getuidname(uid_t uid)
170 static char username[32];
176 memset(username, 0, 32);
177 strncpy(username, pw->pw_name, 32);
183 int main(int argc, char *argv[])
185 char pass[MAXPASS + 1];
188 int force_failure = 0;
189 int retval = UNIX_FAILED;
193 * Catch or ignore as many signal as possible.
198 * we establish that this program is running with non-tty stdin.
199 * this is to discourage casual use. It does *NOT* prevent an
200 * intruder from repeatadly running this program to determine the
201 * password of the current user (brute force attack, but one for
202 * which the attacker must already have gained access to the user's
206 if (isatty(STDIN_FILENO)) {
209 ,"inappropriate use of Unix helper binary [UID=%d]"
212 ,"This binary is not designed for running in this way\n"
213 "-- the system administrator has been informed\n");
214 sleep(10); /* this should discourage/annoy the user */
219 * determine the current user's name is
221 user = getuidname(getuid());
223 /* if the caller specifies the username, verify that user
225 if (strcmp(user, argv[1])) {
230 /* read the nollok/nonull option */
232 npass = read(STDIN_FILENO, option, 8);
235 _log_err(LOG_DEBUG, "no option supplied");
239 if (strncmp(option, "nullok", 8) == 0)
245 /* read the password from stdin (a pipe from the pam_unix module) */
247 npass = read(STDIN_FILENO, pass, MAXPASS);
249 if (npass < 0) { /* is it a valid password? */
251 _log_err(LOG_DEBUG, "no password supplied");
253 } else if (npass >= MAXPASS) {
255 _log_err(LOG_DEBUG, "password too long");
259 /* the password is NULL */
261 retval = _unix_verify_password(user, NULL, opt);
264 /* does pass agree with the official one? */
266 pass[npass] = '\0'; /* NUL terminate */
267 retval = _unix_verify_password(user, pass, opt);
272 memset(pass, '\0', MAXPASS); /* clear memory of the password */
274 /* return pass or fail */
276 if ((retval != UNIX_PASSED) || force_failure) {
284 * Copyright (c) Andrew G. Morgan, 1996. All rights reserved
286 * Redistribution and use in source and binary forms, with or without
287 * modification, are permitted provided that the following conditions
289 * 1. Redistributions of source code must retain the above copyright
290 * notice, and the entire permission notice in its entirety,
291 * including the disclaimer of warranties.
292 * 2. Redistributions in binary form must reproduce the above copyright
293 * notice, this list of conditions and the following disclaimer in the
294 * documentation and/or other materials provided with the distribution.
295 * 3. The name of the author may not be used to endorse or promote
296 * products derived from this software without specific prior
297 * written permission.
299 * ALTERNATIVELY, this product may be distributed under the terms of
300 * the GNU Public License, in which case the provisions of the GPL are
301 * required INSTEAD OF the above restrictions. (This clause is
302 * necessary due to a potential bad interaction between the GPL and
303 * the restrictions contained in a BSD-style copyright.)
305 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
306 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
307 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
308 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
309 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
310 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
311 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
312 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
313 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
314 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
315 * OF THE POSSIBILITY OF SUCH DAMAGE.