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