2 * $Id: uams_krb4.c,v 1.6.10.1 2003-09-11 23:49:30 bfernhomberg Exp $
4 * Copyright (c) 1990,1993 Regents of The University of Michigan.
5 * All Rights Reserved. See COPYRIGHT.
10 #endif /* 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 #else /* STDC_HEADERS */
32 #endif /* HAVE_STRCHR */
33 char *strchr (), *strrchr ();
35 #define memcpy(d,s,n) bcopy ((s), (d), (n))
36 #define memmove(d,s,n) bcopy ((s), (d), (n))
37 #endif /* ! HAVE_MEMCPY */
38 #endif /* STDC_HEADERS */
42 #include <atalk/logger.h>
43 #include <netinet/in.h>
50 #include <netatalk/endian.h>
51 #include <atalk/afp.h>
52 #include <atalk/compat.h>
53 #include <atalk/util.h>
54 #include <atalk/uam.h>
56 static C_Block seskey;
57 static Key_schedule seskeysched;
59 static char realm[ REALM_SZ ];
62 static int validseskey = 0;
63 static int logged = 0;
65 static char instance[ INST_SZ ], name[ ANAME_SZ ];
66 #endif /* UAM_AFSKRB */
72 #include <afs/venus.h>
73 #include <afs/afsint.h>
81 int32_t BeginTimestamp;
89 static __inline__ void lcase( p )
100 static __inline__ void ucase( p )
104 if ( islower( *p )) {
111 #define KRB4CMD_HELO 1
112 #define KRB4RPL_REALM 2
113 #define KRB4WRT_SESS 3
114 #define KRB4RPL_DONE 4
115 #define KRB4RPL_PRINC 5
116 #define KRB4WRT_TOKEN 6
117 #define KRB4WRT_SKIP 7
118 #define KRB4RPL_DONEMUT 8
119 #define KRB4CMD_SESS 9
120 #define KRB4CMD_TOKEN 10
121 #define KRB4CMD_SKIP 11
123 static int krb4_login(void *obj, struct passwd **uam_pwd,
124 char *ibuf, int ibuflen,
125 char *rbuf, int *rbuflen )
134 char inst[ 40 ], princ[ 40 ];
136 if (uam_afpserver_option(obj, UAM_OPTION_USERNAME, &username, &ulen) < 0)
139 if (uam_afpserver_option(obj, UAM_OPTION_PROTOCOL, &proto, NULL) < 0)
144 LOG(log_info, logtype_default, "krb4_login: KRB4CMD_SESS" );
147 memcpy( &len, p, sizeof( u_int16_t ));
148 tkt.length = ntohs( len );
149 p += sizeof( u_int16_t );
151 if ( tkt.length <= 0 || tkt.length > MAX_KTXT_LEN ) {
153 LOG(log_info, logtype_default, "krb4_login: tkt.length = %d", tkt.length );
154 return( AFPERR_BADUAM );
157 memcpy( tkt.dat, p, tkt.length );
164 strcpy( princ, "afpserver" );
167 strcpy( princ, "rcmd" );
171 if( (rc = krb_rd_req( &tkt, princ, inst, 0, &ad, "" ))
173 LOG(log_error, logtype_default,
174 "krb4_login: krb_rd_req(): %s", krb_err_txt[ rc ] );
176 return( AFPERR_BADUAM );
179 LOG(log_info, logtype_default, "krb4_login: %s.%s@%s", ad.pname, ad.pinst,
181 strcpy( realm, ad.prealm );
182 memcpy( seskey, ad.session, sizeof( C_Block ) );
183 key_sched( (C_Block *)seskey, seskeysched );
185 strncpy( username, ad.pname, ulen );
190 *p = KRB4RPL_DONE; /* XXX */
193 if (( pwd = uam_getname( obj, ad.pname, strlen(ad.pname) )) == NULL ) {
197 if (uam_checkuser( pwd ) < 0) {
198 return AFPERR_NOTAUTH;
202 return( AFP_OK ); /* Should this be AFPERR_AUTHCONT? */
205 *p++ = KRB4RPL_PRINC;
206 len = strlen( realm );
215 if (krb_get_lrealm( realm, 1 ) != KSUCCESS ) {
216 LOG(log_error, logtype_default, "krb4_login: can't get local realm!" );
217 return( AFPERR_NOTAUTH );
219 *p++ = KRB4RPL_REALM;
221 len = strlen( realm );
229 LOG(log_info, logtype_default, "krb4_login: bad command %d", *ibuf );
230 return( AFPERR_NOTAUTH );
234 if ( setpag() < 0 ) {
236 LOG(log_error, logtype_default, "krb_login: setpag: %m" );
237 return( AFPERR_BADUAM );
242 return( AFPERR_AUTHCONT );
245 static int krb4_action( void *v1, void *v2, const int i )
251 I have a hunch that problems might arise on platforms
252 with non-16bit short's and non-32bit int's
254 static int krb4_logincont(void *obj, struct passwd **uam_pwd,
255 char *ibuf, int ibuflen,
256 char *rbuf, int *rbuflen)
258 static struct passwd *pwd;
263 char *p, *username, *servername;
267 struct ClearToken ct;
270 int aint, ulen, snlen;
272 if (uam_afpserver_option(obj, UAM_OPTION_USERNAME, &username, &ulen) < 0)
275 if (uam_afpserver_option(obj, UAM_OPTION_HOSTNAME, &servername, &snlen) < 0)
279 switch ( rc = *ibuf++ ) {
283 memcpy( &len, ibuf, sizeof( u_int16_t ) );
284 ibuf += sizeof( len );
287 memcpy( p, &aint, sizeof( int ) );
289 memcpy( p, ibuf, len );
290 pcbc_encrypt( (C_Block *)p, (C_Block *)p, len, seskeysched,
295 memcpy( &len, ibuf, sizeof( u_int16_t ) );
296 ibuf += sizeof( u_int16_t ) );
299 if ( len != sizeof( struct ClearToken ) ) {
300 LOG(log_error, logtype_default, "krb4_logincont: token too short" );
302 return( AFPERR_BADUAM );
304 memcpy( &ct, ibuf, len );
306 pcbc_encrypt( (C_Block *)&ct, (C_Block *)&ct, len,
307 seskeysched, seskey, DECRYPT );
309 aint = sizeof( struct ClearToken );
310 memcpy( p, &aint, sizeof( int ) );
312 memcpy( p, &ct, sizeof( struct ClearToken ) );
313 p += sizeof( struct ClearToken );
316 memcpy( p, &aint, sizeof( int ) );
321 p += strlen( realm ) + 1;
324 vi.in_size = p - buf;
326 vi.out_size = sizeof( buf );
328 if ( pioctl( 0, VIOCSETTOK, &vi, 0 ) < 0 ) {
329 LOG(log_error, logtype_default, "krb4_logincont: pioctl: %m" );
331 return( AFPERR_BADUAM );
337 *p = KRB4RPL_DONE; /* XXX */
340 if (( pwd = uam_getname( obj, username, strlen(username) ) ) == NULL ) {
341 return( AFPERR_NOTAUTH );
344 if (uam_checkuser(pwd) < 0) {
345 return AFPERR_NOTAUTH;
352 /* read in the rest */
353 if (uam_afp_read(obj, rbuf, rbuflen, krb4_action) < 0)
357 switch ( rc = *p++ ) {
359 memcpy( &len, p, sizeof( len ));
360 tkt.length = ntohs( len );
361 p += sizeof( short );
363 if ( tkt.length <= 0 || tkt.length > MAX_KTXT_LEN ) {
364 return( AFPERR_BADUAM );
366 memcpy( tkt.dat, p, tkt.length );
369 if (( rc = krb_rd_req( &tkt, "afpserver", servername,
370 0, &ad, "" )) != RD_AP_OK ) {
371 LOG(log_error, logtype_default, "krb4_logincont: krb_rd_req(): %s", krb_err_txt[ rc ] );
372 return( AFPERR_BADUAM );
375 LOG(log_info, logtype_default, "krb4_login: %s.%s@%s", ad.pname,
376 ad.pinst, ad.prealm );
377 memcpy(realm, ad.prealm, sizeof(realm));
378 memcpy(seskey, ad.session, sizeof( C_Block ));
379 key_sched((C_Block *) seskey, seskeysched );
381 strncpy(username, ad.pname, ulen);
385 *p = KRB4RPL_DONE; /* XXX */
388 if (( pwd = uam_getname( obj, ad.pname, strlen(ad.pname) ))
390 return( AFPERR_PARAM );
396 *p++ = KRB4RPL_PRINC;
397 len = strlen( realm );
403 return( AFPERR_AUTHCONT );
406 memcpy( &len, p, sizeof( len ));
409 memcpy( &cr, p, len );
411 pcbc_encrypt((C_Block *)&cr, (C_Block *)&cr, len,
412 seskeysched, seskey, DES_DECRYPT );
415 cr.ticket_st.length = ntohl( cr.ticket_st.length );
416 memcpy( p, &cr.ticket_st.length, sizeof( int ));
418 memcpy( p, cr.ticket_st.dat, cr.ticket_st.length );
419 p += cr.ticket_st.length;
421 ct.AuthHandle = ntohl( cr.kvno );
422 memcpy( ct.HandShakeKey, cr.session, sizeof( cr.session ));
424 ct.BeginTimestamp = ntohl( cr.issue_date );
425 ct.EndTimestamp = krb_life_to_time( ntohl( cr.issue_date ),
426 ntohl( cr.lifetime ));
428 aint = sizeof( struct ClearToken );
429 memcpy( p, &aint, sizeof( int ));
431 memcpy( p, &ct, sizeof( struct ClearToken ));
432 p += sizeof( struct ClearToken );
435 memcpy( p, &aint, sizeof( int ));
440 p += strlen( realm ) + 1;
443 vi.in_size = p - buf;
445 vi.out_size = sizeof( buf );
446 if ( pioctl( 0, VIOCSETTOK, &vi, 0 ) < 0 ) {
447 LOG(log_error, logtype_default, "krb4_logincont: pioctl: %m" );
448 return( AFPERR_BADUAM );
454 *p = KRB4RPL_DONE; /* XXX */
457 if (( pwd = uam_getname( obj, ad.pname, strlen(ad.pname) ))
459 return( AFPERR_PARAM );
466 LOG(log_info, logtype_default, "krb4_logincont: bad command %d", rc );
468 return( AFPERR_NOTAUTH );
479 #include <rx/rxkad.h>
480 #include <afs/afsint.h>
482 char *ka_LocalCell();
485 addrealm(realm,cells)
494 for(;*ptr != 0 ;ptr++)
495 if(!strcmp(realm,*ptr))
499 *cells=(char**)realloc(*cells,((2+temp)*sizeof(char*)));
502 *ptr=(char*)malloc(strlen(realm)+1);
503 strcpy(*ptr++,realm);
508 static int kcheckuser(pwd,passwd)
514 char realm[MAXKTCREALMLEN];
515 char lorealm[MAXKTCREALMLEN];
517 Date lifetime=MAXKTCTICKETLIFETIME;
519 char **cells=(char **)malloc(sizeof(char*));
522 struct ktc_principal serviceName;
530 temp=(char*)malloc(strlen(pwd->pw_dir)+1);
531 strcpy(temp,pwd->pw_dir);
533 temp=strtok(temp,"/");
534 temp=strtok('\0',"/");
535 ka_CellToRealm(temp,realm,0);
536 addrealm(realm,&cells);
541 authenticate(cells,pwd->pw_name,passwd);
543 rc=ktc_ListTokens(cellNum,&cellNum,&serviceName);
553 static void authenticate(cells,name,passwd)
562 ka_UserAuthenticate(name,/*instance*/"",/*cell*/*ptr++,
563 passwd,/*setpag*/0,&errorstring);
568 #if defined( UAM_AFSKRB ) && defined( AFS )
569 static int afskrb_login(void *obj, struct passwd *uam_pwd,
570 char *ibuf, int ibuflen,
571 char *rbuf, int *rbuflen )
573 KTEXT_ST authent, rpkt;
575 char *p, *q, *username, servername;
576 int len, rc, whoserealm, ulen, snlen;
580 if (uam_afpserver_option(obj, UAM_OPTION_USERNAME, &username, &ulen) < 0)
583 if (uam_afpserver_option(obj, UAM_OPTION_HOSTNAME, &servername, &snlen ) < 0)
586 len = (unsigned char) *ibuf++;
588 if (( p = strchr( ibuf, '@' )) != NULL ) {
594 if ( krb_get_lrealm( realm, 1 ) != KSUCCESS ) {
595 return AFPERR_BADUAM;
599 if (( p = strchr( ibuf, '.' )) != NULL ) {
601 strcpy( instance, p );
605 strcpy( name, ibuf );
607 * We don't have the session key, yet. Get one.
610 if ( validseskey == 0 ) {
611 if ( setpag() < 0 ) {
612 LOG(log_error, logtype_default, "krb_login: setpag: %m" );
613 return AFPERR_BADUAM;
615 krb_set_tkt_string(( tktfile = mktemp( _PATH_AFPTKT )));
616 if (( rc = krb_get_svc_in_tkt( "afpserver", servername, realm,
617 TICKET_GRANTING_TICKET, realm, 255, KEYFILE )) != INTK_OK ) {
618 LOG(log_error, logtype_default, "krb_login: can't get ticket-granting-ticket" );
619 return (( whoserealm ) ? AFPERR_BADUAM : AFPERR_PARAM );
621 if ( krb_mk_req( &authent, name, instance, realm, 0 ) != KSUCCESS ) {
622 return ( AFPERR_PARAM );
624 if ( krb_get_cred( name, instance, realm, &cr ) != KSUCCESS ) {
625 return ( AFPERR_BADUAM );
628 if ( unlink( tktfile ) < 0 ) {
629 LOG(log_error, logtype_default, "krb_login: unlink %s: %m", tktfile );
630 return ( AFPERR_BADUAM );
633 memcpy( seskey, cr.session, sizeof( C_Block ));
634 key_sched((C_Block *) seskey, seskeysched );
636 strncpy(username, name, ulen);
638 memcpy( p, authent.dat, authent.length );
642 if ( kuam_get_in_tkt( name, instance, realm, TICKET_GRANTING_TICKET,
643 realm, 255, &rpkt ) != INTK_OK ) {
644 return ( AFPERR_PARAM );
648 q = (char *)rpkt.dat;
659 len = strlen( realm );
662 memcpy( &slen, q, sizeof( short ));
663 memcpy( p, &slen, sizeof( short ));
664 p += sizeof( short );
665 q += sizeof( short );
666 memcpy( p, q, slen );
670 return( AFPERR_AUTHCONT );
673 static int afskrb_logincont(void *obj, struct passwd *uam_pwd,
674 char *ibuf, int ibuflen,
675 char *rbuf, int *rbuflen )
679 struct ClearToken ct;
681 char buf[ 1024 ], *p;
686 if (uam_afpserver_option(obj, UAM_OPTION_USERNAME, &username, NULL) < 0)
690 memcpy( &clen, ibuf, sizeof( short ));
691 clen = ntohs( clen );
692 ibuf += sizeof( short );
694 pcbc_encrypt((C_Block *)ibuf, (C_Block *)ibuf,
695 clen, seskeysched, seskey, DES_DECRYPT );
696 if ( kuam_set_in_tkt( name, instance, realm, TICKET_GRANTING_TICKET,
697 realm, ibuf ) != INTK_OK ) {
698 return ( AFPERR_PARAM );
701 if ( get_ad_tkt( "afs", "", realm, 255 ) != KSUCCESS ) {
702 return ( AFPERR_PARAM );
704 if ( krb_get_cred( "afs", "", realm, &cr ) != KSUCCESS ) {
705 return ( AFPERR_PARAM );
709 memcpy( p, &cr.ticket_st.length, sizeof( int ));
711 memcpy( p, cr.ticket_st.dat, cr.ticket_st.length );
712 p += cr.ticket_st.length;
714 ct.AuthHandle = cr.kvno;
715 memcpy( ct.HandShakeKey, cr.session, sizeof( cr.session ));
717 ct.BeginTimestamp = cr.issue_date;
718 /* ct.EndTimestamp = cr.issue_date + ( cr.lifetime * 5 * 60 ); */
719 ct.EndTimestamp = krb_life_to_time( cr.issue_date, cr.lifetime );
721 aint = sizeof( struct ClearToken );
722 memcpy( p, &aint, sizeof( int ));
724 memcpy( p, &ct, sizeof( struct ClearToken ));
725 p += sizeof( struct ClearToken );
728 memcpy( p, &aint, sizeof( int ));
733 p += strlen( realm ) + 1;
736 vi.in_size = p - buf;
738 vi.out_size = sizeof( buf );
739 if ( pioctl( 0, VIOCSETTOK, &vi, 0 ) < 0 ) {
740 LOG(log_error, logtype_default, "krb_logincont: pioctl: %m" );
741 return ( AFPERR_BADUAM );
744 if ( unlink( tktfile ) < 0 ) {
745 LOG(log_error, logtype_default, "krb_logincont: %s: %m", tktfile );
746 return ( AFPERR_BADUAM );
749 if (( pwd = uam_getname( obj, username, strlen(username) )) == NULL ) {
750 return ( AFPERR_PARAM );
755 LOG(log_info, logtype_default, "authenticated %s.%s@%s", name, instance, realm );
759 LOG(log_info, logtype_default, "re-authenticated %s.%s@%s", name, instance, realm );
762 #endif /* UAM_AFSKRB AFS */
764 static int uam_setup(const char *path)
767 uam_register(UAM_SERVER_LOGIN, path, "Kerberos IV", krb4_login,
768 krb4_logincont, NULL);
769 /* uam_afpserver_action(); */
772 uam_register(UAM_SERVER_LOGIN, path, "AFS Kerberos", afskrb_login,
773 afskrb_logincont, NULL);
774 /* uam_afpserver_action(); */
775 #endif /* UAM_AFSKRB */
779 static void uam_cleanup(void)
782 /* uam_afpserver_action(); */
783 uam_unregister(UAM_SERVER_LOGIN, "Kerberos IV");
786 /* uam_afpserver_action(); */
787 uam_unregister(UAM_SERVER_LOGIN, "AFS Kerberos");
791 UAM_MODULE_EXPORT struct uam_export uams_krb4 = {
794 uam_setup, uam_cleanup
797 #endif /* KRB or UAM_AFSKRB */