]> git.sur5r.net Git - openldap/blob - clients/tools/ldapvc.c
2ec4cd9c1173acad24a0ca6cae44d543c758b703
[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-2014 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
259         case 'a':  /* request authzid */
260                 req_authzid++;
261                 break;
262
263         case 'b':  /* request authzid */
264                 req_pp++;
265                 break;
266
267         default:
268                 return 0;
269         }
270         return 1;
271 }
272
273
274 int
275 main( int argc, char *argv[] )
276 {
277         int             rc;
278         LDAP            *ld = NULL;
279         char            *matcheddn = NULL, *text = NULL, **refs = NULL;
280         int rcode;
281         char * diag = NULL;
282         struct berval   *scookie = NULL;
283         struct berval   *scred = NULL;
284         int             id, code = 0;
285         LDAPMessage     *res;
286         LDAPControl     **ctrls = NULL;
287         LDAPControl     **vcctrls = NULL;
288         int nvcctrls = 0;
289
290         tool_init( TOOL_VC );
291         prog = lutil_progname( "ldapvc", argc, argv );
292
293         /* LDAPv3 only */
294         protocol = LDAP_VERSION3;
295
296         tool_args( argc, argv );
297
298         if (argc - optind > 0) {
299                 dn = argv[optind++];
300         }
301         if (argc - optind > 0) {
302                 cred.bv_val = strdup(argv[optind++]);
303                 cred.bv_len = strlen(cred.bv_val);
304         }
305         if (argc - optind > 0) {
306                 usage();
307         }
308         if (dn 
309 #ifdef LDAP_API_FEATURE_VERIFY_CREDENTIALS_INTERACTIVE
310            && !vc_sasl_mech 
311 #endif
312            && !cred.bv_val)
313         {
314                 cred.bv_val = strdup(getpassphrase(_("User's password: ")));
315             cred.bv_len = strlen(cred.bv_val);
316         }
317
318 #ifdef LDAP_API_FEATURE_VERIFY_CREDENTIALS_INTERACTIVE
319     if (vc_sasl_mech && (vc_sasl == LDAP_SASL_NONE)) {
320                 vc_sasl = LDAP_SASL_AUTOMATIC;
321         }
322 #endif
323
324         ld = tool_conn_setup( 0, 0 );
325
326         tool_bind( ld );
327
328         if ( dont ) {
329                 rc = LDAP_SUCCESS;
330                 goto skip;
331         }
332
333         tool_server_controls( ld, NULL, 0 );
334
335     if (req_authzid) {
336                 vcctrls = (LDAPControl **) malloc(3*sizeof(LDAPControl *));
337                 vcctrls[nvcctrls] = (LDAPControl *) malloc(sizeof(LDAPControl));
338                 vcctrls[nvcctrls]->ldctl_oid = ldap_strdup(LDAP_CONTROL_AUTHZID_REQUEST);
339                 vcctrls[nvcctrls]->ldctl_iscritical = 0;
340                 vcctrls[nvcctrls]->ldctl_value.bv_val = NULL;
341                 vcctrls[nvcctrls]->ldctl_value.bv_len = 0;
342                 vcctrls[++nvcctrls] = NULL;
343     }
344
345     if (req_pp) {
346                 if (!vcctrls) vcctrls = (LDAPControl **) malloc(3*sizeof(LDAPControl *));
347                 vcctrls[nvcctrls] = (LDAPControl *) malloc(sizeof(LDAPControl));
348                 vcctrls[nvcctrls]->ldctl_oid = ldap_strdup(LDAP_CONTROL_PASSWORDPOLICYREQUEST);
349                 vcctrls[nvcctrls]->ldctl_iscritical = 0;
350                 vcctrls[nvcctrls]->ldctl_value.bv_val = NULL;
351                 vcctrls[nvcctrls]->ldctl_value.bv_len = 0;
352                 vcctrls[++nvcctrls] = NULL;
353     }
354
355 #ifdef LDAP_API_FEATURE_VERIFY_CREDENTIALS_INTERACTIVE
356 #ifdef HAVE_CYRUS_SASL
357     if (vc_sasl_mech) {
358                 int msgid;
359                 void * defaults;
360                 void * context = NULL;
361                 const char *rmech = NULL;
362
363                 defaults = lutil_sasl_defaults(ld,
364                         vc_sasl_mech,
365                         vc_sasl_realm,
366                         vc_sasl_authcid,
367                         cred.bv_val,
368                         sasl_authz_id);
369
370                 do {
371                         rc = ldap_verify_credentials_interactive(ld, dn, vc_sasl_mech,
372                                 vcctrls, NULL, NULL,
373                                 vc_sasl, lutil_sasl_interact, defaults, context,
374                                 res, &rmech, &msgid); 
375
376                         if (rc != LDAP_SASL_BIND_IN_PROGRESS) break;
377
378                         ldap_msgfree(res);
379
380                         if (ldap_result(ld, msgid, LDAP_MSG_ALL, NULL, &res) == -1 || !res) {
381                                 ldap_get_option(ld, LDAP_OPT_RESULT_CODE, (void*) &rc);
382                                 ldap_get_option(ld, LDAP_OPT_DIAGNOSTIC_MESSAGE, (void*) &text);
383                                 tool_perror( "ldap_verify_credentials_interactive", rc, NULL, NULL, text, NULL);
384                                 ldap_memfree(text);
385                                 tool_exit(ld, rc);
386                         }
387                 } while (rc == LDAP_SASL_BIND_IN_PROGRESS);
388
389             lutil_sasl_freedefs(defaults);
390
391             if( rc != LDAP_SUCCESS ) {
392                         ldap_get_option(ld, LDAP_OPT_DIAGNOSTIC_MESSAGE, (void*) &text);
393                     tool_perror( "ldap_verify_credentials", rc, NULL, NULL, text, NULL );
394                     rc = EXIT_FAILURE;
395                     goto skip;
396             }
397
398         } else
399 #endif
400 #endif
401     {
402             rc = ldap_verify_credentials( ld,
403                     NULL,
404                     dn, NULL, cred.bv_val ? &cred: NULL, vcctrls,
405                     NULL, NULL, &id ); 
406     
407             if( rc != LDAP_SUCCESS ) {
408                         ldap_get_option(ld, LDAP_OPT_DIAGNOSTIC_MESSAGE, (void*) &text);
409                     tool_perror( "ldap_verify_credentials", rc, NULL, NULL, text, NULL );
410                     rc = EXIT_FAILURE;
411                     goto skip;
412             }
413
414             for ( ; ; ) {
415                     struct timeval      tv;
416
417                     if ( tool_check_abandon( ld, id ) ) {
418                             tool_exit( ld, LDAP_CANCELLED );
419                     }
420
421                     tv.tv_sec = 0;
422                     tv.tv_usec = 100000;
423
424                     rc = ldap_result( ld, LDAP_RES_ANY, LDAP_MSG_ALL, &tv, &res );
425                     if ( rc < 0 ) {
426                             tool_perror( "ldap_result", rc, NULL, NULL, NULL, NULL );
427                             tool_exit( ld, rc );
428                     }
429
430                     if ( rc != 0 ) {
431                             break;
432                     }
433             }
434         }
435
436         ldap_controls_free(vcctrls);
437         vcctrls = NULL;
438
439         rc = ldap_parse_result( ld, res,
440                 &code, &matcheddn, &text, &refs, &ctrls, 0 );
441
442         if (rc == LDAP_SUCCESS) rc = code;
443
444         if (rc != LDAP_SUCCESS) {
445                 tool_perror( "ldap_parse_result", rc, NULL, matcheddn, text, refs );
446                 rc = EXIT_FAILURE;
447                 goto skip;
448         }
449
450         rc = ldap_parse_verify_credentials( ld, res, &rcode, &diag, &scookie, &scred, &vcctrls );
451         ldap_msgfree(res);
452
453         if (rc != LDAP_SUCCESS) {
454                 tool_perror( "ldap_parse_verify_credentials", rc, NULL, NULL, NULL, NULL );
455                 rc = EXIT_FAILURE;
456                 goto skip;
457         }
458
459         if (rcode != LDAP_SUCCESS) {
460                 printf(_("Failed: %s (%d)\n"), ldap_err2string(rcode), rcode);
461         }
462
463         if (diag && *diag) {
464             printf(_("Diagnostic: %s\n"), diag);
465         }
466
467         if (vcctrls) {
468                 tool_print_ctrls( ld, vcctrls );
469         }
470
471 skip:
472         if ( verbose || code != LDAP_SUCCESS ||
473                 ( matcheddn && *matcheddn ) || ( text && *text ) || refs || ctrls )
474         {
475                 printf( _("Result: %s (%d)\n"), ldap_err2string( code ), code );
476
477                 if( text && *text ) {
478                         printf( _("Additional info: %s\n"), text );
479                 }
480
481                 if( matcheddn && *matcheddn ) {
482                         printf( _("Matched DN: %s\n"), matcheddn );
483                 }
484
485                 if( refs ) {
486                         int i;
487                         for( i=0; refs[i]; i++ ) {
488                                 printf(_("Referral: %s\n"), refs[i] );
489                         }
490                 }
491
492                 if (ctrls) {
493                         tool_print_ctrls( ld, ctrls );
494                         ldap_controls_free( ctrls );
495                 }
496         }
497
498         ber_memfree( text );
499         ber_memfree( matcheddn );
500         ber_memvfree( (void **) refs );
501         ber_bvfree( scookie );
502         ber_bvfree( scred );
503         ber_memfree( diag );
504         free( cred.bv_val );
505
506         /* disconnect from server */
507         tool_exit( ld, code == LDAP_SUCCESS ? EXIT_SUCCESS : EXIT_FAILURE );
508 }