2 * $Id: uams_krb4.c,v 1.4 2001-06-25 20:13:45 rufustfirefly Exp $
4 * Copyright (c) 1990,1993 Regents of The University of Michigan.
5 * All Rights Reserved. See COPYRIGHT.
8 #if defined(HAVE_CONFIG_H)
12 #if defined( KRB ) || defined( UAM_AFSKRB )
15 #endif /* HAVE_UNISTD_H */
18 #endif /* HAVE_FCNTL_H */
19 #include <sys/types.h>
22 #include <sys/socket.h>
28 #include <netinet/in.h>
35 #include <netatalk/endian.h>
36 #include <atalk/afp.h>
37 #include <atalk/compat.h>
38 #include <atalk/util.h>
39 #include <atalk/uam.h>
41 static C_Block seskey;
42 static Key_schedule seskeysched;
44 static char realm[ REALM_SZ ];
47 static int validseskey = 0;
48 static int logged = 0;
50 static char instance[ INST_SZ ], name[ ANAME_SZ ];
51 #endif /* UAM_AFSKRB */
57 #include <afs/venus.h>
58 #include <afs/afsint.h>
66 int32_t BeginTimestamp;
74 static __inline__ void lcase( p )
85 static __inline__ void ucase( p )
96 #define KRB4CMD_HELO 1
97 #define KRB4RPL_REALM 2
98 #define KRB4WRT_SESS 3
99 #define KRB4RPL_DONE 4
100 #define KRB4RPL_PRINC 5
101 #define KRB4WRT_TOKEN 6
102 #define KRB4WRT_SKIP 7
103 #define KRB4RPL_DONEMUT 8
104 #define KRB4CMD_SESS 9
105 #define KRB4CMD_TOKEN 10
106 #define KRB4CMD_SKIP 11
108 static int krb4_login(void *obj, struct passwd **uam_pwd,
109 char *ibuf, int ibuflen,
110 char *rbuf, int *rbuflen )
119 char inst[ 40 ], princ[ 40 ];
121 if (uam_afpserver_option(obj, UAM_OPTION_USERNAME, &username, &ulen) < 0)
124 if (uam_afpserver_option(obj, UAM_OPTION_PROTOCOL, &proto, NULL) < 0)
129 syslog( LOG_INFO, "krb4_login: KRB4CMD_SESS" );
132 memcpy( &len, p, sizeof( u_int16_t ));
133 tkt.length = ntohs( len );
134 p += sizeof( u_int16_t );
136 if ( tkt.length <= 0 || tkt.length > MAX_KTXT_LEN ) {
138 syslog( LOG_INFO, "krb4_login: tkt.length = %d", tkt.length );
139 return( AFPERR_BADUAM );
142 memcpy( tkt.dat, p, tkt.length );
149 strcpy( princ, "afpserver" );
152 strcpy( princ, "rcmd" );
156 if( (rc = krb_rd_req( &tkt, princ, inst, 0, &ad, "" ))
159 "krb4_login: krb_rd_req(): %s", krb_err_txt[ rc ] );
161 return( AFPERR_BADUAM );
164 syslog( LOG_INFO, "krb4_login: %s.%s@%s", ad.pname, ad.pinst,
166 strcpy( realm, ad.prealm );
167 memcpy( seskey, ad.session, sizeof( C_Block ) );
168 key_sched( (C_Block *)seskey, seskeysched );
170 strncpy( username, ad.pname, ulen );
175 *p = KRB4RPL_DONE; /* XXX */
178 if (( pwd = uam_getname( ad.pname, strlen(ad.pname) )) == NULL ) {
182 if (uam_checkuser( pwd ) < 0) {
183 return AFPERR_NOTAUTH;
187 return( AFP_OK ); /* Should this be AFPERR_AUTHCONT? */
190 *p++ = KRB4RPL_PRINC;
191 len = strlen( realm );
200 if (krb_get_lrealm( realm, 1 ) != KSUCCESS ) {
201 syslog( LOG_ERR, "krb4_login: can't get local realm!" );
202 return( AFPERR_NOTAUTH );
204 *p++ = KRB4RPL_REALM;
206 len = strlen( realm );
214 syslog( LOG_INFO, "krb4_login: bad command %d", *ibuf );
215 return( AFPERR_NOTAUTH );
219 if ( setpag() < 0 ) {
221 syslog( LOG_ERR, "krb_login: setpag: %m" );
222 return( AFPERR_BADUAM );
227 return( AFPERR_AUTHCONT );
230 static int krb4_action( void *v1, void *v2, const int i )
236 I have a hunch that problems might arise on platforms
237 with non-16bit short's and non-32bit int's
239 static int krb4_logincont(void *obj, struct passwd **uam_pwd,
240 char *ibuf, int ibuflen,
241 char *rbuf, int *rbuflen)
243 static struct passwd *pwd;
248 char *p, *username, *servername;
252 struct ClearToken ct;
255 int aint, ulen, snlen;
257 if (uam_afpserver_option(obj, UAM_OPTION_USERNAME, &username, &ulen) < 0)
260 if (uam_afpserver_option(obj, UAM_OPTION_HOSTNAME, &servername, &snlen) < 0)
264 switch ( rc = *ibuf++ ) {
268 memcpy( &len, ibuf, sizeof( u_int16_t ) );
269 ibuf += sizeof( len );
272 memcpy( p, &aint, sizeof( int ) );
274 memcpy( p, ibuf, len );
275 pcbc_encrypt( (C_Block *)p, (C_Block *)p, len, seskeysched,
280 memcpy( &len, ibuf, sizeof( u_int16_t ) );
281 ibuf += sizeof( u_int16_t ) );
284 if ( len != sizeof( struct ClearToken ) ) {
285 syslog( LOG_ERR, "krb4_logincont: token too short" );
287 return( AFPERR_BADUAM );
289 memcpy( &ct, ibuf, len );
291 pcbc_encrypt( (C_Block *)&ct, (C_Block *)&ct, len,
292 seskeysched, seskey, DECRYPT );
294 aint = sizeof( struct ClearToken );
295 memcpy( p, &aint, sizeof( int ) );
297 memcpy( p, &ct, sizeof( struct ClearToken ) );
298 p += sizeof( struct ClearToken );
301 memcpy( p, &aint, sizeof( int ) );
306 p += strlen( realm ) + 1;
309 vi.in_size = p - buf;
311 vi.out_size = sizeof( buf );
313 if ( pioctl( 0, VIOCSETTOK, &vi, 0 ) < 0 ) {
314 syslog( LOG_ERR, "krb4_logincont: pioctl: %m" );
316 return( AFPERR_BADUAM );
322 *p = KRB4RPL_DONE; /* XXX */
325 if (( pwd = uam_getname( username, strlen(username) ) ) == NULL ) {
326 return( AFPERR_NOTAUTH );
329 if (uam_checkuser(pwd) < 0) {
330 return AFPERR_NOTAUTH;
337 /* read in the rest */
338 if (uam_afp_read(obj, rbuf, rbuflen, krb4_action) < 0)
342 switch ( rc = *p++ ) {
344 memcpy( &len, p, sizeof( len ));
345 tkt.length = ntohs( len );
346 p += sizeof( short );
348 if ( tkt.length <= 0 || tkt.length > MAX_KTXT_LEN ) {
349 return( AFPERR_BADUAM );
351 memcpy( tkt.dat, p, tkt.length );
354 if (( rc = krb_rd_req( &tkt, "afpserver", servername,
355 0, &ad, "" )) != RD_AP_OK ) {
356 syslog( LOG_ERR, "krb4_logincont: krb_rd_req(): %s", krb_err_txt[ rc ] );
357 return( AFPERR_BADUAM );
360 syslog( LOG_INFO, "krb4_login: %s.%s@%s", ad.pname,
361 ad.pinst, ad.prealm );
362 memcpy(realm, ad.prealm, sizeof(realm));
363 memcpy(seskey, ad.session, sizeof( C_Block ));
364 key_sched((C_Block *) seskey, seskeysched );
366 strncpy(username, ad.pname, ulen);
370 *p = KRB4RPL_DONE; /* XXX */
373 if (( pwd = uam_getname( ad.pname, strlen(ad.pname) ))
375 return( AFPERR_PARAM );
381 *p++ = KRB4RPL_PRINC;
382 len = strlen( realm );
388 return( AFPERR_AUTHCONT );
391 memcpy( &len, p, sizeof( len ));
394 memcpy( &cr, p, len );
396 pcbc_encrypt((C_Block *)&cr, (C_Block *)&cr, len,
397 seskeysched, seskey, DES_DECRYPT );
400 cr.ticket_st.length = ntohl( cr.ticket_st.length );
401 memcpy( p, &cr.ticket_st.length, sizeof( int ));
403 memcpy( p, cr.ticket_st.dat, cr.ticket_st.length );
404 p += cr.ticket_st.length;
406 ct.AuthHandle = ntohl( cr.kvno );
407 memcpy( ct.HandShakeKey, cr.session, sizeof( cr.session ));
409 ct.BeginTimestamp = ntohl( cr.issue_date );
410 ct.EndTimestamp = krb_life_to_time( ntohl( cr.issue_date ),
411 ntohl( cr.lifetime ));
413 aint = sizeof( struct ClearToken );
414 memcpy( p, &aint, sizeof( int ));
416 memcpy( p, &ct, sizeof( struct ClearToken ));
417 p += sizeof( struct ClearToken );
420 memcpy( p, &aint, sizeof( int ));
425 p += strlen( realm ) + 1;
428 vi.in_size = p - buf;
430 vi.out_size = sizeof( buf );
431 if ( pioctl( 0, VIOCSETTOK, &vi, 0 ) < 0 ) {
432 syslog( LOG_ERR, "krb4_logincont: pioctl: %m" );
433 return( AFPERR_BADUAM );
439 *p = KRB4RPL_DONE; /* XXX */
442 if (( pwd = uam_getname( ad.pname, strlen(ad.pname) ))
444 return( AFPERR_PARAM );
451 syslog( LOG_INFO, "krb4_logincont: bad command %d", rc );
453 return( AFPERR_NOTAUTH );
464 #include <rx/rxkad.h>
465 #include <afs/afsint.h>
467 char *ka_LocalCell();
470 addrealm(realm,cells)
479 for(;*ptr != 0 ;ptr++)
480 if(!strcmp(realm,*ptr))
484 *cells=(char**)realloc(*cells,((2+temp)*sizeof(char*)));
487 *ptr=(char*)malloc(strlen(realm)+1);
488 strcpy(*ptr++,realm);
493 static int kcheckuser(pwd,passwd)
499 char realm[MAXKTCREALMLEN];
500 char lorealm[MAXKTCREALMLEN];
502 Date lifetime=MAXKTCTICKETLIFETIME;
504 char **cells=(char **)malloc(sizeof(char*));
507 struct ktc_principal serviceName;
515 temp=(char*)malloc(strlen(pwd->pw_dir)+1);
516 strcpy(temp,pwd->pw_dir);
518 temp=strtok(temp,"/");
519 temp=strtok('\0',"/");
520 ka_CellToRealm(temp,realm,0);
521 addrealm(realm,&cells);
526 authenticate(cells,pwd->pw_name,passwd);
528 rc=ktc_ListTokens(cellNum,&cellNum,&serviceName);
538 static void authenticate(cells,name,passwd)
547 ka_UserAuthenticate(name,/*instance*/"",/*cell*/*ptr++,
548 passwd,/*setpag*/0,&errorstring);
553 #if defined( UAM_AFSKRB ) && defined( AFS )
554 static int afskrb_login(void *obj, struct passwd *uam_pwd,
555 char *ibuf, int ibuflen,
556 char *rbuf, int *rbuflen )
558 KTEXT_ST authent, rpkt;
560 char *p, *q, *username, servername;
561 int len, rc, whoserealm, ulen, snlen;
565 if (uam_afpserver_option(obj, UAM_OPTION_USERNAME, &username, &ulen) < 0)
568 if (uam_afpserver_option(obj, UAM_OPTION_HOSTNAME, &servername, &snlen ) < 0)
571 len = (unsigned char) *ibuf++;
573 if (( p = strchr( ibuf, '@' )) != NULL ) {
579 if ( krb_get_lrealm( realm, 1 ) != KSUCCESS ) {
580 return AFPERR_BADUAM;
584 if (( p = strchr( ibuf, '.' )) != NULL ) {
586 strcpy( instance, p );
590 strcpy( name, ibuf );
592 * We don't have the session key, yet. Get one.
595 if ( validseskey == 0 ) {
596 if ( setpag() < 0 ) {
597 syslog( LOG_ERR, "krb_login: setpag: %m" );
598 return AFPERR_BADUAM;
600 krb_set_tkt_string(( tktfile = mktemp( _PATH_AFPTKT )));
601 if (( rc = krb_get_svc_in_tkt( "afpserver", servername, realm,
602 TICKET_GRANTING_TICKET, realm, 255, KEYFILE )) != INTK_OK ) {
603 syslog( LOG_ERR, "krb_login: can't get ticket-granting-ticket" );
604 return (( whoserealm ) ? AFPERR_BADUAM : AFPERR_PARAM );
606 if ( krb_mk_req( &authent, name, instance, realm, 0 ) != KSUCCESS ) {
607 return ( AFPERR_PARAM );
609 if ( krb_get_cred( name, instance, realm, &cr ) != KSUCCESS ) {
610 return ( AFPERR_BADUAM );
613 if ( unlink( tktfile ) < 0 ) {
614 syslog( LOG_ERR, "krb_login: unlink %s: %m", tktfile );
615 return ( AFPERR_BADUAM );
618 memcpy( seskey, cr.session, sizeof( C_Block ));
619 key_sched((C_Block *) seskey, seskeysched );
621 strncpy(username, name, ulen);
623 memcpy( p, authent.dat, authent.length );
627 if ( kuam_get_in_tkt( name, instance, realm, TICKET_GRANTING_TICKET,
628 realm, 255, &rpkt ) != INTK_OK ) {
629 return ( AFPERR_PARAM );
633 q = (char *)rpkt.dat;
644 len = strlen( realm );
647 memcpy( &slen, q, sizeof( short ));
648 memcpy( p, &slen, sizeof( short ));
649 p += sizeof( short );
650 q += sizeof( short );
651 memcpy( p, q, slen );
655 return( AFPERR_AUTHCONT );
658 static int afskrb_logincont(void *obj, struct passwd *uam_pwd,
659 char *ibuf, int ibuflen,
660 char *rbuf, int *rbuflen )
664 struct ClearToken ct;
666 char buf[ 1024 ], *p;
671 if (uam_afpserver_option(obj, UAM_OPTION_USERNAME, &username, NULL) < 0)
675 memcpy( &clen, ibuf, sizeof( short ));
676 clen = ntohs( clen );
677 ibuf += sizeof( short );
679 pcbc_encrypt((C_Block *)ibuf, (C_Block *)ibuf,
680 clen, seskeysched, seskey, DES_DECRYPT );
681 if ( kuam_set_in_tkt( name, instance, realm, TICKET_GRANTING_TICKET,
682 realm, ibuf ) != INTK_OK ) {
683 return ( AFPERR_PARAM );
686 if ( get_ad_tkt( "afs", "", realm, 255 ) != KSUCCESS ) {
687 return ( AFPERR_PARAM );
689 if ( krb_get_cred( "afs", "", realm, &cr ) != KSUCCESS ) {
690 return ( AFPERR_PARAM );
694 memcpy( p, &cr.ticket_st.length, sizeof( int ));
696 memcpy( p, cr.ticket_st.dat, cr.ticket_st.length );
697 p += cr.ticket_st.length;
699 ct.AuthHandle = cr.kvno;
700 memcpy( ct.HandShakeKey, cr.session, sizeof( cr.session ));
702 ct.BeginTimestamp = cr.issue_date;
703 /* ct.EndTimestamp = cr.issue_date + ( cr.lifetime * 5 * 60 ); */
704 ct.EndTimestamp = krb_life_to_time( cr.issue_date, cr.lifetime );
706 aint = sizeof( struct ClearToken );
707 memcpy( p, &aint, sizeof( int ));
709 memcpy( p, &ct, sizeof( struct ClearToken ));
710 p += sizeof( struct ClearToken );
713 memcpy( p, &aint, sizeof( int ));
718 p += strlen( realm ) + 1;
721 vi.in_size = p - buf;
723 vi.out_size = sizeof( buf );
724 if ( pioctl( 0, VIOCSETTOK, &vi, 0 ) < 0 ) {
725 syslog( LOG_ERR, "krb_logincont: pioctl: %m" );
726 return ( AFPERR_BADUAM );
729 if ( unlink( tktfile ) < 0 ) {
730 syslog( LOG_ERR, "krb_logincont: %s: %m", tktfile );
731 return ( AFPERR_BADUAM );
734 if (( pwd = uam_getname( username )) == NULL ) {
735 return ( AFPERR_PARAM );
740 syslog( LOG_INFO, "authenticated %s.%s@%s", name, instance, realm );
744 syslog( LOG_INFO, "re-authenticated %s.%s@%s", name, instance, realm );
747 #endif /* UAM_AFSKRB AFS */
749 static int uam_setup(const char *path)
752 uam_register(UAM_SERVER_LOGIN, path, "Kerberos IV", krb4_login,
753 krb4_logincont, NULL);
754 /* uam_afpserver_action(); */
757 uam_register(UAM_SERVER_LOGIN, path, "AFS Kerberos", afskrb_login,
758 afskrb_logincont, NULL);
759 /* uam_afpserver_action(); */
760 #endif /* UAM_AFSKRB */
764 static void uam_cleanup(void)
767 /* uam_afpserver_action(); */
768 uam_unregister(UAM_SERVER_LOGIN, "Kerberos IV");
771 /* uam_afpserver_action(); */
772 uam_unregister(UAM_SERVER_LOGIN, "AFS Kerberos");
776 UAM_MODULE_EXPORT struct uam_export uams_krb4 = {
779 uam_setup, uam_cleanup
782 #endif /* KRB or UAM_AFSKRB */