2 * $Id: uams_krb4.c,v 1.3 2001-03-28 22:49:25 samnoble 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 #include <sys/types.h>
18 #include <sys/socket.h>
24 #include <netinet/in.h>
31 #include <netatalk/endian.h>
32 #include <atalk/afp.h>
33 #include <atalk/compat.h>
34 #include <atalk/util.h>
35 #include <atalk/uam.h>
37 static C_Block seskey;
38 static Key_schedule seskeysched;
40 static char realm[ REALM_SZ ];
43 static int validseskey = 0;
44 static int logged = 0;
46 static char instance[ INST_SZ ], name[ ANAME_SZ ];
53 #include <afs/venus.h>
54 #include <afs/afsint.h>
62 int32_t BeginTimestamp;
70 static __inline__ void lcase( p )
81 static __inline__ void ucase( p )
92 #define KRB4CMD_HELO 1
93 #define KRB4RPL_REALM 2
94 #define KRB4WRT_SESS 3
95 #define KRB4RPL_DONE 4
96 #define KRB4RPL_PRINC 5
97 #define KRB4WRT_TOKEN 6
98 #define KRB4WRT_SKIP 7
99 #define KRB4RPL_DONEMUT 8
100 #define KRB4CMD_SESS 9
101 #define KRB4CMD_TOKEN 10
102 #define KRB4CMD_SKIP 11
104 static int krb4_login(void *obj, struct passwd **uam_pwd,
105 char *ibuf, int ibuflen,
106 char *rbuf, int *rbuflen )
115 char inst[ 40 ], princ[ 40 ];
117 if (uam_afpserver_option(obj, UAM_OPTION_USERNAME, &username, &ulen) < 0)
120 if (uam_afpserver_option(obj, UAM_OPTION_PROTOCOL, &proto, NULL) < 0)
125 syslog( LOG_INFO, "krb4_login: KRB4CMD_SESS" );
128 memcpy( &len, p, sizeof( u_int16_t ));
129 tkt.length = ntohs( len );
130 p += sizeof( u_int16_t );
132 if ( tkt.length <= 0 || tkt.length > MAX_KTXT_LEN ) {
134 syslog( LOG_INFO, "krb4_login: tkt.length = %d", tkt.length );
135 return( AFPERR_BADUAM );
138 memcpy( tkt.dat, p, tkt.length );
145 strcpy( princ, "afpserver" );
148 strcpy( princ, "rcmd" );
152 if( (rc = krb_rd_req( &tkt, princ, inst, 0, &ad, "" ))
155 "krb4_login: krb_rd_req(): %s", krb_err_txt[ rc ] );
157 return( AFPERR_BADUAM );
160 syslog( LOG_INFO, "krb4_login: %s.%s@%s", ad.pname, ad.pinst,
162 strcpy( realm, ad.prealm );
163 memcpy( seskey, ad.session, sizeof( C_Block ) );
164 key_sched( (C_Block *)seskey, seskeysched );
166 strncpy( username, ad.pname, ulen );
171 *p = KRB4RPL_DONE; /* XXX */
174 if (( pwd = uam_getname( ad.pname, strlen(ad.pname) )) == NULL ) {
178 if (uam_checkuser( pwd ) < 0) {
179 return AFPERR_NOTAUTH;
183 return( AFP_OK ); /* Should this be AFPERR_AUTHCONT? */
186 *p++ = KRB4RPL_PRINC;
187 len = strlen( realm );
196 if (krb_get_lrealm( realm, 1 ) != KSUCCESS ) {
197 syslog( LOG_ERR, "krb4_login: can't get local realm!" );
198 return( AFPERR_NOTAUTH );
200 *p++ = KRB4RPL_REALM;
202 len = strlen( realm );
210 syslog( LOG_INFO, "krb4_login: bad command %d", *ibuf );
211 return( AFPERR_NOTAUTH );
215 if ( setpag() < 0 ) {
217 syslog( LOG_ERR, "krb_login: setpag: %m" );
218 return( AFPERR_BADUAM );
223 return( AFPERR_AUTHCONT );
226 static int krb4_action( void *v1, void *v2, const int i )
232 I have a hunch that problems might arise on platforms
233 with non-16bit short's and non-32bit int's
235 static int krb4_logincont(void *obj, struct passwd **uam_pwd,
236 char *ibuf, int ibuflen,
237 char *rbuf, int *rbuflen)
239 static struct passwd *pwd;
244 char *p, *username, *servername;
248 struct ClearToken ct;
251 int aint, ulen, snlen;
253 if (uam_afpserver_option(obj, UAM_OPTION_USERNAME, &username, &ulen) < 0)
256 if (uam_afpserver_option(obj, UAM_OPTION_HOSTNAME, &servername, &snlen) < 0)
260 switch ( rc = *ibuf++ ) {
264 memcpy( &len, ibuf, sizeof( u_int16_t ) );
265 ibuf += sizeof( len );
268 memcpy( p, &aint, sizeof( int ) );
270 memcpy( p, ibuf, len );
271 pcbc_encrypt( (C_Block *)p, (C_Block *)p, len, seskeysched,
276 memcpy( &len, ibuf, sizeof( u_int16_t ) );
277 ibuf += sizeof( u_int16_t ) );
280 if ( len != sizeof( struct ClearToken ) ) {
281 syslog( LOG_ERR, "krb4_logincont: token too short" );
283 return( AFPERR_BADUAM );
285 memcpy( &ct, ibuf, len );
287 pcbc_encrypt( (C_Block *)&ct, (C_Block *)&ct, len,
288 seskeysched, seskey, DECRYPT );
290 aint = sizeof( struct ClearToken );
291 memcpy( p, &aint, sizeof( int ) );
293 memcpy( p, &ct, sizeof( struct ClearToken ) );
294 p += sizeof( struct ClearToken );
297 memcpy( p, &aint, sizeof( int ) );
302 p += strlen( realm ) + 1;
305 vi.in_size = p - buf;
307 vi.out_size = sizeof( buf );
309 if ( pioctl( 0, VIOCSETTOK, &vi, 0 ) < 0 ) {
310 syslog( LOG_ERR, "krb4_logincont: pioctl: %m" );
312 return( AFPERR_BADUAM );
318 *p = KRB4RPL_DONE; /* XXX */
321 if (( pwd = uam_getname( username, strlen(username) ) ) == NULL ) {
322 return( AFPERR_NOTAUTH );
325 if (uam_checkuser(pwd) < 0) {
326 return AFPERR_NOTAUTH;
333 /* read in the rest */
334 if (uam_afp_read(obj, rbuf, rbuflen, krb4_action) < 0)
338 switch ( rc = *p++ ) {
340 memcpy( &len, p, sizeof( len ));
341 tkt.length = ntohs( len );
342 p += sizeof( short );
344 if ( tkt.length <= 0 || tkt.length > MAX_KTXT_LEN ) {
345 return( AFPERR_BADUAM );
347 memcpy( tkt.dat, p, tkt.length );
350 if (( rc = krb_rd_req( &tkt, "afpserver", servername,
351 0, &ad, "" )) != RD_AP_OK ) {
352 syslog( LOG_ERR, "krb4_logincont: krb_rd_req(): %s", krb_err_txt[ rc ] );
353 return( AFPERR_BADUAM );
356 syslog( LOG_INFO, "krb4_login: %s.%s@%s", ad.pname,
357 ad.pinst, ad.prealm );
358 memcpy(realm, ad.prealm, sizeof(realm));
359 memcpy(seskey, ad.session, sizeof( C_Block ));
360 key_sched((C_Block *) seskey, seskeysched );
362 strncpy(username, ad.pname, ulen);
366 *p = KRB4RPL_DONE; /* XXX */
369 if (( pwd = uam_getname( ad.pname, strlen(ad.pname) ))
371 return( AFPERR_PARAM );
377 *p++ = KRB4RPL_PRINC;
378 len = strlen( realm );
384 return( AFPERR_AUTHCONT );
387 memcpy( &len, p, sizeof( len ));
390 memcpy( &cr, p, len );
392 pcbc_encrypt((C_Block *)&cr, (C_Block *)&cr, len,
393 seskeysched, seskey, DES_DECRYPT );
396 cr.ticket_st.length = ntohl( cr.ticket_st.length );
397 memcpy( p, &cr.ticket_st.length, sizeof( int ));
399 memcpy( p, cr.ticket_st.dat, cr.ticket_st.length );
400 p += cr.ticket_st.length;
402 ct.AuthHandle = ntohl( cr.kvno );
403 memcpy( ct.HandShakeKey, cr.session, sizeof( cr.session ));
405 ct.BeginTimestamp = ntohl( cr.issue_date );
406 ct.EndTimestamp = krb_life_to_time( ntohl( cr.issue_date ),
407 ntohl( cr.lifetime ));
409 aint = sizeof( struct ClearToken );
410 memcpy( p, &aint, sizeof( int ));
412 memcpy( p, &ct, sizeof( struct ClearToken ));
413 p += sizeof( struct ClearToken );
416 memcpy( p, &aint, sizeof( int ));
421 p += strlen( realm ) + 1;
424 vi.in_size = p - buf;
426 vi.out_size = sizeof( buf );
427 if ( pioctl( 0, VIOCSETTOK, &vi, 0 ) < 0 ) {
428 syslog( LOG_ERR, "krb4_logincont: pioctl: %m" );
429 return( AFPERR_BADUAM );
435 *p = KRB4RPL_DONE; /* XXX */
438 if (( pwd = uam_getname( ad.pname, strlen(ad.pname) ))
440 return( AFPERR_PARAM );
447 syslog( LOG_INFO, "krb4_logincont: bad command %d", rc );
449 return( AFPERR_NOTAUTH );
460 #include <rx/rxkad.h>
461 #include <afs/afsint.h>
463 char *ka_LocalCell();
466 addrealm(realm,cells)
475 for(;*ptr != 0 ;ptr++)
476 if(!strcmp(realm,*ptr))
480 *cells=(char**)realloc(*cells,((2+temp)*sizeof(char*)));
483 *ptr=(char*)malloc(strlen(realm)+1);
484 strcpy(*ptr++,realm);
489 static int kcheckuser(pwd,passwd)
495 char realm[MAXKTCREALMLEN];
496 char lorealm[MAXKTCREALMLEN];
498 Date lifetime=MAXKTCTICKETLIFETIME;
500 char **cells=(char **)malloc(sizeof(char*));
503 struct ktc_principal serviceName;
511 temp=(char*)malloc(strlen(pwd->pw_dir)+1);
512 strcpy(temp,pwd->pw_dir);
514 temp=strtok(temp,"/");
515 temp=strtok('\0',"/");
516 ka_CellToRealm(temp,realm,0);
517 addrealm(realm,&cells);
522 authenticate(cells,pwd->pw_name,passwd);
524 rc=ktc_ListTokens(cellNum,&cellNum,&serviceName);
534 static void authenticate(cells,name,passwd)
543 ka_UserAuthenticate(name,/*instance*/"",/*cell*/*ptr++,
544 passwd,/*setpag*/0,&errorstring);
549 #if defined( UAM_AFSKRB ) && defined( AFS )
550 static int afskrb_login(void *obj, struct passwd *uam_pwd,
551 char *ibuf, int ibuflen,
552 char *rbuf, int *rbuflen )
554 KTEXT_ST authent, rpkt;
556 char *p, *q, *username, servername;
557 int len, rc, whoserealm, ulen, snlen;
561 if (uam_afpserver_option(obj, UAM_OPTION_USERNAME, &username, &ulen) < 0)
564 if (uam_afpserver_option(obj, UAM_OPTION_HOSTNAME, &servername, &snlen ) < 0)
567 len = (unsigned char) *ibuf++;
569 if (( p = strchr( ibuf, '@' )) != NULL ) {
575 if ( krb_get_lrealm( realm, 1 ) != KSUCCESS ) {
576 return AFPERR_BADUAM;
580 if (( p = strchr( ibuf, '.' )) != NULL ) {
582 strcpy( instance, p );
586 strcpy( name, ibuf );
588 * We don't have the session key, yet. Get one.
591 if ( validseskey == 0 ) {
592 if ( setpag() < 0 ) {
593 syslog( LOG_ERR, "krb_login: setpag: %m" );
594 return AFPERR_BADUAM;
596 krb_set_tkt_string(( tktfile = mktemp( _PATH_AFPTKT )));
597 if (( rc = krb_get_svc_in_tkt( "afpserver", servername, realm,
598 TICKET_GRANTING_TICKET, realm, 255, KEYFILE )) != INTK_OK ) {
599 syslog( LOG_ERR, "krb_login: can't get ticket-granting-ticket" );
600 return (( whoserealm ) ? AFPERR_BADUAM : AFPERR_PARAM );
602 if ( krb_mk_req( &authent, name, instance, realm, 0 ) != KSUCCESS ) {
603 return ( AFPERR_PARAM );
605 if ( krb_get_cred( name, instance, realm, &cr ) != KSUCCESS ) {
606 return ( AFPERR_BADUAM );
609 if ( unlink( tktfile ) < 0 ) {
610 syslog( LOG_ERR, "krb_login: unlink %s: %m", tktfile );
611 return ( AFPERR_BADUAM );
614 memcpy( seskey, cr.session, sizeof( C_Block ));
615 key_sched((C_Block *) seskey, seskeysched );
617 strncpy(username, name, ulen);
619 memcpy( p, authent.dat, authent.length );
623 if ( kuam_get_in_tkt( name, instance, realm, TICKET_GRANTING_TICKET,
624 realm, 255, &rpkt ) != INTK_OK ) {
625 return ( AFPERR_PARAM );
629 q = (char *)rpkt.dat;
640 len = strlen( realm );
643 memcpy( &slen, q, sizeof( short ));
644 memcpy( p, &slen, sizeof( short ));
645 p += sizeof( short );
646 q += sizeof( short );
647 memcpy( p, q, slen );
651 return( AFPERR_AUTHCONT );
654 static int afskrb_logincont(void *obj, struct passwd *uam_pwd,
655 char *ibuf, int ibuflen,
656 char *rbuf, int *rbuflen )
660 struct ClearToken ct;
662 char buf[ 1024 ], *p;
667 if (uam_afpserver_option(obj, UAM_OPTION_USERNAME, &username, NULL) < 0)
671 memcpy( &clen, ibuf, sizeof( short ));
672 clen = ntohs( clen );
673 ibuf += sizeof( short );
675 pcbc_encrypt((C_Block *)ibuf, (C_Block *)ibuf,
676 clen, seskeysched, seskey, DES_DECRYPT );
677 if ( kuam_set_in_tkt( name, instance, realm, TICKET_GRANTING_TICKET,
678 realm, ibuf ) != INTK_OK ) {
679 return ( AFPERR_PARAM );
682 if ( get_ad_tkt( "afs", "", realm, 255 ) != KSUCCESS ) {
683 return ( AFPERR_PARAM );
685 if ( krb_get_cred( "afs", "", realm, &cr ) != KSUCCESS ) {
686 return ( AFPERR_PARAM );
690 memcpy( p, &cr.ticket_st.length, sizeof( int ));
692 memcpy( p, cr.ticket_st.dat, cr.ticket_st.length );
693 p += cr.ticket_st.length;
695 ct.AuthHandle = cr.kvno;
696 memcpy( ct.HandShakeKey, cr.session, sizeof( cr.session ));
698 ct.BeginTimestamp = cr.issue_date;
699 /* ct.EndTimestamp = cr.issue_date + ( cr.lifetime * 5 * 60 ); */
700 ct.EndTimestamp = krb_life_to_time( cr.issue_date, cr.lifetime );
702 aint = sizeof( struct ClearToken );
703 memcpy( p, &aint, sizeof( int ));
705 memcpy( p, &ct, sizeof( struct ClearToken ));
706 p += sizeof( struct ClearToken );
709 memcpy( p, &aint, sizeof( int ));
714 p += strlen( realm ) + 1;
717 vi.in_size = p - buf;
719 vi.out_size = sizeof( buf );
720 if ( pioctl( 0, VIOCSETTOK, &vi, 0 ) < 0 ) {
721 syslog( LOG_ERR, "krb_logincont: pioctl: %m" );
722 return ( AFPERR_BADUAM );
725 if ( unlink( tktfile ) < 0 ) {
726 syslog( LOG_ERR, "krb_logincont: %s: %m", tktfile );
727 return ( AFPERR_BADUAM );
730 if (( pwd = uam_getname( username )) == NULL ) {
731 return ( AFPERR_PARAM );
736 syslog( LOG_INFO, "authenticated %s.%s@%s", name, instance, realm );
740 syslog( LOG_INFO, "re-authenticated %s.%s@%s", name, instance, realm );
743 #endif /* UAM_AFSKRB AFS */
745 static int uam_setup(const char *path)
748 uam_register(UAM_SERVER_LOGIN, path, "Kerberos IV", krb4_login,
749 krb4_logincont, NULL);
750 /* uam_afpserver_action(); */
753 uam_register(UAM_SERVER_LOGIN, path, "AFS Kerberos", afskrb_login,
754 afskrb_logincont, NULL);
755 /* uam_afpserver_action(); */
760 static void uam_cleanup(void)
763 /* uam_afpserver_action(); */
764 uam_unregister(UAM_SERVER_LOGIN, "Kerberos IV");
767 /* uam_afpserver_action(); */
768 uam_unregister(UAM_SERVER_LOGIN, "AFS Kerberos");
772 UAM_MODULE_EXPORT struct uam_export uams_krb4 = {
775 uam_setup, uam_cleanup
778 #endif /* KRB or UAM_AFSKRB */