source: trunk/third/cyrus-sasl/saslauthd/auth_pam.c @ 17977

Revision 17977, 7.1 KB checked in by ghudson, 22 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r17976, which included commits to RCS files with non-trunk default branches.
Line 
1/* MODULE: auth_pam */
2
3/* COPYRIGHT
4 * Copyright (c) 2000 Fabian Knittel.  All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain any existing copyright
11 *    notice, and this entire permission notice in its entirety,
12 *    including the disclaimer of warranties.
13 *
14 * 2. Redistributions in binary form must reproduce the above copyright
15 *    notice, this list of conditions and the following disclaimer in
16 *    the documentation and/or other materials provided with the
17 *    distribution.
18 *
19 * 2. Redistributions in binary form must reproduce all prior and current
20 *    copyright notices, this list of conditions, and the following
21 *    disclaimer in the documentation and/or other materials provided
22 *    with the distribution.
23 *
24 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
25 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
26 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
27 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
28 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
30 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
31 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
32 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
33 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
34 * DAMAGE.
35 * END COPYRIGHT */
36
37/*
38 * Pluggable Authentication Modules, PAM(8), based authentication module
39 * for saslauthd.
40 *
41 * Written by Fabian Knittel <fknittel@gmx.de>. Original implementation
42 * Debian's pwcheck_pam daemon by Michael-John Turner <mj@debian.org>.
43 */
44
45/* PUBLIC DEPENDENCIES */
46#include "mechanisms.h"
47#include <stdio.h>
48
49#ifdef AUTH_PAM
50
51# include <string.h>
52# include <syslog.h>
53# include <security/pam_appl.h>
54
55# include "auth_pam.h"
56/* END PUBLIC DEPENDENCIES */
57
58
59/* Structure for application specific data passed through PAM
60 * to our conv call-back routine saslauthd_pam_conv. */
61typedef struct {
62    const char *login;                  /* plaintext authenticator */
63    const char *password;               /* plaintext password */
64    pam_handle_t *pamh;                 /* pointer to PAM handle */
65} pam_appdata;
66
67# define RETURN(x) return strdup(x)
68
69
70/* FUNCTION: saslauthd_pam_conv */
71
72/* SYNOPSIS
73 * Call-back function used by the PAM library to communicate with us. Each
74 * received message expects a response, pointed to by resp.
75 * END SYNOPSIS */
76
77static int                              /* R: PAM return code */
78saslauthd_pam_conv (
79  /* PARAMETERS */
80  int num_msg,                          /* I: number of messages */
81  const struct pam_message **msg,       /* I: pointer to array of messages */
82  struct pam_response **resp,           /* O: pointer to pointer of response */
83  void *appdata_ptr                     /* I: pointer to app specific data */
84  /* END PARAMETERS */
85  )
86{
87    /* VARIABLES */
88    pam_appdata *my_appdata;            /* application specific data */
89    struct pam_response *my_resp;       /* response created by this func */
90    int i;                              /* loop counter */
91    const char *login_prompt;           /* string prompting for user-name */
92    int rc;                             /* return code holder */
93    /* END VARIABLES */
94
95    my_appdata = appdata_ptr;
96
97    my_resp = malloc(sizeof(struct pam_response) * num_msg);
98    if (my_resp == NULL)
99        return PAM_CONV_ERR;
100
101    for (i = 0; i < num_msg; i++)
102        switch (msg[i]->msg_style) {
103        /*
104         * We assume PAM_PROMPT_ECHO_OFF to be a request for password.
105         * This assumption might be unsafe.
106         *
107         * For PAM_PROMPT_ECHO_ON we first check whether the provided
108         * request string matches PAM_USER_PROMPT and, only if they do
109         * match, assume it to be a request for the login.
110         */
111        case PAM_PROMPT_ECHO_OFF:       /* password */
112            my_resp[i].resp = strdup(my_appdata->password);
113            if (my_resp[i].resp == NULL) {
114                syslog(LOG_DEBUG, "DEBUG: saslauthd_pam_conv: strdup failed");
115                goto ret_error;
116            }
117            my_resp[i].resp_retcode = PAM_SUCCESS;
118            break;
119
120        case PAM_PROMPT_ECHO_ON:        /* username? */
121            /* Recheck setting each time, as it might have been changed
122               in the mean-while. */
123            rc = pam_get_item(my_appdata->pamh, PAM_USER_PROMPT,
124                              (void *) &login_prompt);
125            if (rc != PAM_SUCCESS) {
126                syslog(LOG_DEBUG, "DEBUG: saslauthd_pam_conv: unable to read "
127                       "login prompt string: %s",
128                       pam_strerror(my_appdata->pamh, rc));
129                goto ret_error;
130            }
131
132            if (strcmp(msg[i]->msg, login_prompt) == 0) {
133                my_resp[i].resp = strdup(my_appdata->login);
134                my_resp[i].resp_retcode = PAM_SUCCESS;
135            } else {                    /* ignore */
136                syslog(LOG_DEBUG, "DEBUG: saslauthd_pam_conv: unknown prompt "
137                       "string: %s", msg[i]->msg);
138                my_resp[i].resp = NULL;
139                my_resp[i].resp_retcode = PAM_SUCCESS;
140            }
141            break;
142
143        case PAM_ERROR_MSG:             /* ignore */
144        case PAM_TEXT_INFO:             /* ignore */
145            my_resp[i].resp = NULL;
146            my_resp[i].resp_retcode = PAM_SUCCESS;
147            break;
148
149        default:                        /* error */
150            goto ret_error;
151        }
152    *resp = my_resp;
153    return PAM_SUCCESS;
154
155ret_error:
156    /*
157     * Free response structure. Don't free my_resp[i], as that
158     * isn't initialised yet.
159     */
160    {
161        int y;
162
163        for (y = 0; y < i; y++)
164            if (my_resp[y].resp != NULL)
165                free(my_resp[y].resp);
166        free(my_resp);
167    }
168    return PAM_CONV_ERR;
169}
170
171/* END FUNCTION: saslauthd_pam_conv */
172
173/* FUNCTION: auth_pam */
174
175char *                                  /* R: allocated response string */
176auth_pam (
177  /* PARAMETERS */
178  const char *login,                    /* I: plaintext authenticator */
179  const char *password,                 /* I: plaintext password */
180  const char *service,                  /* I: service name */
181  const char *realm __attribute__((unused))
182  /* END PARAMETERS */
183  )
184{
185    /* VARIABLES */
186    pam_appdata my_appdata;             /* application specific data */
187    struct pam_conv my_conv;            /* pam conversion data */
188    pam_handle_t *pamh;                 /* pointer to PAM handle */
189    int rc;                             /* return code holder */
190    /* END VARIABLES */
191
192    my_appdata.login = login;
193    my_appdata.password = password;
194    my_appdata.pamh = NULL;
195
196    my_conv.conv = saslauthd_pam_conv;
197    my_conv.appdata_ptr = &my_appdata;
198
199    rc = pam_start(service, login, &my_conv, &pamh);
200    if (rc != PAM_SUCCESS) {
201        syslog(LOG_DEBUG, "DEBUG: auth_pam: pam_start failed: %s",
202               pam_strerror(pamh, rc));
203        RETURN("NO PAM start error");
204    }
205
206    my_appdata.pamh = pamh;
207
208    rc = pam_authenticate(pamh, PAM_SILENT);
209    if (rc != PAM_SUCCESS) {
210        syslog(LOG_DEBUG, "DEBUG: auth_pam: pam_authenticate failed: %s",
211               pam_strerror(pamh, rc));
212        pam_end(pamh, rc);
213        RETURN("NO PAM auth error");
214    }
215
216    rc = pam_acct_mgmt(pamh, PAM_SILENT);
217    if (rc != PAM_SUCCESS) {
218        syslog(LOG_DEBUG, "DEBUG: auth_pam: pam_acct_mgmt failed: %s",
219               pam_strerror(pamh, rc));
220        pam_end(pamh, rc);
221        RETURN("NO PAM acct error");
222    }
223
224    pam_end(pamh, PAM_SUCCESS);
225    RETURN("OK");
226}
227
228/* END FUNCTION: auth_pam */
229
230#else /* !AUTH_PAM */
231
232char *
233auth_pam(
234  const char *login __attribute__((unused)),
235  const char *password __attribute__((unused)),
236  const char *service __attribute__((unused)),
237  const char *realm __attribute__((unused))
238  )
239{
240    return NULL;
241}
242
243#endif /* !AUTH_PAM */
244
245/* END MODULE: auth_pam */
Note: See TracBrowser for help on using the repository browser.