2 * This program is is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License, version 2 if the
4 * License as published by the Free Software Foundation.
6 * This program is distributed in the hope that it will be useful,
7 * but WITHOUT ANY WARRANTY; without even the implied warranty of
8 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 * GNU General Public License for more details.
11 * You should have received a copy of the GNU General Public License
12 * along with this program; if not, write to the Free Software
13 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 * @brief Interfaces with the PAM library to allow auth via PAM.
21 * @note This was taken from the hacks that miguel a.l. paraz <map@iphil.net>
22 * @note did on radiusd-cistron-1.5.3 and migrated to a separate file.
23 * @note That, in fact, was again based on the original stuff from
24 * @note Jeph Blaize <jblaize@kiva.net> done in May 1997.
26 * @copyright 2000,2006 The FreeRADIUS server project
27 * @copyright 1997 Jeph Blaize <jblaize@kiva.net>
28 * @copyright 1999 miguel a.l. paraz <map@iphil.net>
32 #include <freeradius-devel/radiusd.h>
33 #include <freeradius-devel/modules.h>
37 #ifdef HAVE_SECURITY_PAM_APPL_H
38 #include <security/pam_appl.h>
41 #ifdef HAVE_PAM_PAM_APPL_H
42 #include <pam/pam_appl.h>
50 typedef struct rlm_pam_t {
51 char const *pam_auth_name;
54 static const CONF_PARSER module_config[] = {
55 { "pam_auth", FR_CONF_OFFSET(PW_TYPE_STRING, rlm_pam_t, pam_auth_name), "radiusd" },
56 { NULL, -1, 0, NULL, NULL }
59 /*************************************************************************
63 * Purpose: Dialogue between RADIUS and PAM modules.
65 * jab - stolen from pop3d
67 * Alan DeKok: modified to use PAM's appdata_ptr, so that we're
68 * multi-threaded safe, and don't have any nasty static
69 * variables hanging around.
71 *************************************************************************/
73 typedef struct my_PAM {
79 static int PAM_conv(int num_msg, struct pam_message const **msg, struct pam_response **resp, void *appdata_ptr) {
81 struct pam_response *reply;
82 my_PAM *pam_config = (my_PAM *) appdata_ptr;
84 /* strdup(NULL) doesn't work on some platforms */
85 #define COPY_STRING(s) ((s) ? strdup(s) : NULL)
87 reply = rad_malloc(num_msg * sizeof(struct pam_response));
88 memset(reply, 0, num_msg * sizeof(struct pam_response));
89 for (count = 0; count < num_msg; count++) {
90 switch (msg[count]->msg_style) {
91 case PAM_PROMPT_ECHO_ON:
92 reply[count].resp_retcode = PAM_SUCCESS;
93 reply[count].resp = COPY_STRING(pam_config->username);
95 case PAM_PROMPT_ECHO_OFF:
96 reply[count].resp_retcode = PAM_SUCCESS;
97 reply[count].resp = COPY_STRING(pam_config->password);
104 /* Must be an error of some sort... */
105 for (count = 0; count < num_msg; count++) {
106 if (reply[count].resp) {
107 /* could be a password, let's be sanitary */
108 memset(reply[count].resp, 0, strlen(reply[count].resp));
109 free(reply[count].resp);
113 pam_config->error = 1;
118 /* PAM frees reply (including reply[].resp) */
123 /*************************************************************************
127 * Purpose: Check the users password against the standard UNIX
128 * password table + PAM.
131 *************************************************************************/
135 * for most flexibility, passing a pamauth type to this function
136 * allows you to have multiple authentication types (i.e. multiple
137 * files associated with radius in /etc/pam.d)
139 static int pam_pass(char const *name, char const *passwd, char const *pamauth)
141 pam_handle_t *pamh=NULL;
144 struct pam_conv conv;
147 * Initialize the structures.
149 conv.conv = PAM_conv;
150 conv.appdata_ptr = &pam_config;
151 pam_config.username = name;
152 pam_config.password = passwd;
153 pam_config.error = 0;
155 DEBUG("pam_pass: using pamauth string <%s> for pam.conf lookup", pamauth);
156 retval = pam_start(pamauth, name, &conv, &pamh);
157 if (retval != PAM_SUCCESS) {
158 DEBUG("pam_pass: function pam_start FAILED for <%s>. Reason: %s",
159 name, pam_strerror(pamh, retval));
163 retval = pam_authenticate(pamh, 0);
164 if (retval != PAM_SUCCESS) {
165 DEBUG("pam_pass: function pam_authenticate FAILED for <%s>. Reason: %s",
166 name, pam_strerror(pamh, retval));
167 pam_end(pamh, retval);
172 * FreeBSD 3.x doesn't have account and session management
173 * functions in PAM, while 4.0 does.
175 #if !defined(__FreeBSD_version) || (__FreeBSD_version >= 400000)
176 retval = pam_acct_mgmt(pamh, 0);
177 if (retval != PAM_SUCCESS) {
178 DEBUG("pam_pass: function pam_acct_mgmt FAILED for <%s>. Reason: %s",
179 name, pam_strerror(pamh, retval));
180 pam_end(pamh, retval);
185 DEBUG("pam_pass: authentication succeeded for <%s>", name);
186 pam_end(pamh, retval);
190 /* translate between function declarations */
191 static rlm_rcode_t CC_HINT(nonnull) mod_authenticate(void *instance, REQUEST *request)
195 rlm_pam_t *data = (rlm_pam_t *) instance;
197 char const *pam_auth_string = data->pam_auth_name;
200 * We can only authenticate user requests which HAVE
201 * a User-Name attribute.
203 if (!request->username) {
204 AUTH("rlm_pam: Attribute \"User-Name\" is required for authentication");
205 return RLM_MODULE_INVALID;
209 * We can only authenticate user requests which HAVE
210 * a User-Password attribute.
212 if (!request->password) {
213 AUTH("rlm_pam: Attribute \"User-Password\" is required for authentication");
214 return RLM_MODULE_INVALID;
218 * Ensure that we're being passed a plain-text password,
219 * and not anything else.
221 if (request->password->da->attr != PW_USER_PASSWORD) {
222 AUTH("rlm_pam: Attribute \"User-Password\" is required for authentication. Cannot use \"%s\".", request->password->da->name);
223 return RLM_MODULE_INVALID;
227 * Let the 'users' file over-ride the PAM auth name string,
228 * for backwards compatibility.
230 pair = pairfind(request->config_items, PW_PAM_AUTH, 0, TAG_ANY);
231 if (pair) pam_auth_string = pair->vp_strvalue;
233 r = pam_pass(request->username->vp_strvalue,
234 request->password->vp_strvalue,
238 return RLM_MODULE_OK;
240 return RLM_MODULE_REJECT;
246 RLM_TYPE_THREAD_UNSAFE, /* The PAM libraries are not thread-safe */
249 NULL, /* instantiation */
252 mod_authenticate, /* authenticate */
253 NULL, /* authorize */
254 NULL, /* pre-accounting */
255 NULL, /* accounting */
256 NULL, /* checksimul */
257 NULL, /* pre-proxy */
258 NULL, /* post-proxy */