The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
control.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: b8d3d4188a5ab477d12609ecdcaa1a4c6ce69acd $
19 * @file lib/ldap/control.c
20 * @brief Functions for managing server/client side sort controls.
21 *
22 * @author Arran Cudbard-Bell (a.cudbardb@freeradius.org)
23 * @copyright 2015 Arran Cudbard-Bell (a.cudbardb@freeradius.org)
24 */
25RCSID("$Id: b8d3d4188a5ab477d12609ecdcaa1a4c6ce69acd $")
26
28
29#include <freeradius-devel/ldap/base.h>
30#ifdef LDAP_CONTROL_X_SESSION_TRACKING
31#include <freeradius-devel/radius/radius.h>
32#endif
33
34/** Merge connection and call specific client and server controls
35 *
36 * LDAP_OPT_CLIENT_CONTROLS and LDAP_OPT_SERVER_CONTROLS are useless
37 * because they're overridden in their entirety if any call specific
38 * controls are specified.
39 *
40 * @param[out] serverctrls_out Where to write serverctrls.
41 * @param[out] clientctrls_out Where to write clientctrls.
42 * @param[in] serverctrls_len length of serverctrls array.
43 * @param[in] clientctrls_len length of clientctrls array.
44 * @param[in] conn to get controls from.
45 * @param[in] serverctrls_in from arguments.
46 * @param[in] clientctrls_in from_arguments.
47 */
48 void fr_ldap_control_merge(LDAPControl *serverctrls_out[],
49 LDAPControl *clientctrls_out[],
50 size_t serverctrls_len,
51 size_t clientctrls_len,
53 LDAPControl *serverctrls_in[],
54 LDAPControl *clientctrls_in[])
55{
56 size_t i, num_serverctrls = 0, num_clientctrls = 0;
57
58 if (serverctrls_in) {
59 for (i = 0; serverctrls_in[i] && (num_serverctrls < LDAP_MAX_CONTROLS); i++) {
60 serverctrls_out[num_serverctrls++] = serverctrls_in[i];
61 }
62 }
63
64 if (clientctrls_in) {
65 for (i = 0; clientctrls_in[i] && (num_clientctrls < LDAP_MAX_CONTROLS); i++) {
66 clientctrls_out[num_clientctrls++] = clientctrls_in[i];
67 }
68 }
69
70 for (i = 0; (i < (size_t)conn->serverctrls_cnt) && (num_serverctrls < serverctrls_len); i++) {
71 serverctrls_out[num_serverctrls++] = conn->serverctrls[i].control;
72 }
73
74 for (i = 0; (i < (size_t)conn->clientctrls_cnt) && (num_clientctrls < clientctrls_len); i++) {
75 clientctrls_out[num_clientctrls++] = conn->clientctrls[i].control;
76 }
77
78 serverctrls_out[num_serverctrls] = NULL;
79 clientctrls_out[num_clientctrls] = NULL;
80}
81
82/** Add a serverctrl to a connection handle
83 *
84 * All internal LDAP functions will pass this serverctrl to the server.
85 *
86 * @param conn to add control to.
87 * @param ctrl to add.
88 * @param freeit Whether the control should be freed when the handle is released or closed.
89 * @return
90 * - 0 on success.
91 * - -1 on failure (exceeded maximum controls).
92 */
93int fr_ldap_control_add_server(fr_ldap_connection_t *conn, LDAPControl *ctrl, bool freeit)
94{
95 if ((size_t)conn->serverctrls_cnt >= ((NUM_ELEMENTS(conn->serverctrls)) - 1)) {
96 return -1;
97 }
98
99 conn->serverctrls[conn->serverctrls_cnt].control = ctrl;
100 conn->serverctrls[conn->serverctrls_cnt].freeit = freeit;
101 conn->serverctrls_cnt++;
102
103 return 0;
104}
105
106/** Add a clientctrl to a connection handle
107 *
108 * All internal LDAP functions will pass this clientctrl to libldap.
109 *
110 * @param conn to add control to.
111 * @param ctrl to add.
112 * @param freeit Whether the control should be freed when the handle is released or closed.
113 * @return
114 * - 0 on success.
115 * - -1 on failure (exceeded maximum controls).
116 */
117int fr_ldap_control_add_client(fr_ldap_connection_t *conn, LDAPControl *ctrl, bool freeit)
118{
119 if ((size_t)conn->clientctrls_cnt >= ((NUM_ELEMENTS(conn->clientctrls)) - 1)) {
120 return -1;
121 }
122
123 conn->clientctrls[conn->clientctrls_cnt].control = ctrl;
124 conn->clientctrls[conn->clientctrls_cnt].freeit = freeit;
125 conn->clientctrls_cnt++;
126
127 return 0;
128}
129
130/** Clear and free any controls associated with a connection
131 *
132 * @param conn to clear controls from.
133 */
135{
136 int i;
137
138 for (i = 0; i < conn->serverctrls_cnt; i++) {
139 if (conn->serverctrls[i].freeit) ldap_control_free(conn->serverctrls[i].control);
140 conn->serverctrls[i].freeit = false;
141 conn->serverctrls[i].control = NULL;
142 }
143 conn->serverctrls_cnt = 0;
144
145 for (i = 0; i < conn->clientctrls_cnt; i++) {
146 if (conn->clientctrls[i].freeit) ldap_control_free(conn->clientctrls[i].control);
147 conn->clientctrls[i].freeit = false;
148 conn->clientctrls[i].control = NULL;
149 }
150 conn->clientctrls_cnt = 0;
151}
152
153#ifdef LDAP_CONTROL_X_SESSION_TRACKING
154/** Add session controls to a connection as per draft-wahl-ldap-session
155 *
156 * @note the RFC states that the username identifier, must be the authenticated
157 * user id, not the purported one. As order of operations is configurable,
158 * we're going to leave that up to the server admin to satisfy that
159 * requirement
160 *
161 * For once the RFC is pretty helpful about what should be inserted into the
162 * various values, and maps out RADIUS attributes to formatOIDs, so none of
163 * this is configurable.
164 *
165 * @param conn to add controls to.
166 * @param request to draw attributes from.
167 */
169{
170 /*
171 * The OpenLDAP guys didn't declare the formatOID parameter to
172 * ldap_create_session_tracking_control as const *sigh*.
173 */
174 static char username_oid[] = LDAP_CONTROL_X_SESSION_TRACKING_USERNAME;
175 static char acctsessionid_oid[] = LDAP_CONTROL_X_SESSION_TRACKING_RADIUS_ACCT_SESSION_ID;
176 static char acctmultisessionid_oid[] = LDAP_CONTROL_X_SESSION_TRACKING_RADIUS_ACCT_MULTI_SESSION_ID;
177
178 int ret;
179
180 char ipaddress[INET6_ADDRSTRLEN];
181 char *username = NULL;
182 char *acctsessionid = NULL;
183 char *acctmultisessionid = NULL;
184 char *hostname;
185
186 LDAPControl *username_control = NULL;
187 LDAPControl *acctsessionid_control = NULL;
188 LDAPControl *acctmultisessionid_control = NULL;
189 struct berval tracking_id;
190
191 fr_pair_t const *vp;
192
193 memcpy(&hostname, main_config->name, sizeof(hostname)); /* const / non-const issues */
194
195 /*
196 * @todo - MULTI_PROTOCOL - switch to auto-loaded dictionaries.
197 */
198 for (vp = fr_pair_list_head(&request->request_pairs);
199 vp;
200 vp = fr_pair_list_next(&request->request_pairs, vp)) {
201 if (fr_dict_attr_is_top_level(vp->da)) switch (vp->da->attr) {
202 case FR_NAS_IP_ADDRESS:
203 case FR_NAS_IPV6_ADDRESS:
204 fr_pair_print_value_quoted(&FR_SBUFF_OUT(ipaddress, sizeof(ipaddress)), vp, T_BARE_WORD);
205 break;
206
207 case FR_USER_NAME:
208 memcpy(&username, &vp->vp_strvalue, sizeof(username));
209 break;
210
211 case FR_ACCT_SESSION_ID:
212 memcpy(&acctsessionid, &vp->vp_strvalue, sizeof(acctsessionid));
213 break;
214
215 case FR_ACCT_MULTI_SESSION_ID:
216 memcpy(&acctmultisessionid, &vp->vp_strvalue, sizeof(acctmultisessionid));
217 break;
218 }
219 }
220
221 if (username) {
222 tracking_id.bv_val = username;
223 tracking_id.bv_len = talloc_array_length(username) - 1;
224
225 ret = ldap_create_session_tracking_control(conn->handle, ipaddress,
226 hostname,
227 username_oid,
228 &tracking_id,
229 &username_control);
230 if (ret != LDAP_SUCCESS) {
231 REDEBUG("Failed creating username session tracking control: %s", ldap_err2string(ret));
232 error:
233 if (username_control) ldap_control_free(username_control);
234 if (acctsessionid_control) ldap_control_free(acctsessionid_control);
235 if (acctmultisessionid_control) ldap_control_free(acctmultisessionid_control);
236 return -1;
237 }
238 }
239
240 if (acctsessionid) {
241 tracking_id.bv_val = acctsessionid;
242 tracking_id.bv_len = talloc_array_length(acctsessionid) - 1;
243
244 ret = ldap_create_session_tracking_control(conn->handle, ipaddress,
245 hostname,
246 acctsessionid_oid,
247 &tracking_id,
248 &acctsessionid_control);
249 if (ret != LDAP_SUCCESS) {
250 REDEBUG("Failed creating acctsessionid session tracking control: %s", ldap_err2string(ret));
251 goto error;
252 }
253 }
254
255 if (acctmultisessionid) {
256 tracking_id.bv_val = acctmultisessionid;
257 tracking_id.bv_len = talloc_array_length(acctmultisessionid) - 1;
258
259 ret = ldap_create_session_tracking_control(conn->handle, ipaddress,
260 hostname,
261 acctmultisessionid_oid,
262 &tracking_id,
263 &acctmultisessionid_control);
264 if (ret != LDAP_SUCCESS) {
265 REDEBUG("Failed creating acctmultisessionid session tracking control: %s",
266 ldap_err2string(ret));
267 goto error;
268 }
269 }
270
271 if ((conn->serverctrls_cnt + 3) >= LDAP_MAX_CONTROLS) {
272 REDEBUG("Insufficient space to add session tracking controls");
273 goto error;
274 }
275
276 if (username_control && (fr_ldap_control_add_server(conn, username_control, true) < 0)) goto error;
277
278 if (acctsessionid_control && (fr_ldap_control_add_server(conn, acctsessionid_control, true) < 0)) {
279 conn->serverctrls_cnt--;
280 conn->serverctrls[conn->serverctrls_cnt].control = NULL;
281 goto error;
282 }
283
284 if (acctmultisessionid_control && (fr_ldap_control_add_server(conn, acctmultisessionid_control, true) < 0)) {
285 conn->serverctrls_cnt--;
286 conn->serverctrls[conn->serverctrls_cnt].control = NULL;
287 conn->serverctrls_cnt--;
288 conn->serverctrls[conn->serverctrls_cnt].control = NULL;
289 goto error;
290 }
291
292 return 0;
293}
294#endif
295
296
#define USES_APPLE_DEPRECATED_API
Definition build.h:470
#define RCSID(id)
Definition build.h:483
#define NUM_ELEMENTS(_t)
Definition build.h:337
static bool fr_dict_attr_is_top_level(fr_dict_attr_t const *da)
Return true if this attribute is parented directly off the dictionary root.
Definition dict.h:757
int fr_ldap_control_add_session_tracking(fr_ldap_connection_t *conn, request_t *request)
LDAP * handle
libldap handle.
Definition base.h:333
int serverctrls_cnt
Number of server controls associated with the handle.
Definition base.h:339
bool freeit
Whether the control should be freed after we've finished using it.
Definition base.h:136
fr_ldap_control_t clientctrls[LDAP_MAX_CONTROLS+1]
Client controls to use for all operations with this handle.
Definition base.h:337
int clientctrls_cnt
Number of client controls associated with the handle.
Definition base.h:340
#define LDAP_MAX_CONTROLS
Maximum number of client/server controls.
Definition base.h:94
LDAPControl * control
LDAP control.
Definition base.h:135
fr_ldap_control_t serverctrls[LDAP_MAX_CONTROLS+1]
Server controls to use for all operations with this handle.
Definition base.h:335
Tracks the state of a libldap connection handle.
Definition base.h:332
void fr_ldap_control_clear(fr_ldap_connection_t *conn)
Clear and free any controls associated with a connection.
Definition control.c:134
int fr_ldap_control_add_server(fr_ldap_connection_t *conn, LDAPControl *ctrl, bool freeit)
Add a serverctrl to a connection handle.
Definition control.c:93
int fr_ldap_control_add_client(fr_ldap_connection_t *conn, LDAPControl *ctrl, bool freeit)
Add a clientctrl to a connection handle.
Definition control.c:117
USES_APPLE_DEPRECATED_API void fr_ldap_control_merge(LDAPControl *serverctrls_out[], LDAPControl *clientctrls_out[], size_t serverctrls_len, size_t clientctrls_len, fr_ldap_connection_t *conn, LDAPControl *serverctrls_in[], LDAPControl *clientctrls_in[])
Merge connection and call specific client and server controls.
Definition control.c:48
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
unsigned long int size_t
#define REDEBUG(fmt,...)
Definition radclient.h:52
static char const * hostname(char *buf, size_t buflen, uint32_t ipaddr)
Definition radwho.c:133
username
#define FR_SBUFF_OUT(_start, _len_or_end)
fr_pair_t * vp
Stores an attribute, a value and various bits of other data.
Definition pair.h:68
fr_dict_attr_t const *_CONST da
Dictionary attribute defines the attribute number, vendor and type of the pair.
Definition pair.h:69
@ T_BARE_WORD
Definition token.h:120
fr_pair_t * fr_pair_list_next(fr_pair_list_t const *list, fr_pair_t const *item))
Get the next item in a valuepair list after a specific entry.
Definition pair_inline.c:70
ssize_t fr_pair_print_value_quoted(fr_sbuff_t *out, fr_pair_t const *vp, fr_token_t quote)
Print the value of an attribute to a string.
Definition pair_print.c:53
fr_pair_t * fr_pair_list_head(fr_pair_list_t const *list)
Get the head of a valuepair list.
Definition pair_inline.c:43