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