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