All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
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: ea6c471035c9db93ab9a00117346c7394ac9ac96 $
19  * @file 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  */
25 #include "ldap.h"
26 
27 /** Merge connection and call specific client and server controls
28  *
29  * LDAP_OPT_CLIENT_CONTROLS and LDAP_OPT_SERVER_CONTROLS are useless
30  * because they're overriden in their entirety if any call specific
31  * controls are specified.
32  *
33  * @param[out] serverctrls_out Where to write serverctrls.
34  * @param[out] clientctrls_out Where to write clientctrls.
35  * @param[in] serverctrls_len length of serverctrls array.
36  * @param[in] clientctrls_len length of clientctrls array.
37  * @param[in] conn to get controls from.
38  * @param[in] serverctrls_in from arguments.
39  * @param[in] clientctrls_in from_arguments.
40  */
41  void rlm_ldap_control_merge(LDAPControl *serverctrls_out[],
42  LDAPControl *clientctrls_out[],
43  size_t serverctrls_len,
44  size_t clientctrls_len,
45  ldap_handle_t *conn,
46  LDAPControl *serverctrls_in[],
47  LDAPControl *clientctrls_in[])
48 {
49  size_t i, num_serverctrls = 0, num_clientctrls = 0;
50 
51  if (serverctrls_in) {
52  for (i = 0; serverctrls_in[i] && (num_serverctrls < LDAP_MAX_CONTROLS); i++) {
53  serverctrls_out[num_serverctrls++] = serverctrls_in[i];
54  }
55  }
56 
57  if (clientctrls_in) {
58  for (i = 0; clientctrls_in[i] && (num_clientctrls < LDAP_MAX_CONTROLS); i++) {
59  clientctrls_out[num_clientctrls++] = clientctrls_in[i];
60  }
61  }
62 
63  for (i = 0; (i < (size_t)conn->serverctrls_cnt) && (num_serverctrls < serverctrls_len); i++) {
64  serverctrls_out[num_serverctrls++] = conn->serverctrls[i].control;
65  }
66 
67  for (i = 0; (i < (size_t)conn->clientctrls_cnt) && (num_clientctrls < clientctrls_len); i++) {
68  clientctrls_out[num_clientctrls++] = conn->clientctrls[i].control;
69  }
70 
71  serverctrls_out[num_serverctrls] = NULL;
72  clientctrls_out[num_clientctrls] = NULL;
73 }
74 
75 /** Add a serverctrl to a connection handle
76  *
77  * All internal LDAP functions will pass this serverctrl to the server.
78  *
79  * @param conn to add control to.
80  * @param ctrl to add.
81  * @param freeit Whether the control should be freed when the handle is released or closed.
82  * @return
83  * - 0 on success.
84  * - -1 on failure (exceeded maximum controls).
85  */
86 int rlm_ldap_control_add_server(ldap_handle_t *conn, LDAPControl *ctrl, bool freeit)
87 {
88  if ((size_t)conn->serverctrls_cnt >= ((sizeof(conn->serverctrls) / sizeof(conn->serverctrls[0])) - 1)) {
89  return -1;
90  }
91 
92  conn->serverctrls[conn->serverctrls_cnt].control = ctrl;
93  conn->serverctrls[conn->serverctrls_cnt].freeit = freeit;
94  conn->serverctrls_cnt++;
95 
96  return 0;
97 }
98 
99 /** Add a clientctrl to a connection handle
100  *
101  * All internal LDAP functions will pass this clientctrl to libldap.
102  *
103  * @param conn to add control to.
104  * @param ctrl to add.
105  * @param freeit Whether the control should be freed when the handle is released or closed.
106  * @return
107  * - 0 on success.
108  * - -1 on failure (exceeded maximum controls).
109  */
110 int rlm_ldap_control_add_client(ldap_handle_t *conn, LDAPControl *ctrl, bool freeit)
111 {
112  if ((size_t)conn->clientctrls_cnt >= ((sizeof(conn->clientctrls) / sizeof(conn->clientctrls[0])) - 1)) {
113  return -1;
114  }
115 
116  conn->clientctrls[conn->clientctrls_cnt].control = ctrl;
117  conn->clientctrls[conn->clientctrls_cnt].freeit = freeit;
118  conn->clientctrls_cnt++;
119 
120  return 0;
121 }
122 
123 /** Clear and free any controls associated with a connection
124  *
125  * @param conn to clear controls from.
126  */
128 {
129  int i;
130 
131  for (i = 0; i < conn->serverctrls_cnt; i++) {
132  if (conn->serverctrls[i].freeit) ldap_control_free(conn->serverctrls[i].control);
133  conn->serverctrls[i].freeit = false;
134  conn->serverctrls[i].control = NULL;
135  }
136  conn->serverctrls_cnt = 0;
137 
138  for (i = 0; i < conn->clientctrls_cnt; i++) {
139  if (conn->clientctrls[i].freeit) ldap_control_free(conn->clientctrls[i].control);
140  conn->clientctrls[i].freeit = false;
141  conn->clientctrls[i].control = NULL;
142  }
143  conn->clientctrls_cnt = 0;
144 }
145 
146 #ifdef LDAP_CONTROL_X_SESSION_TRACKING
147 /** Add session controls to a connection as per draft-wahl-ldap-session
148  *
149  * @note the RFC states that the username identifier, must be the authenticated
150  * user id, not the purported one. As order of operations is configurable,
151  * we're going to leave that up to the server admin to satisfy that
152  * requirement
153  *
154  * For once the RFC is pretty helpful about what should be inserted into the
155  * various values, and maps out RADIUS attributes to formatOIDs, so none of
156  * this is configurable.
157  *
158  * @param conn to add controls to.
159  * @param request to draw attributes from.
160  */
162 {
163  /*
164  * The OpenLDAP guys didn't declare the formatOID parameter to
165  * ldap_create_session_tracking_control as const *sigh*.
166  */
167  static char username_oid[] = LDAP_CONTROL_X_SESSION_TRACKING_USERNAME;
168  static char acctsessionid_oid[] = LDAP_CONTROL_X_SESSION_TRACKING_RADIUS_ACCT_SESSION_ID;
169  static char acctmultisessionid_oid[] = LDAP_CONTROL_X_SESSION_TRACKING_RADIUS_ACCT_MULTI_SESSION_ID;
170 
171  int ret;
172 
173  char ipaddress[INET6_ADDRSTRLEN];
174  char *username = NULL;
175  char *acctsessionid = NULL;
176  char *acctmultisessionid = NULL;
177  char *hostname;
178 
179  LDAPControl *username_control = NULL;
180  LDAPControl *acctsessionid_control = NULL;
181  LDAPControl *acctmultisessionid_control = NULL;
182  struct berval tracking_id;
183 
184  vp_cursor_t cursor;
185  VALUE_PAIR const *vp;
186 
187  memcpy(&hostname, &main_config.name, sizeof(hostname)); /* const / non-const issues */
188 
189  for (vp = fr_cursor_init(&cursor, &request->packet->vps);
190  vp;
191  vp = fr_cursor_next(&cursor)) {
192  if (vp->da->vendor == 0) switch (vp->da->attr) {
193  case PW_NAS_IP_ADDRESS:
194  case PW_NAS_IPV6_ADDRESS:
195  fr_pair_value_snprint(ipaddress, sizeof(ipaddress), vp, '\0');
196  break;
197 
198  case PW_USER_NAME:
199  memcpy(&username, &vp->vp_strvalue, sizeof(username));
200  break;
201 
202  case PW_ACCT_SESSION_ID:
203  memcpy(&acctsessionid, &vp->vp_strvalue, sizeof(acctsessionid));
204  break;
205 
206  case PW_ACCT_MULTI_SESSION_ID:
207  memcpy(&acctmultisessionid, &vp->vp_strvalue, sizeof(acctmultisessionid));
208  break;
209  }
210  }
211 
212  if (username) {
213  tracking_id.bv_val = username;
214  tracking_id.bv_len = talloc_array_length(username) - 1;
215 
216  ret = ldap_create_session_tracking_control(conn->handle, ipaddress,
217  hostname,
218  username_oid,
219  &tracking_id,
220  &username_control);
221  if (ret != LDAP_SUCCESS) {
222  REDEBUG("Failed creating username session tracking control: %s", ldap_err2string(ret));
223  error:
224  if (username_control) ldap_control_free(username_control);
225  if (acctsessionid_control) ldap_control_free(acctsessionid_control);
226  if (acctmultisessionid_control) ldap_control_free(acctmultisessionid_control);
227  return -1;
228  }
229  }
230 
231  if (acctsessionid) {
232  tracking_id.bv_val = acctsessionid;
233  tracking_id.bv_len = talloc_array_length(acctsessionid) - 1;
234 
235  ret = ldap_create_session_tracking_control(conn->handle, ipaddress,
236  hostname,
237  acctsessionid_oid,
238  &tracking_id,
239  &acctsessionid_control);
240  if (ret != LDAP_SUCCESS) {
241  REDEBUG("Failed creating acctsessionid session tracking control: %s", ldap_err2string(ret));
242  goto error;
243  }
244  }
245 
246  if (acctmultisessionid) {
247  tracking_id.bv_val = acctmultisessionid;
248  tracking_id.bv_len = talloc_array_length(acctmultisessionid) - 1;
249 
250  ret = ldap_create_session_tracking_control(conn->handle, ipaddress,
251  hostname,
252  acctmultisessionid_oid,
253  &tracking_id,
254  &acctmultisessionid_control);
255  if (ret != LDAP_SUCCESS) {
256  REDEBUG("Failed creating acctmultisessionid session tracking control: %s",
257  ldap_err2string(ret));
258  goto error;
259  }
260  }
261 
262  if ((conn->serverctrls_cnt + 3) >= LDAP_MAX_CONTROLS) {
263  REDEBUG("Insufficient space to add session tracking controls");
264  goto error;
265  }
266 
267  if (username_control && (rlm_ldap_control_add_server(conn, username_control, true) < 0)) goto error;
268 
269  if (acctsessionid_control && (rlm_ldap_control_add_server(conn, acctsessionid_control, true) < 0)) {
270  conn->serverctrls_cnt--;
271  conn->serverctrls[conn->serverctrls_cnt].control = NULL;
272  goto error;
273  }
274 
275  if (acctmultisessionid_control && (rlm_ldap_control_add_server(conn, acctmultisessionid_control, true) < 0)) {
276  conn->serverctrls_cnt--;
277  conn->serverctrls[conn->serverctrls_cnt].control = NULL;
278  conn->serverctrls_cnt--;
279  conn->serverctrls[conn->serverctrls_cnt].control = NULL;
280  goto error;
281  }
282 
283  return 0;
284 }
285 #endif
286 
287 
Tracks the state of a libldap connection handle.
Definition: ldap.h:163
rlm_ldap_control_t serverctrls[LDAP_MAX_CONTROLS+1]
Server controls to use for all operations with this handle.
Definition: ldap.h:170
Main server configuration.
Definition: radiusd.h:108
int rlm_ldap_control_add_server(ldap_handle_t *conn, LDAPControl *ctrl, bool freeit)
Add a serverctrl to a connection handle.
Definition: control.c:86
int rlm_ldap_control_add_session_tracking(ldap_handle_t *conn, REQUEST *request)
LDAPControl * control
LDAP control.
Definition: ldap.h:155
void rlm_ldap_control_merge(LDAPControl *serverctrls_out[], LDAPControl *clientctrls_out[], size_t serverctrls_len, size_t clientctrls_len, ldap_handle_t *conn, LDAPControl *serverctrls_in[], LDAPControl *clientctrls_in[])
Merge connection and call specific client and server controls.
Definition: control.c:41
rlm_ldap_control_t clientctrls[LDAP_MAX_CONTROLS+1]
Client controls to use for all operations with this handle.
Definition: ldap.h:172
void size_t fr_pair_value_snprint(char *out, size_t outlen, VALUE_PAIR const *vp, char quote)
Print the value of an attribute to a string.
Definition: pair.c:2107
VALUE_PAIR * vps
Result of decoding the packet into VALUE_PAIRs.
Definition: libradius.h:162
VALUE_PAIR * fr_cursor_init(vp_cursor_t *cursor, VALUE_PAIR *const *node)
Setup a cursor to iterate over attribute pairs.
Definition: cursor.c:60
static char const * hostname(char *buf, size_t buflen, uint32_t ipaddr)
Definition: radwho.c:149
char const * name
Name of the daemon, usually 'radiusd'.
Definition: radiusd.h:109
int serverctrls_cnt
Number of server controls associated with the handle.
Definition: ldap.h:174
Abstraction to allow iterating over different configurations of VALUE_PAIRs.
Definition: pair.h:144
unsigned int attr
Attribute number.
Definition: dict.h:79
unsigned int vendor
Vendor that defines this attribute.
Definition: dict.h:78
Stores an attribute, a value and various bits of other data.
Definition: pair.h:112
int rlm_ldap_control_add_client(ldap_handle_t *conn, LDAPControl *ctrl, bool freeit)
Add a clientctrl to a connection handle.
Definition: control.c:110
VALUE_PAIR * fr_cursor_next(vp_cursor_t *cursor)
Advanced the cursor to the next VALUE_PAIR.
Definition: cursor.c:263
RADIUS_PACKET * packet
Incoming request.
Definition: radiusd.h:221
int clientctrls_cnt
Number of client controls associated with the handle.
Definition: ldap.h:175
#define REDEBUG(fmt,...)
Definition: log.h:254
bool freeit
Whether the control should be freed after we've finished using it.
Definition: ldap.h:156
fr_dict_attr_t const * da
Dictionary attribute defines the attribute.
Definition: pair.h:113
#define LDAP_MAX_CONTROLS
Maximum number of client/server controls.
Definition: ldap.h:105
LDAP authorization and authentication module headers.
void rlm_ldap_control_clear(ldap_handle_t *conn)
Clear and free any controls associated with a connection.
Definition: control.c:127
LDAP * handle
libldap handle.
Definition: ldap.h:164