3 Copyright Andrew Tridgell <tridge@samba.org> 2000
5 largely based on pam_userdb by Christian Gafton <gafton@redhat.com>
14 #include <sys/types.h>
19 #define MODULE_NAME "pam_winbind"
21 #define PAM_SM_ACCOUNT
22 #include <security/pam_modules.h>
23 #include <security/_pam_macros.h>
25 #define PAM_DEBUG_ARG (1<<0)
26 #define PAM_USE_AUTHTOK_ARG (1<<1)
27 #define PAM_UNKNOWN_OK_ARG (1<<2)
29 #include "winbind_nss_config.h"
30 #include "winbindd_nss.h"
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
);
38 static void _pam_log(int err
, const char *format
, ...)
42 va_start(args
, format
);
43 openlog(MODULE_NAME
, LOG_CONS
|LOG_PID
, LOG_AUTH
);
44 vsyslog(err
, format
, args
);
51 static int _pam_parse(int argc
, const char **argv
)
53 /* step through arguments */
54 for (ctrl
= 0; argc
-- > 0; ++argv
) {
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
;
65 _pam_log(LOG_ERR
, "pam_parse: unknown option; %s", *argv
);
73 /* talk to winbindd */
74 static int winbind_request(int req_type
, const char *user
, const char *pass
)
76 struct winbindd_request request
;
77 struct winbindd_response response
;
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);
84 /* Fill in request and send down pipe */
85 init_request(&request
, req_type
);
87 if (write_sock(&request
, sizeof(request
)) == -1) {
92 if (read_reply(&response
) == -1) {
96 /* Copy reply data from socket */
97 if (response
.result
!= WINBINDD_OK
) {
105 * Looks up an user name and checks the password
110 * -1 = Password incorrect
113 static int user_lookup(const char *user
, const char *pass
)
115 return winbind_request(WINBINDD_PAM_AUTH
, user
, pass
);
119 * Checks if a user has an account
126 static int valid_user(const char *user
)
128 if (getpwnam(user
)) return 0;
132 /* --- authentication management functions --- */
135 * dummy conversation function sending exactly one prompt
136 * and expecting exactly one response from the other party
138 static int converse(pam_handle_t
*pamh
,
139 struct pam_message
**message
,
140 struct pam_response
**response
)
143 struct pam_conv
*conv
;
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
);
150 return retval
; /* propagate error status */
154 static char *_pam_delete(register char *xx
)
162 * This is a conversation function to obtain the user's password
164 static int conversation(pam_handle_t
*pamh
)
166 struct pam_message msg
[2],*pmsg
[2];
167 struct pam_response
*resp
;
172 msg
[0].msg_style
= PAM_PROMPT_ECHO_OFF
;
173 msg
[0].msg
= "Password: ";
175 /* so call the conversation expecting i responses */
177 retval
= converse(pamh
, pmsg
, &resp
);
181 /* interpret the response */
182 if (retval
== PAM_SUCCESS
) { /* a good conversation */
183 token
= x_strdup(resp
[0].resp
);
185 return PAM_AUTHTOK_RECOVER_ERR
;
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
) {
197 _pam_drop_reply(resp
, 1);
199 retval
= (retval
== PAM_SUCCESS
)
200 ? PAM_AUTHTOK_RECOVER_ERR
:retval
;
208 int pam_sm_authenticate(pam_handle_t
*pamh
, int flags
,
209 int argc
, const char **argv
)
211 const char *username
;
212 const char *password
;
213 int retval
= PAM_AUTH_ERR
;
215 /* parse arguments */
216 ctrl
= _pam_parse(argc
, argv
);
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
;
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'",
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
;
243 if (ctrl
& PAM_DEBUG_ARG
)
244 _pam_log(LOG_INFO
, "Verify user `%s' with password `%s'",
247 /* Now use the username to look up password */
248 retval
= user_lookup(username
, password
);
251 /* some sort of system error. The log was already printed */
252 return PAM_SERVICE_ERR
;
254 /* incorrect password */
255 _pam_log(LOG_WARNING
, "user `%s' denied access (incorrect password)", username
);
258 /* the user does not exist */
259 if (ctrl
& PAM_DEBUG_ARG
)
260 _pam_log(LOG_NOTICE
, "user `%s' not found",
262 if (ctrl
& PAM_UNKNOWN_OK_ARG
) {
265 return PAM_USER_UNKNOWN
;
267 /* Otherwise, the authentication looked good */
268 _pam_log(LOG_NOTICE
, "user '%s' granted acces", username
);
271 /* we don't know anything about this return value */
272 _pam_log(LOG_ERR
, "internal module error (retval = %d, user = `%s'",
274 return PAM_SERVICE_ERR
;
276 /* should not be reached */
281 int pam_sm_setcred(pam_handle_t
*pamh
, int flags
,
282 int argc
, const char **argv
)
288 * Account management. We want to verify that the account exists
289 * before returning PAM_SUCCESS
292 int pam_sm_acct_mgmt(pam_handle_t
*pamh
, int flags
,
293 int argc
, const char **argv
)
295 const char *username
;
296 int retval
= PAM_USER_UNKNOWN
;
298 /* parse arguments */
299 ctrl
= _pam_parse(argc
, argv
);
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
;
309 /* Verify the username */
310 retval
= valid_user(username
);
313 /* some sort of system error. The log was already printed */
314 return PAM_SERVICE_ERR
;
316 /* the user does not exist */
317 if (ctrl
& PAM_DEBUG_ARG
)
318 _pam_log(LOG_NOTICE
, "user `%s' not found",
320 if (ctrl
& PAM_UNKNOWN_OK_ARG
)
322 return PAM_USER_UNKNOWN
;
324 /* Otherwise, the authentication looked good */
325 _pam_log(LOG_NOTICE
, "user '%s' granted acces", username
);
328 /* we don't know anything about this return value */
329 _pam_log(LOG_ERR
, "internal module error (retval = %d, user = `%s'",
331 return PAM_SERVICE_ERR
;
334 /* should not be reached */
341 /* static module data */
343 struct pam_module _pam_userdb_modstruct
= {
356 * Copyright (c) Andrew Tridgell <tridge@samba.org> 2000
358 * Redistribution and use in source and binary forms, with or without
359 * modification, are permitted provided that the following conditions
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.
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.)
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.