The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
rlm_unix.c
Go to the documentation of this file.
1/*
2 * This program 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: 89fc57aed8a0e7dc2aeacbfb6688263bc5231436 $
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: 89fc57aed8a0e7dc2aeacbfb6688263bc5231436 $")
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
39#include "config.h"
40
41#ifdef HAVE_SHADOW_H
42# include <shadow.h>
43#endif
44
46static fr_dict_t const *dict_radius;
47
50 { .out = &dict_freeradius, .proto = "freeradius" },
51 { .out = &dict_radius, .proto = "radius" },
53};
54
66
69 { .out = &attr_auth_type, .name = "Auth-Type", .type = FR_TYPE_UINT32, .dict = &dict_freeradius },
70 { .out = &attr_crypt_password, .name = "Password.Crypt", .type = FR_TYPE_STRING, .dict = &dict_freeradius },
71 { .out = &attr_user_name, .name = "User-Name", .type = FR_TYPE_STRING, .dict = &dict_radius },
72 { .out = &attr_login_ip_host, .name = "Login-IP-Host", .type = FR_TYPE_IPV4_ADDR, .dict = &dict_radius },
73 { .out = &attr_framed_ip_address, .name = "Framed-IP-Address", .type = FR_TYPE_IPV4_ADDR, .dict = &dict_radius },
74 { .out = &attr_framed_protocol, .name = "Framed-Protocol", .type = FR_TYPE_UINT32, .dict = &dict_radius },
75 { .out = &attr_nas_ip_address, .name = "NAS-IP-Address", .type = FR_TYPE_IPV4_ADDR, .dict = &dict_radius },
76 { .out = &attr_nas_port, .name = "NAS-Port", .type = FR_TYPE_UINT32, .dict = &dict_radius },
77 { .out = &attr_acct_status_type, .name = "Acct-Status-Type", .type = FR_TYPE_UINT32, .dict = &dict_radius },
78 { .out = &attr_acct_delay_time, .name = "Acct-Delay-Time", .type = FR_TYPE_UINT32, .dict = &dict_radius },
79 { .out = &attr_expr_bool_enum, .name = "Expr-Bool-Enum", .type = FR_TYPE_BOOL, .dict = &dict_freeradius },
81};
82
83/** Check if the user is in the given group
84 *
85 */
86static bool CC_HINT(nonnull) unix_check_group(request_t *request, char const *name)
87{
88 bool rcode = false;
89 struct passwd *pwd;
90 struct group *grp;
91 fr_pair_t *username;
92
93 /*
94 * No user name, can't compare.
95 */
96 username = fr_pair_find_by_da(&request->request_pairs, NULL, attr_user_name);
97 if (!username) return false;
98
99 if (fr_perm_getpwnam(request, &pwd, username->vp_strvalue) < 0) {
100 RPEDEBUG("Failed resolving user name");
101 return false;
102 }
103
104 if (fr_perm_getgrnam(request, &grp, name) < 0) {
105 RPEDEBUG("Failed resolving group name");
106 talloc_free(pwd);
107 return false;
108 }
109
110 /*
111 * The users default group may be the one we're looking
112 * for, in which case we use that.
113 *
114 * Otherwise, we go through the list of groups to see if the group name matches.
115 */
116 if (pwd->pw_gid == grp->gr_gid) {
117 rcode = true;
118
119 } else {
120 char **member;
121
122 for (member = grp->gr_mem; *member; member++) {
123 if (strcmp(*member, pwd->pw_name) == 0) {
124 rcode = true;
125 break;
126 }
127 }
128 }
129
130 /* lifo */
131 talloc_free(grp);
132 talloc_free(pwd);
133
134 return rcode;
135}
136
137
138/** Check if the user is a member of a particular unix group
139 *
140@verbatim
141%unix.group(<name>)
142@endverbatim
143 *
144 * @ingroup xlat_functions
145 */
147 UNUSED xlat_ctx_t const *xctx,
148 request_t *request, fr_value_box_list_t *in)
149{
150 fr_value_box_t *arg = fr_value_box_list_head(in);
151 char const *p = arg->vb_strvalue;
152 fr_value_box_t *vb;
153
155
157 vb->vb_bool = unix_check_group(request, p);
159
160 return XLAT_ACTION_DONE;
161}
162
163
164/*
165 * Read the config
166 */
167static int mod_bootstrap(module_inst_ctx_t const *mctx)
168{
169 xlat_t *xlat;
170 xlat_arg_parser_t *xlat_arg;
171
172 /*
173 * Define the new %unix.group(name) xlat. The register
174 * function automatically adds the module instance name
175 * as a prefix.
176 */
177 xlat = module_rlm_xlat_register(mctx->mi->boot, mctx, "group", unix_group_xlat, FR_TYPE_BOOL);
178 if (!xlat) {
179 PERROR("Failed registering group expansion");
180 return -1;
181 }
182
183 /*
184 * The xlat escape function needs access to inst - so
185 * argument parser details need to be defined here
186 */
187 xlat_arg = talloc_zero_array(xlat, xlat_arg_parser_t, 2);
188 xlat_arg[0] = (xlat_arg_parser_t) {
190 .required = true,
191 .concat = true
192 };
194
195 xlat_func_args_set(xlat, xlat_arg);
196
197 return 0;
198}
199
200
201/*
202 * Pull the users password from where-ever, and add it to
203 * the given vp list.
204 */
205static unlang_action_t CC_HINT(nonnull) mod_authorize(unlang_result_t *p_result, UNUSED module_ctx_t const *mctx, request_t *request)
206{
207 char const *name;
208 char const *encrypted_pass;
209#ifdef HAVE_GETSPNAM
210 struct spwd *spwd = NULL;
211#endif
212 struct passwd *pwd;
213#ifdef HAVE_GETUSERSHELL
214 char *shell;
215#endif
216 fr_pair_t *vp;
217 fr_pair_t *username;
218
219 /*
220 * We can only authenticate user requests which HAVE
221 * a User-Name attribute.
222 */
223 username = fr_pair_find_by_da(&request->request_pairs, NULL, attr_user_name);
224 if (!username) RETURN_UNLANG_NOOP;
225
226 name = username->vp_strvalue;
227 encrypted_pass = NULL;
228
229 if ((pwd = getpwnam(name)) == NULL) {
231 }
232 encrypted_pass = pwd->pw_passwd;
233
234 /*
235 * See if there is a shadow password.
236 *
237 * Only query the _system_ shadow file if the encrypted
238 * password from the passwd file is < 10 characters (i.e.
239 * a valid password would never crypt() to it). This will
240 * prevents users from using NULL password fields as things
241 * stand right now.
242 */
243 if (!encrypted_pass || (strlen(encrypted_pass) < 10)) {
244#ifdef HAVE_GETSPNAM
245 if ((spwd = getspnam(name)) == NULL) {
247 }
248
249 encrypted_pass = spwd->sp_pwdp;
250 if (!encrypted_pass || (strlen(encrypted_pass) < 10)) {
252 }
253#else
255#endif /* HAVE_GETSPNAM */
256 }
257
258#ifdef DENY_SHELL
259 /*
260 * Users with a particular shell are denied access
261 */
262 if (strcmp(pwd->pw_shell, DENY_SHELL) == 0) {
263 REDEBUG("[%s]: invalid shell [%s]", name, pwd->pw_shell);
265 }
266#endif
267
268#ifdef HAVE_GETUSERSHELL
269 /*
270 * Check /etc/shells for a valid shell. If that file
271 * contains /RADIUSD/ANY/SHELL then any shell will do.
272 */
273 while ((shell = getusershell()) != NULL) {
274 if (strcmp(shell, pwd->pw_shell) == 0 ||
275 strcmp(shell, "/RADIUSD/ANY/SHELL") == 0) {
276 break;
277 }
278 }
279 endusershell();
280 if (!shell) {
281 REDEBUG("[%s]: invalid shell [%s]", name, pwd->pw_shell);
283 }
284#endif
285
286#if defined(HAVE_GETSPNAM) && !defined(M_UNIX)
287 /*
288 * Check if password has expired.
289 */
290 if (spwd && spwd->sp_lstchg > 0 && spwd->sp_max >= 0 &&
291 (fr_time_to_sec(request->packet->timestamp) / 86400) > (spwd->sp_lstchg + spwd->sp_max)) {
292 REDEBUG("[%s]: password has expired", name);
294 }
295 /*
296 * Check if account has expired.
297 */
298 if (spwd && spwd->sp_expire > 0 &&
299 (fr_time_to_sec(request->packet->timestamp) / 86400) > spwd->sp_expire) {
300 REDEBUG("[%s]: account has expired", name);
302 }
303#endif
304
305#if defined(__FreeBSD__) || defined(bsdi) || defined(_PWF_EXPIRE)
306 /*
307 * Check if password has expired.
308 */
309 if ((pwd->pw_expire > 0) &&
310 (fr_time_to_sec(request->packet->timestamp) > pwd->pw_expire)) {
311 REDEBUG("[%s]: password has expired", name);
313 }
314#endif
315
316 /*
317 * We might have a passwordless account.
318 *
319 * FIXME: Maybe add Auth-Type := Accept?
320 */
321 if (encrypted_pass[0] == 0) {
323 }
324
326 fr_pair_value_strdup(vp, encrypted_pass, false);
327
329}
330
331
332/* globally exported name */
335 .common = {
336 .magic = MODULE_MAGIC_INIT,
337 .name = "unix",
339 .bootstrap = mod_bootstrap
340 },
341 .method_group = {
342 .bindings = (module_method_binding_t[]){
343 { .section = SECTION_NAME("recv", "Access-Request"), .method = mod_authorize },
345 }
346 }
347};
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:493
#define RCSID(id)
Definition build.h:506
#define UNUSED
Definition build.h:336
static int fr_dcursor_append(fr_dcursor_t *cursor, void *v)
Insert a single item at the end of the list.
Definition dcursor.h:406
#define MEM(x)
Definition debug.h:46
fr_dict_attr_t const ** out
Where to write a pointer to the resolved fr_dict_attr_t.
Definition dict.h:292
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
Definition dict.h:305
#define DICT_AUTOLOAD_TERMINATOR
Definition dict.h:311
static fr_slen_t in
Definition dict.h:882
Specifies an attribute which must be present for the module to function.
Definition dict.h:291
Specifies a dictionary which must be loaded/loadable for the module to function.
Definition dict.h:304
#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:146
talloc_free(hp)
#define PERROR(_fmt,...)
Definition log.h:228
#define RPEDEBUG(fmt,...)
Definition log.h:388
@ 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:247
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:2663
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:707
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:394
int fr_perm_getpwnam(TALLOC_CTX *ctx, struct passwd **out, char const *name)
Resolve a username to a passwd entry.
Definition perm.c:268
#define REDEBUG(fmt,...)
#define RETURN_UNLANG_UPDATED
Definition rcode.h:70
#define RETURN_UNLANG_NOTFOUND
Definition rcode.h:68
#define RETURN_UNLANG_REJECT
Definition rcode.h:62
#define RETURN_UNLANG_NOOP
Definition rcode.h:69
static char const * name
static fr_dict_attr_t const * attr_login_ip_host
Definition rlm_unix.c:58
static bool unix_check_group(request_t *request, char const *name)
Check if the user is in the given group.
Definition rlm_unix.c:86
static unlang_action_t mod_authorize(unlang_result_t *p_result, UNUSED module_ctx_t const *mctx, request_t *request)
Definition rlm_unix.c:205
static fr_dict_attr_t const * attr_crypt_password
Definition rlm_unix.c:56
static fr_dict_t const * dict_freeradius
Definition rlm_unix.c:45
static fr_dict_attr_t const * attr_expr_bool_enum
Definition rlm_unix.c:65
static fr_dict_t const * dict_radius
Definition rlm_unix.c:46
static int mod_bootstrap(module_inst_ctx_t const *mctx)
Definition rlm_unix.c:167
static fr_dict_attr_t const * attr_auth_type
Definition rlm_unix.c:55
static fr_dict_attr_t const * attr_nas_ip_address
Definition rlm_unix.c:61
static fr_dict_attr_t const * attr_framed_ip_address
Definition rlm_unix.c:59
static fr_dict_attr_t const * attr_framed_protocol
Definition rlm_unix.c:60
static fr_dict_attr_t const * attr_nas_port
Definition rlm_unix.c:62
static fr_dict_attr_t const * attr_acct_status_type
Definition rlm_unix.c:63
static fr_dict_attr_t const * attr_user_name
Definition rlm_unix.c:57
static fr_dict_attr_t const * attr_acct_delay_time
Definition rlm_unix.c:64
fr_dict_autoload_t rlm_unix_dict[]
Definition rlm_unix.c:49
module_rlm_t rlm_unix
Definition rlm_unix.c:334
fr_dict_attr_autoload_t rlm_unix_dict_attr[]
Definition rlm_unix.c:68
#define SECTION_NAME(_name1, _name2)
Define a section name consisting of a verb and a noun.
Definition section.h:39
@ MODULE_TYPE_THREAD_UNSAFE
Module is not threadsafe.
Definition module.h:49
module_flags_t flags
Flags that control how a module starts up and how a module is called.
Definition module.h:236
void * boot
Data allocated during the boostrap phase.
Definition module.h:296
#define MODULE_BINDING_TERMINATOR
Terminate a module binding list.
Definition module.h:152
Named methods exported by a module.
Definition module.h:174
#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:36
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:155
#define XLAT_ARG_PARSER_TERMINATOR
Definition xlat.h:170
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 consumed by an xlat function.
Definition xlat.h:145
#define fr_value_box_alloc(_ctx, _type, _enumv)
Allocate a value box of a specific type.
Definition value.h:644
int nonnull(2, 5))
static size_t char ** out
Definition value.h:1030
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