1 /* $NetBSD: ldapvc.c,v 1.2 2021/08/14 16:14:49 christos Exp $ */
2
3 /* ldapvc.c -- a tool for verifying credentials */
4 /* $OpenLDAP$ */
5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
6 *
7 * Copyright 1998-2021 The OpenLDAP Foundation.
8 * Portions Copyright 2010 Kurt D. Zeilenga.
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted only as authorized by the OpenLDAP
13 * Public License.
14 *
15 * A copy of this license is available in the file LICENSE in the
16 * top-level directory of the distribution or, alternatively, at
17 * <http://www.OpenLDAP.org/license.html>.
18 */
19 /* Portions Copyright (c) 1992-1996 Regents of the University of Michigan.
20 * All rights reserved.
21 *
22 * Redistribution and use in source and binary forms are permitted
23 * provided that this notice is preserved and that due credit is given
24 * to the University of Michigan at Ann Arbor. The name of the
25 * University may not be used to endorse or promote products derived
26 * from this software without specific prior written permission. This
27 * software is provided ``as is'' without express or implied warranty.
28 */
29 /* ACKNOWLEDGEMENTS:
30 * This work was originally developed by Kurt D. Zeilenga for inclusion
31 * in OpenLDAP Software based, in part, on other client tools.
32 */
33
34 #include <sys/cdefs.h>
35 __RCSID("$NetBSD: ldapvc.c,v 1.2 2021/08/14 16:14:49 christos Exp $");
36
37 #include "portable.h"
38
39 #include <stdio.h>
40
41 #include <ac/stdlib.h>
42
43 #include <ac/ctype.h>
44 #include <ac/socket.h>
45 #include <ac/string.h>
46 #include <ac/time.h>
47 #include <ac/unistd.h>
48
49 #include <ldap.h>
50 #include "lutil.h"
51 #include "lutil_ldap.h"
52 #include "ldap_defaults.h"
53
54 #include "common.h"
55
56 static int req_authzid = 0;
57 static int req_pp = 0;
58
59 #if defined(LDAP_API_FEATURES_VERIFY_CREDENTIALS_INTERACTIVE) && defined(HAVE_CYRUS_SASL)
60 #define LDAP_SASL_NONE (~0U)
61 static unsigned vc_sasl = LDAP_SASL_NONE;
62 static char *vc_sasl_realm = NULL;
63 static char *vc_sasl_authcid = NULL;
64 static char *vc_sasl_authzid = NULL;
65 static char *vc_sasl_mech = NULL;
66 static char *vc_sasl_secprops = NULL;
67 #endif
68 static char * dn = NULL;
69 static struct berval cred = {0, NULL};
70
71 void
usage(void)72 usage( void )
73 {
74 fprintf( stderr, _("Issue LDAP Verify Credentials operation to verify a user's credentials\n\n"));
75 fprintf( stderr, _("usage: %s [options] [DN [cred]])\n"), prog);
76 fprintf( stderr, _("where:\n"));
77 fprintf( stderr, _(" DN\tDistinguished Name\n"));
78 fprintf( stderr, _(" cred\tCredentials (prompt if not present)\n"));
79 fprintf( stderr, _("options:\n"));
80 fprintf( stderr, _(" -a\tRequest AuthzId\n"));
81 fprintf( stderr, _(" -b\tRequest Password Policy Information\n"));
82 fprintf( stderr, _(" -E sasl=(a[utomatic]|i[nteractive]|q[uiet]>\tSASL mode (defaults to automatic if any other -E option provided, otherwise none))\n"));
83 fprintf( stderr, _(" -E mech=<mech>\tSASL mechanism (default "" e.g. Simple)\n"));
84 fprintf( stderr, _(" -E realm=<realm>\tSASL Realm (defaults to none)\n"));
85 fprintf( stderr, _(" -E authcid=<authcid>\tSASL Authentication Identity (defaults to USER)\n"));
86 fprintf( stderr, _(" -E authzid=<authzid>\tSASL Authorization Identity (defaults to none)\n"));
87 fprintf( stderr, _(" -E secprops=<secprops>\tSASL Security Properties (defaults to none)\n"));
88 tool_common_usage();
89 exit( EXIT_FAILURE );
90 }
91
92
93 const char options[] = "abE:"
94 "d:D:e:h:H:InNO:o:p:QR:U:vVw:WxX:y:Y:Z";
95
96 int
handle_private_option(int i)97 handle_private_option( int i )
98 {
99 switch ( i ) {
100 char *control, *cvalue;
101 case 'E': /* vc extension */
102 if( protocol == LDAP_VERSION2 ) {
103 fprintf( stderr, _("%s: -E incompatible with LDAPv%d\n"),
104 prog, protocol );
105 exit( EXIT_FAILURE );
106 }
107
108 /* should be extended to support comma separated list of
109 * [!]key[=value] parameters, e.g. -E !foo,bar=567
110 */
111
112 cvalue = NULL;
113 if( optarg[0] == '!' ) {
114 optarg++;
115 }
116
117 control = optarg;
118 if ( (cvalue = strchr( control, '=' )) != NULL ) {
119 *cvalue++ = '\0';
120 }
121
122 if (strcasecmp(control, "sasl") == 0) {
123 #if defined(LDAP_API_FEATURES_VERIFY_CREDENTIALS_INTERACTIVE) && defined(HAVE_CYRUS_SASL)
124 if (vc_sasl != LDAP_SASL_NONE) {
125 fprintf(stderr,
126 _("SASL option previously specified\n"));
127 exit(EXIT_FAILURE);
128 }
129 if (cvalue == NULL) {
130 fprintf(stderr,
131 _("missing mode in SASL option\n"));
132 exit(EXIT_FAILURE);
133 }
134
135 switch (*cvalue) {
136 case 'a':
137 case 'A':
138 vc_sasl = LDAP_SASL_AUTOMATIC;
139 break;
140 case 'i':
141 case 'I':
142 vc_sasl = LDAP_SASL_INTERACTIVE;
143 break;
144 case 'q':
145 case 'Q':
146 vc_sasl = LDAP_SASL_QUIET;
147 break;
148 default:
149 fprintf(stderr,
150 _("unknown mode %s in SASL option\n"), cvalue);
151 exit(EXIT_FAILURE);
152 }
153 #else
154 fprintf(stderr,
155 _("%s: not compiled with SASL support\n"), prog);
156 exit(EXIT_FAILURE);
157 #endif
158
159 } else if (strcasecmp(control, "mech") == 0) {
160 #if defined(LDAP_API_FEATURES_VERIFY_CREDENTIALS_INTERACTIVE) && defined(HAVE_CYRUS_SASL)
161 if (vc_sasl_mech) {
162 fprintf(stderr,
163 _("SASL mech previously specified\n"));
164 exit(EXIT_FAILURE);
165 }
166 if (cvalue == NULL) {
167 fprintf(stderr,
168 _("missing mech in SASL option\n"));
169 exit(EXIT_FAILURE);
170 }
171
172 vc_sasl_mech = ber_strdup(cvalue);
173 #else
174 #endif
175
176 } else if (strcasecmp(control, "realm") == 0) {
177 #if defined(LDAP_API_FEATURES_VERIFY_CREDENTIALS_INTERACTIVE) && defined(HAVE_CYRUS_SASL)
178 if (vc_sasl_realm) {
179 fprintf(stderr,
180 _("SASL realm previously specified\n"));
181 exit(EXIT_FAILURE);
182 }
183 if (cvalue == NULL) {
184 fprintf(stderr,
185 _("missing realm in SASL option\n"));
186 exit(EXIT_FAILURE);
187 }
188
189 vc_sasl_realm = ber_strdup(cvalue);
190 #else
191 fprintf(stderr,
192 _("%s: not compiled with SASL support\n"), prog);
193 exit(EXIT_FAILURE);
194 #endif
195
196 } else if (strcasecmp(control, "authcid") == 0) {
197 #if defined(LDAP_API_FEATURES_VERIFY_CREDENTIALS_INTERACTIVE) && defined(HAVE_CYRUS_SASL)
198 if (vc_sasl_authcid) {
199 fprintf(stderr,
200 _("SASL authcid previously specified\n"));
201 exit(EXIT_FAILURE);
202 }
203 if (cvalue == NULL) {
204 fprintf(stderr,
205 _("missing authcid in SASL option\n"));
206 exit(EXIT_FAILURE);
207 }
208
209 vc_sasl_authcid = ber_strdup(cvalue);
210 #else
211 fprintf(stderr,
212 _("%s: not compiled with SASL support\n"), prog);
213 exit(EXIT_FAILURE);
214 #endif
215
216 } else if (strcasecmp(control, "authzid") == 0) {
217 #if defined(LDAP_API_FEATURES_VERIFY_CREDENTIALS_INTERACTIVE) && defined(HAVE_CYRUS_SASL)
218 if (vc_sasl_authzid) {
219 fprintf(stderr,
220 _("SASL authzid previously specified\n"));
221 exit(EXIT_FAILURE);
222 }
223 if (cvalue == NULL) {
224 fprintf(stderr,
225 _("missing authzid in SASL option\n"));
226 exit(EXIT_FAILURE);
227 }
228
229 vc_sasl_authzid = ber_strdup(cvalue);
230 #else
231 fprintf(stderr,
232 _("%s: not compiled with SASL support\n"), prog);
233 exit(EXIT_FAILURE);
234 #endif
235
236 } else if (strcasecmp(control, "secprops") == 0) {
237 #if defined(LDAP_API_FEATURES_VERIFY_CREDENTIALS_INTERACTIVE) && defined(HAVE_CYRUS_SASL)
238 if (vc_sasl_secprops) {
239 fprintf(stderr,
240 _("SASL secprops previously specified\n"));
241 exit(EXIT_FAILURE);
242 }
243 if (cvalue == NULL) {
244 fprintf(stderr,
245 _("missing secprops in SASL option\n"));
246 exit(EXIT_FAILURE);
247 }
248
249 vc_sasl_secprops = ber_strdup(cvalue);
250 #else
251 fprintf(stderr,
252 _("%s: not compiled with SASL support\n"), prog);
253 exit(EXIT_FAILURE);
254 #endif
255
256 } else {
257 fprintf( stderr, _("Invalid Verify Credentials extension name: %s\n"), control );
258 usage();
259 }
260 break;
261
262 case 'a': /* request authzid */
263 req_authzid++;
264 break;
265
266 case 'b': /* request authzid */
267 req_pp++;
268 break;
269
270 default:
271 return 0;
272 }
273 return 1;
274 }
275
276
277 int
main(int argc,char * argv[])278 main( int argc, char *argv[] )
279 {
280 int rc;
281 LDAP *ld = NULL;
282 char *matcheddn = NULL, *text = NULL, **refs = NULL;
283 int rcode;
284 char * diag = NULL;
285 struct berval *scookie = NULL;
286 struct berval *scred = NULL;
287 int id, code = 0;
288 LDAPMessage *res;
289 LDAPControl **ctrls = NULL;
290 LDAPControl **vcctrls = NULL;
291 int nvcctrls = 0;
292
293 tool_init( TOOL_VC );
294 prog = lutil_progname( "ldapvc", argc, argv );
295
296 /* LDAPv3 only */
297 protocol = LDAP_VERSION3;
298
299 tool_args( argc, argv );
300
301 if (argc - optind > 0) {
302 dn = argv[optind++];
303 }
304 if (argc - optind > 0) {
305 cred.bv_val = strdup(argv[optind++]);
306 cred.bv_len = strlen(cred.bv_val);
307 }
308 if (argc - optind > 0) {
309 usage();
310 }
311 if (dn
312 #ifdef LDAP_API_FEATURE_VERIFY_CREDENTIALS_INTERACTIVE
313 && !vc_sasl_mech
314 #endif
315 && !cred.bv_val)
316 {
317 cred.bv_val = strdup(getpassphrase(_("User's password: ")));
318 cred.bv_len = strlen(cred.bv_val);
319 }
320
321 #ifdef LDAP_API_FEATURE_VERIFY_CREDENTIALS_INTERACTIVE
322 if (vc_sasl_mech && (vc_sasl == LDAP_SASL_NONE)) {
323 vc_sasl = LDAP_SASL_AUTOMATIC;
324 }
325 #endif
326
327 ld = tool_conn_setup( 0, 0 );
328
329 tool_bind( ld );
330
331 if ( dont ) {
332 rc = LDAP_SUCCESS;
333 goto skip;
334 }
335
336 tool_server_controls( ld, NULL, 0 );
337
338 if (req_authzid) {
339 vcctrls = (LDAPControl **) malloc(3*sizeof(LDAPControl *));
340 vcctrls[nvcctrls] = (LDAPControl *) malloc(sizeof(LDAPControl));
341 vcctrls[nvcctrls]->ldctl_oid = ldap_strdup(LDAP_CONTROL_AUTHZID_REQUEST);
342 vcctrls[nvcctrls]->ldctl_iscritical = 0;
343 vcctrls[nvcctrls]->ldctl_value.bv_val = NULL;
344 vcctrls[nvcctrls]->ldctl_value.bv_len = 0;
345 vcctrls[++nvcctrls] = NULL;
346 }
347
348 if (req_pp) {
349 if (!vcctrls) vcctrls = (LDAPControl **) malloc(3*sizeof(LDAPControl *));
350 vcctrls[nvcctrls] = (LDAPControl *) malloc(sizeof(LDAPControl));
351 vcctrls[nvcctrls]->ldctl_oid = ldap_strdup(LDAP_CONTROL_PASSWORDPOLICYREQUEST);
352 vcctrls[nvcctrls]->ldctl_iscritical = 0;
353 vcctrls[nvcctrls]->ldctl_value.bv_val = NULL;
354 vcctrls[nvcctrls]->ldctl_value.bv_len = 0;
355 vcctrls[++nvcctrls] = NULL;
356 }
357
358 #ifdef LDAP_API_FEATURE_VERIFY_CREDENTIALS_INTERACTIVE
359 #ifdef HAVE_CYRUS_SASL
360 if (vc_sasl_mech) {
361 int msgid;
362 void * defaults;
363 void * context = NULL;
364 const char *rmech = NULL;
365
366 defaults = lutil_sasl_defaults(ld,
367 vc_sasl_mech,
368 vc_sasl_realm,
369 vc_sasl_authcid,
370 cred.bv_val,
371 sasl_authz_id);
372
373 do {
374 rc = ldap_verify_credentials_interactive(ld, dn, vc_sasl_mech,
375 vcctrls, NULL, NULL,
376 vc_sasl, lutil_sasl_interact, defaults, context,
377 res, &rmech, &msgid);
378
379 if (rc != LDAP_SASL_BIND_IN_PROGRESS) break;
380
381 ldap_msgfree(res);
382
383 if (ldap_result(ld, msgid, LDAP_MSG_ALL, NULL, &res) == -1 || !res) {
384 ldap_get_option(ld, LDAP_OPT_RESULT_CODE, (void*) &rc);
385 ldap_get_option(ld, LDAP_OPT_DIAGNOSTIC_MESSAGE, (void*) &text);
386 tool_perror( "ldap_verify_credentials_interactive", rc, NULL, NULL, text, NULL);
387 ldap_memfree(text);
388 tool_exit(ld, rc);
389 }
390 } while (rc == LDAP_SASL_BIND_IN_PROGRESS);
391
392 lutil_sasl_freedefs(defaults);
393
394 if( rc != LDAP_SUCCESS ) {
395 ldap_get_option(ld, LDAP_OPT_DIAGNOSTIC_MESSAGE, (void*) &text);
396 tool_perror( "ldap_verify_credentials", rc, NULL, NULL, text, NULL );
397 rc = EXIT_FAILURE;
398 goto skip;
399 }
400
401 } else
402 #endif
403 #endif
404 {
405 rc = ldap_verify_credentials( ld,
406 NULL,
407 dn, NULL, cred.bv_val ? &cred: NULL, vcctrls,
408 NULL, NULL, &id );
409
410 if( rc != LDAP_SUCCESS ) {
411 ldap_get_option(ld, LDAP_OPT_DIAGNOSTIC_MESSAGE, (void*) &text);
412 tool_perror( "ldap_verify_credentials", rc, NULL, NULL, text, NULL );
413 rc = EXIT_FAILURE;
414 goto skip;
415 }
416
417 for ( ; ; ) {
418 struct timeval tv;
419
420 if ( tool_check_abandon( ld, id ) ) {
421 tool_exit( ld, LDAP_CANCELLED );
422 }
423
424 tv.tv_sec = 0;
425 tv.tv_usec = 100000;
426
427 rc = ldap_result( ld, LDAP_RES_ANY, LDAP_MSG_ALL, &tv, &res );
428 if ( rc < 0 ) {
429 tool_perror( "ldap_result", rc, NULL, NULL, NULL, NULL );
430 tool_exit( ld, rc );
431 }
432
433 if ( rc != 0 ) {
434 break;
435 }
436 }
437 }
438
439 ldap_controls_free(vcctrls);
440 vcctrls = NULL;
441
442 rc = ldap_parse_result( ld, res,
443 &code, &matcheddn, &text, &refs, &ctrls, 0 );
444
445 if (rc == LDAP_SUCCESS) rc = code;
446
447 if (rc != LDAP_SUCCESS) {
448 tool_perror( "ldap_parse_result", rc, NULL, matcheddn, text, refs );
449 rc = EXIT_FAILURE;
450 goto skip;
451 }
452
453 rc = ldap_parse_verify_credentials( ld, res, &rcode, &diag, &scookie, &scred, &vcctrls );
454 ldap_msgfree(res);
455
456 if (rc != LDAP_SUCCESS) {
457 tool_perror( "ldap_parse_verify_credentials", rc, NULL, NULL, NULL, NULL );
458 rc = EXIT_FAILURE;
459 goto skip;
460 }
461
462 if (rcode != LDAP_SUCCESS) {
463 printf(_("Failed: %s (%d)\n"), ldap_err2string(rcode), rcode);
464 }
465
466 if (diag && *diag) {
467 printf(_("Diagnostic: %s\n"), diag);
468 }
469
470 if (vcctrls) {
471 tool_print_ctrls( ld, vcctrls );
472 }
473
474 skip:
475 if ( verbose || code != LDAP_SUCCESS ||
476 ( matcheddn && *matcheddn ) || ( text && *text ) || refs || ctrls )
477 {
478 printf( _("Result: %s (%d)\n"), ldap_err2string( code ), code );
479
480 if( text && *text ) {
481 printf( _("Additional info: %s\n"), text );
482 }
483
484 if( matcheddn && *matcheddn ) {
485 printf( _("Matched DN: %s\n"), matcheddn );
486 }
487
488 if( refs ) {
489 int i;
490 for( i=0; refs[i]; i++ ) {
491 printf(_("Referral: %s\n"), refs[i] );
492 }
493 }
494
495 if (ctrls) {
496 tool_print_ctrls( ld, ctrls );
497 ldap_controls_free( ctrls );
498 }
499 }
500
501 ber_memfree( text );
502 ber_memfree( matcheddn );
503 ber_memvfree( (void **) refs );
504 ber_bvfree( scookie );
505 ber_bvfree( scred );
506 ber_memfree( diag );
507 free( cred.bv_val );
508
509 /* disconnect from server */
510 tool_exit( ld, code == LDAP_SUCCESS ? EXIT_SUCCESS : EXIT_FAILURE );
511 }
512