The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
rlm_pam.c
Go to the documentation of this file.
1/*
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 as published by
4 * the Free Software Foundation; either version 2 of the License, or (at
5 * your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15 */
16
17/**
18 * $Id: 9686d20a9d38e616f127d4abdf342911220b08ea $
19 * @file rlm_pam.c
20 * @brief Interfaces with the PAM library to allow auth via PAM.
21 *
22 * @note This was taken from the hacks that miguel a.l. paraz <map@iphil.net>
23 * did on radiusd-cistron-1.5.3 and migrated to a separate file.
24 * That, in fact, was again based on the original stuff from
25 * Jeph Blaize <jblaize@kiva.net> done in May 1997.
26 *
27 * @copyright 2000,2006 The FreeRADIUS server project
28 * @copyright 1997 Jeph Blaize (jblaize@kiva.net)
29 * @copyright 1999 miguel a.l. paraz (map@iphil.net)
30 */
31RCSID("$Id: 9686d20a9d38e616f127d4abdf342911220b08ea $")
32
33#include <freeradius-devel/server/base.h>
34#include <freeradius-devel/server/module_rlm.h>
35
36#include "config.h"
37
38#ifdef HAVE_SECURITY_PAM_APPL_H
39# include <security/pam_appl.h>
40#endif
41
42#ifdef HAVE_PAM_PAM_APPL_H
43# include <pam/pam_appl.h>
44#endif
45
46#ifdef HAVE_SYSLOG_H
47# include <syslog.h>
48#endif
49
50typedef struct {
51 char const *pam_auth_name;
52} rlm_pam_t;
53
54typedef struct {
55 request_t *request; //!< The current request.
56 char const *username; //!< Username to provide to PAM when prompted.
57 char const *password; //!< Password to provide to PAM when prompted.
58 bool error; //!< True if pam_conv failed.
60
61static const conf_parser_t module_config[] = {
62 { FR_CONF_OFFSET("pam_auth", rlm_pam_t, pam_auth_name) },
64};
65
67static fr_dict_t const *dict_radius;
68
71 { .out = &dict_freeradius, .proto = "freeradius" },
72 { .out = &dict_radius, .proto = "radius" },
73 { NULL }
74};
75
79
82 { .out = &attr_pam_auth, .name = "Pam-Auth", .type = FR_TYPE_STRING, .dict = &dict_freeradius },
83 { .out = &attr_user_name, .name = "User-Name", .type = FR_TYPE_STRING, .dict = &dict_radius },
84 { .out = &attr_user_password, .name = "User-Password", .type = FR_TYPE_STRING, .dict = &dict_radius },
85 { NULL }
86};
87
88static int mod_instantiate(module_inst_ctx_t const *mctx)
89{
90 rlm_pam_t *inst = talloc_get_type_abort(mctx->mi->data, rlm_pam_t);
91
92 if (!inst->pam_auth_name) inst->pam_auth_name = main_config->name;
93
94 return 0;
95}
96
97/** Dialogue between RADIUS and PAM modules
98 *
99 * Uses PAM's appdata_ptr so it's thread safe, and doesn't
100 * have any nasty static variables hanging around.
101 */
102static int pam_conv(int num_msg, struct pam_message const **msg, struct pam_response **resp, void *appdata_ptr)
103{
104 int count;
105 struct pam_response *reply;
106 request_t *request;
107 rlm_pam_data_t *pam_config = (rlm_pam_data_t *) appdata_ptr;
108
109 request = pam_config->request;
110
111#define COPY_STRING(s) ((s) ? talloc_strdup(reply, s) : NULL)
112 MEM(reply = talloc_zero_array(NULL, struct pam_response, num_msg));
113 for (count = 0; count < num_msg; count++) {
114 switch (msg[count]->msg_style) {
115 case PAM_PROMPT_ECHO_ON:
116 reply[count].resp_retcode = PAM_SUCCESS;
117 reply[count].resp = COPY_STRING(pam_config->username);
118 break;
119
120 case PAM_PROMPT_ECHO_OFF:
121 reply[count].resp_retcode = PAM_SUCCESS;
122 reply[count].resp = COPY_STRING(pam_config->password);
123 break;
124
125 case PAM_TEXT_INFO:
126 RDEBUG2("%s", msg[count]->msg);
127 break;
128
129 case PAM_ERROR_MSG:
130 default:
131 RERROR("PAM conversation failed");
132 /* Must be an error of some sort... */
133 for (count = 0; count < num_msg; count++) {
134 if (msg[count]->msg_style == PAM_ERROR_MSG) RERROR("%s", msg[count]->msg);
135 if (reply[count].resp) {
136 /* could be a password, let's be sanitary */
137 memset(reply[count].resp, 0, strlen(reply[count].resp));
138 }
139 }
140 talloc_free(reply);
141 pam_config->error = true;
142 return PAM_CONV_ERR;
143 }
144 }
145 *resp = reply;
146 /* PAM frees reply (including reply[].resp) */
147
148 return PAM_SUCCESS;
149}
150
151/** Check the users password against the standard UNIX password table + PAM.
152 *
153 * @note For most flexibility, passing a pamauth type to this function
154 * allows you to have multiple authentication types (i.e. multiple
155 * files associated with radius in /etc/pam.d).
156 *
157 * @param request The current request.
158 * @param username User to authenticate.
159 * @param passwd Password to authenticate with,
160 * @param pamauth Type of PAM authentication.
161 * @return
162 * - 0 on success.
163 * - -1 on failure.
164 */
165static int do_pam(request_t *request, char const *username, char const *passwd, char const *pamauth)
166{
167 pam_handle_t *handle = NULL;
168 int ret;
169 rlm_pam_data_t pam_config;
170 struct pam_conv conv;
171
172 /*
173 * Initialize the structures
174 */
175 conv.conv = pam_conv;
176 conv.appdata_ptr = &pam_config;
177 pam_config.request = request;
178 pam_config.username = username;
179 pam_config.password = passwd;
180 pam_config.error = false;
181
182 RDEBUG2("Using pamauth string \"%s\" for pam.conf lookup", pamauth);
183
184 ret = pam_start(pamauth, username, &conv, &handle);
185 if (ret != PAM_SUCCESS) {
186 RERROR("pam_start failed: %s", pam_strerror(handle, ret));
187 return -1;
188 }
189
190 ret = pam_authenticate(handle, 0);
191 if (ret != PAM_SUCCESS) {
192 RERROR("pam_authenticate failed: %s", pam_strerror(handle, ret));
193 pam_end(handle, ret);
194 return -1;
195 }
196
197 /*
198 * FreeBSD 3.x doesn't have account and session management
199 * functions in PAM, while 4.0 does.
200 */
201#if !defined(__FreeBSD_version) || (__FreeBSD_version >= 400000)
202 ret = pam_acct_mgmt(handle, 0);
203 if (ret != PAM_SUCCESS) {
204 RERROR("pam_acct_mgmt failed: %s", pam_strerror(handle, ret));
205 pam_end(handle, ret);
206 return -1;
207 }
208#endif
209 RDEBUG2("Authentication succeeded");
210 pam_end(handle, ret);
211 return 0;
212}
213
214static unlang_action_t CC_HINT(nonnull) mod_authenticate(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
215{
217 int ret;
218 fr_pair_t *pair;
219
220 char const *pam_auth_string = data->pam_auth_name;
221 fr_pair_t *username, *password;
222
223 username = fr_pair_find_by_da(&request->request_pairs, NULL, attr_user_name);
224 password = fr_pair_find_by_da(&request->request_pairs, NULL, attr_user_password);
225
226 /*
227 * We can only authenticate user requests which HAVE
228 * a User-Name attribute.
229 */
230 if (!username) {
231 REDEBUG("Attribute \"User-Name\" is required for authentication");
233 }
234
235 if (!password) {
236 REDEBUG("Attribute \"User-Password\" is required for authentication");
238 }
239
240 /*
241 * Make sure the supplied password isn't empty
242 */
243 if (password->vp_length == 0) {
244 REDEBUG("User-Password must not be empty");
246 }
247
248 /*
249 * Log the password
250 */
251 if (RDEBUG_ENABLED3) {
252 RDEBUG("Login attempt with password \"%pV\"", &password->data);
253 } else {
254 RDEBUG2("Login attempt with password");
255 }
256
257 /*
258 * Let control list over-ride the PAM auth name string,
259 * for backwards compatibility.
260 */
261 pair = fr_pair_find_by_da(&request->control_pairs, NULL, attr_pam_auth);
262 if (pair) pam_auth_string = pair->vp_strvalue;
263
264 ret = do_pam(request, username->vp_strvalue, password->vp_strvalue, pam_auth_string);
265 if (ret < 0) RETURN_MODULE_REJECT;
266
268}
269
270extern module_rlm_t rlm_pam;
272 .common = {
273 .magic = MODULE_MAGIC_INIT,
274 .name = "pam",
275 .flags = MODULE_TYPE_THREAD_UNSAFE, /* The PAM libraries are not thread-safe */
276 .inst_size = sizeof(rlm_pam_t),
279 },
280 .method_group = {
281 .bindings = (module_method_binding_t[]){
282 { .section = SECTION_NAME("authenticate", CF_IDENT_ANY), .method = mod_authenticate },
284 }
285 }
286};
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
Definition action.h:35
log_entry msg
Definition acutest.h:794
#define RCSID(id)
Definition build.h:483
#define CONF_PARSER_TERMINATOR
Definition cf_parse.h:642
#define FR_CONF_OFFSET(_name, _struct, _field)
conf_parser_t which parses a single CONF_PAIR, writing the result to a field in a struct
Definition cf_parse.h:268
Defines a CONF_PAIR to C data type mapping.
Definition cf_parse.h:579
#define CF_IDENT_ANY
Definition cf_util.h:78
#define MEM(x)
Definition debug.h:36
fr_dict_attr_t const ** out
Where to write a pointer to the resolved fr_dict_attr_t.
Definition dict.h:268
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
Definition dict.h:281
Specifies an attribute which must be present for the module to function.
Definition dict.h:267
Specifies a dictionary which must be loaded/loadable for the module to function.
Definition dict.h:280
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
Definition dl_module.h:63
#define RDEBUG_ENABLED3
True if request debug level 1-3 messages are enabled.
Definition log.h:335
#define RERROR(fmt,...)
Definition log.h:298
talloc_free(reap)
main_config_t const * main_config
Main server configuration.
Definition main_config.c:69
char const * name
Name of the daemon, usually 'radiusd'.
Definition main_config.h:52
@ FR_TYPE_STRING
String of printable characters.
module_instance_t const * mi
Instance of the module being instantiated.
Definition module_ctx.h:42
module_instance_t * mi
Instance of the module being instantiated.
Definition module_ctx.h:51
Temporary structure to hold arguments for module calls.
Definition module_ctx.h:41
Temporary structure to hold arguments for instantiation calls.
Definition module_ctx.h:50
module_t common
Common fields presented by all modules.
Definition module_rlm.h:39
fr_pair_t * fr_pair_find_by_da(fr_pair_list_t const *list, fr_pair_t const *prev, fr_dict_attr_t const *da)
Find the first pair with a matching da.
Definition pair.c:693
static const conf_parser_t config[]
Definition base.c:183
#define REDEBUG(fmt,...)
Definition radclient.h:52
#define RDEBUG2(fmt,...)
Definition radclient.h:54
#define RDEBUG(fmt,...)
Definition radclient.h:53
#define RETURN_MODULE_REJECT
Definition rcode.h:55
#define RETURN_MODULE_INVALID
Definition rcode.h:59
#define RETURN_MODULE_OK
Definition rcode.h:57
rlm_rcode_t
Return codes indicating the result of the module call.
Definition rcode.h:40
static fr_dict_attr_t const * attr_user_password
Definition rlm_pam.c:78
char const * password
Password to provide to PAM when prompted.
Definition rlm_pam.c:57
fr_dict_autoload_t rlm_pam_dict[]
Definition rlm_pam.c:70
fr_dict_attr_autoload_t rlm_pam_dict_attr[]
Definition rlm_pam.c:81
static fr_dict_attr_t const * attr_pam_auth
Definition rlm_pam.c:76
static fr_dict_t const * dict_freeradius
Definition rlm_pam.c:66
static fr_dict_t const * dict_radius
Definition rlm_pam.c:67
static unlang_action_t mod_authenticate(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
Definition rlm_pam.c:214
static int pam_conv(int num_msg, struct pam_message const **msg, struct pam_response **resp, void *appdata_ptr)
Dialogue between RADIUS and PAM modules.
Definition rlm_pam.c:102
bool error
True if pam_conv failed.
Definition rlm_pam.c:58
char const * username
Username to provide to PAM when prompted.
Definition rlm_pam.c:56
request_t * request
The current request.
Definition rlm_pam.c:55
#define COPY_STRING(s)
char const * pam_auth_name
Definition rlm_pam.c:51
static fr_dict_attr_t const * attr_user_name
Definition rlm_pam.c:77
static int do_pam(request_t *request, char const *username, char const *passwd, char const *pamauth)
Check the users password against the standard UNIX password table + PAM.
Definition rlm_pam.c:165
static const conf_parser_t module_config[]
Definition rlm_pam.c:61
static int mod_instantiate(module_inst_ctx_t const *mctx)
Definition rlm_pam.c:88
module_rlm_t rlm_pam
Definition rlm_pam.c:271
static int instantiate(module_inst_ctx_t const *mctx)
Definition rlm_rest.c:1310
username
#define SECTION_NAME(_name1, _name2)
Define a section name consisting of a verb and a noun.
Definition section.h:40
@ MODULE_TYPE_THREAD_UNSAFE
Module is not threadsafe.
Definition module.h:48
module_flags_t flags
Flags that control how a module starts up and how a module is called.
Definition module.h:227
void * data
Module's instance data.
Definition module.h:271
#define MODULE_BINDING_TERMINATOR
Terminate a module binding list.
Definition module.h:151
Named methods exported by a module.
Definition module.h:173
return count
Definition module.c:163
eap_aka_sim_process_conf_t * inst
Stores an attribute, a value and various bits of other data.
Definition pair.h:68
#define talloc_get_type_abort_const
Definition talloc.h:282
static fr_slen_t data
Definition value.h:1265
int nonnull(2, 5))