]> granicus.if.org Git - linux-pam/blob - modules/pam_pwdb/pwdb_chkpwd.c
Relevant BUGIDs: 133542
[linux-pam] / modules / pam_pwdb / pwdb_chkpwd.c
1 /*
2  * $Id$
3  *
4  * This program is designed to run setuid(root) or with sufficient
5  * privilege to read all of the unix password databases. It is designed
6  * to provide a mechanism for the current user (defined by this
7  * process' real uid) to verify their own password.
8  *
9  * The password is read from the standard input. The exit status of
10  * this program indicates whether the user is authenticated or not.
11  *
12  * Copyright information is located at the end of the file.
13  *
14  */
15
16 #include <security/_pam_aconf.h>
17
18 #include <stdarg.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <syslog.h>
23 #include <unistd.h>
24
25 #include <security/_pam_macros.h>
26
27 #define MAXPASS      200        /* the maximum length of a password */
28
29 #define UNIX_PASSED  (PWDB_SUCCESS)
30 #define UNIX_FAILED  (PWDB_SUCCESS+1)
31
32 #include <pwdb/pwdb_public.h>
33
34 /* syslogging function for errors and other information */
35
36 static void _log_err(int err, const char *format, ...)
37 {
38     va_list args;
39
40     va_start(args, format);
41     openlog("pwdb_chkpwd", LOG_CONS|LOG_PID, LOG_AUTH);
42     vsyslog(err, format, args);
43     va_end(args);
44     closelog();
45 }
46
47 #define PWDB_NO_MD_COMPAT
48 #include "pam_unix_md.-c"
49
50 static int _unix_verify_passwd(const char *salt, const char *p)
51 {
52     char *pp=NULL;
53     int retval;
54
55     if (p == NULL) {
56         if (*salt == '\0') {
57             retval = UNIX_PASSED;
58         } else {
59             retval = UNIX_FAILED;
60         }
61     } else {
62         pp = _pam_md(p, salt);
63         p = NULL;                     /* no longer needed here */
64
65         if ( strcmp( pp, salt ) == 0 ) {
66             retval = UNIX_PASSED;
67         } else {
68             retval = UNIX_FAILED;
69         }
70     }
71
72     /* clean up */
73     {
74         char *tp = pp;
75         if (pp != NULL) {
76             while(tp && *tp)
77                 *tp++ = '\0';
78             free(pp);
79             pp = tp = NULL;
80         }
81     }
82
83     return retval;
84 }
85
86 int main(int argc, char **argv)
87 {
88     const struct pwdb *pw=NULL;
89     const struct pwdb_entry *pwe=NULL;
90     char pass[MAXPASS+1];
91     int npass, force_failure=0;
92     int retval=UNIX_FAILED;
93
94     /*
95      * we establish that this program is running with non-tty stdin.
96      * this is to discourage casual use. It does *NOT* prevent an
97      * intruder from repeatadly running this program to determine the
98      * password of the current user (brute force attack, but one for
99      * which the attacker must already have gained access to the user's
100      * account).
101      */
102
103     if ( isatty(STDIN_FILENO) ) {
104         _log_err(LOG_NOTICE
105                  , "inappropriate use of PWDB helper binary [UID=%d]"
106                  , getuid() );
107         fprintf(stderr,
108                 "This program is not designed for running in this way\n"
109                 "-- the system administrator has been informed\n");
110         exit(UNIX_FAILED);
111     }
112
113     /*
114      * determine the current user's name:
115      */
116
117     retval = pwdb_start();
118     if (retval != PWDB_SUCCESS) {
119         _log_err(LOG_ALERT, "failed to open pwdb");
120         retval = UNIX_FAILED;
121     }
122     if (retval != UNIX_FAILED) {
123         retval = pwdb_locate("user", PWDB_DEFAULT, PWDB_NAME_UNKNOWN,
124                              getuid(), &pw);
125     }
126     if (retval != PWDB_SUCCESS) {
127         _log_err(LOG_ALERT, "could not identify user");
128         while (pwdb_end() != PWDB_SUCCESS);
129         exit(UNIX_FAILED);
130     }
131     if (argc == 2) {
132         if (pwdb_get_entry(pw, "user", &pwe) == PWDB_SUCCESS) {
133             if (pwe == NULL) {
134                 force_failure = 1;
135             } else {
136                 if (strcmp((const char *) pwe->value, argv[1])) {
137                     force_failure = 1;
138                 }
139                 pwdb_entry_delete(&pwe);
140             }
141         }
142     }
143
144     /* read the password from stdin (a pipe from the pam_pwdb module) */
145
146     npass = read(STDIN_FILENO, pass, MAXPASS);
147
148     if (npass < 0) {                             /* is it a valid password? */
149         _log_err(LOG_DEBUG, "no password supplied");
150         retval = UNIX_FAILED;
151     } else if (npass >= MAXPASS-1) {
152         _log_err(LOG_DEBUG, "password too long");
153         retval = UNIX_FAILED;
154     } else if (pwdb_get_entry(pw, "passwd", &pwe) != PWDB_SUCCESS) {
155         _log_err(LOG_WARNING, "password not found");
156         retval = UNIX_FAILED;
157     } else {
158         if (npass <= 0) {
159             /* the password is NULL */
160
161             retval = _unix_verify_passwd((const char *)(pwe->value), NULL);
162         } else {
163             /* does pass agree with the official one? */
164
165             pass[npass] = '\0';                     /* NUL terminate */
166             retval = _unix_verify_passwd((const char *)(pwe->value), pass);
167         }
168     }
169
170     memset(pass, '\0', MAXPASS);        /* clear memory of the password */
171     while (pwdb_end() != PWDB_SUCCESS);
172
173     if ((retval != UNIX_FAILED) && force_failure) {
174         retval = UNIX_FAILED;
175     }
176     
177     /* return pass or fail */
178
179     exit(retval);
180 }
181
182 /*
183  * Copyright (c) Andrew G. Morgan, 1997. All rights reserved
184  *
185  * Redistribution and use in source and binary forms, with or without
186  * modification, are permitted provided that the following conditions
187  * are met:
188  * 1. Redistributions of source code must retain the above copyright
189  *    notice, and the entire permission notice in its entirety,
190  *    including the disclaimer of warranties.
191  * 2. Redistributions in binary form must reproduce the above copyright
192  *    notice, this list of conditions and the following disclaimer in the
193  *    documentation and/or other materials provided with the distribution.
194  * 3. The name of the author may not be used to endorse or promote
195  *    products derived from this software without specific prior
196  *    written permission.
197  * 
198  * ALTERNATIVELY, this product may be distributed under the terms of
199  * the GNU Public License, in which case the provisions of the GPL are
200  * required INSTEAD OF the above restrictions.  (This clause is
201  * necessary due to a potential bad interaction between the GPL and
202  * the restrictions contained in a BSD-style copyright.)
203  * 
204  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
205  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
206  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
207  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
208  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
209  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
210  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
211  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
212  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
213  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
214  * OF THE POSSIBILITY OF SUCH DAMAGE.
215  */