2 * $Id: uams_krb4.c,v 1.10 2009-10-15 11:39:48 didg 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>
27 #include <atalk/logger.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 void lcase( p )
85 static 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, size_t ibuflen,
110 char *rbuf, size_t *rbuflen )
120 char inst[ 40 ], princ[ 40 ];
122 if (uam_afpserver_option(obj, UAM_OPTION_USERNAME, &username, &ulen) < 0)
125 if (uam_afpserver_option(obj, UAM_OPTION_PROTOCOL, &proto, NULL) < 0)
130 LOG(log_info, logtype_default, "krb4_login: KRB4CMD_SESS" );
133 memcpy( &len, p, sizeof( u_int16_t ));
134 tkt.length = ntohs( len );
135 p += sizeof( u_int16_t );
137 if ( tkt.length <= 0 || tkt.length > MAX_KTXT_LEN ) {
139 LOG(log_info, logtype_default, "krb4_login: tkt.length = %d", tkt.length );
140 return( AFPERR_BADUAM );
143 memcpy( tkt.dat, p, tkt.length );
150 strcpy( princ, "afpserver" );
153 strcpy( princ, "rcmd" );
157 if( (rc = krb_rd_req( &tkt, princ, inst, 0, &ad, "" ))
159 LOG(log_error, logtype_default,
160 "krb4_login: krb_rd_req(): %s", krb_err_txt[ rc ] );
162 return( AFPERR_BADUAM );
165 LOG(log_info, logtype_default, "krb4_login: %s.%s@%s", ad.pname, ad.pinst,
167 strcpy( realm, ad.prealm );
168 memcpy( seskey, ad.session, sizeof( C_Block ) );
169 key_sched( (C_Block *)seskey, seskeysched );
171 strncpy( username, ad.pname, ulen );
176 *p = KRB4RPL_DONE; /* XXX */
179 if (( pwd = uam_getname( obj, ad.pname, strlen(ad.pname) )) == NULL ) {
183 if (uam_checkuser( pwd ) < 0) {
184 return AFPERR_NOTAUTH;
188 return( AFP_OK ); /* Should this be AFPERR_AUTHCONT? */
191 *p++ = KRB4RPL_PRINC;
192 len = strlen( realm );
201 if (krb_get_lrealm( realm, 1 ) != KSUCCESS ) {
202 LOG(log_error, logtype_default, "krb4_login: can't get local realm!" );
203 return( AFPERR_NOTAUTH );
205 *p++ = KRB4RPL_REALM;
207 len = strlen( realm );
215 LOG(log_info, logtype_default, "krb4_login: bad command %d", *ibuf );
216 return( AFPERR_NOTAUTH );
220 if ( setpag() < 0 ) {
222 LOG(log_error, logtype_default, "krb_login: setpag: %s", strerror(errno) );
223 return( AFPERR_BADUAM );
228 return( AFPERR_AUTHCONT );
231 static int krb4_action( void *v1, void *v2, const int i )
237 I have a hunch that problems might arise on platforms
238 with non-16bit short's and non-32bit int's
240 static int krb4_logincont(void *obj, struct passwd **uam_pwd,
241 char *ibuf, size_t ibuflen,
242 char *rbuf, size_t *rbuflen)
244 static struct passwd *pwd;
249 char *p, *username, *servername;
253 struct ClearToken ct;
256 int aint, ulen, snlen;
258 if (uam_afpserver_option(obj, UAM_OPTION_USERNAME, &username, &ulen) < 0)
261 if (uam_afpserver_option(obj, UAM_OPTION_HOSTNAME, &servername, &snlen) < 0)
265 switch ( rc = *ibuf++ ) {
269 memcpy( &len, ibuf, sizeof( u_int16_t ) );
270 ibuf += sizeof( len );
273 memcpy( p, &aint, sizeof( int ) );
275 memcpy( p, ibuf, len );
276 pcbc_encrypt( (C_Block *)p, (C_Block *)p, len, seskeysched,
281 memcpy( &len, ibuf, sizeof( u_int16_t ) );
282 ibuf += sizeof( u_int16_t ) );
285 if ( len != sizeof( struct ClearToken ) ) {
286 LOG(log_error, logtype_default, "krb4_logincont: token too short" );
288 return( AFPERR_BADUAM );
290 memcpy( &ct, ibuf, len );
292 pcbc_encrypt( (C_Block *)&ct, (C_Block *)&ct, len,
293 seskeysched, seskey, DECRYPT );
295 aint = sizeof( struct ClearToken );
296 memcpy( p, &aint, sizeof( int ) );
298 memcpy( p, &ct, sizeof( struct ClearToken ) );
299 p += sizeof( struct ClearToken );
302 memcpy( p, &aint, sizeof( int ) );
307 p += strlen( realm ) + 1;
310 vi.in_size = p - buf;
312 vi.out_size = sizeof( buf );
314 if ( pioctl( 0, VIOCSETTOK, &vi, 0 ) < 0 ) {
315 LOG(log_error, logtype_default, "krb4_logincont: pioctl: %s", strerror(errno) );
317 return( AFPERR_BADUAM );
323 *p = KRB4RPL_DONE; /* XXX */
326 if (( pwd = uam_getname( obj, username, strlen(username) ) ) == NULL ) {
327 return( AFPERR_NOTAUTH );
330 if (uam_checkuser(pwd) < 0) {
331 return AFPERR_NOTAUTH;
338 /* read in the rest */
339 if (uam_afp_read(obj, rbuf, rbuflen, krb4_action) < 0)
343 switch ( rc = *p++ ) {
345 memcpy( &len, p, sizeof( len ));
346 tkt.length = ntohs( len );
347 p += sizeof( short );
349 if ( tkt.length <= 0 || tkt.length > MAX_KTXT_LEN ) {
350 return( AFPERR_BADUAM );
352 memcpy( tkt.dat, p, tkt.length );
355 if (( rc = krb_rd_req( &tkt, "afpserver", servername,
356 0, &ad, "" )) != RD_AP_OK ) {
357 LOG(log_error, logtype_default, "krb4_logincont: krb_rd_req(): %s", krb_err_txt[ rc ] );
358 return( AFPERR_BADUAM );
361 LOG(log_info, logtype_default, "krb4_login: %s.%s@%s", ad.pname,
362 ad.pinst, ad.prealm );
363 memcpy(realm, ad.prealm, sizeof(realm));
364 memcpy(seskey, ad.session, sizeof( C_Block ));
365 key_sched((C_Block *) seskey, seskeysched );
367 strncpy(username, ad.pname, ulen);
371 *p = KRB4RPL_DONE; /* XXX */
374 if (( pwd = uam_getname( obj, ad.pname, strlen(ad.pname) ))
376 return( AFPERR_PARAM );
382 *p++ = KRB4RPL_PRINC;
383 len = strlen( realm );
389 return( AFPERR_AUTHCONT );
392 memcpy( &len, p, sizeof( len ));
395 memcpy( &cr, p, len );
397 pcbc_encrypt((C_Block *)&cr, (C_Block *)&cr, len,
398 seskeysched, seskey, DES_DECRYPT );
401 cr.ticket_st.length = ntohl( cr.ticket_st.length );
402 memcpy( p, &cr.ticket_st.length, sizeof( int ));
404 memcpy( p, cr.ticket_st.dat, cr.ticket_st.length );
405 p += cr.ticket_st.length;
407 ct.AuthHandle = ntohl( cr.kvno );
408 memcpy( ct.HandShakeKey, cr.session, sizeof( cr.session ));
410 ct.BeginTimestamp = ntohl( cr.issue_date );
411 ct.EndTimestamp = krb_life_to_time( ntohl( cr.issue_date ),
412 ntohl( cr.lifetime ));
414 aint = sizeof( struct ClearToken );
415 memcpy( p, &aint, sizeof( int ));
417 memcpy( p, &ct, sizeof( struct ClearToken ));
418 p += sizeof( struct ClearToken );
421 memcpy( p, &aint, sizeof( int ));
426 p += strlen( realm ) + 1;
429 vi.in_size = p - buf;
431 vi.out_size = sizeof( buf );
432 if ( pioctl( 0, VIOCSETTOK, &vi, 0 ) < 0 ) {
433 LOG(log_error, logtype_default, "krb4_logincont: pioctl: %s", strerror(errno) );
434 return( AFPERR_BADUAM );
440 *p = KRB4RPL_DONE; /* XXX */
443 if (( pwd = uam_getname( obj, ad.pname, strlen(ad.pname) ))
445 return( AFPERR_PARAM );
452 LOG(log_info, logtype_default, "krb4_logincont: bad command %d", rc );
454 return( AFPERR_NOTAUTH );
465 #include <rx/rxkad.h>
466 #include <afs/afsint.h>
468 char *ka_LocalCell();
471 addrealm(realm,cells)
480 for(;*ptr != 0 ;ptr++)
481 if(!strcmp(realm,*ptr))
485 *cells=(char**)realloc(*cells,((2+temp)*sizeof(char*)));
488 *ptr=(char*)malloc(strlen(realm)+1);
489 strcpy(*ptr++,realm);
494 static int kcheckuser(pwd,passwd)
500 char realm[MAXKTCREALMLEN];
501 char lorealm[MAXKTCREALMLEN];
503 Date lifetime=MAXKTCTICKETLIFETIME;
505 char **cells=(char **)malloc(sizeof(char*));
508 struct ktc_principal serviceName;
516 temp=(char*)malloc(strlen(pwd->pw_dir)+1);
517 strcpy(temp,pwd->pw_dir);
519 temp=strtok(temp,"/");
520 temp=strtok('\0',"/");
521 ka_CellToRealm(temp,realm,0);
522 addrealm(realm,&cells);
527 authenticate(cells,pwd->pw_name,passwd);
529 rc=ktc_ListTokens(cellNum,&cellNum,&serviceName);
539 static void authenticate(cells,name,passwd)
548 ka_UserAuthenticate(name,/*instance*/"",/*cell*/*ptr++,
549 passwd,/*setpag*/0,&errorstring);
554 #if defined( UAM_AFSKRB ) && defined( AFS )
555 static int afskrb_login(void *obj, struct passwd *uam_pwd,
556 char *ibuf, size_t ibuflen,
557 char *rbuf, size_t *rbuflen )
559 KTEXT_ST authent, rpkt;
561 char *p, *q, *username, servername;
562 int len, rc, whoserealm, ulen, snlen;
566 if (uam_afpserver_option(obj, UAM_OPTION_USERNAME, &username, &ulen) < 0)
569 if (uam_afpserver_option(obj, UAM_OPTION_HOSTNAME, &servername, &snlen ) < 0)
572 len = (unsigned char) *ibuf++;
574 if (( p = strchr( ibuf, '@' )) != NULL ) {
580 if ( krb_get_lrealm( realm, 1 ) != KSUCCESS ) {
581 return AFPERR_BADUAM;
585 if (( p = strchr( ibuf, '.' )) != NULL ) {
587 strcpy( instance, p );
591 strcpy( name, ibuf );
593 * We don't have the session key, yet. Get one.
596 if ( validseskey == 0 ) {
597 if ( setpag() < 0 ) {
598 LOG(log_error, logtype_default, "krb_login: setpag: %s", strerror(errno) );
599 return AFPERR_BADUAM;
601 krb_set_tkt_string(( tktfile = mktemp( _PATH_AFPTKT )));
602 if (( rc = krb_get_svc_in_tkt( "afpserver", servername, realm,
603 TICKET_GRANTING_TICKET, realm, 255, KEYFILE )) != INTK_OK ) {
604 LOG(log_error, logtype_default, "krb_login: can't get ticket-granting-ticket" );
605 return (( whoserealm ) ? AFPERR_BADUAM : AFPERR_PARAM );
607 if ( krb_mk_req( &authent, name, instance, realm, 0 ) != KSUCCESS ) {
608 return ( AFPERR_PARAM );
610 if ( krb_get_cred( name, instance, realm, &cr ) != KSUCCESS ) {
611 return ( AFPERR_BADUAM );
614 if ( unlink( tktfile ) < 0 ) {
615 LOG(log_error, logtype_default, "krb_login: unlink %s: %s", tktfile, strerror(errno) );
616 return ( AFPERR_BADUAM );
619 memcpy( seskey, cr.session, sizeof( C_Block ));
620 key_sched((C_Block *) seskey, seskeysched );
622 strncpy(username, name, ulen);
624 memcpy( p, authent.dat, authent.length );
628 if ( kuam_get_in_tkt( name, instance, realm, TICKET_GRANTING_TICKET,
629 realm, 255, &rpkt ) != INTK_OK ) {
630 return ( AFPERR_PARAM );
634 q = (char *)rpkt.dat;
645 len = strlen( realm );
648 memcpy( &slen, q, sizeof( short ));
649 memcpy( p, &slen, sizeof( short ));
650 p += sizeof( short );
651 q += sizeof( short );
652 memcpy( p, q, slen );
656 return( AFPERR_AUTHCONT );
659 static int afskrb_logincont(void *obj, struct passwd *uam_pwd,
660 char *ibuf, size_t ibuflen,
661 char *rbuf, size_t *rbuflen )
665 struct ClearToken ct;
667 char buf[ 1024 ], *p;
672 if (uam_afpserver_option(obj, UAM_OPTION_USERNAME, &username, NULL) < 0)
676 memcpy( &clen, ibuf, sizeof( short ));
677 clen = ntohs( clen );
678 ibuf += sizeof( short );
680 pcbc_encrypt((C_Block *)ibuf, (C_Block *)ibuf,
681 clen, seskeysched, seskey, DES_DECRYPT );
682 if ( kuam_set_in_tkt( name, instance, realm, TICKET_GRANTING_TICKET,
683 realm, ibuf ) != INTK_OK ) {
684 return ( AFPERR_PARAM );
687 if ( get_ad_tkt( "afs", "", realm, 255 ) != KSUCCESS ) {
688 return ( AFPERR_PARAM );
690 if ( krb_get_cred( "afs", "", realm, &cr ) != KSUCCESS ) {
691 return ( AFPERR_PARAM );
695 memcpy( p, &cr.ticket_st.length, sizeof( int ));
697 memcpy( p, cr.ticket_st.dat, cr.ticket_st.length );
698 p += cr.ticket_st.length;
700 ct.AuthHandle = cr.kvno;
701 memcpy( ct.HandShakeKey, cr.session, sizeof( cr.session ));
703 ct.BeginTimestamp = cr.issue_date;
704 /* ct.EndTimestamp = cr.issue_date + ( cr.lifetime * 5 * 60 ); */
705 ct.EndTimestamp = krb_life_to_time( cr.issue_date, cr.lifetime );
707 aint = sizeof( struct ClearToken );
708 memcpy( p, &aint, sizeof( int ));
710 memcpy( p, &ct, sizeof( struct ClearToken ));
711 p += sizeof( struct ClearToken );
714 memcpy( p, &aint, sizeof( int ));
719 p += strlen( realm ) + 1;
722 vi.in_size = p - buf;
724 vi.out_size = sizeof( buf );
725 if ( pioctl( 0, VIOCSETTOK, &vi, 0 ) < 0 ) {
726 LOG(log_error, logtype_default, "krb_logincont: pioctl: %s", strerror(errno) );
727 return ( AFPERR_BADUAM );
730 if ( unlink( tktfile ) < 0 ) {
731 LOG(log_error, logtype_default, "krb_logincont: %s: %s", tktfile, strerror(errno) );
732 return ( AFPERR_BADUAM );
735 if (( pwd = uam_getname( obj, username, strlen(username) )) == NULL ) {
736 return ( AFPERR_PARAM );
741 LOG(log_info, logtype_default, "authenticated %s.%s@%s", name, instance, realm );
745 LOG(log_info, logtype_default, "re-authenticated %s.%s@%s", name, instance, realm );
748 #endif /* UAM_AFSKRB AFS */
750 static int uam_setup(const char *path)
753 uam_register(UAM_SERVER_LOGIN, path, "Kerberos IV", krb4_login,
754 krb4_logincont, NULL);
755 /* uam_afpserver_action(); */
758 uam_register(UAM_SERVER_LOGIN, path, "AFS Kerberos", afskrb_login,
759 afskrb_logincont, NULL);
760 /* uam_afpserver_action(); */
761 #endif /* UAM_AFSKRB */
765 static void uam_cleanup(void)
768 /* uam_afpserver_action(); */
769 uam_unregister(UAM_SERVER_LOGIN, "Kerberos IV");
772 /* uam_afpserver_action(); */
773 uam_unregister(UAM_SERVER_LOGIN, "AFS Kerberos");
777 UAM_MODULE_EXPORT struct uam_export uams_krb4 = {
780 uam_setup, uam_cleanup
783 #endif /* KRB or UAM_AFSKRB */