The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
rlm_unix.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: 4ccdca7b06aefd46654db1322bf39323506d20a9 $
19 * @file rlm_unix.c
20 * @brief Unixy things
21 *
22 * @copyright 2000,2006 The FreeRADIUS server project
23 * @copyright 2000 Jeff Carneal (jeff@apex.net)
24 * @copyright 2000 Alan Curry (pacman@world.std.com)
25 */
26RCSID("$Id: 4ccdca7b06aefd46654db1322bf39323506d20a9 $")
28
29#define LOG_PREFIX mctx->mi->name
30
31#include <freeradius-devel/radius/radius.h>
32#include <freeradius-devel/server/base.h>
33#include <freeradius-devel/server/module_rlm.h>
34#include <freeradius-devel/util/skip.h>
35#include <freeradius-devel/util/perm.h>
36#include <freeradius-devel/unlang/xlat_func.h>
37
38#include <grp.h>
39#include <pwd.h>
40#include <sys/stat.h>
41
42#include "config.h"
43
44#ifdef HAVE_SHADOW_H
45# include <shadow.h>
46#endif
47
49static fr_dict_t const *dict_radius;
50
53 { .out = &dict_freeradius, .proto = "freeradius" },
54 { .out = &dict_radius, .proto = "radius" },
55 { NULL }
56};
57
69
72 { .out = &attr_auth_type, .name = "Auth-Type", .type = FR_TYPE_UINT32, .dict = &dict_freeradius },
73 { .out = &attr_crypt_password, .name = "Password.Crypt", .type = FR_TYPE_STRING, .dict = &dict_freeradius },
74 { .out = &attr_user_name, .name = "User-Name", .type = FR_TYPE_STRING, .dict = &dict_radius },
75 { .out = &attr_login_ip_host, .name = "Login-IP-Host", .type = FR_TYPE_IPV4_ADDR, .dict = &dict_radius },
76 { .out = &attr_framed_ip_address, .name = "Framed-IP-Address", .type = FR_TYPE_IPV4_ADDR, .dict = &dict_radius },
77 { .out = &attr_framed_protocol, .name = "Framed-Protocol", .type = FR_TYPE_UINT32, .dict = &dict_radius },
78 { .out = &attr_nas_ip_address, .name = "NAS-IP-Address", .type = FR_TYPE_IPV4_ADDR, .dict = &dict_radius },
79 { .out = &attr_nas_port, .name = "NAS-Port", .type = FR_TYPE_UINT32, .dict = &dict_radius },
80 { .out = &attr_acct_status_type, .name = "Acct-Status-Type", .type = FR_TYPE_UINT32, .dict = &dict_radius },
81 { .out = &attr_acct_delay_time, .name = "Acct-Delay-Time", .type = FR_TYPE_UINT32, .dict = &dict_radius },
82 { .out = &attr_expr_bool_enum, .name = "Expr-Bool-Enum", .type = FR_TYPE_BOOL, .dict = &dict_freeradius },
83 { NULL }
84};
85
86/** Check if the user is in the given group
87 *
88 */
89static bool CC_HINT(nonnull) unix_check_group(request_t *request, char const *name)
90{
91 bool rcode = false;
92 struct passwd *pwd;
93 struct group *grp;
95
96 /*
97 * No user name, can't compare.
98 */
99 username = fr_pair_find_by_da(&request->request_pairs, NULL, attr_user_name);
100 if (!username) return false;
101
102 if (fr_perm_getpwnam(request, &pwd, username->vp_strvalue) < 0) {
103 RPEDEBUG("Failed resolving user name");
104 return false;
105 }
106
107 if (fr_perm_getgrnam(request, &grp, name) < 0) {
108 RPEDEBUG("Failed resolving group name");
109 talloc_free(pwd);
110 return false;
111 }
112
113 /*
114 * The users default group may be the one we're looking
115 * for, in which case we use that.
116 *
117 * Otherwise, we go through the list of groups to see if the group name matches.
118 */
119 if (pwd->pw_gid == grp->gr_gid) {
120 rcode = true;
121
122 } else {
123 char **member;
124
125 for (member = grp->gr_mem; *member; member++) {
126 if (strcmp(*member, pwd->pw_name) == 0) {
127 rcode = true;
128 break;
129 }
130 }
131 }
132
133 /* lifo */
134 talloc_free(grp);
135 talloc_free(pwd);
136
137 return rcode;
138}
139
140
141/** Check if the user is a member of a particular unix group
142 *
143@verbatim
144%unix.group(<name>)
145@endverbatim
146 *
147 * @ingroup xlat_functions
148 */
150 UNUSED xlat_ctx_t const *xctx,
151 request_t *request, fr_value_box_list_t *in)
152{
153 fr_value_box_t *arg = fr_value_box_list_head(in);
154 char const *p = arg->vb_strvalue;
155 fr_value_box_t *vb;
156
158
160 vb->vb_bool = unix_check_group(request, p);
162
163 return XLAT_ACTION_DONE;
164}
165
166
167/*
168 * Read the config
169 */
170static int mod_bootstrap(module_inst_ctx_t const *mctx)
171{
172 xlat_t *xlat;
173 xlat_arg_parser_t *xlat_arg;
174
175 /*
176 * Define the new %unix.group(name) xlat. The register
177 * function automatically adds the module instance name
178 * as a prefix.
179 */
180 xlat = module_rlm_xlat_register(mctx->mi->boot, mctx, "group", unix_group_xlat, FR_TYPE_BOOL);
181 if (!xlat) {
182 PERROR("Failed registering group expansion");
183 return -1;
184 }
185
186 /*
187 * The xlat escape function needs access to inst - so
188 * argument parser details need to be defined here
189 */
190 xlat_arg = talloc_zero_array(xlat, xlat_arg_parser_t, 2);
191 xlat_arg[0] = (xlat_arg_parser_t) {
193 .required = true,
194 .concat = true
195 };
197
198 xlat_func_args_set(xlat, xlat_arg);
199
200 return 0;
201}
202
203
204/*
205 * Pull the users password from where-ever, and add it to
206 * the given vp list.
207 */
208static unlang_action_t CC_HINT(nonnull) mod_authorize(rlm_rcode_t *p_result, UNUSED module_ctx_t const *mctx, request_t *request)
209{
210 char const *name;
211 char const *encrypted_pass;
212#ifdef HAVE_GETSPNAM
213 struct spwd *spwd = NULL;
214#endif
215 struct passwd *pwd;
216#ifdef HAVE_GETUSERSHELL
217 char *shell;
218#endif
219 fr_pair_t *vp;
221
222 /*
223 * We can only authenticate user requests which HAVE
224 * a User-Name attribute.
225 */
226 username = fr_pair_find_by_da(&request->request_pairs, NULL, attr_user_name);
228
229 name = username->vp_strvalue;
230 encrypted_pass = NULL;
231
232 if ((pwd = getpwnam(name)) == NULL) {
234 }
235 encrypted_pass = pwd->pw_passwd;
236
237#ifdef HAVE_GETSPNAM
238 /*
239 * See if there is a shadow password.
240 *
241 * Only query the _system_ shadow file if the encrypted
242 * password from the passwd file is < 10 characters (i.e.
243 * a valid password would never crypt() to it). This will
244 * prevents users from using NULL password fields as things
245 * stand right now.
246 */
247 if ((!encrypted_pass) || (strlen(encrypted_pass) < 10)) {
248 if ((spwd = getspnam(name)) == NULL) {
250 }
251 encrypted_pass = spwd->sp_pwdp;
252 }
253#endif /* HAVE_GETSPNAM */
254
255#ifdef DENY_SHELL
256 /*
257 * Users with a particular shell are denied access
258 */
259 if (strcmp(pwd->pw_shell, DENY_SHELL) == 0) {
260 REDEBUG("Invalid shell", name);
262 }
263#endif
264
265#ifdef HAVE_GETUSERSHELL
266 /*
267 * Check /etc/shells for a valid shell. If that file
268 * contains /RADIUSD/ANY/SHELL then any shell will do.
269 */
270 while ((shell = getusershell()) != NULL) {
271 if (strcmp(shell, pwd->pw_shell) == 0 ||
272 strcmp(shell, "/RADIUSD/ANY/SHELL") == 0) {
273 break;
274 }
275 }
276 endusershell();
277 if (!shell) {
278 REDEBUG("[%s]: invalid shell [%s]", name, pwd->pw_shell);
280 }
281#endif
282
283#if defined(HAVE_GETSPNAM) && !defined(M_UNIX)
284 /*
285 * Check if password has expired.
286 */
287 if (spwd && spwd->sp_lstchg > 0 && spwd->sp_max >= 0 &&
288 (fr_time_to_sec(request->packet->timestamp) / 86400) > (spwd->sp_lstchg + spwd->sp_max)) {
289 REDEBUG("[%s]: password has expired", name);
291 }
292 /*
293 * Check if account has expired.
294 */
295 if (spwd && spwd->sp_expire > 0 &&
296 (fr_time_to_sec(request->packet->timestamp) / 86400) > spwd->sp_expire) {
297 REDEBUG("[%s]: account has expired", name);
299 }
300#endif
301
302#if defined(__FreeBSD__) || defined(bsdi) || defined(_PWF_EXPIRE)
303 /*
304 * Check if password has expired.
305 */
306 if ((pwd->pw_expire > 0) &&
307 (fr_time_to_sec(request->packet->timestamp) > pwd->pw_expire)) {
308 REDEBUG("[%s]: password has expired", name);
310 }
311#endif
312
313 /*
314 * We might have a passwordless account.
315 *
316 * FIXME: Maybe add Auth-Type := Accept?
317 */
318 if (encrypted_pass[0] == 0)
320
322 fr_pair_value_strdup(vp, encrypted_pass, false);
323
325}
326
327
328/* globally exported name */
331 .common = {
332 .magic = MODULE_MAGIC_INIT,
333 .name = "unix",
335 .bootstrap = mod_bootstrap
336 },
337 .method_group = {
338 .bindings = (module_method_binding_t[]){
339 { .section = SECTION_NAME("recv", "Access-Request"), .method = mod_authorize },
341 }
342 }
343};
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
Definition action.h:35
#define USES_APPLE_DEPRECATED_API
Definition build.h:472
#define RCSID(id)
Definition build.h:485
#define UNUSED
Definition build.h:317
static int fr_dcursor_append(fr_dcursor_t *cursor, void *v)
Insert a single item at the end of the list.
Definition dcursor.h:408
#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:273
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
Definition dict.h:286
static fr_slen_t in
Definition dict.h:840
Specifies an attribute which must be present for the module to function.
Definition dict.h:272
Specifies a dictionary which must be loaded/loadable for the module to function.
Definition dict.h:285
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
Definition dl_module.h:63
static xlat_action_t unix_group_xlat(TALLOC_CTX *ctx, fr_dcursor_t *out, UNUSED xlat_ctx_t const *xctx, request_t *request, fr_value_box_list_t *in)
Check if the user is a member of a particular unix group.
Definition rlm_unix.c:149
#define PERROR(_fmt,...)
Definition log.h:228
#define RPEDEBUG(fmt,...)
Definition log.h:376
talloc_free(reap)
@ FR_TYPE_IPV4_ADDR
32 Bit IPv4 Address.
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_UINT32
32 Bit unsigned integer.
@ FR_TYPE_BOOL
A truth value.
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
xlat_t * module_rlm_xlat_register(TALLOC_CTX *ctx, module_inst_ctx_t const *mctx, char const *name, xlat_func_t func, fr_type_t return_type)
Definition module_rlm.c:243
module_t common
Common fields presented by all modules.
Definition module_rlm.h:39
int fr_pair_value_strdup(fr_pair_t *vp, char const *src, bool tainted)
Copy data into an "string" data type.
Definition pair.c:2645
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:697
int fr_perm_getgrnam(TALLOC_CTX *ctx, struct group **out, char const *name)
Resolve a group name to a group database entry.
Definition perm.c:392
int fr_perm_getpwnam(TALLOC_CTX *ctx, struct passwd **out, char const *name)
Resolve a username to a passwd entry.
Definition perm.c:266
#define REDEBUG(fmt,...)
Definition radclient.h:52
#define RETURN_MODULE_REJECT
Definition rcode.h:56
#define RETURN_MODULE_NOOP
Definition rcode.h:63
#define RETURN_MODULE_UPDATED
Definition rcode.h:64
rlm_rcode_t
Return codes indicating the result of the module call.
Definition rcode.h:40
#define RETURN_MODULE_NOTFOUND
Definition rcode.h:62
static char const * name
username
static fr_dict_attr_t const * attr_login_ip_host
Definition rlm_unix.c:61
static bool unix_check_group(request_t *request, char const *name)
Check if the user is in the given group.
Definition rlm_unix.c:89
static fr_dict_attr_t const * attr_crypt_password
Definition rlm_unix.c:59
static fr_dict_t const * dict_freeradius
Definition rlm_unix.c:48
static fr_dict_attr_t const * attr_expr_bool_enum
Definition rlm_unix.c:68
static fr_dict_t const * dict_radius
Definition rlm_unix.c:49
static int mod_bootstrap(module_inst_ctx_t const *mctx)
Definition rlm_unix.c:170
static fr_dict_attr_t const * attr_auth_type
Definition rlm_unix.c:58
static fr_dict_attr_t const * attr_nas_ip_address
Definition rlm_unix.c:64
static fr_dict_attr_t const * attr_framed_ip_address
Definition rlm_unix.c:62
static fr_dict_attr_t const * attr_framed_protocol
Definition rlm_unix.c:63
static fr_dict_attr_t const * attr_nas_port
Definition rlm_unix.c:65
static fr_dict_attr_t const * attr_acct_status_type
Definition rlm_unix.c:66
static fr_dict_attr_t const * attr_user_name
Definition rlm_unix.c:60
static fr_dict_attr_t const * attr_acct_delay_time
Definition rlm_unix.c:67
fr_dict_autoload_t rlm_unix_dict[]
Definition rlm_unix.c:52
module_rlm_t rlm_unix
Definition rlm_unix.c:330
static unlang_action_t mod_authorize(rlm_rcode_t *p_result, UNUSED module_ctx_t const *mctx, request_t *request)
Definition rlm_unix.c:208
fr_dict_attr_autoload_t rlm_unix_dict_attr[]
Definition rlm_unix.c:71
#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:228
void * boot
Data allocated during the boostrap phase.
Definition module.h:275
#define MODULE_BINDING_TERMINATOR
Terminate a module binding list.
Definition module.h:151
Named methods exported by a module.
Definition module.h:173
#define pair_update_control(_attr, _da)
Return or allocate a fr_pair_t in the control list.
Definition pair.h:140
#define fr_skip_whitespace(_p)
Skip whitespace ('\t', '\n', '\v', '\f', '\r', ' ')
Definition skip.h:37
fr_pair_t * vp
Stores an attribute, a value and various bits of other data.
Definition pair.h:68
static int64_t fr_time_to_sec(fr_time_t when)
Convert an fr_time_t (internal time) to number of sec since the unix epoch (wallclock time)
Definition time.h:731
fr_type_t type
Type to cast argument to.
Definition xlat.h:154
#define XLAT_ARG_PARSER_TERMINATOR
Definition xlat.h:169
xlat_action_t
Definition xlat.h:37
@ XLAT_ACTION_DONE
We're done evaluating this level of nesting.
Definition xlat.h:43
Definition for a single argument consumend by an xlat function.
Definition xlat.h:144
#define fr_value_box_alloc(_ctx, _type, _enumv)
Allocate a value box of a specific type.
Definition value.h:640
int nonnull(2, 5))
static size_t char ** out
Definition value.h:1020
An xlat calling ctx.
Definition xlat_ctx.h:49
int xlat_func_args_set(xlat_t *x, xlat_arg_parser_t const args[])
Register the arguments of an xlat.
Definition xlat_func.c:363