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>
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 void lcase( p )
100 static 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, size_t ibuflen,
125 char *rbuf, size_t *rbuflen )
135 char inst[ 40 ], princ[ 40 ];
137 if (uam_afpserver_option(obj, UAM_OPTION_USERNAME, &username, &ulen) < 0)
140 if (uam_afpserver_option(obj, UAM_OPTION_PROTOCOL, &proto, NULL) < 0)
145 LOG(log_info, logtype_default, "krb4_login: KRB4CMD_SESS" );
148 memcpy( &len, p, sizeof( u_int16_t ));
149 tkt.length = ntohs( len );
150 p += sizeof( u_int16_t );
152 if ( tkt.length <= 0 || tkt.length > MAX_KTXT_LEN ) {
154 LOG(log_info, logtype_default, "krb4_login: tkt.length = %d", tkt.length );
155 return( AFPERR_BADUAM );
158 memcpy( tkt.dat, p, tkt.length );
165 strcpy( princ, "afpserver" );
168 strcpy( princ, "rcmd" );
172 if( (rc = krb_rd_req( &tkt, princ, inst, 0, &ad, "" ))
174 LOG(log_error, logtype_default,
175 "krb4_login: krb_rd_req(): %s", krb_err_txt[ rc ] );
177 return( AFPERR_BADUAM );
180 LOG(log_info, logtype_default, "krb4_login: %s.%s@%s", ad.pname, ad.pinst,
182 strcpy( realm, ad.prealm );
183 memcpy( seskey, ad.session, sizeof( C_Block ) );
184 key_sched( (C_Block *)seskey, seskeysched );
186 strncpy( username, ad.pname, ulen );
191 *p = KRB4RPL_DONE; /* XXX */
194 if (( pwd = uam_getname( obj, ad.pname, strlen(ad.pname) )) == NULL ) {
198 if (uam_checkuser( pwd ) < 0) {
199 return AFPERR_NOTAUTH;
203 return( AFP_OK ); /* Should this be AFPERR_AUTHCONT? */
206 *p++ = KRB4RPL_PRINC;
207 len = strlen( realm );
216 if (krb_get_lrealm( realm, 1 ) != KSUCCESS ) {
217 LOG(log_error, logtype_default, "krb4_login: can't get local realm!" );
218 return( AFPERR_NOTAUTH );
220 *p++ = KRB4RPL_REALM;
222 len = strlen( realm );
230 LOG(log_info, logtype_default, "krb4_login: bad command %d", *ibuf );
231 return( AFPERR_NOTAUTH );
235 if ( setpag() < 0 ) {
237 LOG(log_error, logtype_default, "krb_login: setpag: %s", strerror(errno) );
238 return( AFPERR_BADUAM );
243 return( AFPERR_AUTHCONT );
246 static int krb4_action( void *v1, void *v2, const int i )
252 I have a hunch that problems might arise on platforms
253 with non-16bit short's and non-32bit int's
255 static int krb4_logincont(void *obj, struct passwd **uam_pwd,
256 char *ibuf, size_t ibuflen,
257 char *rbuf, size_t *rbuflen)
259 static struct passwd *pwd;
264 char *p, *username, *servername;
268 struct ClearToken ct;
271 int aint, ulen, snlen;
273 if (uam_afpserver_option(obj, UAM_OPTION_USERNAME, &username, &ulen) < 0)
276 if (uam_afpserver_option(obj, UAM_OPTION_HOSTNAME, &servername, &snlen) < 0)
280 switch ( rc = *ibuf++ ) {
284 memcpy( &len, ibuf, sizeof( u_int16_t ) );
285 ibuf += sizeof( len );
288 memcpy( p, &aint, sizeof( int ) );
290 memcpy( p, ibuf, len );
291 pcbc_encrypt( (C_Block *)p, (C_Block *)p, len, seskeysched,
296 memcpy( &len, ibuf, sizeof( u_int16_t ) );
297 ibuf += sizeof( u_int16_t ) );
300 if ( len != sizeof( struct ClearToken ) ) {
301 LOG(log_error, logtype_default, "krb4_logincont: token too short" );
303 return( AFPERR_BADUAM );
305 memcpy( &ct, ibuf, len );
307 pcbc_encrypt( (C_Block *)&ct, (C_Block *)&ct, len,
308 seskeysched, seskey, DECRYPT );
310 aint = sizeof( struct ClearToken );
311 memcpy( p, &aint, sizeof( int ) );
313 memcpy( p, &ct, sizeof( struct ClearToken ) );
314 p += sizeof( struct ClearToken );
317 memcpy( p, &aint, sizeof( int ) );
322 p += strlen( realm ) + 1;
325 vi.in_size = p - buf;
327 vi.out_size = sizeof( buf );
329 if ( pioctl( 0, VIOCSETTOK, &vi, 0 ) < 0 ) {
330 LOG(log_error, logtype_default, "krb4_logincont: pioctl: %s", strerror(errno) );
332 return( AFPERR_BADUAM );
338 *p = KRB4RPL_DONE; /* XXX */
341 if (( pwd = uam_getname( obj, username, strlen(username) ) ) == NULL ) {
342 return( AFPERR_NOTAUTH );
345 if (uam_checkuser(pwd) < 0) {
346 return AFPERR_NOTAUTH;
353 /* read in the rest */
354 if (uam_afp_read(obj, rbuf, rbuflen, krb4_action) < 0)
358 switch ( rc = *p++ ) {
360 memcpy( &len, p, sizeof( len ));
361 tkt.length = ntohs( len );
362 p += sizeof( short );
364 if ( tkt.length <= 0 || tkt.length > MAX_KTXT_LEN ) {
365 return( AFPERR_BADUAM );
367 memcpy( tkt.dat, p, tkt.length );
370 if (( rc = krb_rd_req( &tkt, "afpserver", servername,
371 0, &ad, "" )) != RD_AP_OK ) {
372 LOG(log_error, logtype_default, "krb4_logincont: krb_rd_req(): %s", krb_err_txt[ rc ] );
373 return( AFPERR_BADUAM );
376 LOG(log_info, logtype_default, "krb4_login: %s.%s@%s", ad.pname,
377 ad.pinst, ad.prealm );
378 memcpy(realm, ad.prealm, sizeof(realm));
379 memcpy(seskey, ad.session, sizeof( C_Block ));
380 key_sched((C_Block *) seskey, seskeysched );
382 strncpy(username, ad.pname, ulen);
386 *p = KRB4RPL_DONE; /* XXX */
389 if (( pwd = uam_getname( obj, ad.pname, strlen(ad.pname) ))
391 return( AFPERR_PARAM );
397 *p++ = KRB4RPL_PRINC;
398 len = strlen( realm );
404 return( AFPERR_AUTHCONT );
407 memcpy( &len, p, sizeof( len ));
410 memcpy( &cr, p, len );
412 pcbc_encrypt((C_Block *)&cr, (C_Block *)&cr, len,
413 seskeysched, seskey, DES_DECRYPT );
416 cr.ticket_st.length = ntohl( cr.ticket_st.length );
417 memcpy( p, &cr.ticket_st.length, sizeof( int ));
419 memcpy( p, cr.ticket_st.dat, cr.ticket_st.length );
420 p += cr.ticket_st.length;
422 ct.AuthHandle = ntohl( cr.kvno );
423 memcpy( ct.HandShakeKey, cr.session, sizeof( cr.session ));
425 ct.BeginTimestamp = ntohl( cr.issue_date );
426 ct.EndTimestamp = krb_life_to_time( ntohl( cr.issue_date ),
427 ntohl( cr.lifetime ));
429 aint = sizeof( struct ClearToken );
430 memcpy( p, &aint, sizeof( int ));
432 memcpy( p, &ct, sizeof( struct ClearToken ));
433 p += sizeof( struct ClearToken );
436 memcpy( p, &aint, sizeof( int ));
441 p += strlen( realm ) + 1;
444 vi.in_size = p - buf;
446 vi.out_size = sizeof( buf );
447 if ( pioctl( 0, VIOCSETTOK, &vi, 0 ) < 0 ) {
448 LOG(log_error, logtype_default, "krb4_logincont: pioctl: %s", strerror(errno) );
449 return( AFPERR_BADUAM );
455 *p = KRB4RPL_DONE; /* XXX */
458 if (( pwd = uam_getname( obj, ad.pname, strlen(ad.pname) ))
460 return( AFPERR_PARAM );
467 LOG(log_info, logtype_default, "krb4_logincont: bad command %d", rc );
469 return( AFPERR_NOTAUTH );
480 #include <rx/rxkad.h>
481 #include <afs/afsint.h>
483 char *ka_LocalCell();
486 addrealm(realm,cells)
495 for(;*ptr != 0 ;ptr++)
496 if(!strcmp(realm,*ptr))
500 *cells=(char**)realloc(*cells,((2+temp)*sizeof(char*)));
503 *ptr=(char*)malloc(strlen(realm)+1);
504 strcpy(*ptr++,realm);
509 static int kcheckuser(pwd,passwd)
515 char realm[MAXKTCREALMLEN];
516 char lorealm[MAXKTCREALMLEN];
518 Date lifetime=MAXKTCTICKETLIFETIME;
520 char **cells=(char **)malloc(sizeof(char*));
523 struct ktc_principal serviceName;
531 temp=(char*)malloc(strlen(pwd->pw_dir)+1);
532 strcpy(temp,pwd->pw_dir);
534 temp=strtok(temp,"/");
535 temp=strtok('\0',"/");
536 ka_CellToRealm(temp,realm,0);
537 addrealm(realm,&cells);
542 authenticate(cells,pwd->pw_name,passwd);
544 rc=ktc_ListTokens(cellNum,&cellNum,&serviceName);
554 static void authenticate(cells,name,passwd)
563 ka_UserAuthenticate(name,/*instance*/"",/*cell*/*ptr++,
564 passwd,/*setpag*/0,&errorstring);
569 #if defined( UAM_AFSKRB ) && defined( AFS )
570 static int afskrb_login(void *obj, struct passwd *uam_pwd,
571 char *ibuf, size_t ibuflen,
572 char *rbuf, size_t *rbuflen )
574 KTEXT_ST authent, rpkt;
576 char *p, *q, *username, servername;
577 int len, rc, whoserealm, ulen, snlen;
581 if (uam_afpserver_option(obj, UAM_OPTION_USERNAME, &username, &ulen) < 0)
584 if (uam_afpserver_option(obj, UAM_OPTION_HOSTNAME, &servername, &snlen ) < 0)
587 len = (unsigned char) *ibuf++;
589 if (( p = strchr( ibuf, '@' )) != NULL ) {
595 if ( krb_get_lrealm( realm, 1 ) != KSUCCESS ) {
596 return AFPERR_BADUAM;
600 if (( p = strchr( ibuf, '.' )) != NULL ) {
602 strcpy( instance, p );
606 strcpy( name, ibuf );
608 * We don't have the session key, yet. Get one.
611 if ( validseskey == 0 ) {
612 if ( setpag() < 0 ) {
613 LOG(log_error, logtype_default, "krb_login: setpag: %s", strerror(errno) );
614 return AFPERR_BADUAM;
616 krb_set_tkt_string(( tktfile = mktemp( _PATH_AFPTKT )));
617 if (( rc = krb_get_svc_in_tkt( "afpserver", servername, realm,
618 TICKET_GRANTING_TICKET, realm, 255, KEYFILE )) != INTK_OK ) {
619 LOG(log_error, logtype_default, "krb_login: can't get ticket-granting-ticket" );
620 return (( whoserealm ) ? AFPERR_BADUAM : AFPERR_PARAM );
622 if ( krb_mk_req( &authent, name, instance, realm, 0 ) != KSUCCESS ) {
623 return ( AFPERR_PARAM );
625 if ( krb_get_cred( name, instance, realm, &cr ) != KSUCCESS ) {
626 return ( AFPERR_BADUAM );
629 if ( unlink( tktfile ) < 0 ) {
630 LOG(log_error, logtype_default, "krb_login: unlink %s: %s", tktfile, strerror(errno) );
631 return ( AFPERR_BADUAM );
634 memcpy( seskey, cr.session, sizeof( C_Block ));
635 key_sched((C_Block *) seskey, seskeysched );
637 strncpy(username, name, ulen);
639 memcpy( p, authent.dat, authent.length );
643 if ( kuam_get_in_tkt( name, instance, realm, TICKET_GRANTING_TICKET,
644 realm, 255, &rpkt ) != INTK_OK ) {
645 return ( AFPERR_PARAM );
649 q = (char *)rpkt.dat;
660 len = strlen( realm );
663 memcpy( &slen, q, sizeof( short ));
664 memcpy( p, &slen, sizeof( short ));
665 p += sizeof( short );
666 q += sizeof( short );
667 memcpy( p, q, slen );
671 return( AFPERR_AUTHCONT );
674 static int afskrb_logincont(void *obj, struct passwd *uam_pwd,
675 char *ibuf, size_t ibuflen,
676 char *rbuf, size_t *rbuflen )
680 struct ClearToken ct;
682 char buf[ 1024 ], *p;
687 if (uam_afpserver_option(obj, UAM_OPTION_USERNAME, &username, NULL) < 0)
691 memcpy( &clen, ibuf, sizeof( short ));
692 clen = ntohs( clen );
693 ibuf += sizeof( short );
695 pcbc_encrypt((C_Block *)ibuf, (C_Block *)ibuf,
696 clen, seskeysched, seskey, DES_DECRYPT );
697 if ( kuam_set_in_tkt( name, instance, realm, TICKET_GRANTING_TICKET,
698 realm, ibuf ) != INTK_OK ) {
699 return ( AFPERR_PARAM );
702 if ( get_ad_tkt( "afs", "", realm, 255 ) != KSUCCESS ) {
703 return ( AFPERR_PARAM );
705 if ( krb_get_cred( "afs", "", realm, &cr ) != KSUCCESS ) {
706 return ( AFPERR_PARAM );
710 memcpy( p, &cr.ticket_st.length, sizeof( int ));
712 memcpy( p, cr.ticket_st.dat, cr.ticket_st.length );
713 p += cr.ticket_st.length;
715 ct.AuthHandle = cr.kvno;
716 memcpy( ct.HandShakeKey, cr.session, sizeof( cr.session ));
718 ct.BeginTimestamp = cr.issue_date;
719 /* ct.EndTimestamp = cr.issue_date + ( cr.lifetime * 5 * 60 ); */
720 ct.EndTimestamp = krb_life_to_time( cr.issue_date, cr.lifetime );
722 aint = sizeof( struct ClearToken );
723 memcpy( p, &aint, sizeof( int ));
725 memcpy( p, &ct, sizeof( struct ClearToken ));
726 p += sizeof( struct ClearToken );
729 memcpy( p, &aint, sizeof( int ));
734 p += strlen( realm ) + 1;
737 vi.in_size = p - buf;
739 vi.out_size = sizeof( buf );
740 if ( pioctl( 0, VIOCSETTOK, &vi, 0 ) < 0 ) {
741 LOG(log_error, logtype_default, "krb_logincont: pioctl: %s", strerror(errno) );
742 return ( AFPERR_BADUAM );
745 if ( unlink( tktfile ) < 0 ) {
746 LOG(log_error, logtype_default, "krb_logincont: %s: %s", tktfile, strerror(errno) );
747 return ( AFPERR_BADUAM );
750 if (( pwd = uam_getname( obj, username, strlen(username) )) == NULL ) {
751 return ( AFPERR_PARAM );
756 LOG(log_info, logtype_default, "authenticated %s.%s@%s", name, instance, realm );
760 LOG(log_info, logtype_default, "re-authenticated %s.%s@%s", name, instance, realm );
763 #endif /* UAM_AFSKRB AFS */
765 static int uam_setup(const char *path)
768 uam_register(UAM_SERVER_LOGIN, path, "Kerberos IV", krb4_login,
769 krb4_logincont, NULL);
770 /* uam_afpserver_action(); */
773 uam_register(UAM_SERVER_LOGIN, path, "AFS Kerberos", afskrb_login,
774 afskrb_logincont, NULL);
775 /* uam_afpserver_action(); */
776 #endif /* UAM_AFSKRB */
780 static void uam_cleanup(void)
783 /* uam_afpserver_action(); */
784 uam_unregister(UAM_SERVER_LOGIN, "Kerberos IV");
787 /* uam_afpserver_action(); */
788 uam_unregister(UAM_SERVER_LOGIN, "AFS Kerberos");
792 UAM_MODULE_EXPORT struct uam_export uams_krb4 = {
795 uam_setup, uam_cleanup
798 #endif /* KRB or UAM_AFSKRB */