The FreeRADIUS server $Id: f3670dba8951ca10eb4948feb3dc3db9423a334f $
Loading...
Searching...
No Matches
edir.c
Go to the documentation of this file.
1/*
2 * This program 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: c5309d4d06120eef379d2d20530c60ef5d6735f9 $
19 * @file lib/ldap/edir.c
20 * @brief LDAP extension for reading eDirectory universal password.
21 *
22 * To contact Novell about this file by physical or electronic mail, you may
23 * find current contact information at www.novell.com.
24 *
25 * @copyright 2012 Olivier Beytrison (olivier@heliosnet.org)
26 * @copyright 2012 Alan DeKok (aland@freeradius.org)
27 * @copyright 2002-2004 Novell, Inc.
28 */
29RCSID("$Id: c5309d4d06120eef379d2d20530c60ef5d6735f9 $")
30
32
33#include <freeradius-devel/util/debug.h>
34#include <freeradius-devel/ldap/base.h>
35
36/* NMAS error codes */
37#define NMAS_E_BASE (-1600)
38
39#define NMAS_E_FRAG_FAILURE (NMAS_E_BASE-31) /* -1631 0xFFFFF9A1 */
40#define NMAS_E_SYSTEM_RESOURCES (NMAS_E_BASE-34) /* -1634 0xFFFFF99E */
41#define NMAS_E_INSUFFICIENT_MEMORY (NMAS_E_BASE-35) /* -1635 0xFFFFF99D */
42#define NMAS_E_NOT_SUPPORTED (NMAS_E_BASE-36) /* -1636 0xFFFFF99C */
43#define NMAS_E_INVALID_PARAMETER (NMAS_E_BASE-43) /* -1643 0xFFFFF995 */
44#define NMAS_E_INVALID_VERSION (NMAS_E_BASE-52) /* -1652 0xFFFFF98C */
45#define NMAS_E_ACCESS_NOT_ALLOWED (NMAS_E_BASE-59) /* -1659 0xFFFFF985 */
46#define NMAS_E_INVALID_SPM_REQUEST (NMAS_E_BASE-97) /* -1697 0xFFFFF95F */
47
48/* OID of LDAP extension calls to read Universal Password */
49#define NMASLDAP_GET_PASSWORD_REQUEST "2.16.840.1.113719.1.39.42.100.13"
50#define NMASLDAP_GET_PASSWORD_RESPONSE "2.16.840.1.113719.1.39.42.100.14"
51
52#define NMAS_LDAP_EXT_VERSION 1
53
61
62/** Takes the object DN and BER encodes the data into the BER value which is used as part of the request
63 *
64 @verbatim
65 RequestBer contents:
66 clientVersion INTEGER
67 targetObjectDN OCTET STRING
68 @endverbatim
69 *
70 * @param[out] request_bv where to write the request BER value (must be freed with ber_bvfree).
71 * @param[in] dn to query for.
72 * @return
73 * - 0 on success.
74 * - < 0 on error.
75 */
76static int ber_encode_request_data(char const *dn, struct berval **request_bv)
77{
78 int err = 0;
79 int rc = 0;
80 BerElement *request_ber = NULL;
81
82 if (!dn || !*dn) {
84 goto finish;
85 }
86
87 /* Allocate a BerElement for the request parameters.*/
88 if ((request_ber = ber_alloc()) == NULL) {
90 goto finish;
91 }
92
93 rc = ber_printf(request_ber, "{io}", NMAS_LDAP_EXT_VERSION, dn, strlen(dn) + 1);
94 if (rc < 0) {
96 goto finish;
97 }
98
99 /*
100 * Convert the BER we just built to a berval that we'll
101 * send with the extended request.
102 */
103 if (ber_flatten(request_ber, request_bv) < 0) {
105 goto finish;
106 }
107
108finish:
109 if (request_ber) ber_free(request_ber, 1);
110
111 return err;
112}
113
114/** Converts the reply into server version and a return code
115 *
116 * This function takes the reply BER Value and decodes the NMAS server version and return code and if a non
117 * null retData buffer was supplied, tries to decode the the return data and length.
118 *
119 @verbatim
120 ResponseBer contents:
121 server_version INTEGER
122 error INTEGER
123 data OCTET STRING
124 @endverbatim
125 *
126 * @param[in] reply_bv reply data from extended request.
127 * @param[out] server_version that responded.
128 * @param[out] out data.
129 * @param[out] outlen Length of data written to out.
130 * @return
131 * - 0 on success.
132 * - < 0 on error.
133 */
134static int ber_decode_login_data(struct berval *reply_bv, int *server_version, void *out, size_t *outlen)
135{
136 int rc = 0;
137 int err = 0;
138 BerElement *reply_ber = NULL;
139
140 fr_assert(out != NULL);
141 fr_assert(outlen != NULL);
142
143 if ((reply_ber = ber_init(reply_bv)) == NULL) {
145 goto finish;
146 }
147
148 rc = ber_scanf(reply_ber, "{iis}", server_version, &err, out, outlen);
149 if (rc == -1) {
151 goto finish;
152 }
153
154finish:
155 if (reply_ber) ber_free(reply_ber, 1);
156
157 return err;
158}
159
160/** Handle results of retrieving Universal Password
161 *
162 * @param p_result Result of current operation.
163 * @param request Current request.
164 * @param uctx eDir lookup context.
165 * @return One of the RLM_MODULE_* values.
166 */
168{
169 ldap_edir_ctx_t *edir_ctx = talloc_get_type_abort(uctx, ldap_edir_ctx_t);
170 fr_ldap_query_t *query = edir_ctx->query;
172 fr_pair_t *vp;
173 char *reply_oid = NULL;
174 struct berval *reply_bv = NULL;
175 size_t bufsize;
176 char buffer[256];
177 int err = 0;
178 int server_version;
179
180 switch (query->ret){
181 case LDAP_SUCCESS:
182 break;
183
184 default:
185 REDEBUG("Failed retrieving Universal Password");
186 rcode = RLM_MODULE_FAIL;
187 goto finish;
188 }
189
190 err = ldap_parse_extended_result(query->ldap_conn->handle, query->result, &reply_oid, &reply_bv, false);
191
192 if (err != LDAP_SUCCESS) {
193 REDEBUG("Failed to parse extended result: %s", ldap_err2string(err));
194 rcode = RLM_MODULE_FAIL;
195 goto finish;
196 }
197
198 /* Make sure there is a return OID */
199 if (!reply_oid) {
201 goto finish;
202 }
203
204 /* Is this what we were expecting to get back. */
205 if (strcmp(reply_oid, NMASLDAP_GET_PASSWORD_RESPONSE) != 0) {
207 goto finish;
208 }
209
210 /* Do we have a good returned berval? */
211 if (!reply_bv) {
212 /*
213 * No; returned berval means we experienced a rather
214 * drastic error. Return operations error.
215 */
217 goto finish;
218 }
219
220 bufsize = sizeof(buffer);
221 err = ber_decode_login_data(reply_bv, &server_version, buffer, &bufsize);
222 if (err) goto finish;
223
224 if (server_version != NMAS_LDAP_EXT_VERSION) {
226 goto finish;
227 }
228
229 /*
230 * Add Password.Cleartext attribute to the request
231 */
232 MEM(pair_update_control(&vp, edir_ctx->password_da) >= 0);
233 fr_pair_value_bstrndup(vp, buffer, bufsize, true);
234
235 if (RDEBUG_ENABLED3) {
236 RDEBUG3("Added eDirectory password. control.%pP", vp);
237 } else {
238 RDEBUG2("Added eDirectory password");
239 }
240
241finish:
242 /*
243 * Free any libldap allocated resources.
244 */
245 if (reply_bv) ber_bvfree(reply_bv);
246 if (reply_oid) ldap_memfree(reply_oid);
247
248 if (err) {
249 REDEBUG("Failed to retrieve eDirectory password: (%i) %s", err, fr_ldap_edir_errstr(err));
250 rcode = RLM_MODULE_FAIL;
251 }
252
253 RETURN_UNLANG_RCODE(rcode);
254}
255
256/** Cancel an in progress Universal Password lookup
257 *
258 */
260{
261 ldap_edir_ctx_t *edir_ctx = talloc_get_type_abort(uctx, ldap_edir_ctx_t);
262
263 if (!edir_ctx->query || !edir_ctx->query->treq) return;
264
266}
267
268/** Initiate retrieval of the universal password from Novell eDirectory
269 *
270 * @param[out] p_result Where to write the result of the operation.
271 * @param[in] request Current request.
272 * @param[in] dn of the user whose password is to be retrieved.
273 * @param[in] ttrunk on which to send the LDAP request.
274 * @param[in] password_da DA to use when creating password attribute.
275 * @return
276 * - UNLANG_ACTION_PUSHED_CHILD on success.
277 * - UNLANG_ACTION_FAIL on failure.
278 */
280 request_t *request, char const *dn, fr_ldap_thread_trunk_t *ttrunk,
281 fr_dict_attr_t const *password_da)
282{
283 ldap_edir_ctx_t *edir_ctx;
285 int err = 0;
286
287 if (!dn || !*dn) {
288 REDEBUG("Missing DN");
290 }
291
293
294 *edir_ctx = (ldap_edir_ctx_t) {
296 .ttrunk = ttrunk,
297 .password_da = password_da
298 };
299
300 err = ber_encode_request_data(dn, &edir_ctx->dn);
301 if (err) {
302 REDEBUG("Failed to encode user DN: %s", fr_ldap_edir_errstr(err));
303 talloc_free(edir_ctx);
305 }
306
308 request,
309 NULL,
312 UNLANG_SUB_FRAME, edir_ctx) == UNLANG_ACTION_FAIL) {
313 talloc_free(edir_ctx);
315 }
316
317 ua = fr_ldap_trunk_extended(edir_ctx, &edir_ctx->query, request, ttrunk,
318 edir_ctx->reqoid, edir_ctx->dn, NULL, NULL);
319 if (ua == UNLANG_ACTION_FAIL) {
321 talloc_free(edir_ctx);
323 }
324
325 return ua;
326}
327
328char const *fr_ldap_edir_errstr(int code)
329{
330 switch (code) {
332 return "BER manipulation failed";
333
336 return "Insufficient memory or system resources";
337
339 return "Server response indicated Universal Password is not supported (missing password response OID)";
340
342 return "Bad arguments passed to eDir functions";
343
345 return "LDAP EXT version does not match expected version " STRINGIFY(NMAS_LDAP_EXT_VERSION);
346
348 return "Bound user does not have sufficient rights to read the Universal Password of users";
349
351 return "Universal password is not enabled for the container of this user object";
352
353 default:
354 return ldap_err2string(code);
355 }
356}
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
static int const char char buffer[256]
Definition acutest.h:635
static uint8_t request[4]
#define USES_APPLE_DEPRECATED_API
Definition build.h:547
#define RCSID(id)
Definition build.h:560
#define STRINGIFY(x)
Definition build.h:216
#define UNUSED
Definition build.h:384
#define MEM(x)
Definition debug.h:38
#define NMAS_E_INVALID_VERSION
Definition edir.c:44
static int ber_encode_request_data(char const *dn, struct berval **request_bv)
Takes the object DN and BER encodes the data into the BER value which is used as part of the request.
Definition edir.c:76
#define NMAS_E_SYSTEM_RESOURCES
Definition edir.c:40
#define NMAS_E_FRAG_FAILURE
Definition edir.c:39
#define NMAS_E_ACCESS_NOT_ALLOWED
Definition edir.c:45
static int ber_decode_login_data(struct berval *reply_bv, int *server_version, void *out, size_t *outlen)
Converts the reply into server version and a return code.
Definition edir.c:134
fr_dict_attr_t const * password_da
Definition edir.c:59
static void ldap_edir_get_password_cancel(UNUSED request_t *request, UNUSED fr_signal_t action, void *uctx)
Cancel an in progress Universal Password lookup.
Definition edir.c:259
#define NMASLDAP_GET_PASSWORD_REQUEST
Definition edir.c:49
fr_ldap_thread_trunk_t * ttrunk
Definition edir.c:56
static unlang_action_t ldap_edir_get_password_resume(unlang_result_t *p_result, request_t *request, void *uctx)
Handle results of retrieving Universal Password.
Definition edir.c:167
char const * fr_ldap_edir_errstr(int code)
Definition edir.c:328
#define NMASLDAP_GET_PASSWORD_RESPONSE
Definition edir.c:50
#define NMAS_E_INVALID_PARAMETER
Definition edir.c:43
unlang_action_t fr_ldap_edir_get_password(unlang_result_t *p_result, request_t *request, char const *dn, fr_ldap_thread_trunk_t *ttrunk, fr_dict_attr_t const *password_da)
Initiate retrieval of the universal password from Novell eDirectory.
Definition edir.c:279
char const * reqoid
Definition edir.c:57
#define NMAS_LDAP_EXT_VERSION
Definition edir.c:52
#define NMAS_E_INSUFFICIENT_MEMORY
Definition edir.c:41
struct berval * dn
Definition edir.c:58
#define NMAS_E_NOT_SUPPORTED
Definition edir.c:42
#define NMAS_E_INVALID_SPM_REQUEST
Definition edir.c:46
fr_ldap_query_t * query
Definition edir.c:55
#define unlang_function_push_with_result(_result_p, _request, _func, _repeat, _signal, _sigmask, _top_frame, _uctx)
Push a generic function onto the unlang stack that produces a result.
Definition function.h:146
talloc_free(hp)
void unlang_interpet_frame_discard(request_t *request)
Discard the bottom most frame on the request's stack.
Definition interpret.c:2511
TALLOC_CTX * unlang_interpret_frame_talloc_ctx(request_t *request)
Get a talloc_ctx which is valid only for this frame.
Definition interpret.c:2053
#define UNLANG_SUB_FRAME
Definition interpret.h:37
LDAP * handle
libldap handle.
Definition base.h:342
fr_ldap_result_code_t ret
Result code.
Definition base.h:472
trunk_request_t * treq
Trunk request this query is associated with.
Definition base.h:458
fr_ldap_connection_t * ldap_conn
LDAP connection this query is running on.
Definition base.h:459
LDAPMessage * result
Head of LDAP results list.
Definition base.h:470
LDAP query structure.
Definition base.h:424
Thread LDAP trunk structure.
Definition base.h:401
unlang_action_t fr_ldap_trunk_extended(TALLOC_CTX *ctx, fr_ldap_query_t **out, request_t *request, fr_ldap_thread_trunk_t *ttrunk, char const *reqoid, struct berval *reqdata, LDAPControl **serverctrls, LDAPControl **clientctrls)
Run an async LDAP "extended operation" query on a trunk connection.
Definition base.c:903
#define RDEBUG_ENABLED3
True if request debug level 1-3 messages are enabled.
Definition log.h:352
#define RDEBUG3(fmt,...)
Definition log.h:360
int fr_pair_value_bstrndup(fr_pair_t *vp, char const *src, size_t len, bool tainted)
Copy data into a "string" type value pair.
Definition pair.c:2747
#define fr_assert(_expr)
Definition rad_assert.h:37
#define REDEBUG(fmt,...)
#define RDEBUG2(fmt,...)
#define RETURN_UNLANG_RCODE(_rcode)
Definition rcode.h:61
#define RETURN_UNLANG_FAIL
Definition rcode.h:63
rlm_rcode_t
Return codes indicating the result of the module call.
Definition rcode.h:44
@ RLM_MODULE_OK
The module is OK, continue.
Definition rcode.h:49
@ RLM_MODULE_FAIL
Module failed, don't reply.
Definition rcode.h:48
#define pair_update_control(_attr, _da)
Return or allocate a fr_pair_t in the control list.
Definition pair.h:140
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
fr_pair_t * vp
Stores an attribute, a value and various bits of other data.
Definition pair.h:68
void trunk_request_signal_cancel(trunk_request_t *treq)
Cancel a trunk request.
Definition trunk.c:2216
static fr_sbuff_err_t char ** out
Definition value.h:1061