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