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