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: d1cc1b6c0b534884d13c5976fef7ddd0d7fe27f3 $
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: d1cc1b6c0b534884d13c5976fef7ddd0d7fe27f3 $")
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/perm.h>
35#include <freeradius-devel/unlang/xlat_func.h>
36
37#include <grp.h>
38#include <pwd.h>
39#include <sys/stat.h>
40
41#include "config.h"
42
43#ifdef HAVE_SHADOW_H
44# include <shadow.h>
45#endif
46
48static fr_dict_t const *dict_radius;
49
52 { .out = &dict_freeradius, .proto = "freeradius" },
53 { .out = &dict_radius, .proto = "radius" },
54 { NULL }
55};
56
68
71 { .out = &attr_auth_type, .name = "Auth-Type", .type = FR_TYPE_UINT32, .dict = &dict_freeradius },
72 { .out = &attr_crypt_password, .name = "Password.Crypt", .type = FR_TYPE_STRING, .dict = &dict_freeradius },
73 { .out = &attr_user_name, .name = "User-Name", .type = FR_TYPE_STRING, .dict = &dict_radius },
74 { .out = &attr_login_ip_host, .name = "Login-IP-Host", .type = FR_TYPE_IPV4_ADDR, .dict = &dict_radius },
75 { .out = &attr_framed_ip_address, .name = "Framed-IP-Address", .type = FR_TYPE_IPV4_ADDR, .dict = &dict_radius },
76 { .out = &attr_framed_protocol, .name = "Framed-Protocol", .type = FR_TYPE_UINT32, .dict = &dict_radius },
77 { .out = &attr_nas_ip_address, .name = "NAS-IP-Address", .type = FR_TYPE_IPV4_ADDR, .dict = &dict_radius },
78 { .out = &attr_nas_port, .name = "NAS-Port", .type = FR_TYPE_UINT32, .dict = &dict_radius },
79 { .out = &attr_acct_status_type, .name = "Acct-Status-Type", .type = FR_TYPE_UINT32, .dict = &dict_radius },
80 { .out = &attr_acct_delay_time, .name = "Acct-Delay-Time", .type = FR_TYPE_UINT32, .dict = &dict_radius },
81 { .out = &attr_expr_bool_enum, .name = "Expr-Bool-Enum", .type = FR_TYPE_BOOL, .dict = &dict_freeradius },
82 { NULL }
83};
84
85/** Check if the user is in the given group
86 *
87 */
88static bool CC_HINT(nonnull) unix_check_group(request_t *request, char const *name)
89{
90 bool rcode = false;
91 struct passwd *pwd;
92 struct group *grp;
94
95 /*
96 * No user name, can't compare.
97 */
98 username = fr_pair_find_by_da(&request->request_pairs, NULL, attr_user_name);
99 if (!username) return false;
100
101 if (fr_perm_getpwnam(request, &pwd, username->vp_strvalue) < 0) {
102 RPEDEBUG("Failed resolving user name");
103 return false;
104 }
105
106 if (fr_perm_getgrnam(request, &grp, name) < 0) {
107 RPEDEBUG("Failed resolving group name");
108 talloc_free(pwd);
109 return false;
110 }
111
112 /*
113 * The users default group may be the one we're looking
114 * for, in which case we use that.
115 *
116 * Otherwise, we go through the list of groups to see if the group name matches.
117 */
118 if (pwd->pw_gid == grp->gr_gid) {
119 rcode = true;
120
121 } else {
122 char **member;
123
124 for (member = grp->gr_mem; *member; member++) {
125 if (strcmp(*member, pwd->pw_name) == 0) {
126 rcode = true;
127 break;
128 }
129 }
130 }
131
132 /* lifo */
133 talloc_free(grp);
134 talloc_free(pwd);
135
136 return rcode;
137}
138
139
140/** Check if the user is a member of a particular unix group
141 *
142@verbatim
143%unix.group(<name>)
144@endverbatim
145 *
146 * @ingroup xlat_functions
147 */
149 UNUSED xlat_ctx_t const *xctx,
150 request_t *request, fr_value_box_list_t *in)
151{
152 fr_value_box_t *arg = fr_value_box_list_head(in);
153 char const *p = arg->vb_strvalue;
154 fr_value_box_t *vb;
155
157
159 vb->vb_bool = unix_check_group(request, p);
161
162 return XLAT_ACTION_DONE;
163}
164
165
166/*
167 * Read the config
168 */
169static int mod_bootstrap(module_inst_ctx_t const *mctx)
170{
171 xlat_t *xlat;
172 xlat_arg_parser_t *xlat_arg;
173
174 /*
175 * Define the new %unix.group(name) xlat. The register
176 * function automatically adds the module instance name
177 * as a prefix.
178 */
179 xlat = module_rlm_xlat_register(mctx->mi->boot, mctx, "group", unix_group_xlat, FR_TYPE_BOOL);
180 if (!xlat) {
181 PERROR("Failed registering group expansion");
182 return -1;
183 }
184
185 /*
186 * The xlat escape function needs access to inst - so
187 * argument parser details need to be defined here
188 */
189 xlat_arg = talloc_zero_array(xlat, xlat_arg_parser_t, 2);
190 xlat_arg[0] = (xlat_arg_parser_t) {
192 .required = true,
193 .concat = true
194 };
196
197 xlat_func_args_set(xlat, xlat_arg);
198
199 return 0;
200}
201
202
203/*
204 * Pull the users password from where-ever, and add it to
205 * the given vp list.
206 */
207static unlang_action_t CC_HINT(nonnull) mod_authorize(rlm_rcode_t *p_result, UNUSED module_ctx_t const *mctx, request_t *request)
208{
209 char const *name;
210 char const *encrypted_pass;
211#ifdef HAVE_GETSPNAM
212 struct spwd *spwd = NULL;
213#endif
214 struct passwd *pwd;
215#ifdef HAVE_GETUSERSHELL
216 char *shell;
217#endif
218 fr_pair_t *vp;
220
221 /*
222 * We can only authenticate user requests which HAVE
223 * a User-Name attribute.
224 */
225 username = fr_pair_find_by_da(&request->request_pairs, NULL, attr_user_name);
227
228 name = username->vp_strvalue;
229 encrypted_pass = NULL;
230
231 if ((pwd = getpwnam(name)) == NULL) {
233 }
234 encrypted_pass = pwd->pw_passwd;
235
236#ifdef HAVE_GETSPNAM
237 /*
238 * See if there is a shadow password.
239 *
240 * Only query the _system_ shadow file if the encrypted
241 * password from the passwd file is < 10 characters (i.e.
242 * a valid password would never crypt() to it). This will
243 * prevents users from using NULL password fields as things
244 * stand right now.
245 */
246 if ((!encrypted_pass) || (strlen(encrypted_pass) < 10)) {
247 if ((spwd = getspnam(name)) == NULL) {
249 }
250 encrypted_pass = spwd->sp_pwdp;
251 }
252#endif /* HAVE_GETSPNAM */
253
254#ifdef DENY_SHELL
255 /*
256 * Users with a particular shell are denied access
257 */
258 if (strcmp(pwd->pw_shell, DENY_SHELL) == 0) {
259 REDEBUG("Invalid shell", name);
261 }
262#endif
263
264#ifdef HAVE_GETUSERSHELL
265 /*
266 * Check /etc/shells for a valid shell. If that file
267 * contains /RADIUSD/ANY/SHELL then any shell will do.
268 */
269 while ((shell = getusershell()) != NULL) {
270 if (strcmp(shell, pwd->pw_shell) == 0 ||
271 strcmp(shell, "/RADIUSD/ANY/SHELL") == 0) {
272 break;
273 }
274 }
275 endusershell();
276 if (!shell) {
277 REDEBUG("[%s]: invalid shell [%s]", name, pwd->pw_shell);
279 }
280#endif
281
282#if defined(HAVE_GETSPNAM) && !defined(M_UNIX)
283 /*
284 * Check if password has expired.
285 */
286 if (spwd && spwd->sp_lstchg > 0 && spwd->sp_max >= 0 &&
287 (fr_time_to_sec(request->packet->timestamp) / 86400) > (spwd->sp_lstchg + spwd->sp_max)) {
288 REDEBUG("[%s]: password has expired", name);
290 }
291 /*
292 * Check if account has expired.
293 */
294 if (spwd && spwd->sp_expire > 0 &&
295 (fr_time_to_sec(request->packet->timestamp) / 86400) > spwd->sp_expire) {
296 REDEBUG("[%s]: account has expired", name);
298 }
299#endif
300
301#if defined(__FreeBSD__) || defined(bsdi) || defined(_PWF_EXPIRE)
302 /*
303 * Check if password has expired.
304 */
305 if ((pwd->pw_expire > 0) &&
306 (fr_time_to_sec(request->packet->timestamp) > pwd->pw_expire)) {
307 REDEBUG("[%s]: password has expired", name);
309 }
310#endif
311
312 /*
313 * We might have a passwordless account.
314 *
315 * FIXME: Maybe add Auth-Type := Accept?
316 */
317 if (encrypted_pass[0] == 0)
319
321 fr_pair_value_strdup(vp, encrypted_pass, false);
322
324}
325
326
327/* globally exported name */
330 .common = {
331 .magic = MODULE_MAGIC_INIT,
332 .name = "unix",
334 .bootstrap = mod_bootstrap
335 },
336 .method_group = {
337 .bindings = (module_method_binding_t[]){
338 { .section = SECTION_NAME("recv", "Access-Request"), .method = mod_authorize },
340 }
341 }
342};
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:470
#define RCSID(id)
Definition build.h:483
#define UNUSED
Definition build.h:315
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: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
static fr_slen_t in
Definition dict.h:823
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
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:148
#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.
#define fr_skip_whitespace(_p)
Skip whitespace ('\t', '\n', '\v', '\f', '\r', ' ')
Definition misc.h:59
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:257
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:2634
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
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:55
#define RETURN_MODULE_NOOP
Definition rcode.h:62
#define RETURN_MODULE_UPDATED
Definition rcode.h:63
rlm_rcode_t
Return codes indicating the result of the module call.
Definition rcode.h:40
#define RETURN_MODULE_NOTFOUND
Definition rcode.h:61
static char const * name
username
static fr_dict_attr_t const * attr_login_ip_host
Definition rlm_unix.c:60
static bool unix_check_group(request_t *request, char const *name)
Check if the user is in the given group.
Definition rlm_unix.c:88
static fr_dict_attr_t const * attr_crypt_password
Definition rlm_unix.c:58
static fr_dict_t const * dict_freeradius
Definition rlm_unix.c:47
static fr_dict_attr_t const * attr_expr_bool_enum
Definition rlm_unix.c:67
static fr_dict_t const * dict_radius
Definition rlm_unix.c:48
static int mod_bootstrap(module_inst_ctx_t const *mctx)
Definition rlm_unix.c:169
static fr_dict_attr_t const * attr_auth_type
Definition rlm_unix.c:57
static fr_dict_attr_t const * attr_nas_ip_address
Definition rlm_unix.c:63
static fr_dict_attr_t const * attr_framed_ip_address
Definition rlm_unix.c:61
static fr_dict_attr_t const * attr_framed_protocol
Definition rlm_unix.c:62
static fr_dict_attr_t const * attr_nas_port
Definition rlm_unix.c:64
static fr_dict_attr_t const * attr_acct_status_type
Definition rlm_unix.c:65
static fr_dict_attr_t const * attr_user_name
Definition rlm_unix.c:59
static fr_dict_attr_t const * attr_acct_delay_time
Definition rlm_unix.c:66
fr_dict_autoload_t rlm_unix_dict[]
Definition rlm_unix.c:51
module_rlm_t rlm_unix
Definition rlm_unix.c:329
static unlang_action_t mod_authorize(rlm_rcode_t *p_result, UNUSED module_ctx_t const *mctx, request_t *request)
Definition rlm_unix.c:207
fr_dict_attr_autoload_t rlm_unix_dict_attr[]
Definition rlm_unix.c:70
#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 * boot
Data allocated during the boostrap phase.
Definition module.h:274
#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
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:168
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:147
#define fr_value_box_alloc(_ctx, _type, _enumv)
Allocate a value box of a specific type.
Definition value.h:621
int nonnull(2, 5))
static size_t char ** out
Definition value.h:997
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:365