The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
profile.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: a0aa62a9d9ff4df8f234f01affe51e6602dff675 $
19 * @file rlm_ldap.c
20 * @brief LDAP authorization and authentication module.
21 *
22 * @author Arran Cudbard-Bell (a.cudbardb@freeradius.org)
23 * @author Alan DeKok (aland@freeradius.org)
24 *
25 * @copyright 2012,2015 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
26 * @copyright 2013,2015 Network RADIUS SAS (legal@networkradius.com)
27 * @copyright 2012 Alan DeKok (aland@freeradius.org)
28 * @copyright 1999-2013 The FreeRADIUS Server Project.
29 */
30RCSID("$Id: a0aa62a9d9ff4df8f234f01affe51e6602dff675 $")
31
33
34#include "rlm_ldap.h"
35#include <freeradius-devel/ldap/conf.h>
36
37#include <freeradius-devel/server/map_proc.h>
38#include <freeradius-devel/server/module_rlm.h>
39
40/** Holds state of in progress async profile lookups
41 *
42 */
43typedef struct {
44 fr_ldap_result_code_t *ret; //!< Result of the query and applying the map.
45 int *applied; //!< Number of profiles applied.
47 char const *dn;
51
52/** Process the results of a profile lookup
53 *
54 */
56{
57 ldap_profile_ctx_t *profile_ctx = talloc_get_type_abort(uctx, ldap_profile_ctx_t);
58 fr_ldap_query_t *query = profile_ctx->query;
59 LDAP *handle;
60 LDAPMessage *entry = NULL;
61 int ldap_errno;
62 char *dn = NULL;
63 int ret;
64 bool fallthrough;
65
66 /*
67 * Tell the caller what happened
68 */
69 if (profile_ctx->ret) *profile_ctx->ret = query->ret;
70
71 switch (query->ret) {
73 break;
74
77 RDEBUG2("Profile object \"%s\" not found", profile_ctx->dn);
78 goto finish;
79
80 default:
81 goto finish;
82 }
83
84 fr_assert(query->result);
85 handle = query->ldap_conn->handle;
86
87 entry = ldap_first_entry(handle, query->result);
88 if (!entry) {
89 ldap_get_option(handle, LDAP_OPT_RESULT_CODE, &ldap_errno);
90 REDEBUG("Failed retrieving entry: %s", ldap_err2string(ldap_errno));
91 if (profile_ctx->ret) *profile_ctx->ret = LDAP_RESULT_NO_RESULT;
92 goto finish;
93 }
94
95 RDEBUG2("Processing profile attributes");
96 RINDENT();
97 while (entry) {
98 if (RDEBUG_ENABLED2) {
99 dn = ldap_get_dn(handle, entry);
100 RDEBUG2("Processing \"%s\"", dn);
101 ldap_memfree(dn);
102 }
103
104 // Set fallthrough to the configured default
105 fallthrough = profile_ctx->inst->profile.fallthrough_def;
106
107 RINDENT();
108 ret = fr_ldap_map_do(request, profile_ctx->inst->profile.check_attr, profile_ctx->inst->valuepair_attr,
109 profile_ctx->expanded, entry);
110 if (ret < 0) {
111 if (profile_ctx->ret) *profile_ctx->ret = LDAP_RESULT_ERROR;
112 } else {
113 if (profile_ctx->applied) *profile_ctx->applied += ret;
114 }
115
116 if (profile_ctx->inst->profile.fallthrough_attr) {
117 struct berval **values;
118 int count;
119 char *value;
120 xlat_exp_head_t *cond_expr = NULL;
121 fr_value_box_list_t res;
122
123 tmpl_rules_t const parse_rules = {
124 .attr = {
125 .dict_def = request->proto_dict,
126 .list_def = request_attr_request,
127 },
128 .xlat = {
129 .runtime_el = unlang_interpret_event_list(request),
130 },
131 .at_runtime = true,
132 };
133
134 values = ldap_get_values_len(handle, entry, profile_ctx->inst->profile.fallthrough_attr);
135 count = ldap_count_values_len(values);
136 if (count == 0) goto free_values;
137 if (count > 1) {
138 RWARN("%s returned more than 1 value. Only evaluating the first.",
139 profile_ctx->inst->profile.fallthrough_attr);
140 }
141 value = fr_ldap_berval_to_string(request, values[0]);
142
143 RDEBUG3("Parsing fallthrough condition %s", value);
144 if (xlat_tokenize_expression(request, &cond_expr,
145 &FR_SBUFF_IN(value, talloc_array_length(value) - 1),
146 NULL, &parse_rules) < 0) {
147 RPEDEBUG("Failed parsing '%s' value \"%s\"", profile_ctx->inst->profile.fallthrough_attr, value);
148 goto free;
149 }
150
151 if (xlat_impure_func(cond_expr)) {
152 fr_strerror_const("Fallthrough expression cannot depend on functions which call external databases");
153 goto free;
154 }
155
156 RDEBUG2("Checking fallthrough condition %s", value);
157 fr_value_box_list_init(&res);
158 if (unlang_xlat_eval(request, &res, request, cond_expr) < 0) {
159 RPEDEBUG("Failed evaluating condition");
160 goto free;
161 }
162 fallthrough = (fr_value_box_list_head(&res) && fr_value_box_is_truthy(fr_value_box_list_head(&res))) ? true : false;
163 fr_value_box_list_talloc_free(&res);
164 RDEBUG2("Fallthrough condition evaluated to %s", fallthrough ? "true" : "false");
165 free:
167 talloc_free(cond_expr);
168 free_values:
169 ldap_value_free_len(values);
170 }
171
172 entry = ldap_next_entry(handle, entry);
173 REXDENT();
174 if (!fallthrough) break;
175 }
176 REXDENT();
177
178finish:
179 talloc_free(profile_ctx);
181}
182
183/** Cancel an in progress profile lookup
184 *
185 */
186static void ldap_map_profile_cancel(UNUSED request_t *request, UNUSED fr_signal_t action, void *uctx)
187{
188 ldap_profile_ctx_t *profile_ctx = talloc_get_type_abort(uctx, ldap_profile_ctx_t);
189
190 if (!profile_ctx->query || !profile_ctx->query->treq) return;
191
193}
194
195/** Search for and apply an LDAP profile
196 *
197 * LDAP profiles are mapped using the same attribute map as user objects, they're used to add common
198 * sets of attributes to the request.
199 *
200 * @param[out] ret Where to write the result of the query.
201 * @param[out] applied Where to write the number of profiles applied.
202 * @param[in] inst LDAP module instance.
203 * @param[in] request Current request.
204 * @param[in] ttrunk Trunk connection on which to run LDAP queries.
205 * @param[in] dn of profile object to apply.
206 * @param[in] scope to apply when looking up profiles.
207 * @param[in] filter to apply when looking up profiles.
208 * @param[in] expanded Structure containing a list of xlat
209 * expanded attribute names and mapping information.
210 * @return One of the RLM_MODULE_* values.
211 */
213 rlm_ldap_t const *inst, request_t *request, fr_ldap_thread_trunk_t *ttrunk,
214 char const *dn, int scope, char const *filter, fr_ldap_map_exp_t const *expanded)
215{
216 ldap_profile_ctx_t *profile_ctx;
217 LDAPControl *serverctrls[] = { inst->profile.obj_sort_ctrl, NULL };
218
219 if (!dn || !*dn) return UNLANG_ACTION_CALCULATE_RESULT;
220
221 MEM(profile_ctx = talloc(unlang_interpret_frame_talloc_ctx(request), ldap_profile_ctx_t));
222 *profile_ctx = (ldap_profile_ctx_t) {
223 .ret = ret,
224 .applied = applied,
225 .dn = dn,
226 .expanded = expanded,
227 .inst = inst
228 };
229 if (ret) *ret = LDAP_RESULT_ERROR;
230
231 if (unlang_function_push(request,
232 NULL,
236 profile_ctx) < 0) {
237 talloc_free(profile_ctx);
238 return UNLANG_ACTION_FAIL;
239 }
240
241 return fr_ldap_trunk_search(profile_ctx, &profile_ctx->query, request, ttrunk, dn,
242 scope, filter,
243 expanded->attrs, serverctrls, NULL);
244}
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
Definition action.h:35
@ UNLANG_ACTION_FAIL
Encountered an unexpected error.
Definition action.h:36
@ UNLANG_ACTION_CALCULATE_RESULT
Calculate a new section rlm_rcode_t value.
Definition action.h:37
#define USES_APPLE_DEPRECATED_API
Definition build.h:472
#define RCSID(id)
Definition build.h:485
#define UNUSED
Definition build.h:317
#define MEM(x)
Definition debug.h:36
Test enumeration values.
Definition dict_test.h:92
#define unlang_function_push(_request, _func, _repeat, _signal, _sigmask, _top_frame, _uctx)
Push a generic function onto the unlang stack.
Definition function.h:179
free(array)
TALLOC_CTX * unlang_interpret_frame_talloc_ctx(request_t *request)
Get a talloc_ctx which is valid only for this frame.
Definition interpret.c:1661
fr_event_list_t * unlang_interpret_event_list(request_t *request)
Get the event list for the current interpreter.
Definition interpret.c:2013
#define UNLANG_SUB_FRAME
Definition interpret.h:37
int fr_ldap_map_do(request_t *request, char const *check_attr, char const *valuepair_attr, fr_ldap_map_exp_t const *expanded, LDAPMessage *entry)
Convert attribute map into valuepairs.
Definition map.c:335
LDAP * handle
libldap handle.
Definition base.h:333
fr_ldap_result_code_t ret
Result code.
Definition base.h:470
trunk_request_t * treq
Trunk request this query is associated with.
Definition base.h:456
char * fr_ldap_berval_to_string(TALLOC_CTX *ctx, struct berval const *in)
Convert a berval to a talloced string.
Definition util.c:443
fr_ldap_connection_t * ldap_conn
LDAP connection this query is running on.
Definition base.h:457
fr_ldap_result_code_t
LDAP query result codes.
Definition base.h:188
@ LDAP_RESULT_ERROR
A general error occurred.
Definition base.h:191
@ LDAP_RESULT_SUCCESS
Successfully got LDAP results.
Definition base.h:190
@ LDAP_RESULT_NO_RESULT
No results returned.
Definition base.h:194
@ LDAP_RESULT_BAD_DN
The requested DN does not exist.
Definition base.h:193
LDAPMessage * result
Head of LDAP results list.
Definition base.h:468
char const * attrs[LDAP_MAX_ATTRMAP+LDAP_MAP_RESERVED+1]
Reserve some space for access attributes.
Definition base.h:372
Result of expanding the RHS of a set of maps.
Definition base.h:370
LDAP query structure.
Definition base.h:422
Thread LDAP trunk structure.
Definition base.h:399
unlang_action_t fr_ldap_trunk_search(TALLOC_CTX *ctx, fr_ldap_query_t **out, request_t *request, fr_ldap_thread_trunk_t *ttrunk, char const *base_dn, int scope, char const *filter, char const *const *attrs, LDAPControl **serverctrls, LDAPControl **clientctrls)
Run an async search LDAP query on a trunk connection.
Definition base.c:720
#define REXDENT()
Exdent (unindent) R* messages by one level.
Definition log.h:443
#define RDEBUG3(fmt,...)
Definition log.h:343
#define RWARN(fmt,...)
Definition log.h:297
#define RPEDEBUG(fmt,...)
Definition log.h:376
#define RINDENT()
Indent R* messages by one level.
Definition log.h:430
talloc_free(reap)
int * applied
Number of profiles applied.
Definition profile.c:45
unlang_action_t rlm_ldap_map_profile(fr_ldap_result_code_t *ret, int *applied, rlm_ldap_t const *inst, request_t *request, fr_ldap_thread_trunk_t *ttrunk, char const *dn, int scope, char const *filter, fr_ldap_map_exp_t const *expanded)
Search for and apply an LDAP profile.
Definition profile.c:212
static void ldap_map_profile_cancel(UNUSED request_t *request, UNUSED fr_signal_t action, void *uctx)
Cancel an in progress profile lookup.
Definition profile.c:186
fr_ldap_result_code_t * ret
Result of the query and applying the map.
Definition profile.c:44
rlm_ldap_t const * inst
Definition profile.c:48
char const * dn
Definition profile.c:47
fr_ldap_map_exp_t const * expanded
Definition profile.c:49
fr_ldap_query_t * query
Definition profile.c:46
static unlang_action_t ldap_map_profile_resume(request_t *request, void *uctx)
Process the results of a profile lookup.
Definition profile.c:55
Holds state of in progress async profile lookups.
Definition profile.c:43
#define fr_assert(_expr)
Definition rad_assert.h:38
#define REDEBUG(fmt,...)
Definition radclient.h:52
#define RDEBUG_ENABLED2()
Definition radclient.h:50
#define RDEBUG2(fmt,...)
Definition radclient.h:54
fr_dict_attr_t const * request_attr_request
Definition request.c:43
char const * valuepair_attr
Generic dynamic mapping attribute, contains a RADIUS attribute and value.
Definition rlm_ldap.h:93
struct rlm_ldap_t::@175 profile
#define FR_SBUFF_IN(_start, _len_or_end)
tmpl_attr_rules_t attr
Rules/data for parsing attribute references.
Definition tmpl.h:335
Optional arguments passed to vp_tmpl functions.
Definition tmpl.h:332
fr_signal_t
Signals that can be generated/processed by request signal handlers.
Definition signal.h:38
@ FR_SIGNAL_CANCEL
Request has been cancelled.
Definition signal.h:40
return count
Definition module.c:155
eap_aka_sim_process_conf_t * inst
fr_dict_t const * dict_def
Default dictionary to use with unqualified attribute references.
Definition tmpl.h:273
void trunk_request_signal_cancel(trunk_request_t *treq)
Cancel a trunk request.
Definition trunk.c:2151
int unlang_xlat_eval(TALLOC_CTX *ctx, fr_value_box_list_t *out, request_t *request, xlat_exp_head_t const *xlat)
Evaluate a "pure" (or not impure) xlat.
Definition xlat.c:728
bool xlat_impure_func(xlat_exp_head_t const *head)
fr_slen_t xlat_tokenize_expression(TALLOC_CTX *ctx, xlat_exp_head_t **head, fr_sbuff_t *in, fr_sbuff_parse_rules_t const *p_rules, tmpl_rules_t const *t_rules))
Definition xlat_expr.c:3124
#define fr_strerror_const(_msg)
Definition strerror.h:223
bool fr_value_box_is_truthy(fr_value_box_t const *in)
Check truthiness of values.
Definition value.c:6587