]> git.sur5r.net Git - openldap/blob - clients/ud/auth.c
Exit loop after matching command is found in openldap_ldap_init_w_conf
[openldap] / clients / ud / auth.c
1 /* $OpenLDAP$ */
2 /*
3  * Copyright 1998-1999 The OpenLDAP Foundation, All Rights Reserved.
4  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
5  */
6 /*
7  * Copyright (c) 1991, 1992 Regents of the University of Michigan.
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms are permitted
11  * provided that this notice is preserved and that due credit is given
12  * to the University of Michigan at Ann Arbor. The name of the University
13  * may not be used to endorse or promote products derived from this
14  * software without specific prior written permission. This software
15  * is provided ``as is'' without express or implied warranty.
16  */
17
18 #include "portable.h"
19
20 #include <stdio.h>
21
22 #include <ac/stdlib.h>
23
24 #include <ac/ctype.h>
25 #include <ac/krb.h>
26 #include <ac/string.h>
27 #include <ac/time.h>
28 #include <ac/unistd.h>
29
30 #ifdef HAVE_PWD_H
31 #include <pwd.h>
32 #endif
33
34 #include <lber.h>
35 #include <ldap.h>
36
37 #include "ldap_defaults.h"
38 #include "ud.h"
39
40 #ifdef LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND
41 static char tktpath[20];        /* ticket file path */
42 static int kinit();
43 static int valid_tgt();
44 #endif
45
46 static void set_bound_dn(char *s);
47
48
49 int
50 auth( char *who, int implicit )
51 {
52         int rc;                 /* return code from ldap_bind() */
53         char *passwd = NULL;    /* returned by getpass() */
54         char **rdns;            /* for fiddling with the DN */
55         int authmethod;
56         int name_provided;      /* was a name passed in? */
57 #ifdef HAVE_GETPWUID
58         struct passwd *pw;      /* for getting user id */
59 #else
60         char *user;
61 #endif
62         char uidname[20];
63 #ifdef LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND
64         char **krbnames;        /* for kerberos names */
65         int kinited, ikrb;
66         char buf[5];
67         extern int krb_debug;
68 #endif
69         LDAPMessage *mp;        /* returned from find() */
70         static char prompt[MED_BUF_SIZE];       /* place for us to sprintf the prompt */
71         static char name[MED_BUF_SIZE]; /* place to store the user's name */
72         static char password[MED_BUF_SIZE];     /* password entered by user */
73
74 #ifdef DEBUG
75         if (debug & D_TRACE)
76                 fprintf(stderr, "auth(%s, NULL)\n", who);
77 #endif
78         name_provided = ( who != NULL );
79
80         /*
81          *  The user needs to bind.  If <who> is not specified, we
82          *  assume that authenticating as user id is what user wants.
83          */
84         if (who == NULL && implicit) {
85                 uidname[0] = '\0';
86
87 #ifdef HAVE_GETPWUID
88                 if ((pw = getpwuid((uid_t)geteuid())) != (struct passwd *) NULL) {
89                         sprintf(uidname, "uid=%s", pw->pw_name);
90                 }
91 #else
92                 user = getenv("USER");
93                 if(user == NULL) user = getenv("USERNAME");
94                 if(user == NULL) user = getenv("LOGNAME");
95
96                 if(user != NULL) {
97                         sprintf(uidname, "uid=%s", user);
98                 }
99 #endif
100
101                 if(uidname[0] != '\0') {
102                         who = uidname;
103                 }
104         }
105
106         if ( who == NULL ) {
107                 if ( implicit )
108                         printf( "You must first authenticate yourself to the Directory.\n" );
109 #ifdef UOFM
110                 printf("  What is your name or uniqname? ");
111 #else
112                 printf("  What is your name or user id? ");
113 #endif
114                 fflush(stdout);
115                 fetch_buffer(name, sizeof(name), stdin);
116                 if (name[0] == '\0')
117                         return( -1 );
118                 who = name;
119         }
120
121 #ifdef DEBUG
122         if (debug & D_AUTHENTICAT)
123                 printf("  Authenticating as \"%s\"\n", who);
124 #endif
125
126         /*
127          *  Bail out if the name is bogus.  If not, strip off the junk
128          *  at the start of the DN, build a prompt, and get a password 
129          *  from the user.  Then perform the ldap_bind().
130          */
131         if ((mp = find(who, TRUE)) == NULL) {
132                 printf("  I could not find \"%s\" in the Directory.\n", who);
133                 printf("  I used a search base of ");
134                 printbase("", search_base);
135                 printf("\n");
136 #ifdef DEBUG
137                 if (debug & D_AUTHENTICAT)
138                         printf("  Could not find \"%s\"\n", who);
139 #endif
140                 return(-1);
141         }
142
143         /*
144          *  Fill in the Entry structure.  May be handy later.
145          */
146         (void) parse_answer(mp);
147
148         rdns = ldap_explode_dn(Entry.DN, TRUE);
149         printf("  Authenticating to the directory as \"%s\"...\n", *rdns );
150
151 #ifdef LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND
152         /*
153          * First, if the user has a choice of auth methods, ask which
154          * one they want to use.  if they want kerberos, ask which
155          * krbname they want to bind as.
156          */
157
158         if ( (krbnames = ldap_get_values( ld, mp, "krbName" )) != NULL ) {
159                 int     choice, hassimple;
160
161                 hassimple = (ldap_compare_s( ld, Entry.DN, 
162                                 "userPassword", "x" ) == LDAP_COMPARE_FALSE);
163                 (void) ldap_msgfree(mp);
164
165                 /* if we're running as a server (e.g., out of inetd) */
166                 if ( ! isatty( 1 ) ) {
167                         strcpy( tktpath, "/tmp/ud_tktXXXXXX" );
168                         mktemp( tktpath );
169                         krb_set_tkt_string( tktpath );
170                 }
171
172                 kinited = valid_tgt( krbnames );
173
174                 if ( hassimple && !kinited ) {
175                         printf("  Which password would you like to use?\n");
176                         printf("    1 -> LDAP password\n");
177 #ifdef UOFM
178                         printf("    2 -> UMICH password (aka Uniqname or Kerberos password)\n");
179 #else
180                         printf("    2 -> Kerberos password\n");
181 #endif
182
183                         do {
184                                 printf("  Enter 1 or 2: ");
185                                 fflush(stdout);
186
187                                 fetch_buffer(buf, sizeof(buf), stdin);
188                                 choice = atoi(buf);
189                         } while (choice != 1 && choice != 2);
190
191                         authmethod = (choice == 1 ? LDAP_AUTH_SIMPLE :
192                             LDAP_AUTH_KRBV4);
193                 } else {
194                         authmethod = LDAP_AUTH_KRBV4;
195                 }
196         } else {
197                 authmethod = LDAP_AUTH_SIMPLE;
198                 (void) ldap_msgfree(mp);
199         }
200
201         /*
202          * if they are already kinited, we don't need to ask for a 
203          * password.
204          */
205
206         if ( authmethod == LDAP_AUTH_KRBV4 ) {
207                 if ( ! kinited ) {
208                         if ( krbnames[1] != NULL ) {
209                                 int     i;
210
211                                 /* ask which one to use */
212 #ifdef UOFM
213                                 printf("  Which UMICH (aka Kerberos or uniqname) name would you like to use?\n");
214 #else
215                                 printf("  Which Kerberos name would you like to use?\n");
216 #endif
217                                 for ( i = 0; krbnames[i] != NULL; i++ ) {
218                                         printf( "    %d -> %s\n", i + 1,
219                                             krbnames[i] );
220                                 }
221                                 do {
222                                         printf("  Enter a number between 1 and %d: ", i );
223                                         fflush( stdout );
224
225                                         fetch_buffer(buf, sizeof(buf), stdin);
226                                         ikrb = atoi(buf) - 1;
227                                 } while ( ikrb > i - 1 || ikrb < 0 );
228                         } else {
229                                 ikrb = 0;
230                         }
231
232                         /* kinit */
233                         if ( kinit( krbnames[ikrb] ) != 0 ) {
234                                 (void) ldap_value_free(rdns);
235                                 (void) ldap_value_free(krbnames);
236                                 return(-1);
237                         }
238                 }
239         } else {
240 #endif
241                 authmethod = LDAP_AUTH_SIMPLE;
242                 sprintf(prompt, "  Enter your LDAP password: ");
243                 do {
244                         passwd = getpass(prompt);
245                 } while (passwd != NULL && *passwd == '\0');
246                 if (passwd == NULL) {
247                         (void) ldap_value_free(rdns);
248                         return(0);
249                 }
250 #ifdef LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND
251         }
252         (void) ldap_value_free(krbnames);
253 #endif
254         ldap_flush_cache( ld );
255         rc = ldap_bind_s(ld, Entry.DN, passwd, authmethod);
256         if (rc != LDAP_SUCCESS) {
257                 int ld_errno;
258                 ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &ld_errno);
259                 if (ld_errno == LDAP_NO_SUCH_ATTRIBUTE)
260                         fprintf(stderr, "  Entry has no password\n");
261                 else if (ld_errno == LDAP_INVALID_CREDENTIALS)
262 #ifdef LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND
263                         if ( authmethod == LDAP_AUTH_KRBV4 ) {
264                                 fprintf(stderr, "  The Kerberos credentials are invalid.\n");
265                         } else {
266 #endif
267                                 fprintf(stderr, "  The password you provided is incorrect.\n");
268 #ifdef LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND
269                         }
270 #endif
271                 else
272                         ldap_perror(ld, "ldap_bind_s" );
273                 (void) ldap_bind_s(ld, default_bind_object,
274                          (char *) NULL, LDAP_AUTH_SIMPLE);
275                 if (default_bind_object == NULL)
276                         set_bound_dn(NULL);
277                 else
278                         set_bound_dn(default_bind_object);
279                 bind_status = UD_NOT_BOUND;
280                 if (verbose)
281                         printf("  Authentication failed.\n\n");
282                 (void) ldap_value_free(rdns);
283                 return(-1);
284         }
285         else if (verbose)
286                 printf("  Authentication successful.\n\n");
287         else
288                 printf("\n");
289         set_bound_dn(Entry.DN);
290         bind_status = UD_BOUND;
291         if (passwd != NULL)
292                 (void) strcpy(password, passwd);
293         (void) ldap_value_free(rdns);
294         return(0);
295 }
296
297 #ifdef LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND
298
299 #define FIVEMINS        ( 5 * 60 )
300 #define TGT             "krbtgt"
301
302 static int
303 valid_tgt( char **names )
304 {
305         int             i;
306         char            name[ ANAME_SZ ], inst[ INST_SZ ], realm[ REALM_SZ ];
307         CREDENTIALS     cred;
308
309         for ( i = 0; names[i] != NULL; i++ ) {
310                 if ( kname_parse( name, inst, realm, names[i] ) != KSUCCESS ) {
311                         fprintf( stderr, "Bad format for krbName %s\n",
312                             names[i] );
313                         fprintf( stderr, "Contact x500@umich.edu\n" );
314                         return( 0 );
315                 }
316
317 #ifdef HAVE_AFS_KERBEROS
318                 /*
319                  * realm must be uppercase for krb_ routines
320                  */
321                 ldap_pvt_str2upper( realm );
322 #endif /* HAVE_AFS_KERBEROS */
323
324                 /*
325                 * check ticket file for a valid ticket granting ticket
326                 * my check is: have ticket granting ticket and it is good for
327                 * at least 5 more minutes
328                 */
329                 if ( krb_get_cred( TGT, realm, realm,
330                     &cred ) == KSUCCESS && time( 0 ) + FIVEMINS <
331                     cred.issue_date + (u_char)cred.lifetime * FIVEMINS ) {
332                         return( 1 );
333                 }
334         }
335
336         return( 0 );
337 }
338
339 static char *kauth_name;
340
341 #ifndef HAVE_KTH_KERBEROS
342
343 /*ARGSUSED*/
344 int
345 krbgetpass( char *user, char *inst, char *realm, char *pw, C_Block key )
346 {
347         char    *p, lcrealm[ REALM_SZ ], prompt[256], *passwd;
348
349 #ifdef UOFM
350         sprintf(prompt, "  Enter the UMICH password (same as Uniqname or Kerberos password)\n  for %s: ", kauth_name );
351 #else
352         sprintf(prompt, "  Enter Kerberos password for %s: ", kauth_name );
353 #endif
354         do {
355                 passwd = getpass(prompt);
356         } while (passwd != NULL && *passwd == '\0');
357         if (passwd == NULL) {
358                 return(-1);
359         }
360
361 #ifdef HAVE_AFS_KERBEROS
362         strcpy( lcrealm, realm );
363         for ( p = lcrealm; *p != '\0'; ++p ) {
364                 *p = TOLOWER( (unsigned char) *p );
365         }
366
367         ka_StringToKey( passwd, lcrealm, key );
368 #else /* HAVE_AFS_KERBEROS */
369         string_to_key( passwd, key );
370 #endif /* HAVE_AFS_KERBEROS */
371
372         return( 0 );
373 }
374 #endif /* HAVE_KTH_KERBEROS */
375
376 static int
377 kinit( char *kname )
378 {
379         int     rc;
380         char    name[ ANAME_SZ ], inst[ INST_SZ ], realm[ REALM_SZ ];
381
382         kauth_name = kname;
383
384         if ( kname_parse( name, inst, realm, kname ) != KSUCCESS ) {
385                 fprintf( stderr, "Bad format for krbName %s\n",
386                     kname );
387                 fprintf( stderr, "Contact x500@umich.edu\n" );
388                 return( -1 );
389         }
390
391 #ifdef HAVE_AFS_KERBEROS
392         /* realm must be uppercase for AFS krb_ routines */
393         ldap_pvt_str2upper( realm );
394 #endif /* HAVE_AFS_KERBEROS */
395
396 #ifdef HAVE_KTH_KERBEROS
397         /* Kth kerberos knows how to do both string to keys */
398         rc = krb_get_pw_in_tkt( name, inst, realm, TGT, realm,
399                 DEFAULT_TKT_LIFE, 0 );
400 #else
401         rc = krb_get_in_tkt( name, inst, realm, TGT, realm,
402             DEFAULT_TKT_LIFE, krbgetpass, NULL, NULL );
403 #endif
404
405         if ( rc != KSUCCESS ) {
406                 switch ( rc ) {
407                 case SKDC_CANT:
408                         fprintf( stderr, "Can't contact Kerberos server for %s\n", realm );
409                         break;
410                 default:
411                         fprintf( stderr, "%s: %s\n", name, krb_err_txt[ rc ] );
412                         break;
413                 }
414                 return( -1 );
415         }
416
417         return( 0 );
418 }
419
420 void
421 destroy_tickets( void )
422 {
423         if ( *tktpath != '\0' ) {
424                 unlink( tktpath );
425         }
426 }
427 #endif
428
429 static void
430 set_bound_dn( char *s )
431 {
432         if (bound_dn != NULL)
433                 Free(bound_dn);
434         bound_dn = (s == NULL) ? NULL : strdup(s);
435 }