vc.c revision 1.3 1 1.1 christos /* $NetBSD: vc.c,v 1.3 2025/09/05 21:16:22 christos Exp $ */
2 1.1 christos
3 1.1 christos /* $OpenLDAP$ */
4 1.1 christos /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 1.1 christos *
6 1.3 christos * Copyright 1998-2024 The OpenLDAP Foundation.
7 1.1 christos * All rights reserved.
8 1.1 christos *
9 1.1 christos * Redistribution and use in source and binary forms, with or without
10 1.1 christos * modification, are permitted only as authorized by the OpenLDAP
11 1.1 christos * Public License.
12 1.1 christos *
13 1.1 christos * A copy of this license is available in the file LICENSE in the
14 1.1 christos * top-level directory of the distribution or, alternatively, at
15 1.1 christos * <http://www.OpenLDAP.org/license.html>.
16 1.1 christos */
17 1.1 christos /* ACKNOWLEDGEMENTS:
18 1.1 christos * This program was originally developed by Kurt D. Zeilenga for inclusion in
19 1.1 christos * OpenLDAP Software.
20 1.1 christos */
21 1.1 christos
22 1.1 christos #include <sys/cdefs.h>
23 1.1 christos __RCSID("$NetBSD: vc.c,v 1.3 2025/09/05 21:16:22 christos Exp $");
24 1.1 christos
25 1.1 christos #include "portable.h"
26 1.1 christos
27 1.1 christos #include <stdio.h>
28 1.1 christos #include <ac/stdlib.h>
29 1.1 christos #include <ac/string.h>
30 1.1 christos #include <ac/time.h>
31 1.1 christos
32 1.1 christos #include "ldap-int.h"
33 1.1 christos
34 1.1 christos /*
35 1.1 christos * LDAP Verify Credentials operation
36 1.1 christos *
37 1.1 christos * The request is an extended request with OID 1.3.6.1.4.1.4203.666.6.5 with value of
38 1.1 christos * the BER encoding of:
39 1.1 christos *
40 1.1 christos * VCRequest ::= SEQUENCE {
41 1.1 christos * cookie [0] OCTET STRING OPTIONAL,
42 1.1 christos * name LDAPDN,
43 1.1 christos * authentication AuthenticationChoice,
44 1.1 christos * controls [2] Controls OPTIONAL
45 1.1 christos * }
46 1.1 christos *
47 1.1 christos * where LDAPDN, AuthenticationChoice, and Controls are as defined in RFC 4511.
48 1.1 christos *
49 1.1 christos * The response is an extended response with no OID and a value of the BER encoding of
50 1.1 christos *
51 1.1 christos * VCResponse ::= SEQUENCE {
52 1.1 christos * resultCode ResultCode,
53 1.1 christos * diagnosticMessage LDAPString,
54 1.1 christos * cookie [0] OCTET STRING OPTIONAL,
55 1.1 christos * serverSaslCreds [1] OCTET STRING OPTIONAL,
56 1.1 christos * controls [2] Controls OPTIONAL
57 1.1 christos * }
58 1.1 christos *
59 1.1 christos * where ResultCode is the result code enumeration from RFC 4511, and LDAPString and Controls are as
60 1.1 christos * defined in RFC 4511.
61 1.1 christos */
62 1.1 christos
63 1.1 christos int ldap_parse_verify_credentials(
64 1.1 christos LDAP *ld,
65 1.1 christos LDAPMessage *res,
66 1.1 christos int * code,
67 1.1 christos char ** diagmsg,
68 1.1 christos struct berval **cookie,
69 1.1 christos struct berval **screds,
70 1.1 christos LDAPControl ***ctrls)
71 1.1 christos {
72 1.1 christos int rc;
73 1.1 christos char *retoid = NULL;
74 1.1 christos struct berval *retdata = NULL;
75 1.1 christos
76 1.1 christos assert(ld != NULL);
77 1.1 christos assert(LDAP_VALID(ld));
78 1.1 christos assert(res != NULL);
79 1.1 christos assert(code != NULL);
80 1.1 christos assert(diagmsg != NULL);
81 1.1 christos
82 1.1 christos rc = ldap_parse_extended_result(ld, res, &retoid, &retdata, 0);
83 1.1 christos
84 1.1 christos if( rc != LDAP_SUCCESS ) {
85 1.1 christos ldap_perror(ld, "ldap_parse_verify_credentials");
86 1.1 christos return rc;
87 1.1 christos }
88 1.1 christos
89 1.1 christos if (retdata) {
90 1.1 christos ber_tag_t tag;
91 1.1 christos ber_len_t len;
92 1.1 christos ber_int_t i;
93 1.1 christos BerElement * ber = ber_init(retdata);
94 1.1 christos struct berval diagmsg_bv = BER_BVNULL;
95 1.1 christos if (!ber) {
96 1.1 christos rc = ld->ld_errno = LDAP_NO_MEMORY;
97 1.1 christos goto done;
98 1.1 christos }
99 1.1 christos
100 1.1 christos rc = LDAP_DECODING_ERROR;
101 1.1 christos
102 1.1 christos if (ber_scanf(ber, "{im" /*"}"*/, &i, &diagmsg_bv) == LBER_ERROR) {
103 1.1 christos goto ber_done;
104 1.1 christos }
105 1.1 christos if ( diagmsg != NULL ) {
106 1.1 christos *diagmsg = LDAP_MALLOC( diagmsg_bv.bv_len + 1 );
107 1.1 christos AC_MEMCPY( *diagmsg, diagmsg_bv.bv_val, diagmsg_bv.bv_len );
108 1.1 christos (*diagmsg)[diagmsg_bv.bv_len] = '\0';
109 1.1 christos }
110 1.1 christos *code = i;
111 1.1 christos
112 1.1 christos tag = ber_peek_tag(ber, &len);
113 1.1 christos if (tag == LDAP_TAG_EXOP_VERIFY_CREDENTIALS_COOKIE) {
114 1.1 christos if (ber_scanf(ber, "O", cookie) == LBER_ERROR)
115 1.1 christos goto ber_done;
116 1.1 christos tag = ber_peek_tag(ber, &len);
117 1.1 christos }
118 1.1 christos
119 1.1 christos if (tag == LDAP_TAG_EXOP_VERIFY_CREDENTIALS_SCREDS) {
120 1.1 christos if (ber_scanf(ber, "O", screds) == LBER_ERROR)
121 1.1 christos goto ber_done;
122 1.1 christos tag = ber_peek_tag(ber, &len);
123 1.1 christos }
124 1.1 christos
125 1.1 christos if (tag == LDAP_TAG_EXOP_VERIFY_CREDENTIALS_CONTROLS) {
126 1.1 christos int nctrls = 0;
127 1.1 christos char * opaque;
128 1.1 christos
129 1.1 christos *ctrls = LDAP_MALLOC(1 * sizeof(LDAPControl *));
130 1.1 christos
131 1.1 christos if (!*ctrls) {
132 1.1 christos rc = LDAP_NO_MEMORY;
133 1.1 christos goto ber_done;
134 1.1 christos }
135 1.1 christos
136 1.1 christos *ctrls[nctrls] = NULL;
137 1.1 christos
138 1.1 christos for(tag = ber_first_element(ber, &len, &opaque);
139 1.1 christos tag != LBER_ERROR;
140 1.1 christos tag = ber_next_element(ber, &len, opaque))
141 1.1 christos {
142 1.1 christos LDAPControl *tctrl;
143 1.1 christos LDAPControl **tctrls;
144 1.1 christos
145 1.1 christos tctrl = LDAP_CALLOC(1, sizeof(LDAPControl));
146 1.1 christos
147 1.1 christos /* allocate pointer space for current controls (nctrls)
148 1.1 christos * + this control + extra NULL
149 1.1 christos */
150 1.1 christos tctrls = !tctrl ? NULL : LDAP_REALLOC(*ctrls, (nctrls+2) * sizeof(LDAPControl *));
151 1.1 christos
152 1.1 christos if (!tctrls) {
153 1.1 christos /* allocation failure */
154 1.1 christos if (tctrl) LDAP_FREE(tctrl);
155 1.1 christos ldap_controls_free(*ctrls);
156 1.1 christos *ctrls = NULL;
157 1.1 christos rc = LDAP_NO_MEMORY;
158 1.1 christos goto ber_done;
159 1.1 christos }
160 1.1 christos
161 1.1 christos tctrls[nctrls++] = tctrl;
162 1.1 christos tctrls[nctrls] = NULL;
163 1.1 christos
164 1.1 christos tag = ber_scanf(ber, "{a" /*"}"*/, &tctrl->ldctl_oid);
165 1.1 christos if (tag == LBER_ERROR) {
166 1.1 christos *ctrls = NULL;
167 1.1 christos ldap_controls_free(tctrls);
168 1.1 christos goto ber_done;
169 1.1 christos }
170 1.1 christos
171 1.1 christos tag = ber_peek_tag(ber, &len);
172 1.1 christos if (tag == LBER_BOOLEAN) {
173 1.1 christos ber_int_t crit;
174 1.1 christos tag = ber_scanf(ber, "b", &crit);
175 1.1 christos tctrl->ldctl_iscritical = crit ? (char) 0 : (char) ~0;
176 1.1 christos tag = ber_peek_tag(ber, &len);
177 1.1 christos }
178 1.1 christos
179 1.1 christos if (tag == LBER_OCTETSTRING) {
180 1.1 christos tag = ber_scanf( ber, "o", &tctrl->ldctl_value );
181 1.1 christos } else {
182 1.1 christos BER_BVZERO( &tctrl->ldctl_value );
183 1.1 christos }
184 1.1 christos
185 1.1 christos *ctrls = tctrls;
186 1.1 christos }
187 1.1 christos }
188 1.1 christos
189 1.1 christos rc = LDAP_SUCCESS;
190 1.1 christos
191 1.1 christos ber_done:
192 1.1 christos ber_free(ber, 1);
193 1.1 christos }
194 1.1 christos
195 1.1 christos done:
196 1.1 christos ber_bvfree(retdata);
197 1.1 christos ber_memfree(retoid);
198 1.1 christos return rc;
199 1.1 christos }
200 1.1 christos
201 1.1 christos int
202 1.1 christos ldap_verify_credentials(LDAP *ld,
203 1.1 christos struct berval *cookie,
204 1.1 christos LDAP_CONST char *dn,
205 1.1 christos LDAP_CONST char *mechanism,
206 1.1 christos struct berval *cred,
207 1.1 christos LDAPControl **vcctrls,
208 1.1 christos LDAPControl **sctrls,
209 1.1 christos LDAPControl **cctrls,
210 1.1 christos int *msgidp)
211 1.1 christos {
212 1.1 christos int rc;
213 1.1 christos BerElement *ber;
214 1.1 christos struct berval reqdata;
215 1.1 christos
216 1.1 christos assert(ld != NULL);
217 1.1 christos assert(LDAP_VALID(ld));
218 1.1 christos assert(msgidp != NULL);
219 1.1 christos
220 1.1 christos ber = ber_alloc_t(LBER_USE_DER);
221 1.1 christos if (dn == NULL) dn = "";
222 1.1 christos
223 1.1 christos if (mechanism == LDAP_SASL_SIMPLE) {
224 1.1 christos assert(!cookie);
225 1.1 christos
226 1.1 christos rc = ber_printf(ber, "{stO" /*"}"*/,
227 1.1 christos dn, LDAP_AUTH_SIMPLE, cred);
228 1.1 christos
229 1.1 christos } else {
230 1.1 christos if (!cred || BER_BVISNULL(cred)) {
231 1.1 christos if (cookie) {
232 1.1 christos rc = ber_printf(ber, "{tOst{sN}" /*"}"*/,
233 1.1 christos LDAP_TAG_EXOP_VERIFY_CREDENTIALS_COOKIE, cookie,
234 1.1 christos dn, LDAP_AUTH_SASL, mechanism);
235 1.1 christos } else {
236 1.1 christos rc = ber_printf(ber, "{st{sN}N" /*"}"*/,
237 1.1 christos dn, LDAP_AUTH_SASL, mechanism);
238 1.1 christos }
239 1.1 christos } else {
240 1.1 christos if (cookie) {
241 1.1 christos rc = ber_printf(ber, "{tOst{sON}" /*"}"*/,
242 1.1 christos LDAP_TAG_EXOP_VERIFY_CREDENTIALS_COOKIE, cookie,
243 1.1 christos dn, LDAP_AUTH_SASL, mechanism, cred);
244 1.1 christos } else {
245 1.1 christos rc = ber_printf(ber, "{st{sON}" /*"}"*/,
246 1.1 christos dn, LDAP_AUTH_SASL, mechanism, cred);
247 1.1 christos }
248 1.1 christos }
249 1.1 christos }
250 1.1 christos
251 1.1 christos if (rc < 0) {
252 1.1 christos rc = ld->ld_errno = LDAP_ENCODING_ERROR;
253 1.1 christos goto done;
254 1.1 christos }
255 1.1 christos
256 1.1 christos if (vcctrls && *vcctrls) {
257 1.1 christos LDAPControl *const *c;
258 1.1 christos
259 1.1 christos rc = ber_printf(ber, "t{" /*"}"*/, LDAP_TAG_EXOP_VERIFY_CREDENTIALS_CONTROLS);
260 1.1 christos
261 1.1 christos for (c=vcctrls; *c; c++) {
262 1.1 christos rc = ldap_pvt_put_control(*c, ber);
263 1.1 christos if (rc != LDAP_SUCCESS) {
264 1.1 christos rc = ld->ld_errno = LDAP_ENCODING_ERROR;
265 1.1 christos goto done;
266 1.1 christos }
267 1.1 christos }
268 1.1 christos
269 1.1 christos rc = ber_printf(ber, /*"{{"*/ "}N}");
270 1.1 christos
271 1.1 christos } else {
272 1.1 christos rc = ber_printf(ber, /*"{"*/ "N}");
273 1.1 christos }
274 1.1 christos
275 1.1 christos if (rc < 0) {
276 1.1 christos rc = ld->ld_errno = LDAP_ENCODING_ERROR;
277 1.1 christos goto done;
278 1.1 christos }
279 1.1 christos
280 1.1 christos
281 1.1 christos rc = ber_flatten2(ber, &reqdata, 0);
282 1.1 christos if (rc < 0) {
283 1.1 christos rc = ld->ld_errno = LDAP_ENCODING_ERROR;
284 1.1 christos goto done;
285 1.1 christos }
286 1.1 christos
287 1.1 christos rc = ldap_extended_operation(ld, LDAP_EXOP_VERIFY_CREDENTIALS,
288 1.1 christos &reqdata, sctrls, cctrls, msgidp);
289 1.1 christos
290 1.1 christos done:
291 1.1 christos ber_free(ber, 1);
292 1.1 christos return rc;
293 1.1 christos }
294 1.1 christos
295 1.1 christos int
296 1.1 christos ldap_verify_credentials_s(
297 1.1 christos LDAP *ld,
298 1.1 christos struct berval *cookie,
299 1.1 christos LDAP_CONST char *dn,
300 1.1 christos LDAP_CONST char *mechanism,
301 1.1 christos struct berval *cred,
302 1.1 christos LDAPControl **vcictrls,
303 1.1 christos LDAPControl **sctrls,
304 1.1 christos LDAPControl **cctrls,
305 1.1 christos int *rcode,
306 1.1 christos char **diagmsg,
307 1.1 christos struct berval **scookie,
308 1.1 christos struct berval **scred,
309 1.1 christos LDAPControl ***vcoctrls)
310 1.1 christos {
311 1.1 christos int rc;
312 1.1 christos int msgid;
313 1.1 christos LDAPMessage *res;
314 1.1 christos
315 1.1 christos rc = ldap_verify_credentials(ld, cookie, dn, mechanism, cred, vcictrls, sctrls, cctrls, &msgid);
316 1.1 christos if (rc != LDAP_SUCCESS) return rc;
317 1.1 christos
318 1.1 christos if (ldap_result(ld, msgid, LDAP_MSG_ALL, (struct timeval *) NULL, &res) == -1 || !res) {
319 1.1 christos return ld->ld_errno;
320 1.1 christos }
321 1.1 christos
322 1.1 christos rc = ldap_parse_verify_credentials(ld, res, rcode, diagmsg, scookie, scred, vcoctrls);
323 1.1 christos if (rc != LDAP_SUCCESS) {
324 1.1 christos ldap_msgfree(res);
325 1.1 christos return rc;
326 1.1 christos }
327 1.1 christos
328 1.1 christos return( ldap_result2error(ld, res, 1));
329 1.1 christos }
330 1.1 christos
331 1.1 christos #ifdef LDAP_API_FEATURE_VERIFY_CREDENTIALS_INTERACTIVE
332 1.1 christos int
333 1.1 christos ldap_verify_credentials_interactive (
334 1.1 christos LDAP *ld,
335 1.1 christos LDAP_CONST char *dn, /* usually NULL */
336 1.1 christos LDAP_CONST char *mech,
337 1.1 christos LDAPControl **vcControls,
338 1.1 christos LDAPControl **serverControls,
339 1.1 christos LDAPControl **clientControls,
340 1.1 christos
341 1.1 christos /* should be client controls */
342 1.1 christos unsigned flags,
343 1.1 christos LDAP_SASL_INTERACT_PROC *proc,
344 1.1 christos void *defaults,
345 1.1 christos void *context;
346 1.1 christos
347 1.1 christos /* as obtained from ldap_result() */
348 1.1 christos LDAPMessage *result,
349 1.1 christos
350 1.1 christos /* returned during bind processing */
351 1.1 christos const char **rmech,
352 1.1 christos int *msgid )
353 1.1 christos {
354 1.1 christos if (!ld && context) {
355 1.1 christos assert(!dn);
356 1.1 christos assert(!mech);
357 1.1 christos assert(!vcControls);
358 1.1 christos assert(!serverControls);
359 1.1 christos assert(!defaults);
360 1.1 christos assert(!result);
361 1.1 christos assert(!rmech);
362 1.1 christos assert(!msgid);
363 1.1 christos
364 1.1 christos /* special case to avoid having to expose a separate dispose context API */
365 1.1 christos sasl_dispose((sasl_conn_t)context);
366 1.1 christos return LDAP_SUCCESS;
367 1.1 christos }
368 1.1 christos
369 1.1 christos ld->ld_errno = LDAP_NOT_SUPPORTED;
370 1.1 christos return ld->ld_errno;
371 1.1 christos }
372 1.1 christos #endif
373