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