]> granicus.if.org Git - linux-pam/blob - modules/pam_userdb/pam_userdb.c
Relevant BUGIDs: 476971
[linux-pam] / modules / pam_userdb / pam_userdb.c
1 /* pam_userdb module */
2  
3 /*
4  * $Id$
5  * Written by Cristian Gafton <gafton@redhat.com> 1996/09/10
6  * See the end of the file for Copyright Information
7  */
8
9 #include <security/_pam_aconf.h>
10
11 #include <stdlib.h>
12 #include <unistd.h>
13 #include <string.h>
14 #include <syslog.h>
15 #include <stdarg.h>
16 #include <sys/types.h>
17 #include <sys/stat.h>
18 #include <fcntl.h>
19 #include <errno.h>
20
21 #include "pam_userdb.h"
22
23 #ifdef HAVE_NDBM_H
24 # include <ndbm.h>
25 #else
26 # ifdef HAVE_DB_H
27 #  define DB_DBM_HSEARCH    1 /* use the dbm interface */
28 #  include <db.h>
29 # else
30 #  error "failed to find a libdb or equivalent"
31 # endif
32 #endif
33
34 /*
35  * here, we make a definition for the externally accessible function
36  * in this file (this definition is required for static a module
37  * but strongly encouraged generally) it is used to instruct the
38  * modules include file to define the function prototypes.
39  */
40
41 #define PAM_SM_AUTH
42 #define PAM_SM_ACCOUNT
43
44 #include <security/pam_modules.h>
45
46 /* some syslogging */
47
48 static void _pam_log(int err, const char *format, ...)
49 {
50     va_list args;
51
52     va_start(args, format);
53     openlog(MODULE_NAME, LOG_CONS|LOG_PID, LOG_AUTH);
54     vsyslog(err, format, args);
55     va_end(args);
56     closelog();
57 }
58
59 char * database  = NULL;
60 static int ctrl  = 0;
61
62 static int _pam_parse(int argc, const char **argv)
63 {
64      /* step through arguments */
65      for (ctrl = 0; argc-- > 0; ++argv) {
66
67           /* generic options */
68
69           if (!strcmp(*argv,"debug"))
70                ctrl |= PAM_DEBUG_ARG;
71           else if (!strcasecmp(*argv, "icase"))
72               ctrl |= PAM_ICASE_ARG;
73           else if (!strcasecmp(*argv, "dump"))
74               ctrl |= PAM_DUMP_ARG;
75           else if (!strncasecmp(*argv,"db=", 3)) {
76               database = strdup((*argv) + 3);
77               if (database == NULL)
78                   _pam_log(LOG_ERR, "pam_parse: could not parse argument \"%s\"",
79                            *argv);
80           } else {
81                _pam_log(LOG_ERR, "pam_parse: unknown option; %s", *argv);
82           }
83      }
84
85      return ctrl;
86 }
87
88
89 /*
90  * Looks up an user name in a database and checks the password
91  *
92  * return values:
93  *       1  = User not found
94  *       0  = OK
95  *      -1  = Password incorrect
96  *      -2  = System error
97  */
98 static int user_lookup(const char *user, const char *pass)
99 {
100     DBM *dbm;
101     datum key, data;
102
103     /* Open the DB file. */
104     dbm = dbm_open(database, O_RDONLY, 0644);
105     if (dbm == NULL) {
106         _pam_log(LOG_ERR, "user_lookup: could not open database `%s'",
107                  database);
108         return -2;
109     }
110
111     if (ctrl &PAM_DUMP_ARG) {
112         _pam_log(LOG_INFO, "Database dump:");
113         for (key = dbm_firstkey(dbm);  key.dptr != NULL;
114              key = dbm_nextkey(dbm)) {
115             data = dbm_fetch(dbm, key);
116             _pam_log(LOG_INFO, "key[len=%d] = `%s', data[len=%d] = `%s'",
117                      key.dsize, key.dptr, data.dsize, data.dptr);
118         }
119     } 
120     /* do some more init work */
121
122     memset(&key, 0, sizeof(key));
123     memset(&data, 0, sizeof(data));
124     key.dptr = x_strdup(user);
125     key.dsize = strlen(user);
126     user = NULL;
127
128     if (key.dptr) {
129         data = dbm_fetch(dbm, key);
130         memset(key.dptr, 0, key.dsize);
131         free(key.dptr);
132     }
133
134     if (ctrl & PAM_DEBUG_ARG) {
135         _pam_log(LOG_INFO, "password in database is [%p]`%s', len is %d",
136                  data.dptr, (char *) data.dptr, data.dsize);
137     }
138
139     if (data.dptr != NULL) {
140         int compare = 0;
141         
142         if (strlen(pass) != data.dsize) {
143             compare = 1;
144         } else if (ctrl & PAM_ICASE_ARG) {
145             compare = strncasecmp(data.dptr, pass, data.dsize);
146         } else {
147             compare = strncmp(data.dptr, pass, data.dsize);
148         }
149         dbm_close(dbm);
150         if (compare == 0)
151             return 0; /* match */
152         else
153             return -1; /* wrong */
154     } else {
155         if (ctrl & PAM_DEBUG_ARG) {    
156             _pam_log(LOG_INFO, "error returned by dbm_fetch: %s",
157                      strerror(errno));
158         }
159         dbm_close(dbm);
160         /* probably we should check dbm_error() here */
161         return 1; /* not found */
162     }
163
164     /* NOT REACHED */
165     return -2;
166 }
167
168 /* --- authentication management functions (only) --- */
169
170 PAM_EXTERN
171 int pam_sm_authenticate(pam_handle_t *pamh, int flags,
172                         int argc, const char **argv)
173 {
174      const char *username;
175      const char *password;
176      int retval = PAM_AUTH_ERR;
177     
178      /* parse arguments */
179      ctrl = _pam_parse(argc, argv);
180
181      /* Get the username */
182      retval = pam_get_user(pamh, &username, NULL);
183      if ((retval != PAM_SUCCESS) || (!username)) {
184         if (ctrl & PAM_DEBUG_ARG)
185             _pam_log(LOG_DEBUG,"can not get the username");
186         return PAM_SERVICE_ERR;
187      }
188      
189      /* Converse just to be sure we have the password */
190      retval = conversation(pamh);
191      if (retval != PAM_SUCCESS) {
192          _pam_log(LOG_ERR, "could not obtain password for `%s'",
193                   username);
194          return -2;
195      }
196      
197      /* Get the password */
198      retval = pam_get_item(pamh, PAM_AUTHTOK, (const void **)&password);
199      if (retval != PAM_SUCCESS) {
200          _pam_log(LOG_ERR, "Could not retrive user's password");
201          return -2;
202      }
203      
204      if (ctrl & PAM_DEBUG_ARG)
205          _pam_log(LOG_INFO, "Verify user `%s' with password `%s'",
206                   username, password);
207      
208      /* Now use the username to look up password in the database file */
209      retval = user_lookup(username, password);
210      switch (retval) {
211          case -2:
212              /* some sort of system error. The log was already printed */
213              return PAM_SERVICE_ERR;    
214          case -1:
215              /* incorrect password */
216              _pam_log(LOG_WARNING,
217                       "user `%s' denied access (incorrect password)",
218                       username);
219              return PAM_AUTH_ERR;
220          case 1:
221              /* the user does not exist in the database */
222              if (ctrl & PAM_DEBUG_ARG)
223                  _pam_log(LOG_NOTICE, "user `%s' not found in the database",
224                           username);
225              return PAM_USER_UNKNOWN;
226          case 0:
227              /* Otherwise, the authentication looked good */
228              _pam_log(LOG_NOTICE, "user '%s' granted acces", username);
229              return PAM_SUCCESS;
230          default:
231              /* we don't know anything about this return value */
232              _pam_log(LOG_ERR,
233                       "internal module error (retval = %d, user = `%s'",
234                       retval, username);
235              return PAM_SERVICE_ERR;
236      }
237
238      /* should not be reached */
239      return PAM_IGNORE;
240 }
241
242 PAM_EXTERN
243 int pam_sm_setcred(pam_handle_t *pamh, int flags,
244                    int argc, const char **argv)
245 {
246     return PAM_SUCCESS;
247 }
248
249 PAM_EXTERN
250 int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags,
251                    int argc, const char **argv)
252 {
253     return PAM_SUCCESS;
254 }
255
256
257 #ifdef PAM_STATIC
258
259 /* static module data */
260
261 struct pam_module _pam_userdb_modstruct = {
262      "pam_userdb",
263      pam_sm_authenticate,
264      pam_sm_setcred,
265      NULL,
266      NULL,
267      NULL,
268      NULL,
269 };
270
271 #endif
272
273 /*
274  * Copyright (c) Cristian Gafton <gafton@redhat.com>, 1999
275  *                                              All rights reserved
276  *
277  * Redistribution and use in source and binary forms, with or without
278  * modification, are permitted provided that the following conditions
279  * are met:
280  * 1. Redistributions of source code must retain the above copyright
281  *    notice, and the entire permission notice in its entirety,
282  *    including the disclaimer of warranties.
283  * 2. Redistributions in binary form must reproduce the above copyright
284  *    notice, this list of conditions and the following disclaimer in the
285  *    documentation and/or other materials provided with the distribution.
286  * 3. The name of the author may not be used to endorse or promote
287  *    products derived from this software without specific prior
288  *    written permission.
289  *
290  * ALTERNATIVELY, this product may be distributed under the terms of
291  * the GNU Public License, in which case the provisions of the GPL are
292  * required INSTEAD OF the above restrictions.  (This clause is
293  * necessary due to a potential bad interaction between the GPL and
294  * the restrictions contained in a BSD-style copyright.)
295  *
296  * THIS SOFTWARE IS PROVIDED `AS IS'' AND ANY EXPRESS OR IMPLIED
297  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
298  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
299  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
300  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
301  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
302  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
303  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
304  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
305  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
306  * OF THE POSSIBILITY OF SUCH DAMAGE.
307  */