]> arthur.barton.de Git - netatalk.git/blob - etc/uams/uams_krb4/uams_krb4.c
Initial revision
[netatalk.git] / etc / uams / uams_krb4 / uams_krb4.c
1 /*
2  * Copyright (c) 1990,1993 Regents of The University of Michigan.
3  * All Rights Reserved.  See COPYRIGHT.
4  */
5
6
7 #if defined( KRB ) || defined( UAM_AFSKRB )
8 #include <unistd.h>
9 #include <fcntl.h>
10 #include <sys/types.h>
11 #include <sys/time.h>
12 #include <sys/stat.h>
13 #include <sys/socket.h>
14 #include <limits.h>
15 #include <string.h>
16 #include <ctype.h>
17 #include <pwd.h>
18 #include <syslog.h>
19 #include <netinet/in.h>
20 #include <des.h>
21 #include <krb.h>
22 #include <prot.h>
23
24 #include <netatalk/endian.h>
25 #include <atalk/afp.h>
26 #include <atalk/compat.h>
27 #include <atalk/util.h>
28
29 static C_Block                  seskey;
30 static Key_schedule             seskeysched;
31
32 static char             realm[ REALM_SZ ];
33
34 #ifdef UAM_AFSKRB
35 static int              validseskey = 0;
36 static int              logged = 0;
37 static char             *tktfile;
38 static char             instance[ INST_SZ ], name[ ANAME_SZ ];
39 #endif /*UAM_AFSKRB*/
40
41 #ifdef AFS
42 #include <afs/stds.h>
43 #include <rx/rxkad.h>
44 #include <afs/afs.h>
45 #include <afs/venus.h>
46 #include <afs/afsint.h>
47
48 char *ka_LocalCell();
49
50 struct ClearToken {
51     int32_t AuthHandle;
52     char HandShakeKey[8];
53     int32_t ViceId;
54     int32_t BeginTimestamp;
55     int32_t EndTimestamp;
56 };
57 #endif /*AFS*/
58
59
60 #ifdef KRB
61
62 static __inline__ void lcase( p )
63     char        *p;
64 {
65     for (; *p; p++ ) {
66         if ( isupper( *p )) {
67             *p = tolower( *p );
68         }
69     }
70     return;
71 }
72
73 static __inline__ void ucase( p )
74     char        *p;
75 {
76     for (; *p; p++ ) {
77         if ( islower( *p )) {
78             *p = toupper( *p );
79         }
80     }
81     return;
82 }
83
84 #define KRB4CMD_HELO    1
85 #define KRB4RPL_REALM   2
86 #define KRB4WRT_SESS    3
87 #define KRB4RPL_DONE    4
88 #define KRB4RPL_PRINC   5
89 #define KRB4WRT_TOKEN   6
90 #define KRB4WRT_SKIP    7
91 #define KRB4RPL_DONEMUT 8
92
93
94 static int krb4_login(void *obj, struct passwd **uam_pwd,
95                       char *ibuf, int ibuflen,
96                       char *rbuf, int *rbuflen )
97 {
98     char                *p;
99     int                 len;
100
101     *rbuflen = 0;
102     if ( *ibuf != KRB4CMD_HELO ) {
103         syslog( LOG_INFO, "krb4_login: bad command %d", *ibuf );
104         return( AFPERR_NOTAUTH );
105     }
106
107     p = rbuf;
108     if ( krb_get_lrealm( realm, 1 ) != KSUCCESS ) {
109         syslog( LOG_ERR, "krb4_login: can't get local realm!" );
110         return( AFPERR_NOTAUTH );
111     }
112
113     *p++ = KRB4RPL_REALM;
114     *p++ = 1;
115     len = strlen( realm );
116     *p++ = len;
117     strcpy( p, realm );
118     p += len + 1;
119
120 #ifdef AFS
121     if ( setpag() < 0 ) {
122         syslog( LOG_ERR, "krb_login: setpag: %m" );
123         return( AFPERR_BADUAM );
124     }
125 #endif /*AFS*/
126
127     *rbuflen = p - rbuf;
128     return( AFPERR_AUTHCONT );
129 }
130
131 static int krb4_logincont(void *obj, struct passwd **uam_pwd,
132                           char *ibuf, int ibuflen,
133                           char *rbuf, int *rbuflen)
134 {
135     static struct passwd        *pwd;
136     KTEXT_ST            tkt;
137     static AUTH_DAT     ad;
138     int                 rc;
139     u_int16_t           len;
140     char                *p, *username;
141     CREDENTIALS         cr;
142 #ifdef AFS
143     struct ViceIoctl    vi;
144     struct ClearToken   ct;
145 #endif /*AFS*/
146     char                buf[ 1024 ];
147     int                 aint, ulen;
148
149     if (uam_afp_read(obj, rbuf, rbuflen) < 0) /* read in the rest. */
150       return AFPERR_PARAM;
151
152     *rbuflen = 0;
153     if (uam_afpserver_option(obj, UAM_OPTION_USERNAME, &username) < 0)
154       return AFPERR_MISC;
155     
156     if (uam_afpserver_option(obj, UAM_OPTION_USERNAMELEN, &ulen) < 0)
157       return AFPERR_MISC;
158
159     p = rbuf;
160
161     switch ( rc = *p++ ) {
162     case KRB4WRT_SESS :
163         memcpy( &len, p, sizeof( len ));
164         tkt.length = ntohs( len );
165         p += sizeof( short );
166
167         if ( tkt.length <= 0 || tkt.length > MAX_KTXT_LEN ) {
168             return( AFPERR_BADUAM );
169         }
170         memcpy( tkt.dat, p, tkt.length );
171         p += tkt.length;
172
173         if (( rc = krb_rd_req( &tkt, "afpserver", obj->Obj, 0, &ad, "" ))
174                 != RD_AP_OK ) {
175             syslog( LOG_ERR, "krb4_logincont: krb_rd_req: %s",
176                     krb_err_txt[ rc ] );
177             return( AFPERR_BADUAM );
178         }
179
180         syslog( LOG_INFO, "krb4_login: %s.%s@%s", ad.pname, ad.pinst,
181                 ad.prealm );
182         memcpy(realm, ad.prealm, sizeof(realm));
183         memcpy(seskey, ad.session, sizeof( C_Block ));
184         key_sched((C_Block *) seskey, seskeysched );
185
186         strncpy(username, ad.pname, ulen);
187
188         p = rbuf;
189 #ifndef AFS
190         *p = KRB4RPL_DONE;      /* XXX */
191         *rbuflen = 1;
192
193         if (( pwd = uam_getname( ad.pname, strlen(ad.pname) )) == NULL ) {
194             return( AFPERR_PARAM );
195         }
196         *uam_pwd = pwd;
197         return AFP_OK;
198 #else AFS
199         /* get principals */
200         *p++ = KRB4RPL_PRINC;
201         len = strlen( realm );
202         *p++ = len + 1;
203         *p++ = '@';
204         strcpy( p, realm );
205         p += len + 1;
206         *rbuflen = p - rbuf;
207         return( AFPERR_AUTHCONT );
208
209     case KRB4WRT_TOKEN :
210         memcpy( &len, p, sizeof( len ));
211         len = ntohs( len );
212         p += sizeof( len );
213         memcpy( &cr, p, len );
214
215         pcbc_encrypt((C_Block *)&cr, (C_Block *)&cr, len, seskeysched,
216                 seskey, DES_DECRYPT );
217
218         p = buf;
219         cr.ticket_st.length = ntohl( cr.ticket_st.length );
220         memcpy( p, &cr.ticket_st.length, sizeof( int ));
221         p += sizeof( int );
222         memcpy( p, cr.ticket_st.dat, cr.ticket_st.length );
223         p += cr.ticket_st.length;
224
225         ct.AuthHandle = ntohl( cr.kvno );
226         memcpy( ct.HandShakeKey, cr.session, sizeof( cr.session ));
227         ct.ViceId = 0;
228         ct.BeginTimestamp = ntohl( cr.issue_date );
229         ct.EndTimestamp = krb_life_to_time( ntohl( cr.issue_date ),
230                 ntohl( cr.lifetime ));
231
232         aint = sizeof( struct ClearToken );
233         memcpy( p, &aint, sizeof( int ));
234         p += sizeof( int );
235         memcpy( p, &ct, sizeof( struct ClearToken ));
236         p += sizeof( struct ClearToken );
237
238         aint = 0;
239         memcpy( p, &aint, sizeof( int ));
240         p += sizeof( int );
241
242         lcase( realm );
243         strcpy( p, realm );
244         p += strlen( realm ) + 1;
245
246         vi.in = buf;
247         vi.in_size = p - buf;
248         vi.out = buf;
249         vi.out_size = sizeof( buf );
250         if ( pioctl( 0, VIOCSETTOK, &vi, 0 ) < 0 ) {
251             syslog( LOG_ERR, "krb4_logincont: pioctl: %m" );
252             return( AFPERR_BADUAM );
253         }
254         /* FALL THROUGH */
255
256     case KRB4WRT_SKIP :
257         p = rbuf;
258         *p = KRB4RPL_DONE;      /* XXX */
259         *rbuflen = 1;
260
261         if (( pwd = uam_getname( ad.pname, strlen(ad.pname) )) == NULL ) {
262             return( AFPERR_PARAM );
263         }
264         *uam_pwd = pwd;
265         return AFP_OK;
266 #endif /*AFS*/
267
268     default :
269         syslog( LOG_INFO, "krb4_logincont: bad command %d", rc );
270         return( AFPERR_NOTAUTH );
271         break;
272     }
273 }
274
275 #endif /*KRB*/
276
277
278 #ifdef AFS
279 #include <rx/rxkad.h>
280 #include <afs/afsint.h>
281
282 char *ka_LocalCell();
283
284 static void
285 addrealm(realm,cells)
286     char *realm;
287         char ***cells;
288 {
289     char **ptr;
290         int temp;
291
292         ptr= *cells;
293
294     for(;*ptr != 0 ;ptr++)
295         if(!strcmp(realm,*ptr))
296             return;
297
298         temp=ptr- *cells;
299         *cells=(char**)realloc(*cells,((2+temp)*sizeof(char*)));
300         ptr= *cells+temp;
301
302     *ptr=(char*)malloc(strlen(realm)+1);
303     strcpy(*ptr++,realm);
304         *ptr=0;
305     return;
306 }
307
308 static int kcheckuser(pwd,passwd)
309         struct passwd *pwd;
310         char *passwd;
311 {
312         int32_t code;
313         char *instance="";
314         char realm[MAXKTCREALMLEN];
315         char lorealm[MAXKTCREALMLEN];
316         char *cell;
317         Date lifetime=MAXKTCTICKETLIFETIME;
318         int rval;
319         char **cells=(char **)malloc(sizeof(char*));
320         char *temp;
321         int rc,cellNum;
322         struct ktc_principal serviceName;
323
324         *cells=0;
325
326         code = ka_Init(0);
327
328         {
329                 char *temp,*temp1;
330                 temp=(char*)malloc(strlen(pwd->pw_dir)+1);
331                 strcpy(temp,pwd->pw_dir);
332                 temp1=temp;
333                 temp=strtok(temp,"/");
334                 temp=strtok('\0',"/");
335                 ka_CellToRealm(temp,realm,0);
336                 addrealm(realm,&cells);
337                 free(temp1);
338         }
339
340         setpag();
341         authenticate(cells,pwd->pw_name,passwd);
342         cellNum=0;
343         rc=ktc_ListTokens(cellNum,&cellNum,&serviceName);
344         if(rc)
345                 rval=1;
346         else{
347                 rval=0;
348         }
349
350         return(rval);
351 }
352
353 static void authenticate(cells,name,passwd)
354         char **cells;
355         char *name;
356         char *passwd;
357 {
358         char **ptr=cells;
359         char *errorstring;
360
361         while(*ptr){
362             ka_UserAuthenticate(name,/*instance*/"",/*cell*/*ptr++,
363                     passwd,/*setpag*/0,&errorstring);
364         }
365 }
366 #endif /*AFS*/
367
368 #if defined( UAM_AFSKRB ) && defined( AFS )
369 static int afskrb_login(void *obj, struct passwd *uam_pwd,
370                         char *ibuf, int ibuflen, 
371                         char *rbuf, int *rbuflen )
372 {
373     KTEXT_ST    authent, rpkt;
374     CREDENTIALS cr;
375     char        *p, *q, *username;
376     int         len, rc, whoserealm, ulen;
377     short       slen;
378
379     *rbuflen = 0;
380     if (uam_afpserver_option(obj, UAM_OPTION_USERNAME, &username) < 0)
381       return AFPERR_MISC;
382     
383     if (uam_afpserver_option(obj, UAM_OPTION_USERNAMELEN, &ulen) < 0)
384       return AFPERR_MISC;
385
386     len = (unsigned char) *ibuf++;
387     ibuf[ len ] = '\0';
388     if (( p = strchr( ibuf, '@' )) != NULL ) {
389         *p++ = '\0';
390         strcpy( realm, p );
391         ucase( realm );
392         whoserealm = 0;
393     } else {
394         if ( krb_get_lrealm( realm, 1 ) != KSUCCESS ) {
395             return AFPERR_BADUAM;
396         }
397         whoserealm = 1;
398     }
399     if (( p = strchr( ibuf, '.' )) != NULL ) {
400         *p++ = '\0';
401         strcpy( instance, p );
402     } else {
403         *instance = '\0';
404     }
405     strcpy( name, ibuf );
406     /*
407      * We don't have the session key, yet. Get one.
408      */
409     p = rbuf;
410     if ( validseskey == 0 ) {
411         if ( setpag() < 0 ) {
412             syslog( LOG_ERR, "krb_login: setpag: %m" );
413             return AFPERR_BADUAM;
414         }
415         krb_set_tkt_string(( tktfile = mktemp( _PATH_AFPTKT )));
416         if (( rc =  krb_get_svc_in_tkt( "afpserver", Obj, realm,
417                 TICKET_GRANTING_TICKET, realm, 255, KEYFILE )) != INTK_OK ) {
418             syslog( LOG_ERR, "krb_login: can't get ticket-granting-ticket" );
419             return (( whoserealm ) ? AFPERR_BADUAM : AFPERR_PARAM );
420         }
421         if ( krb_mk_req( &authent, name, instance, realm, 0 ) != KSUCCESS ) {
422             return ( AFPERR_PARAM );
423         }
424         if ( krb_get_cred( name, instance, realm, &cr ) != KSUCCESS ) {
425             return ( AFPERR_BADUAM );
426         }
427
428         if ( unlink( tktfile ) < 0 ) {
429             syslog( LOG_ERR, "krb_login: unlink %s: %m", tktfile );
430             return ( AFPERR_BADUAM );
431         }
432
433         memcpy( seskey, cr.session, sizeof( C_Block ));
434         key_sched((C_Block *) seskey, seskeysched );
435         validseskey = 1;
436         strncpy(username, name, ulen);
437
438         memcpy( p, authent.dat, authent.length );
439         p += authent.length;
440     }
441
442     if ( kuam_get_in_tkt( name, instance, realm, TICKET_GRANTING_TICKET,
443             realm, 255, &rpkt ) != INTK_OK ) {
444         return ( AFPERR_PARAM );
445     }
446
447
448     q = (char *)rpkt.dat;
449     *p++ = *q++;
450     *p++ = *q++;
451     while ( *q++ )
452         ;
453     while ( *q++ )
454         ;
455     while ( *q++ )
456         ;
457     q += 10;
458
459     len = strlen( realm );
460     strcpy( p, realm );
461     p += len + 1;
462     memcpy( &slen, q, sizeof( short ));
463     memcpy( p, &slen, sizeof( short ));
464     p += sizeof( short );
465     q += sizeof( short );
466     memcpy( p, q, slen );
467     p += slen;
468
469     *rbuflen = p - rbuf;
470     return( AFPERR_AUTHCONT );
471 }
472
473 static int afskrb_logincont(void *obj, struct passwd *uam_pwd,
474                             char *ibuf, int ibuflen, 
475                             char *rbuf, int *rbuflen )
476 {
477     CREDENTIALS         cr;
478     struct ViceIoctl    vi;
479     struct ClearToken   ct;
480     struct passwd       *pwd;
481     char                buf[ 1024 ], *p;
482     int                 aint;
483     short               clen;
484
485     *rbuflen = 0;
486     if (uam_afpserver_option(obj, UAM_OPTION_USERNAME, &username) < 0)
487       return AFPERR_MISC;
488     
489     ibuf += 2;
490     memcpy( &clen, ibuf, sizeof( short ));
491     clen = ntohs( clen );
492     ibuf += sizeof( short );
493
494     pcbc_encrypt((C_Block *)ibuf, (C_Block *)ibuf,
495             clen, seskeysched, seskey, DES_DECRYPT );
496     if ( kuam_set_in_tkt( name, instance, realm, TICKET_GRANTING_TICKET,
497             realm, ibuf ) != INTK_OK ) {
498         return ( AFPERR_PARAM );
499     }
500
501     if ( get_ad_tkt( "afs", "", realm, 255 ) != KSUCCESS ) {
502         return ( AFPERR_PARAM );
503     }
504     if ( krb_get_cred( "afs", "", realm, &cr ) != KSUCCESS ) {
505         return ( AFPERR_PARAM );
506     }
507
508     p = buf;
509     memcpy( p, &cr.ticket_st.length, sizeof( int ));
510     p += sizeof( int );
511     memcpy( p, cr.ticket_st.dat, cr.ticket_st.length );
512     p += cr.ticket_st.length;
513
514     ct.AuthHandle = cr.kvno;
515     memcpy( ct.HandShakeKey, cr.session, sizeof( cr.session ));
516     ct.ViceId = 0;
517     ct.BeginTimestamp = cr.issue_date;
518     /* ct.EndTimestamp = cr.issue_date + ( cr.lifetime * 5 * 60 ); */
519     ct.EndTimestamp = krb_life_to_time( cr.issue_date, cr.lifetime );
520
521     aint = sizeof( struct ClearToken );
522     memcpy( p, &aint, sizeof( int ));
523     p += sizeof( int );
524     memcpy( p, &ct, sizeof( struct ClearToken ));
525     p += sizeof( struct ClearToken );
526
527     aint = 0;
528     memcpy( p, &aint, sizeof( int ));
529     p += sizeof( int );
530
531     lcase( realm );
532     strcpy( p, realm );
533     p += strlen( realm ) + 1;
534
535     vi.in = buf;
536     vi.in_size = p - buf;
537     vi.out = buf;
538     vi.out_size = sizeof( buf );
539     if ( pioctl( 0, VIOCSETTOK, &vi, 0 ) < 0 ) {
540         syslog( LOG_ERR, "krb_logincont: pioctl: %m" );
541         return ( AFPERR_BADUAM );
542     }
543
544     if ( unlink( tktfile ) < 0 ) {
545         syslog( LOG_ERR, "krb_logincont: %s: %m", tktfile );
546         return ( AFPERR_BADUAM );
547     }
548
549     if (( pwd = uam_getname( username )) == NULL ) {
550         return ( AFPERR_PARAM );
551     }
552
553     if ( logged == 0 ) {
554         logged = 1;
555         syslog( LOG_INFO, "authenticated %s.%s@%s", name, instance, realm );
556         *uam_pwd = pwd;
557         return AFP_OK;
558     }
559     syslog( LOG_INFO, "re-authenticated %s.%s@%s", name, instance, realm );
560     return( AFP_OK );
561 }
562 #endif /* UAM_AFSKRB AFS */
563
564 int uam_setup()
565 {
566 #ifdef KRB
567    uam_register(UAM_SERVER_LOGIN, "Kerberos IV", krb4_login, 
568                 krb4_logincont, NULL);
569    /* uam_afpserver_action(); */
570 #endif
571 #ifdef UAM_AFSKRB
572    uam_register(UAM_SERVER_LOGIN, "AFS Kerberos", afskrb_login, 
573                 afskrb_logincont, NULL);
574    /* uam_afpserver_action(); */
575 #endif
576 }
577
578 int uam_cleanup()
579 {
580 #ifdef KRB
581    /* uam_afpserver_action(); */
582    uam_unregister(UAM_SERVER_LOGIN, "Kerberos IV");
583 #endif
584 #ifdef UAM_AFSKRB
585    /* uam_afpserver_action(); */
586    uam_unregister(UAM_SERVER_LOGIN, "AFS Kerberos");
587 #endif
588 }
589
590 #endif /* KRB or UAM_AFSKRB */