549d8c9a8a8ccd4add6ca743b8d6711d0b4cbab2
[kai/samba.git] / source / nsswitch / pam_winbind.c
1 /* pam_winbind module
2
3    Copyright Andrew Tridgell <tridge@samba.org> 2000
4
5    largely based on pam_userdb by Christian Gafton <gafton@redhat.com> 
6 */
7
8 #include <features.h>
9 #include <stdlib.h>
10 #include <unistd.h>
11 #include <string.h>
12 #include <syslog.h>
13 #include <stdarg.h>
14 #include <sys/types.h>
15 #include <sys/stat.h>
16 #include <fcntl.h>
17 #include <errno.h>
18
19 #define MODULE_NAME "pam_winbind"
20 #define PAM_SM_AUTH
21 #define PAM_SM_ACCOUNT
22 #include <security/pam_modules.h>
23 #include <security/_pam_macros.h>
24
25 #define PAM_DEBUG_ARG (1<<0)
26 #define PAM_USE_AUTHTOK_ARG (1<<1)
27 #define PAM_UNKNOWN_OK_ARG (1<<2)
28
29 #include "ntdom_config.h"
30 #include "winbindd_ntdom.h"
31
32 /* prototypes from common.c */
33 void init_request(struct winbindd_request *req,int rq_type);
34 int write_sock(void *buffer, int count);
35 int read_reply(struct winbindd_response *response);
36
37 /* some syslogging */
38 static void _pam_log(int err, const char *format, ...)
39 {
40         va_list args;
41
42         va_start(args, format);
43         openlog(MODULE_NAME, LOG_CONS|LOG_PID, LOG_AUTH);
44         vsyslog(err, format, args);
45         va_end(args);
46         closelog();
47 }
48
49 static int ctrl  = 0;
50
51 static int _pam_parse(int argc, const char **argv)
52 {
53      /* step through arguments */
54      for (ctrl = 0; argc-- > 0; ++argv) {
55
56           /* generic options */
57
58           if (!strcmp(*argv,"debug"))
59                ctrl |= PAM_DEBUG_ARG;
60           else if (!strcasecmp(*argv, "use_authtok"))
61               ctrl |= PAM_USE_AUTHTOK_ARG;
62           else if (!strcasecmp(*argv, "unknown_ok"))
63               ctrl |= PAM_UNKNOWN_OK_ARG;
64           else {
65                _pam_log(LOG_ERR, "pam_parse: unknown option; %s", *argv);
66           }
67      }
68
69      return ctrl;
70 }
71
72
73 /* talk to winbindd */
74 static int winbind_request(int req_type, const char *user, const char *pass)
75 {
76         struct winbindd_request request;
77         struct winbindd_response response;
78
79         ZERO_STRUCT(request);
80
81         strncpy(request.data.auth.user, user, sizeof(request.data.auth.user)-1);
82         strncpy(request.data.auth.pass, pass, sizeof(request.data.auth.pass)-1);
83         
84         /* Fill in request and send down pipe */
85         init_request(&request, req_type);
86         
87         if (write_sock(&request, sizeof(request)) == -1) {
88                 return -2;
89         }
90         
91         /* Wait for reply */
92         if (read_reply(&response) == -1) {
93                 return -2;
94         }
95
96         /* Copy reply data from socket */
97         if (response.result != WINBINDD_OK) {
98                 return 1;
99         }
100         
101         return 0;
102 }
103
104 /*
105  * Looks up an user name and checks the password
106  *
107  * return values:
108  *       1  = User not found
109  *       0  = OK
110  *      -1  = Password incorrect
111  *      -2  = System error
112  */
113 static int user_lookup(const char *user, const char *pass)
114 {
115         return winbind_request(WINBINDD_PAM_AUTH, user, pass);
116 }
117
118 /*
119  * Checks if a user has an account
120  *
121  * return values:
122  *       1  = User not found
123  *       0  = OK
124  *      -1  = System error
125  */
126 static int valid_user(const char *user)
127 {
128         if (getpwnam(user)) return 0;
129         return 1;
130 }
131
132 /* --- authentication management functions --- */
133
134 /*
135  * dummy conversation function sending exactly one prompt
136  * and expecting exactly one response from the other party
137  */
138 static int converse(pam_handle_t *pamh,
139                     struct pam_message **message,
140                     struct pam_response **response)
141 {
142     int retval;
143     struct pam_conv *conv;
144
145     retval = pam_get_item(pamh, PAM_CONV, (const void **) &conv ) ;
146     if (retval == PAM_SUCCESS)
147         retval = conv->conv(1, (const struct pam_message **)message,
148                             response, conv->appdata_ptr);
149         
150     return retval; /* propagate error status */
151 }
152
153
154 static char *_pam_delete(register char *xx)
155 {
156     _pam_overwrite(xx);
157     _pam_drop(xx);
158     return NULL;
159 }
160
161 /*
162  * This is a conversation function to obtain the user's password
163  */
164 static int conversation(pam_handle_t *pamh)
165 {
166     struct pam_message msg[2],*pmsg[2];
167     struct pam_response *resp;
168     int retval;
169     char * token;
170     
171     pmsg[0] = &msg[0];
172     msg[0].msg_style = PAM_PROMPT_ECHO_OFF;
173     msg[0].msg = "Password: ";
174
175     /* so call the conversation expecting i responses */
176     resp = NULL;
177     retval = converse(pamh, pmsg, &resp);
178
179     if (resp != NULL) {
180         char * const item;
181         /* interpret the response */
182         if (retval == PAM_SUCCESS) {     /* a good conversation */
183             token = x_strdup(resp[0].resp);
184             if (token == NULL) {
185                 return PAM_AUTHTOK_RECOVER_ERR;
186             }
187         }
188
189         /* set the auth token */
190         retval = pam_set_item(pamh, PAM_AUTHTOK, token);
191         token = _pam_delete(token);   /* clean it up */
192         if ( (retval != PAM_SUCCESS) ||
193              (retval = pam_get_item(pamh, PAM_AUTHTOK, (const void **) &item)) != PAM_SUCCESS ) {
194             return retval;
195         }
196         
197         _pam_drop_reply(resp, 1);
198     } else {
199         retval = (retval == PAM_SUCCESS)
200             ? PAM_AUTHTOK_RECOVER_ERR:retval ;
201     }
202
203     return retval;
204 }
205
206
207 PAM_EXTERN
208 int pam_sm_authenticate(pam_handle_t *pamh, int flags,
209                         int argc, const char **argv)
210 {
211      const char *username;
212      const char *password;
213      int retval = PAM_AUTH_ERR;
214     
215      /* parse arguments */
216      ctrl = _pam_parse(argc, argv);
217
218      /* Get the username */
219      retval = pam_get_user(pamh, &username, NULL);
220      if ((retval != PAM_SUCCESS) || (!username)) {
221         if (ctrl & PAM_DEBUG_ARG)
222             _pam_log(LOG_DEBUG,"can not get the username");
223         return PAM_SERVICE_ERR;
224      }
225      
226      if ((ctrl & PAM_USE_AUTHTOK_ARG) == 0) {
227          /* Converse just to be sure we have the password */
228          retval = conversation(pamh);
229          if (retval != PAM_SUCCESS) {
230              _pam_log(LOG_ERR, "could not obtain password for `%s'",
231                       username);
232              return PAM_CONV_ERR;
233          }
234      }
235      
236      /* Get the password */
237      retval = pam_get_item(pamh, PAM_AUTHTOK, (const void **) &password);
238      if (retval != PAM_SUCCESS) {
239          _pam_log(LOG_ERR, "Could not retrive user's password");
240          return PAM_AUTHTOK_ERR;
241      }
242      
243      if (ctrl & PAM_DEBUG_ARG)
244          _pam_log(LOG_INFO, "Verify user `%s' with password `%s'",
245                   username, password);
246      
247      /* Now use the username to look up password */
248      retval = user_lookup(username, password);
249      switch (retval) {
250          case -2:
251              /* some sort of system error. The log was already printed */
252              return PAM_SERVICE_ERR;    
253          case -1:
254              /* incorrect password */
255              _pam_log(LOG_WARNING, "user `%s' denied access (incorrect password)", username);
256              return PAM_AUTH_ERR;
257          case 1:
258                  /* the user does not exist */
259              if (ctrl & PAM_DEBUG_ARG)
260                  _pam_log(LOG_NOTICE, "user `%s' not found",
261                           username);
262              if (ctrl & PAM_UNKNOWN_OK_ARG) {
263                  return PAM_IGNORE;
264              }   
265              return PAM_USER_UNKNOWN;
266          case 0:
267              /* Otherwise, the authentication looked good */
268              _pam_log(LOG_NOTICE, "user '%s' granted acces", username);
269              return PAM_SUCCESS;
270          default:
271              /* we don't know anything about this return value */
272              _pam_log(LOG_ERR, "internal module error (retval = %d, user = `%s'",
273                       retval, username);
274              return PAM_SERVICE_ERR;
275      }
276      /* should not be reached */
277      return PAM_IGNORE;
278 }
279
280 PAM_EXTERN
281 int pam_sm_setcred(pam_handle_t *pamh, int flags,
282                    int argc, const char **argv)
283 {
284     return PAM_SUCCESS;
285 }
286
287 /*
288  * Account management. We want to verify that the account exists 
289  * before returning PAM_SUCCESS
290  */
291 PAM_EXTERN
292 int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags,
293                    int argc, const char **argv)
294 {
295     const char *username;
296     int retval = PAM_USER_UNKNOWN;
297
298     /* parse arguments */
299     ctrl = _pam_parse(argc, argv);
300
301     /* Get the username */
302     retval = pam_get_user(pamh, &username, NULL);
303     if ((retval != PAM_SUCCESS) || (!username)) {
304         if (ctrl & PAM_DEBUG_ARG)
305             _pam_log(LOG_DEBUG,"can not get the username");
306         return PAM_SERVICE_ERR;
307     }
308
309     /* Verify the username */
310     retval = valid_user(username);
311     switch (retval) {
312         case -1:
313             /* some sort of system error. The log was already printed */
314             return PAM_SERVICE_ERR;
315         case 1:
316             /* the user does not exist */
317             if (ctrl & PAM_DEBUG_ARG)
318                 _pam_log(LOG_NOTICE, "user `%s' not found",
319                          username);
320             if (ctrl & PAM_UNKNOWN_OK_ARG)
321                 return PAM_IGNORE;
322             return PAM_USER_UNKNOWN;
323         case 0:
324             /* Otherwise, the authentication looked good */
325             _pam_log(LOG_NOTICE, "user '%s' granted acces", username);
326             return PAM_SUCCESS;
327         default:
328             /* we don't know anything about this return value */
329             _pam_log(LOG_ERR, "internal module error (retval = %d, user = `%s'",
330                      retval, username);
331             return PAM_SERVICE_ERR;
332     }
333     
334     /* should not be reached */
335     return PAM_IGNORE;
336 }
337
338
339 #ifdef PAM_STATIC
340
341 /* static module data */
342
343 struct pam_module _pam_userdb_modstruct = {
344      MODULE_NAME,
345      pam_sm_authenticate,
346      pam_sm_setcred,
347      pam_sm_acct_mgmt,
348      NULL,
349      NULL,
350      NULL,
351 };
352
353 #endif
354
355 /*
356  * Copyright (c) Andrew Tridgell <tridge@samba.org> 2000
357  *
358  * Redistribution and use in source and binary forms, with or without
359  * modification, are permitted provided that the following conditions
360  * are met:
361  * 1. Redistributions of source code must retain the above copyright
362  *    notice, and the entire permission notice in its entirety,
363  *    including the disclaimer of warranties.
364  * 2. Redistributions in binary form must reproduce the above copyright
365  *    notice, this list of conditions and the following disclaimer in the
366  *    documentation and/or other materials provided with the distribution.
367  * 3. The name of the author may not be used to endorse or promote
368  *    products derived from this software without specific prior
369  *    written permission.
370  *
371  * ALTERNATIVELY, this product may be distributed under the terms of
372  * the GNU Public License, in which case the provisions of the GPL are
373  * required INSTEAD OF the above restrictions.  (This clause is
374  * necessary due to a potential bad interaction between the GPL and
375  * the restrictions contained in a BSD-style copyright.)
376  *
377  * THIS SOFTWARE IS PROVIDED `AS IS'' AND ANY EXPRESS OR IMPLIED
378  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
379  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
380  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
381  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
382  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
383  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
384  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
385  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
386  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
387  * OF THE POSSIBILITY OF SUCH DAMAGE.
388  */