All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
clients.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: 1b8f10c2a87e88a46c0977edd5b77cef0e766417 $
19  * @file clients.c
20  * @brief LDAP module dynamic clients.
21  *
22  * @author Arran Cudbard-Bell <a.cudbardb@freeradius.org>
23  * @copyright 2013,2015 Arran Cudbard-Bell <a.cudbardb@freeradius.org>
24  * @copyright 2013-2015 The FreeRADIUS Server Project.
25  */
26 #include <freeradius-devel/rad_assert.h>
27 #include <ctype.h>
28 
29 #include "ldap.h"
30 
31 /** Iterate over pairs in mapping section recording their values in an array
32  *
33  * This array is the list of attributes we retrieve from LDAP, and is NULL
34  * terminated.
35  *
36  * If we hit a CONF_SECTION we recurse and process its CONF_PAIRS too.
37  *
38  * @param[out] values array of char pointers.
39  * @param[in,out] idx records current array offset.
40  * @param[in] cs to iterate over.
41  * @return
42  * - 0 on success.
43  * - -1 on failure.
44  */
45 static int rlm_ldap_client_get_attrs(char const **values, int *idx, CONF_SECTION const *cs)
46 {
47  CONF_ITEM const *ci;
48 
49  for (ci = cf_item_find_next(cs, NULL);
50  ci != NULL;
51  ci = cf_item_find_next(cs, ci)) {
52  char const *value;
53 
54  if (cf_item_is_section(ci)) {
55  if (rlm_ldap_client_get_attrs(values, idx, cf_item_to_section(ci)) < 0) return -1;
56  continue;
57  }
58 
59  value = cf_pair_value(cf_item_to_pair(ci));
60  if (!value) return -1;
61 
62  values[(*idx)++] = value;
63  }
64 
65  values[*idx] = NULL;
66 
67  return 0;
68 }
69 
70 typedef struct ldap_client_data {
72  LDAPMessage *entry;
74 
75 static int _get_client_value(char **out, CONF_PAIR const *cp, void *data)
76 {
77  struct berval **values;
78  ldap_client_data_t *this = data;
79 
80  values = ldap_get_values_len(this->conn->handle, this->entry, cf_pair_value(cp));
81  if (!values) {
82  *out = NULL;
83  return 0;
84  }
85 
86  *out = rlm_ldap_berval_to_string(NULL, values[0]);
87  ldap_value_free_len(values);
88 
89  if (!*out) return -1;
90  return 0;
91 }
92 
93 /** Load clients from LDAP on server start
94  *
95  * @param[in] inst rlm_ldap configuration.
96  * @param[in] tmpl to use as the base for the new client.
97  * @param[in] map to load client attribute/LDAP attribute mappings from.
98  * @return
99  * - 0 on success.
100  * - -1 on failure.
101  */
103 {
104  int ret = 0;
105  ldap_rcode_t status;
106  ldap_handle_t *conn = NULL;
107 
108  char const **attrs = NULL;
109 
110  CONF_PAIR *cp;
111  int count = 0, idx = 0;
112 
113  LDAPMessage *result = NULL;
114  LDAPMessage *entry;
115  char *dn = NULL;
116 
117  RADCLIENT *c;
118 
119  LDAP_DBG("Loading dynamic clients");
120 
122 
123  count = cf_pair_count(map);
124  count++;
125 
126  /*
127  * Create an array of LDAP attributes to feed to rlm_ldap_search.
128  */
129  attrs = talloc_array(inst, char const *, count);
130  if (rlm_ldap_client_get_attrs(attrs, &idx, map) < 0) {
131  talloc_free(attrs);
132  return -1;
133  }
134 
135  conn = mod_conn_get(inst, NULL);
136  if (!conn) {
137  talloc_free(attrs);
138  return -1;
139  }
140 
141  /*
142  * Perform all searches as the admin user.
143  */
144  if (conn->rebound) {
145  status = rlm_ldap_bind(inst, NULL, &conn, conn->inst->admin_identity, conn->inst->admin_password,
146  &(conn->inst->admin_sasl), true, NULL, NULL);
147  if (status != LDAP_PROC_SUCCESS) {
148  ret = -1;
149  goto finish;
150  }
151 
152  rad_assert(conn);
153 
154  conn->rebound = false;
155  }
156 
157  status = rlm_ldap_search(&result, inst, NULL, &conn, inst->clientobj_base_dn, inst->clientobj_scope,
158  inst->clientobj_filter, attrs, NULL, NULL);
159  switch (status) {
160  case LDAP_PROC_SUCCESS:
161  break;
162 
163  case LDAP_PROC_NO_RESULT:
164  LDAP_INFO("No clients were found in the directory");
165  ret = 0;
166  goto finish;
167 
168  default:
169  ret = -1;
170  goto finish;
171  }
172 
173  rad_assert(conn);
174  entry = ldap_first_entry(conn->handle, result);
175  if (!entry) {
176  int ldap_errno;
177 
178  ldap_get_option(conn->handle, LDAP_OPT_RESULT_CODE, &ldap_errno);
179  LDAP_ERR("Failed retrieving entry: %s", ldap_err2string(ldap_errno));
180 
181  ret = -1;
182  goto finish;
183  }
184 
185  do {
187 
188  CONF_SECTION *client;
189  char *id;
190 
191  struct berval **values;
192 
193  id = dn = ldap_get_dn(conn->handle, entry);
194  if (!dn) {
195  int ldap_errno;
196 
197  ldap_get_option(conn->handle, LDAP_OPT_RESULT_CODE, &ldap_errno);
198  LDAP_ERR("Retrieving object DN from entry failed: %s", ldap_err2string(ldap_errno));
199 
200  goto finish;
201  }
202  rlm_ldap_normalise_dn(dn, dn);
203 
204  cp = cf_pair_find(map, "identifier");
205  if (cp) {
206  values = ldap_get_values_len(conn->handle, entry, cf_pair_value(cp));
207  if (values) id = rlm_ldap_berval_to_string(NULL, values[0]);
208  ldap_value_free_len(values);
209  }
210 
211  /*
212  * Iterate over mapping sections
213  */
214  client = tmpl ? cf_section_dup(NULL, tmpl, "client", id, true) :
215  cf_section_alloc(NULL, "client", id);
216 
217  data.conn = conn;
218  data.entry = entry;
219 
220  if (client_map_section(client, map, _get_client_value, &data) < 0) {
221  talloc_free(client);
222  ret = -1;
223  goto finish;
224  }
225 
226  /*
227  *@todo these should be parented from something
228  */
229  c = client_afrom_cs(NULL, client, false, false);
230  if (!c) {
231  talloc_free(client);
232  ret = -1;
233  goto finish;
234  }
235 
236  /*
237  * Client parents the CONF_SECTION which defined it
238  */
239  talloc_steal(c, client);
240 
241  if (!client_add(NULL, c)) {
242  LDAP_ERR("Failed to add client \"%s\", possible duplicate?", dn);
243  ret = -1;
244  client_free(c);
245  goto finish;
246  }
247 
248  LDAP_DBG("Client \"%s\" added", dn);
249 
250  ldap_memfree(dn);
251  dn = NULL;
252  } while ((entry = ldap_next_entry(conn->handle, entry)));
253 
254 finish:
255  talloc_free(attrs);
256  if (dn) ldap_memfree(dn);
257  if (result) ldap_msgfree(result);
258 
259  mod_conn_release(inst, conn);
260 
261  return ret;
262 }
263 
Tracks the state of a libldap connection handle.
Definition: ldap.h:163
Operation was successfull.
Definition: ldap.h:397
RADCLIENT * client_afrom_cs(TALLOC_CTX *ctx, CONF_SECTION *cs, bool in_server, bool with_coa)
Allocate a new client from a config section.
Definition: client.c:858
char const * clientobj_base_dn
DN to search for clients under.
Definition: ldap.h:281
char const * admin_identity
Identity we bind as when we need to query the LDAP directory.
Definition: ldap.h:188
char const * admin_password
Password used in administrative bind.
Definition: ldap.h:190
bool client_add(RADCLIENT_LIST *clients, RADCLIENT *client)
Add a client to a RADCLIENT_LIST.
Definition: client.c:192
static int _get_client_value(char **out, CONF_PAIR const *cp, void *data)
Definition: clients.c:75
#define inst
static expr_map_t map[]
Definition: rlm_expr.c:169
ldap_rcode_t
Codes returned by rlm_ldap internal functions.
Definition: ldap.h:395
CONF_SECTION * cf_item_to_section(CONF_ITEM const *item)
Cast a CONF_ITEM to a CONF_SECTION.
Definition: conffile.c:196
size_t rlm_ldap_normalise_dn(char *out, char const *in)
Normalise escape sequences in a DN.
Definition: ldap.c:312
CONF_PAIR * cf_pair_find(CONF_SECTION const *, char const *name)
Definition: conffile.c:3478
char const * cf_pair_value(CONF_PAIR const *pair)
Definition: conffile.c:3506
struct ldap_client_data ldap_client_data_t
#define LDAP_DBG(fmt,...)
Definition: ldap.h:426
#define LDAP_INFO(fmt,...)
Definition: ldap.h:420
#define rad_assert(expr)
Definition: rad_assert.h:38
CONF_SECTION * cf_section_dup(CONF_SECTION *parent, CONF_SECTION const *cs, char const *name1, char const *name2, bool copy_meta)
Duplicate a configuration section.
Definition: conffile.c:697
bool cf_item_is_section(CONF_ITEM const *item)
Definition: conffile.c:3923
#define LDAP_ERR(fmt,...)
Definition: ldap.h:435
bool rebound
Whether the connection has been rebound to something other than the admin user.
Definition: ldap.h:165
char const * clientobj_filter
Filter to retrieve only client objects.
Definition: ldap.h:280
CONF_PAIR * cf_item_to_pair(CONF_ITEM const *item)
Cast a CONF_ITEM to a CONF_PAIR.
Definition: conffile.c:181
ldap_rcode_t rlm_ldap_bind(rlm_ldap_t const *inst, REQUEST *request, ldap_handle_t **pconn, char const *dn, char const *password, ldap_sasl *sasl, bool retry, LDAPControl **serverctrls, LDAPControl **clientctrls)
Bind to the LDAP directory as a user.
Definition: ldap.c:751
int cf_pair_count(CONF_SECTION const *cs)
Count the number of conf pairs beneath a section.
Definition: conffile.c:3887
ldap_rcode_t rlm_ldap_search(LDAPMessage **result, rlm_ldap_t const *inst, REQUEST *request, ldap_handle_t **pconn, char const *dn, int scope, char const *filter, char const *const *attrs, LDAPControl **serverctrls, LDAPControl **clientctrls)
Search for something in the LDAP directory.
Definition: ldap.c:880
Configuration AVP similar to a VALUE_PAIR.
Definition: conffile.c:82
static int mod_conn_get(void **handle, UNUSED rlm_cache_config_t const *config, void *driver_inst, UNUSED REQUEST *request)
Get a memcached handle.
rlm_ldap_t * inst
rlm_ldap configuration.
Definition: ldap.h:177
Describes a host allowed to send packets to the server.
Definition: clients.h:35
uint8_t data[]
Definition: eap_pwd.h:625
int clientobj_scope
Search scope.
Definition: ldap.h:283
int rlm_ldap_client_load(rlm_ldap_t const *inst, CONF_SECTION *tmpl, CONF_SECTION *map)
Load clients from LDAP on server start.
Definition: clients.c:102
static void mod_conn_release(UNUSED rlm_cache_config_t const *config, void *driver_inst, UNUSED REQUEST *request, rlm_cache_handle_t *handle)
Release a memcached handle.
CONF_SECTION * cf_section_alloc(CONF_SECTION *parent, char const *name1, char const *name2)
Allocate a CONF_SECTION.
Definition: conffile.c:626
CONF_ITEM * cf_item_find_next(CONF_SECTION const *section, CONF_ITEM const *item)
Return the next item after a CONF_ITEM.
Definition: conffile.c:3850
char * rlm_ldap_berval_to_string(TALLOC_CTX *ctx, struct berval const *in)
Convert a berval to a talloced string.
Definition: ldap.c:281
static int rlm_ldap_client_get_attrs(char const **values, int *idx, CONF_SECTION const *cs)
Iterate over pairs in mapping section recording their values in an array.
Definition: clients.c:45
ldap_sasl admin_sasl
SASL parameters used when binding as the admin.
Definition: ldap.h:192
ldap_handle_t * conn
Definition: clients.c:71
LDAP authorization and authentication module headers.
int client_map_section(CONF_SECTION *out, CONF_SECTION const *map, client_value_cb_t func, void *data)
Create a client CONF_SECTION using a mapping section to map values from a result set to client attrib...
Definition: client.c:775
LDAPMessage * entry
Definition: clients.c:72
LDAP * handle
libldap handle.
Definition: ldap.h:164
Got no results.
Definition: ldap.h:412
void client_free(RADCLIENT *client)
Definition: client.c:62