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