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