[23153] in Source-Commits
/svn/athena r22814 - in trunk/athena/lib/zephyr: . h h/zephyr lib server zhm
daemon@ATHENA.MIT.EDU (ghudson@MIT.EDU)
Thu Apr 3 13:52:35 2008
Date: Thu, 3 Apr 2008 13:51:49 -0400 (EDT)
From: ghudson@MIT.EDU
Message-Id: <200804031751.NAA06985@drugstore.mit.edu>
To: source-commits@MIT.EDU
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Author: ghudson
Date: 2008-04-03 13:51:46 -0400 (Thu, 03 Apr 2008)
New Revision: 22814
Added:
trunk/athena/lib/zephyr/lib/ZCkZAut.c
trunk/athena/lib/zephyr/lib/ZMakeZcode.c
trunk/athena/lib/zephyr/lib/ZReadZcode.c
Modified:
trunk/athena/lib/zephyr/configure.in
trunk/athena/lib/zephyr/h/internal.h
trunk/athena/lib/zephyr/h/zephyr/zephyr.h
trunk/athena/lib/zephyr/lib/Makefile.in
trunk/athena/lib/zephyr/lib/ZCkAuth.c
trunk/athena/lib/zephyr/lib/ZFmtAuth.c
trunk/athena/lib/zephyr/lib/ZFmtNotice.c
trunk/athena/lib/zephyr/lib/ZFmtSmRaw.c
trunk/athena/lib/zephyr/lib/ZGetSender.c
trunk/athena/lib/zephyr/lib/ZInit.c
trunk/athena/lib/zephyr/lib/ZMkAuth.c
trunk/athena/lib/zephyr/lib/ZParseNot.c
trunk/athena/lib/zephyr/lib/ZVariables.c
trunk/athena/lib/zephyr/lib/Zinternal.c
trunk/athena/lib/zephyr/server/bdump.c
trunk/athena/lib/zephyr/server/client.c
trunk/athena/lib/zephyr/server/dispatch.c
trunk/athena/lib/zephyr/server/kstuff.c
trunk/athena/lib/zephyr/server/main.c
trunk/athena/lib/zephyr/server/realm.c
trunk/athena/lib/zephyr/server/server.c
trunk/athena/lib/zephyr/server/subscr.c
trunk/athena/lib/zephyr/server/uloc.c
trunk/athena/lib/zephyr/server/zserver.h
trunk/athena/lib/zephyr/server/zsrv_conf.h
trunk/athena/lib/zephyr/zhm/zhm_client.c
Log:
From Karl Ramm (incorporating work from Jeff Hutzelman and others):
Add krb5 support to Zephyr.
Modified: trunk/athena/lib/zephyr/configure.in
===================================================================
--- trunk/athena/lib/zephyr/configure.in 2008-04-03 17:32:17 UTC (rev 22813)
+++ trunk/athena/lib/zephyr/configure.in 2008-04-03 17:51:46 UTC (rev 22814)
@@ -37,7 +37,7 @@
AC_HEADER_SYS_WAIT
AC_CHECK_HEADERS(fcntl.h paths.h termios.h sgtty.h unistd.h malloc.h)
AC_CHECK_HEADERS(sys/filio.h sys/ioctl.h sys/time.h sys/file.h sys/utsname.h)
-AC_CHECK_HEADERS(sys/select.h sys/msgbuf.h sys/cdefs.h)
+AC_CHECK_HEADERS(sys/select.h sys/msgbuf.h sys/cdefs.h krb5_err.h)
if test "$no_x" != "yes"; then
XCLIENTS=xzwrite
@@ -86,12 +86,13 @@
AC_SUBST(SLIB)
ATHENA_KRB4
+ATHENA_KRB5
ATHENA_HESIOD
ATHENA_REGEXP
ATHENA_ARES
ATHENA_UTIL_COM_ERR
ATHENA_UTIL_SS
-LIBS="$KRB4_LIBS $HESIOD_LIBS $LIBS"
+LIBS="$KRB5_LIBS $KRB4_LIBS $HESIOD_LIBS $LIBS"
dnl Checks for library functions.
AC_PROG_GCC_TRADITIONAL
@@ -100,7 +101,60 @@
AC_FUNC_SETPGRP
AC_CHECK_FUNCS(putenv strchr memcpy memmove waitpid getlogin strerror random)
AC_CHECK_FUNCS(lrand48 gethostid getsid getpgid krb_get_err_text krb_log)
+AC_CHECK_FUNCS(krb5_free_data krb5_c_make_checksum krb5_cc_set_default_name)
+AC_MSG_CHECKING(for krb5_auth_con_getauthenticator taking double pointer)
+AC_CACHE_VAL(ac_cv_krb5_auth_con_getauthenticator_takes_double_pointer, [
+local_save_CPPFLAGS="$CPPFLAGS"
+CPPFLAGS="${CPPFLAGS} ${KRB5_INC_FLAGS}"
+AC_TRY_COMPILE(
+[#define socklen_t int
+#define ssize_t int
+#include <krb5.h>
+krb5_error_code
+krb5_auth_con_getauthenticator(krb5_context context,
+ krb5_auth_context auth_context,
+ krb5_authenticator *authenticator);],
+[krb5_error_code foo = krb5_auth_con_getauthenticator(0, 0, 0);],
+ac_cv_krb5_auth_con_getauthenticator_takes_double_pointer=no,
+ac_cv_krb5_auth_con_getauthenticator_takes_double_pointer=yes)
+])
+CPPFLAGS="${local_save_CPPFLAGS}"
+if test "$ac_cv_krb5_auth_con_getauthenticator_takes_double_pointer" = yes; then
+ AC_DEFINE(KRB5_AUTH_CON_GETAUTHENTICATOR_TAKES_DOUBLE_POINTER)dnl
+fi
+AC_MSG_RESULT($ac_cv_krb5_auth_con_getauthenticator_takes_double_pointer)
+
+AC_MSG_CHECKING(for enc_part2 in struct krb5_ticket)
+AC_CACHE_VAL(ac_cv_have_krb5_ticket_enc_part2, [
+local_save_CPPFLAGS="$CPPFLAGS"
+CPPFLAGS="${CPPFLAGS} ${KRB5_INC_FLAGS}"
+AC_TRY_COMPILE(
+[#include <krb5.h>], [krb5_ticket _tkt; _tkt.enc_part2;],
+ac_cv_have_krb5_ticket_enc_part2=yes,
+ac_cv_have_krb5_ticket_enc_part2=no)
+])
+CPPFLAGS="${local_save_CPPFLAGS}"
+if test "$ac_cv_have_krb5_ticket_enc_part2" = yes; then
+ AC_DEFINE(HAVE_KRB5_TICKET_ENC_PART2)dnl
+fi
+AC_MSG_RESULT($ac_cv_have_krb5_ticket_enc_part2)
+
+AC_MSG_CHECKING(for enctype in struct krb5_keyblock)
+AC_CACHE_VAL(ac_cv_have_krb5_creds_keyblock_enctype, [
+local_save_CPPFLAGS="$CPPFLAGS"
+CPPFLAGS="${CPPFLAGS} ${KRB5_INC_FLAGS}"
+AC_TRY_COMPILE(
+[#include <krb5.h>], [krb5_creds _creds; _creds.keyblock.enctype;],
+ac_cv_have_krb5_creds_keyblock_enctype=yes,
+ac_cv_have_krb5_creds_keyblock_enctype=no)
+])
+CPPFLAGS="${local_save_CPPFLAGS}"
+if test "$ac_cv_have_krb5_creds_keyblock_enctype" = yes; then
+ AC_DEFINE(HAVE_KRB5_CREDS_KEYBLOCK_ENCTYPE)dnl
+fi
+AC_MSG_RESULT($ac_cv_have_krb5_creds_keyblock_enctype)
+
AC_CONFIG_HEADER(h/config.h)
AC_OUTPUT(Makefile clients/Makefile clients/xzwrite/Makefile
clients/zaway/Makefile clients/zctl/Makefile
Modified: trunk/athena/lib/zephyr/h/internal.h
===================================================================
--- trunk/athena/lib/zephyr/h/internal.h 2008-04-03 17:32:17 UTC (rev 22813)
+++ trunk/athena/lib/zephyr/h/internal.h 2008-04-03 17:51:46 UTC (rev 22814)
@@ -11,6 +11,10 @@
#include <krb_err.h>
#endif
+#ifdef HAVE_KRB5
+#include <krb5.h>
+#endif
+
#ifdef HAVE_HESIOD
#include <hesiod.h>
#endif
@@ -34,6 +38,13 @@
#define Z_NOTICETIMELIMIT 30 /* Time to wait for fragments */
#define Z_INITFILTERSIZE 30 /* Starting size of uid filter */
+#define Z_AUTHMODE_NONE 0 /* no authentication */
+#define Z_AUTHMODE_KRB4 1 /* authenticate using Kerberos V4 */
+#define Z_AUTHMODE_KRB5 2 /* authenticate using Kerberos V5 */
+
+#define Z_KEYUSAGE_CLT_CKSUM 1027 /* client->server notice checksum */
+#define Z_KEYUSAGE_SRV_CKSUM 1029 /* server->client notice checksum */
+
struct _Z_Hole {
struct _Z_Hole *next;
int first;
@@ -64,6 +75,11 @@
extern int __HM_set; /* 0 if dest addr set, 1 otherwise */
extern int __Zephyr_server; /* 0 if normal client, 1 if server or zhm */
+#ifdef HAVE_KRB5
+extern krb5_context Z_krb5_ctx;
+Code_t Z_krb5_lookup_cksumtype(krb5_enctype, krb5_cksumtype *);
+#endif
+
extern ZLocations_t *__locate_list;
extern int __locate_num;
extern int __locate_next;
@@ -97,5 +113,48 @@
int (*pred) __P((ZNotice_t *, void *)), void *arg,
int timeout));
+
+Code_t Z_NewFormatHeader __P((ZNotice_t *, char *, int, int *, Z_AuthProc));
+Code_t Z_NewFormatAuthHeader __P((ZNotice_t *, char *, int, int *, Z_AuthProc));
+Code_t Z_NewFormatRawHeader __P((ZNotice_t *, char *, int, int *, char **,
+ int *, char **, char **));
+Code_t Z_AsciiFormatRawHeader __P((ZNotice_t *, char *, int, int *, char **,
+ int *, char **, char **));
+
+void Z_gettimeofday(struct _ZTimeval *ztv, struct timezone *tz);
+
+#ifdef HAVE_KRB5
+int ZGetCreds(krb5_creds **creds_out);
+int ZGetCredsRealm(krb5_creds **creds_out, char *realm);
+Code_t Z_Checksum(krb5_data *cksumbuf, krb5_keyblock *keyblock, krb5_cksumtype cksumtype, char **asn1_data, int *asn1_len);
+Code_t Z_ExtractEncCksum(krb5_keyblock *keyblock, krb5_enctype *enctype, krb5_cksumtype *cksumtype);
+int Z_krb5_verify_cksum(krb5_keyblock *keyblock, krb5_data *cksumbuf, krb5_cksumtype cksumtype, char *asn1_data, int asn1_len);
+Code_t Z_InsertZcodeChecksum(krb5_keyblock *keyblock, ZNotice_t *notice,
+ char *buffer,
+ char *cksum_start, int cksum_len,
+ char *cstart, char *cend, int buffer_len,
+ int *length_ajdust);
+#endif
+
+#ifdef HAVE_KRB5_CREDS_KEYBLOCK_ENCTYPE
+#define Z_keydata(keyblock) ((keyblock)->contents)
+#define Z_keylen(keyblock) ((keyblock)->length)
+#define Z_credskey(creds) (&(creds)->keyblock)
+#define Z_enctype(keyblock) ((keyblock)->enctype)
+#else
+#define Z_keydata(keyblock) ((keyblock)->keyvalue.data)
+#define Z_keylen(keyblock) ((keyblock)->keyvalue.length)
+#define Z_credskey(creds) (&(creds)->session)
+#define Z_enctype(keyblock) ((keyblock)->keytype)
+#endif
+
+#ifdef HAVE_KRB5_TICKET_ENC_PART2
+#define Z_tktprincp(tkt) ((tkt)->enc_part2 != 0)
+#define Z_tktprinc(tkt) ((tkt)->enc_part2->client)
+#else
+#define Z_tktprincp(tkt) ((tkt)->client != 0)
+#define Z_tktprinc(tkt) ((tkt)->client)
+#endif
+
#endif /* __INTERNAL_H__ */
Modified: trunk/athena/lib/zephyr/h/zephyr/zephyr.h
===================================================================
--- trunk/athena/lib/zephyr/h/zephyr/zephyr.h 2008-04-03 17:32:17 UTC (rev 22813)
+++ trunk/athena/lib/zephyr/h/zephyr/zephyr.h 2008-04-03 17:51:46 UTC (rev 22814)
@@ -39,6 +39,7 @@
#define SERVER_SVCNAME "zephyr-clt"
#define SERVER_SERVICE "zephyr"
#define SERVER_INSTANCE "zephyr"
+#define SERVER_KRB5_SERVICE "zephyr"
#define ZVERSIONHDR "ZEPH"
#define ZVERSIONMAJOR 0
@@ -62,14 +63,19 @@
} ZNotice_Kind_t;
extern ZCONST char *ZNoticeKinds[9];
+struct _ZTimeval {
+ int tv_sec;
+ int tv_usec;
+};
+
/* Unique ID format */
typedef struct _ZUnique_Id_t {
struct in_addr zuid_addr;
- struct timeval tv;
+ struct _ZTimeval tv;
} ZUnique_Id_t;
/* Checksum */
-typedef unsigned long ZChecksum_t;
+typedef unsigned int ZChecksum_t;
/* Notice definition */
typedef struct _ZNotice_t {
@@ -78,7 +84,7 @@
ZNotice_Kind_t z_kind;
ZUnique_Id_t z_uid;
#define z_sender_addr z_uid.zuid_addr
- struct timeval z_time;
+ struct _ZTimeval z_time;
unsigned short z_port;
int z_auth;
int z_checked_auth;
@@ -93,6 +99,7 @@
char *z_multinotice;
ZUnique_Id_t z_multiuid;
ZChecksum_t z_checksum;
+ char *z_ascii_checksum;
int z_num_other_fields;
char *z_other_fields[Z_MAXOTHERFIELDS];
caddr_t z_message;
@@ -134,6 +141,8 @@
/* Defines for ZFormatNotice, et al. */
typedef Code_t (*Z_AuthProc) ZP((ZNotice_t*, char *, int, int *));
Code_t ZMakeAuthentication ZP((ZNotice_t*, char *,int, int*));
+Code_t ZMakeZcodeAuthentication ZP((ZNotice_t*, char *,int, int*));
+Code_t ZMakeZcodeRealmAuthentication ZP((ZNotice_t*, char *,int, int*, char*));
char *ZGetSender ZP((void));
char *ZGetVariable ZP((char *));
@@ -147,6 +156,7 @@
Code_t ZReadAscii ZP((char*, int, unsigned char*, int));
Code_t ZReadAscii32 ZP((char *, int, unsigned long *));
Code_t ZReadAscii16 ZP((char *, int, unsigned short *));
+Code_t ZReadZcode ZP((unsigned char*, unsigned char*, int, int *));
Code_t ZSendPacket ZP((char*, int, int));
Code_t ZSendList ZP((ZNotice_t*, char *[], int, Z_AuthProc));
Code_t ZSrvSendList ZP((ZNotice_t*, char*[], int, Z_AuthProc, Code_t (*)()));
@@ -170,8 +180,12 @@
Code_t ZMakeAscii ZP((char*, int, unsigned char*, int));
Code_t ZMakeAscii32 ZP((char *, int, unsigned long));
Code_t ZMakeAscii16 ZP((char *, int, unsigned int));
+Code_t ZMakeZcode ZP((char*, int, unsigned char*, int));
+Code_t ZMakeZcode32 ZP((char *, int, unsigned long));
Code_t ZReceivePacket ZP((ZPacket_t, int*, struct sockaddr_in*));
Code_t ZCheckAuthentication ZP((ZNotice_t*, struct sockaddr_in*));
+Code_t ZCheckZcodeAuthentication ZP((ZNotice_t*, struct sockaddr_in*));
+Code_t ZCheckZcodeRealmAuthentication ZP((ZNotice_t*, struct sockaddr_in*, char *realm));
Code_t ZInitLocationInfo ZP((char *hostname, char *tty));
Code_t ZSetLocation ZP((char *exposure));
Code_t ZUnsetLocation ZP((void));
@@ -248,6 +262,7 @@
#define SRV_TIMEOUT 30
#define ZAUTH (ZMakeAuthentication)
+#define ZCAUTH (ZMakeZcodeAuthentication)
#define ZNOAUTH ((Z_AuthProc)0)
/* Packet strings */
Modified: trunk/athena/lib/zephyr/lib/Makefile.in
===================================================================
--- trunk/athena/lib/zephyr/lib/Makefile.in 2008-04-03 17:32:17 UTC (rev 22813)
+++ trunk/athena/lib/zephyr/lib/Makefile.in 2008-04-03 17:51:46 UTC (rev 22814)
@@ -37,7 +37,8 @@
ZPeekIfNot.lo ZPeekNot.lo ZPeekPkt.lo ZPending.lo ZReadAscii.lo \
ZRecvNot.lo ZRecvPkt.lo ZRetSubs.lo ZSendList.lo ZSendNot.lo \
ZSendPkt.lo ZSendRaw.lo ZSendRLst.lo ZSetDest.lo ZSetFD.lo ZSetSrv.lo \
- ZSubs.lo ZVariables.lo ZWait4Not.lo Zinternal.lo
+ ZSubs.lo ZVariables.lo ZWait4Not.lo Zinternal.lo ZMakeZcode.lo \
+ ZReadZcode.lo ZCkZAut.lo
.SUFFIXES: .lo
Modified: trunk/athena/lib/zephyr/lib/ZCkAuth.c
===================================================================
--- trunk/athena/lib/zephyr/lib/ZCkAuth.c 2008-04-03 17:32:17 UTC (rev 22813)
+++ trunk/athena/lib/zephyr/lib/ZCkAuth.c 2008-04-03 17:51:46 UTC (rev 22814)
@@ -17,6 +17,10 @@
#include <internal.h>
+#if defined(HAVE_KRB5) && !HAVE_KRB5_FREE_DATA
+#define krb5_free_data(ctx, dat) free((dat)->data)
+#endif
+
/* Check authentication of the notice.
If it looks authentic but fails the Kerberos check, return -1.
If it looks authentic and passes the Kerberos check, return 1.
@@ -28,30 +32,49 @@
Code_t ZCheckAuthentication(notice, from)
ZNotice_t *notice;
struct sockaddr_in *from;
-{
-#ifdef HAVE_KRB4
+{
+#if 0
+#if defined(HAVE_KRB4) || defined(HAVE_KRB5)
int result;
ZChecksum_t our_checksum;
+ C_Block *session;
+#ifdef HAVE_KRB5
+ krb5_creds *creds_out;
+#else
CREDENTIALS cred;
-
+#endif
/* If the value is already known, return it. */
if (notice->z_checked_auth != ZAUTH_UNSET)
return (notice->z_checked_auth);
if (!notice->z_auth)
return (ZAUTH_NO);
-
+
+#ifdef HAVE_KRB5
+ result = ZGetCreds(&creds_out);
+ if (result)
+ return ZAUTH_NO;
+ /* HOLDING: creds_out */
+
+ if (creds_out->keyblock.enctype != ENCTYPE_DES_CBC_CRC)
+ return (ZAUTH_NO);
+ session = (C_Block *)creds_out->keyblock.contents;
+
+#else
if ((result = krb_get_cred(SERVER_SERVICE, SERVER_INSTANCE,
__Zephyr_realm, &cred)) != 0)
return (ZAUTH_NO);
+ session = (C_Block *)cred.session;
+#endif
+
#ifdef NOENCRYPTION
our_checksum = 0;
#else
our_checksum = des_quad_cksum(notice->z_packet, NULL,
notice->z_default_format+
strlen(notice->z_default_format)+1-
- notice->z_packet, 0, cred.session);
+ notice->z_packet, 0, session);
#endif
/* if mismatched checksum, then the packet was corrupted */
return ((our_checksum == notice->z_checksum) ? ZAUTH_YES : ZAUTH_FAILED);
@@ -59,4 +82,7 @@
#else
return (notice->z_auth ? ZAUTH_YES : ZAUTH_NO);
#endif
+#else
+ ZCheckZcodeAuthentication(notice, from);
+#endif
}
Added: trunk/athena/lib/zephyr/lib/ZCkZAut.c
Modified: trunk/athena/lib/zephyr/lib/ZFmtAuth.c
===================================================================
--- trunk/athena/lib/zephyr/lib/ZFmtAuth.c 2008-04-03 17:32:17 UTC (rev 22813)
+++ trunk/athena/lib/zephyr/lib/ZFmtAuth.c 2008-04-03 17:51:46 UTC (rev 22814)
@@ -16,7 +16,7 @@
#include <internal.h>
-#ifdef HAVE_KRB4
+#if defined(HAVE_KRB4) || defined(HAVE_KRB5)
Code_t ZFormatAuthenticNotice(notice, buffer, buffer_len, len, session)
ZNotice_t *notice;
register char *buffer;
@@ -62,3 +62,71 @@
return (ZERR_NONE);
}
#endif
+
+#ifdef HAVE_KRB5
+Code_t ZFormatAuthenticNoticeV5(notice, buffer, buffer_len, len, keyblock)
+ ZNotice_t *notice;
+ register char *buffer;
+ register int buffer_len;
+ int *len;
+ krb5_keyblock *keyblock;
+{
+ ZNotice_t newnotice;
+ char *ptr;
+ int retval, hdrlen, hdr_adj;
+ krb5_enctype enctype;
+ krb5_cksumtype cksumtype;
+ int valid;
+ char *svcinst, *x, *y;
+ int key_len;
+ char *cksum_start, *cstart, *cend;
+ int cksum_len;
+
+ key_len = Z_keylen(keyblock);
+ retval = Z_ExtractEncCksum(keyblock, &enctype, &cksumtype);
+ if (retval)
+ return (ZAUTH_FAILED);
+
+ if (key_len == 8 && (enctype == ENCTYPE_DES_CBC_CRC ||
+ enctype == ENCTYPE_DES_CBC_MD4 ||
+ enctype == ENCTYPE_DES_CBC_MD5)) {
+ C_Block tmp;
+ memcpy(&tmp, Z_keydata(keyblock), key_len);
+ return ZFormatAuthenticNotice(notice, buffer, buffer_len, len,
+ tmp);
+ }
+
+ newnotice = *notice;
+ newnotice.z_auth = 1;
+ newnotice.z_authent_len = 0;
+ newnotice.z_ascii_authent = "";
+
+ if ((retval = Z_NewFormatRawHeader(&newnotice, buffer, buffer_len,
+ &hdrlen,
+ &cksum_start, &cksum_len, &cstart,
+ &cend)) != ZERR_NONE)
+ return (retval);
+
+ retval = Z_InsertZcodeChecksum(keyblock, &newnotice, buffer,
+ cksum_start, cksum_len, cstart, cend,
+ buffer_len, &hdr_adj);
+ if (retval)
+ return retval;
+
+ hdrlen += hdr_adj;
+
+ ptr = buffer+hdrlen;
+
+ if (newnotice.z_message_len+hdrlen > buffer_len)
+ return (ZERR_PKTLEN);
+
+ (void) memcpy(ptr, newnotice.z_message, newnotice.z_message_len);
+
+ *len = hdrlen+newnotice.z_message_len;
+
+ if (*len > Z_MAXPKTLEN)
+ return (ZERR_PKTLEN);
+
+ return (ZERR_NONE);
+}
+#endif
Modified: trunk/athena/lib/zephyr/lib/ZFmtNotice.c
===================================================================
--- trunk/athena/lib/zephyr/lib/ZFmtNotice.c 2008-04-03 17:32:17 UTC (rev 22813)
+++ trunk/athena/lib/zephyr/lib/ZFmtNotice.c 2008-04-03 17:51:46 UTC (rev 22814)
@@ -41,3 +41,29 @@
return (ZERR_NONE);
}
+
+Code_t ZNewFormatNotice(notice, buffer, ret_len, cert_routine)
+ register ZNotice_t *notice;
+ char **buffer;
+ int *ret_len;
+ Z_AuthProc cert_routine;
+{
+ char header[Z_MAXHEADERLEN];
+ int hdrlen;
+ Code_t retval;
+
+ if ((retval = Z_NewFormatHeader(notice, header, sizeof(header), &hdrlen,
+ cert_routine)) != ZERR_NONE)
+ return (retval);
+
+ *ret_len = hdrlen+notice->z_message_len;
+
+ /* Length can never be zero, don't have to worry about malloc(0). */
+ if (!(*buffer = (char *) malloc((unsigned)*ret_len)))
+ return (ENOMEM);
+
+ (void) memcpy(*buffer, header, hdrlen);
+ (void) memcpy(*buffer+hdrlen, notice->z_message, notice->z_message_len);
+
+ return (ZERR_NONE);
+}
Modified: trunk/athena/lib/zephyr/lib/ZFmtSmRaw.c
===================================================================
--- trunk/athena/lib/zephyr/lib/ZFmtSmRaw.c 2008-04-03 17:32:17 UTC (rev 22813)
+++ trunk/athena/lib/zephyr/lib/ZFmtSmRaw.c 2008-04-03 17:51:46 UTC (rev 22814)
@@ -37,3 +37,26 @@
return (ZERR_NONE);
}
+
+Code_t ZNewFormatSmallRawNotice(notice, buffer, ret_len)
+ ZNotice_t *notice;
+ ZPacket_t buffer;
+ int *ret_len;
+{
+ Code_t retval;
+ int hdrlen;
+
+ if ((retval = Z_AsciiFormatRawHeader(notice, buffer, Z_MAXHEADERLEN,
+ &hdrlen, NULL, NULL, NULL, NULL))
+ != ZERR_NONE)
+ return (retval);
+
+ *ret_len = hdrlen+notice->z_message_len;
+
+ if (*ret_len > Z_MAXPKTLEN)
+ return (ZERR_PKTLEN);
+
+ (void) memcpy(buffer+hdrlen, notice->z_message, notice->z_message_len);
+
+ return (ZERR_NONE);
+}
Modified: trunk/athena/lib/zephyr/lib/ZGetSender.c
===================================================================
--- trunk/athena/lib/zephyr/lib/ZGetSender.c 2008-04-03 17:32:17 UTC (rev 22813)
+++ trunk/athena/lib/zephyr/lib/ZGetSender.c 2008-04-03 17:51:46 UTC (rev 22814)
@@ -22,31 +22,55 @@
char *ZGetSender()
{
struct passwd *pw;
+ static char *sender = NULL;
+#ifdef HAVE_KRB5
+ krb5_ccache ccache;
+ krb5_principal principal;
+ char *prname;
+ int result;
+ char pname[ANAME_SZ], pinst[INST_SZ], prealm[REALM_SZ]; /*XXX*/
+#else
#ifdef HAVE_KRB4
char pname[ANAME_SZ], pinst[INST_SZ], prealm[REALM_SZ];
- static char sender[ANAME_SZ+INST_SZ+REALM_SZ+3] = "";
-#else
- static char sender[128] = "";
+#endif
#endif
/* Return it if already cached */
- if (*sender)
+ if (sender)
return (sender);
+#ifdef HAVE_KRB5
+ result = krb5_cc_default(Z_krb5_ctx, &ccache);
+ if (!result) {
+ result = krb5_cc_get_principal(Z_krb5_ctx, ccache, &principal);
+ if (!result) {
+ krb5_unparse_name(Z_krb5_ctx, principal, &prname);
+ sender = strdup(prname);
+ krb5_free_principal(Z_krb5_ctx, principal);
+ return sender;
+ }
+ krb5_cc_close(Z_krb5_ctx, ccache);
+ }
+#else
#ifdef HAVE_KRB4
if (krb_get_tf_fullname((char *)TKT_FILE, pname, pinst, prealm) == KSUCCESS)
{
- (void) sprintf(sender, "%s%s%s@%s", pname, (pinst[0]?".":""),
- pinst, prealm);
+ sender = malloc(ANAME_SZ+INST_SZ+REALM_SZ+3);
+ if (sender)
+ (void) sprintf(sender, "%s%s%s@%s", pname, (pinst[0]?".":""),
+ pinst, prealm);
return (sender);
}
#endif
+#endif
/* XXX a uid_t is a u_short (now), but getpwuid
* wants an int. AARGH! */
pw = getpwuid((int) getuid());
if (!pw)
return ("unknown");
- (void) sprintf(sender, "%s@%s", pw->pw_name, __Zephyr_realm);
+ sender = malloc(strlen(pw->pw_name) + strlen(__Zephyr_realm) + 2);
+ if (sender)
+ (void) sprintf(sender, "%s@%s", pw->pw_name, __Zephyr_realm);
return (sender);
}
Modified: trunk/athena/lib/zephyr/lib/ZInit.c
===================================================================
--- trunk/athena/lib/zephyr/lib/ZInit.c 2008-04-03 17:32:17 UTC (rev 22813)
+++ trunk/athena/lib/zephyr/lib/ZInit.c 2008-04-03 17:51:46 UTC (rev 22814)
@@ -21,6 +21,12 @@
#ifdef HAVE_KRB4
#include <krb_err.h>
#endif
+#ifdef HAVE_KRB5
+#include <krb5.h>
+#endif
+#ifdef HAVE_KRB5_ERR_H
+#include <krb5_err.h>
+#endif
#ifndef INADDR_NONE
#define INADDR_NONE 0xffffffff
@@ -36,13 +42,22 @@
int s, sinsize = sizeof(sin);
Code_t code;
ZNotice_t notice;
+#ifdef HAVE_KRB5
+ char **krealms = NULL;
+#else
#ifdef HAVE_KRB4
char *krealm = NULL;
int krbval;
char d1[ANAME_SZ], d2[INST_SZ];
+#endif
+#endif
+#ifdef HAVE_KRB4
initialize_krb_error_table();
#endif
+#ifdef HAVE_KRB5
+ initialize_krb5_error_table();
+#endif
initialize_zeph_error_table();
@@ -67,6 +82,11 @@
__Q_Tail = NULL;
__Q_Head = NULL;
+#ifdef HAVE_KRB5
+ if ((code = krb5_init_context(&Z_krb5_ctx)))
+ return(code);
+#endif
+
/* if the application is a server, there might not be a zhm. The
code will fall back to something which might not be "right",
but this is is ok, since none of the servers call krb_rd_req. */
@@ -85,9 +105,15 @@
If this code ever support a multiplexing zhm, this will have to
be made smarter, and probably per-message */
+#ifdef HAVE_KRB5
+ code = krb5_get_host_realm(Z_krb5_ctx, notice.z_message, &krealms);
+ if (code)
+ return(code);
+#else
#ifdef HAVE_KRB4
krealm = krb_realmofhost(notice.z_message);
#endif
+#endif
hostent = gethostbyname(notice.z_message);
if (hostent && hostent->h_addrtype == AF_INET)
memcpy(&servaddr, hostent->h_addr, sizeof(servaddr));
@@ -95,6 +121,24 @@
ZFreeNotice(¬ice);
}
+#ifdef HAVE_KRB5
+ if (krealms) {
+ strcpy(__Zephyr_realm, krealms[0]);
+ krb5_free_host_realm(Z_krb5_ctx, krealms);
+ } else {
+ char *p; /* XXX define this somewhere portable */
+ /* XXX check ticket file here */
+ code = krb5_get_default_realm(Z_krb5_ctx, &p);
+ strcpy(__Zephyr_realm, p);
+#ifdef HAVE_KRB5_FREE_DEFAULT_REALM
+ krb5_free_default_realm(Z_krb5_ctx, p);
+#else
+ free(p);
+#endif
+ if (code)
+ return code;
+ }
+#else
#ifdef HAVE_KRB4
if (krealm) {
strcpy(__Zephyr_realm, krealm);
@@ -106,6 +150,7 @@
#else
strcpy(__Zephyr_realm, "local-realm");
#endif
+#endif
__My_addr.s_addr = INADDR_NONE;
if (servaddr.s_addr != INADDR_NONE) {
Added: trunk/athena/lib/zephyr/lib/ZMakeZcode.c
Modified: trunk/athena/lib/zephyr/lib/ZMkAuth.c
===================================================================
--- trunk/athena/lib/zephyr/lib/ZMkAuth.c 2008-04-03 17:32:17 UTC (rev 22813)
+++ trunk/athena/lib/zephyr/lib/ZMkAuth.c 2008-04-03 17:51:46 UTC (rev 22814)
@@ -20,6 +20,10 @@
#include <krb_err.h>
#endif
+#if defined(HAVE_KRB5) && !HAVE_KRB5_FREE_DATA
+#define krb5_free_data(ctx, dat) free((dat)->data)
+#endif
+
Code_t ZResetAuthentication () {
return ZERR_NONE;
}
@@ -30,15 +34,39 @@
int buffer_len;
int *len;
{
-#ifdef HAVE_KRB4
+#if 1
+ return ZMakeZcodeAuthentication(notice, buffer, buffer_len, len/*?XXX*/);
+#else
+#if defined(HAVE_KRB4) || defined(HAVE_KRB5)
int result;
time_t now;
KTEXT_ST authent;
char *cstart, *cend;
ZChecksum_t checksum;
CREDENTIALS cred;
- extern unsigned long des_quad_cksum();
+ C_Block *session;
+#ifdef HAVE_KRB5
+ krb5_creds *creds_out;
+ result = ZGetCreds(&creds_out);
+ if (result)
+ return result;
+
+ result = krb5_524_convert_creds(Z_krb5_ctx, creds_out, &cred);
+ /* krb5_free_creds(Z_krb5_ctx, creds_out);*/
+ if (result)
+ return result;
+ /* HOLDING: creds_out */
+
+ if (creds_out->keyblock.enctype != ENCTYPE_DES_CBC_CRC)
+ return (KRB5_BAD_ENCTYPE);
+ session = (C_Block *)creds_out->keyblock.contents;
+
+ result = krb_mk_req_creds(&authent, &cred, 0);
+ if (result != MK_AP_OK)
+ return result + krb_err_base;
+#endif
+#ifndef HAVE_KRB5
result = krb_mk_req(&authent, SERVER_SERVICE,
SERVER_INSTANCE, __Zephyr_realm, 0);
if (result != MK_AP_OK)
@@ -48,6 +76,9 @@
if (result != KSUCCESS)
return (result+krb_err_base);
+ session = (C_Block *)cred.session;
+#endif
+
notice->z_auth = 1;
notice->z_authent_len = authent.length;
notice->z_ascii_authent = (char *)malloc((unsigned)authent.length*3);
@@ -69,11 +100,11 @@
return(result);
/* Compute a checksum over the header and message. */
- checksum = des_quad_cksum(buffer, NULL, cstart - buffer, 0, cred.session);
+ checksum = des_quad_cksum(buffer, NULL, cstart - buffer, 0, session);
checksum ^= des_quad_cksum(cend, NULL, buffer + *len - cend, 0,
- cred.session);
+ session);
checksum ^= des_quad_cksum(notice->z_message, NULL, notice->z_message_len,
- 0, cred.session);
+ 0, session);
notice->z_checksum = checksum;
ZMakeAscii32(cstart, buffer + buffer_len - cstart, checksum);
@@ -85,4 +116,151 @@
notice->z_ascii_authent = "";
return (Z_FormatRawHeader(notice, buffer, buffer_len, len, NULL, NULL));
#endif
+#endif
}
+
+Code_t ZMakeZcodeAuthentication(notice, buffer, buffer_len, phdr_len)
+ register ZNotice_t *notice;
+ char *buffer;
+ int buffer_len;
+ int *phdr_len;
+{
+ return ZMakeZcodeRealmAuthentication(notice, buffer, buffer_len, phdr_len,
+ __Zephyr_realm);
+}
+
+Code_t ZMakeZcodeRealmAuthentication(notice, buffer, buffer_len, phdr_len,
+ realm)
+ register ZNotice_t *notice;
+ char *buffer;
+ int buffer_len;
+ int *phdr_len;
+ char *realm;
+{
+#ifdef HAVE_KRB5
+ krb5_error_code result;
+ krb5_creds *creds;
+ krb5_keyblock *keyblock;
+ krb5_enctype enctype;
+ krb5_cksumtype cksumtype;
+ krb5_auth_context authctx;
+ krb5_data *authent;
+ char *svcinst, *x, *y;
+ char *cksum_start, *cstart, *cend, *asn1_data;
+ int i, cksum_len, zcode_len, asn1_len, phdr_adj;
+
+ result = ZGetCredsRealm(&creds, realm);
+ if (result)
+ return result;
+ /* HOLDING: creds */
+
+ /* Figure out what checksum type to use */
+ keyblock = Z_credskey(creds);
+ /* HOLDING: creds */
+
+ /* Create the authenticator */
+ result = krb5_auth_con_init(Z_krb5_ctx, &authctx);
+ if (result) {
+ krb5_free_creds(Z_krb5_ctx, creds);
+ return (result);
+ }
+
+ authent = (krb5_data *)malloc(sizeof(krb5_data));
+
+ /* HOLDING: creds, authctx */
+ result = krb5_mk_req_extended(Z_krb5_ctx, &authctx, 0 /* options */,
+ 0 /* in_data */, creds, authent);
+ krb5_auth_con_free(Z_krb5_ctx, authctx);
+ if (result) {
+ krb5_free_creds(Z_krb5_ctx, creds);
+ return (result);
+ }
+ /* HOLDING: creds, authent */
+
+ /* Encode the authenticator */
+ notice->z_auth = 1;
+ notice->z_authent_len = authent->length;
+ zcode_len = authent->length * 2 + 2; /* 2x growth plus Z and null */
+ notice->z_ascii_authent = (char *)malloc(zcode_len);
+ if (!notice->z_ascii_authent) {
+ krb5_free_data(Z_krb5_ctx, authent);
+ krb5_free_creds(Z_krb5_ctx, creds);
+ return (ENOMEM);
+ }
+ /* HOLDING: creds, authent, notice->z_ascii_authent */
+ result = ZMakeZcode(notice->z_ascii_authent, zcode_len,
+ authent->data, authent->length);
+ krb5_free_data(Z_krb5_ctx, authent);
+ if (result) {
+ free(notice->z_ascii_authent);
+ krb5_free_creds(Z_krb5_ctx, creds);
+ return (result);
+ }
+ /* HOLDING: creds, notice->z_ascii_authent */
+
+ /* format the notice header, with a zero checksum */
+ result = Z_NewFormatRawHeader(notice, buffer, buffer_len, phdr_len,
+ &cksum_start, &cksum_len, &cstart, &cend);
+ free(notice->z_ascii_authent);
+ notice->z_authent_len = 0;
+ if (result) {
+ krb5_free_creds(Z_krb5_ctx, creds);
+ return (result);
+ }
+ result = Z_InsertZcodeChecksum(keyblock, notice, buffer, cksum_start,
+ cksum_len, cstart, cend, buffer_len,
+ &phdr_adj);
+ krb5_free_creds(Z_krb5_ctx, creds);
+ if (result) {
+ return result;
+ }
+ *phdr_len += phdr_adj;
+
+ return (result);
+#endif /* HAVE_KRB5 */
+}
+
+#ifdef HAVE_KRB5
+int ZGetCreds(krb5_creds **creds_out) {
+ return ZGetCredsRealm(creds_out, __Zephyr_realm);
+}
+
+int ZGetCredsRealm(krb5_creds **creds_out, char *realm) {
+ krb5_creds creds_in;
+ krb5_ccache ccache; /* XXX make this a global or static?*/
+ int result;
+
+ result = krb5_cc_default(Z_krb5_ctx, &ccache);
+ if (result)
+ return result;
+
+ memset((char *)&creds_in, 0, sizeof(creds_in));
+ result = krb5_build_principal(Z_krb5_ctx, &creds_in.server,
+ strlen(realm),
+ realm,
+ SERVER_SERVICE, SERVER_INSTANCE, 0);
+ if (result) {
+ krb5_cc_close(Z_krb5_ctx, ccache);
+ return result;
+ }
+
+ result = krb5_cc_get_principal(Z_krb5_ctx, ccache, &creds_in.client);
+ if (result) {
+ krb5_free_cred_contents(Z_krb5_ctx, &creds_in); /* I also hope this is ok */
+ krb5_cc_close(Z_krb5_ctx, ccache);
+ return result;
+ }
+
+#ifdef HAVE_KRB5_CREDS_KEYBLOCK_ENCTYPE
+ creds_in.keyblock.enctype = ENCTYPE_DES_CBC_CRC; /* XXX? */
+#else
+ creds_in.session.keytype = KEYTYPE_DES; /* XXX? */
+#endif
+
+ result = krb5_get_credentials(Z_krb5_ctx, 0, ccache, &creds_in, creds_out);
+ krb5_cc_close(Z_krb5_ctx, ccache);
+ krb5_free_cred_contents(Z_krb5_ctx, &creds_in); /* I also hope this is ok */
+
+ return result;
+}
+#endif
Modified: trunk/athena/lib/zephyr/lib/ZParseNot.c
===================================================================
--- trunk/athena/lib/zephyr/lib/ZParseNot.c 2008-04-03 17:32:17 UTC (rev 22813)
+++ trunk/athena/lib/zephyr/lib/ZParseNot.c 2008-04-03 17:51:46 UTC (rev 22814)
@@ -209,12 +209,23 @@
else
notice->z_default_format = "";
- if (ZReadAscii32(ptr, end-ptr, &temp) == ZERR_BADFIELD)
- BAD_PACKET;
- notice->z_checksum = temp;
- numfields--;
- ptr = next_field(ptr, end);
+ if (numfields && ptr < end) {
+ notice->z_ascii_checksum = ptr;
+ if (ZReadAscii32(ptr, end-ptr, &temp) == ZERR_BADFIELD)
+ notice->z_checksum = 0;
+ else
+ notice->z_checksum = temp;
+
+ numfields--;
+ ptr = next_field (ptr, end);
+ }
+ else
+ {
+ notice->z_ascii_checksum = "";
+ notice->z_checksum = 0;
+ }
+
if (numfields && ptr < end) {
notice->z_multinotice = ptr;
numfields--;
Added: trunk/athena/lib/zephyr/lib/ZReadZcode.c
Modified: trunk/athena/lib/zephyr/lib/ZVariables.c
===================================================================
--- trunk/athena/lib/zephyr/lib/ZVariables.c 2008-04-03 17:32:17 UTC (rev 22813)
+++ trunk/athena/lib/zephyr/lib/ZVariables.c 2008-04-03 17:51:46 UTC (rev 22814)
@@ -36,7 +36,7 @@
if ((ret = get_varval(varfile, var)) != ZERR_NONE)
return (ret);
- sprintf(varfile, "%s/zephyr.vars", SYSCONFDIR);
+ sprintf(varfile, "%s/zephyr/zephyr.vars", SYSCONFDIR);
return (get_varval(varfile, var));
}
Modified: trunk/athena/lib/zephyr/lib/Zinternal.c
===================================================================
--- trunk/athena/lib/zephyr/lib/Zinternal.c 2008-04-03 17:32:17 UTC (rev 22813)
+++ trunk/athena/lib/zephyr/lib/Zinternal.c 2008-04-03 17:51:46 UTC (rev 22814)
@@ -44,9 +44,60 @@
int __subscriptions_next;
int Z_discarded_packets = 0;
-#ifdef HAVE_KRB4
-C_Block __Zephyr_session;
-#endif
+#ifdef HAVE_KRB5
+/* This context is used throughout */
+krb5_context Z_krb5_ctx;
+
+static struct cksum_map_s {
+ krb5_enctype e;
+ krb5_cksumtype c;
+} cksum_map[] = {
+ /* per RFC1510 and draft-ietf-krb-wg-crypto-02.txt */
+ { ENCTYPE_NULL, CKSUMTYPE_RSA_MD5 },
+ { ENCTYPE_DES_CBC_CRC, CKSUMTYPE_RSA_MD5_DES },
+ { ENCTYPE_DES_CBC_MD4, CKSUMTYPE_RSA_MD4_DES },
+ { ENCTYPE_DES_CBC_MD5, CKSUMTYPE_RSA_MD5_DES },
+
+ /*
+ * The implementors hate us, and are inconsistent with names for
+ * most things defined after RFC1510. Note that des3-cbc-sha1
+ * and des3-cbc-sha1-kd are listed by number to avoid confusion
+ * caused by inconsistency between the names used in the specs
+ * and those used by implementations.
+ * -- jhutz, 30-Nov-2002
+ */
+
+ /* source lost in history (an expired internet-draft) */
+ { 5 /* des3-cbc-md5 */, 9 /* rsa-md5-des3 */ },
+ { 7 /* des3-cbc-sha1 */, 13 /* hmac-sha1-des3 */ },
+
+ /* per draft-ietf-krb-wg-crypto-02.txt */
+ { 16 /* des3-cbc-sha1-kd */, 12 /* hmac-sha1-des3-kd */ },
+
+ /* per draft-raeburn-krb-rijndael-krb-02.txt */
+ { 17 /* aes128-cts-hmac-sha1-96 */, 15 /* hmac-sha1-96-aes128 */ },
+ { 18 /* aes256-cts-hmac-sha1-96 */, 16 /* hmac-sha1-96-aes256 */ },
+
+ /* per draft-brezak-win2k-krb-rc4-hmac-04.txt */
+ { 23 /* rc4-hmac */, -138 /* hmac-md5 */ },
+ { 24 /* rc4-hmac-exp */, -138 /* hmac-md5 */ },
+};
+#define N_CKSUM_MAP (sizeof(cksum_map) / sizeof(struct cksum_map_s))
+
+Code_t Z_krb5_lookup_cksumtype(krb5_enctype e, krb5_cksumtype *c)
+{
+ int i;
+
+ for (i = 0; i < N_CKSUM_MAP; i++) {
+ if (cksum_map[i].e == e) {
+ *c = cksum_map[i].c;
+ return ZERR_NONE;
+ }
+ }
+ return KRB5_PROG_ETYPE_NOSUPP;
+}
+#endif /* HAVE_KRB5 */
+
char __Zephyr_realm[REALM_SZ];
#ifdef Z_DEBUG
@@ -58,6 +109,8 @@
static int Z_AddField __P((char **ptr, char *field, char *end));
static int find_or_insert_uid __P((ZUnique_Id_t *uid, ZNotice_Kind_t kind));
+static Code_t Z_ZcodeFormatRawHeader __P((ZNotice_t *, char *, int, int *, char **,
+ int *, char **, char **, int cksumtype));
/* Find or insert uid in the old uids buffer. The buffer is a sorted
* circular queue. We make the assumption that most packets arrive in
@@ -580,6 +633,14 @@
return (ZERR_NONE);
}
+void Z_gettimeofday(struct _ZTimeval *ztv, struct timezone *tz)
+{
+ struct timeval tv;
+ (void) gettimeofday(&tv, tz); /* yeah, yeah, I know */
+ ztv->tv_sec=tv.tv_sec;
+ ztv->tv_usec=tv.tv_usec;
+}
+
Code_t Z_FormatHeader(notice, buffer, buffer_len, len, cert_routine)
ZNotice_t *notice;
char *buffer;
@@ -609,7 +670,7 @@
notice->z_multinotice = "";
- (void) gettimeofday(¬ice->z_uid.tv, (struct timezone *)0);
+ (void) Z_gettimeofday(¬ice->z_uid.tv, (struct timezone *)0);
notice->z_uid.tv.tv_sec = htonl((u_long) notice->z_uid.tv.tv_sec);
notice->z_uid.tv.tv_usec = htonl((u_long) notice->z_uid.tv.tv_usec);
@@ -625,6 +686,52 @@
return Z_FormatAuthHeader(notice, buffer, buffer_len, len, cert_routine);
}
+Code_t Z_NewFormatHeader(notice, buffer, buffer_len, len, cert_routine)
+ ZNotice_t *notice;
+ char *buffer;
+ int buffer_len;
+ int *len;
+ Z_AuthProc cert_routine;
+{
+ Code_t retval;
+ static char version[BUFSIZ]; /* default init should be all \0 */
+ struct sockaddr_in name;
+ struct timeval tv;
+ int namelen = sizeof(name);
+
+ if (!notice->z_sender)
+ notice->z_sender = ZGetSender();
+
+ if (notice->z_port == 0) {
+ if (ZGetFD() < 0) {
+ retval = ZOpenPort((u_short *)0);
+ if (retval != ZERR_NONE)
+ return (retval);
+ }
+ retval = getsockname(ZGetFD(), (struct sockaddr *) &name, &namelen);
+ if (retval != 0)
+ return (retval);
+ notice->z_port = name.sin_port;
+ }
+
+ notice->z_multinotice = "";
+
+ (void) gettimeofday(&tv, (struct timezone *)0);
+ notice->z_uid.tv.tv_sec = htonl((u_long) tv.tv_sec);
+ notice->z_uid.tv.tv_usec = htonl((u_long) tv.tv_usec);
+
+ (void) memcpy(¬ice->z_uid.zuid_addr, &__My_addr, sizeof(__My_addr));
+
+ notice->z_multiuid = notice->z_uid;
+
+ if (!version[0])
+ (void) sprintf(version, "%s%d.%d", ZVERSIONHDR, ZVERSIONMAJOR,
+ ZVERSIONMINOR);
+ notice->z_version = version;
+
+ return Z_NewFormatAuthHeader(notice, buffer, buffer_len, len, cert_routine);
+}
+
Code_t Z_FormatAuthHeader(notice, buffer, buffer_len, len, cert_routine)
ZNotice_t *notice;
char *buffer;
@@ -644,6 +751,210 @@
return ((*cert_routine)(notice, buffer, buffer_len, len));
}
+Code_t Z_NewFormatAuthHeader(notice, buffer, buffer_len, len, cert_routine)
+ ZNotice_t *notice;
+ char *buffer;
+ int buffer_len;
+ int *len;
+ Z_AuthProc cert_routine;
+{
+ if (!cert_routine) {
+ notice->z_auth = 0;
+ notice->z_authent_len = 0;
+ notice->z_ascii_authent = "";
+ notice->z_checksum = 0;
+ return (Z_FormatRawHeader(notice, buffer, buffer_len,
+ len, NULL, NULL));
+ }
+
+ return ((*cert_routine)(notice, buffer, buffer_len, len));
+}
+
+Code_t Z_NewFormatRawHeader(notice, buffer, buffer_len, hdr_len,
+ cksum_start, cksum_len, cstart, cend)
+ ZNotice_t *notice;
+ char *buffer;
+ int buffer_len;
+ int *hdr_len;
+ char **cksum_start;
+ int *cksum_len;
+ char **cstart, **cend;
+{
+ return(Z_ZcodeFormatRawHeader(notice, buffer, buffer_len, hdr_len,
+ cksum_start, cksum_len, cstart, cend, 0));
+}
+
+Code_t Z_AsciiFormatRawHeader(notice, buffer, buffer_len, hdr_len,
+ cksum_start, cksum_len, cstart, cend)
+ ZNotice_t *notice;
+ char *buffer;
+ int buffer_len;
+ int *hdr_len;
+ char **cksum_start;
+ int *cksum_len;
+ char **cstart, **cend;
+{
+ return(Z_ZcodeFormatRawHeader(notice, buffer, buffer_len, hdr_len,
+ cksum_start, cksum_len, cstart, cend, 1));
+}
+
+static Code_t Z_ZcodeFormatRawHeader(notice, buffer, buffer_len, hdr_len, cksum_start,
+ cksum_len, cstart, cend, cksumstyle)
+ ZNotice_t *notice;
+ char *buffer;
+ int buffer_len;
+ int *hdr_len;
+ char **cksum_start;
+ int *cksum_len;
+ char **cstart, **cend;
+ int cksumstyle;
+{
+ static char version_nogalaxy[BUFSIZ]; /* default init should be all \0 */
+ char newrecip[BUFSIZ];
+ char *ptr, *end;
+ int i;
+
+ if (!notice->z_class)
+ notice->z_class = "";
+
+ if (!notice->z_class_inst)
+ notice->z_class_inst = "";
+
+ if (!notice->z_opcode)
+ notice->z_opcode = "";
+
+ if (!notice->z_recipient)
+ notice->z_recipient = "";
+
+ if (!notice->z_default_format)
+ notice->z_default_format = "";
+
+ ptr = buffer;
+ end = buffer+buffer_len;
+
+ if (cksum_start)
+ *cksum_start = ptr;
+
+ (void) sprintf(version_nogalaxy, "%s%d.%d", ZVERSIONHDR,
+ ZVERSIONMAJOR, ZVERSIONMINOR);
+
+ notice->z_version = version_nogalaxy;
+
+ if (Z_AddField(&ptr, version_nogalaxy, end))
+ return (ZERR_HEADERLEN);
+
+ if (ZMakeAscii32(ptr, end-ptr,
+ Z_NUMFIELDS + notice->z_num_other_fields)
+ == ZERR_FIELDLEN)
+ return (ZERR_HEADERLEN);
+ ptr += strlen(ptr)+1;
+
+ if (ZMakeAscii32(ptr, end-ptr, notice->z_kind) == ZERR_FIELDLEN)
+ return (ZERR_HEADERLEN);
+ ptr += strlen(ptr)+1;
+
+ if (ZMakeAscii(ptr, end-ptr, (unsigned char *)¬ice->z_uid,
+ sizeof(ZUnique_Id_t)) == ZERR_FIELDLEN)
+ return (ZERR_HEADERLEN);
+ ptr += strlen(ptr)+1;
+
+ if (ZMakeAscii16(ptr, end-ptr, ntohs(notice->z_port)) == ZERR_FIELDLEN)
+ return (ZERR_HEADERLEN);
+ ptr += strlen(ptr)+1;
+
+ if (ZMakeAscii32(ptr, end-ptr, notice->z_auth) == ZERR_FIELDLEN)
+ return (ZERR_HEADERLEN);
+ ptr += strlen(ptr)+1;
+
+ if (ZMakeAscii32(ptr, end-ptr, notice->z_authent_len) == ZERR_FIELDLEN)
+ return (ZERR_HEADERLEN);
+ ptr += strlen(ptr)+1;
+
+ if (Z_AddField(&ptr, notice->z_ascii_authent, end))
+ return (ZERR_HEADERLEN);
+ if (Z_AddField(&ptr, notice->z_class, end))
+ return (ZERR_HEADERLEN);
+ if (Z_AddField(&ptr, notice->z_class_inst, end))
+ return (ZERR_HEADERLEN);
+ if (Z_AddField(&ptr, notice->z_opcode, end))
+ return (ZERR_HEADERLEN);
+ if (Z_AddField(&ptr, notice->z_sender, end))
+ return (ZERR_HEADERLEN);
+ if (strchr(notice->z_recipient, '@') || !*notice->z_recipient) {
+ if (Z_AddField(&ptr, notice->z_recipient, end))
+ return (ZERR_HEADERLEN);
+ }
+ else {
+ if (strlen(notice->z_recipient) + strlen(__Zephyr_realm) + 2 >
+ sizeof(newrecip))
+ return (ZERR_HEADERLEN);
+ (void) sprintf(newrecip, "%s@%s", notice->z_recipient, __Zephyr_realm);
+ if (Z_AddField(&ptr, newrecip, end))
+ return (ZERR_HEADERLEN);
+ }
+ if (Z_AddField(&ptr, notice->z_default_format, end))
+ return (ZERR_HEADERLEN);
+
+ /* copy back the end pointer location for crypto checksum */
+ if (cstart)
+ *cstart = ptr;
+ if (cksumstyle == 1) {
+ if (Z_AddField(&ptr, notice->z_ascii_checksum, end))
+ return (ZERR_HEADERLEN);
+ } else {
+#ifdef xZCODE_K4SUM
+ if (ZMakeZcode32(ptr, end-ptr, notice->z_checksum) == ZERR_FIELDLEN)
+ return ZERR_HEADERLEN;
+#else
+ if (ZMakeAscii32(ptr, end-ptr, notice->z_checksum) == ZERR_FIELDLEN)
+ return (ZERR_HEADERLEN);
+#endif
+ ptr += strlen(ptr)+1;
+ }
+ if (cend)
+ *cend = ptr;
+
+ if (Z_AddField(&ptr, notice->z_multinotice, end))
+ return (ZERR_HEADERLEN);
+
+ if (ZMakeAscii(ptr, end-ptr, (unsigned char *)¬ice->z_multiuid,
+ sizeof(ZUnique_Id_t)) == ZERR_FIELDLEN)
+ return (ZERR_HEADERLEN);
+ ptr += strlen(ptr)+1;
+
+ for (i=0;i<notice->z_num_other_fields;i++)
+ if (Z_AddField(&ptr, notice->z_other_fields[i], end))
+ return (ZERR_HEADERLEN);
+
+ if (cksum_len)
+ *cksum_len = ptr-*cksum_start;
+
+ *hdr_len = ptr-buffer;
+
+#if 0
+ {
+ printf("Z_FormatRawHeader output:\n");
+ for (i = 0; i < *hdr_len; i += 16) {
+ int i2;
+ printf("%03d:", i);
+ for (i2 = i; i2 < i+16 && i2 < *hdr_len; i2++)
+ printf(" %02x", buffer[i2] & 0xff);
+ for (; i2 < i+16; i2++)
+ printf(" ");
+ printf(" ");
+ for (i2 = i; i2 < i+16 && i2 < *hdr_len; i2++)
+ printf("%c",
+ ((buffer[i2] > 0 && buffer[i2] < 127 && isprint(buffer[i2]))
+ ? buffer[i2]
+ : '.'));
+ printf("\n");
+ }
+ }
+#endif
+
+ return (ZERR_NONE);
+}
+
Code_t Z_FormatRawHeader(notice, buffer, buffer_len, len, cstart, cend)
ZNotice_t *notice;
char *buffer;
@@ -734,7 +1045,7 @@
if (cstart)
*cstart = ptr;
if (ZMakeAscii32(ptr, end-ptr, notice->z_checksum) == ZERR_FIELDLEN)
- return (ZERR_HEADERLEN);
+ return (ZERR_HEADERLEN);
ptr += strlen(ptr)+1;
if (cend)
*cend = ptr;
@@ -878,8 +1189,8 @@
(void) sprintf(multi, "%d/%d", offset, notice->z_message_len);
partnotice.z_multinotice = multi;
if (offset > 0) {
- (void) gettimeofday(&partnotice.z_uid.tv,
- (struct timezone *)0);
+ (void) Z_gettimeofday(&partnotice.z_uid.tv,
+ (struct timezone *)0);
partnotice.z_uid.tv.tv_sec =
htonl((u_long) partnotice.z_uid.tv.tv_sec);
partnotice.z_uid.tv.tv_usec =
@@ -987,3 +1298,186 @@
}
#endif /* Z_DEBUG */
+#ifdef HAVE_KRB5
+Code_t Z_Checksum(krb5_data *cksumbuf, krb5_keyblock *keyblock,
+ krb5_cksumtype cksumtype,
+ char **asn1_data, int *asn1_len) {
+ krb5_error_code result;
+ char *data;
+ int len;
+#if HAVE_KRB5_C_MAKE_CHECKSUM
+ krb5_checksum checksum;
+#else
+ Checksum checksum;
+ krb5_crypto cryptctx;
+#endif
+
+#if HAVE_KRB5_C_MAKE_CHECKSUM
+ /* Create the checksum -- MIT crypto API */
+ result = krb5_c_make_checksum(Z_krb5_ctx, cksumtype,
+ keyblock, Z_KEYUSAGE_CLT_CKSUM,
+ cksumbuf, &checksum);
+ if (result)
+ return result;
+ /* HOLDING: checksum */
+
+ data = checksum.contents;
+ len = checksum.length;
+#else
+ /* Create the checksum -- heimdal crypto API */
+ result = krb5_crypto_init(Z_krb5_ctx, keyblock, keyblock->keytype,
+ &cryptctx);
+ if (result)
+ return result;
+
+ /* HOLDING: cryptctx */
+ result = krb5_create_checksum(Z_krb5_ctx, cryptctx,
+ Z_KEYUSAGE_CLT_CKSUM, cksumtype,
+ cksumbuf->data, cksumbuf->length,
+ &checksum);
+ krb5_crypto_destroy(Z_krb5_ctx, cryptctx);
+ if (result)
+ return result;
+
+ len = checksum.checksum.length;
+ data = checksum.checksum.data;
+ /* HOLDING: checksum */
+#endif
+
+ *asn1_data = malloc(len);
+ if (*asn1_data == NULL)
+ return errno;
+ memcpy(*asn1_data, data, len);
+ *asn1_len = len;
+
+#if HAVE_KRB5_C_MAKE_CHECKSUM
+ krb5_free_checksum_contents(Z_krb5_ctx, &checksum);
+#else
+ free_Checksum(&checksum);
+#endif
+
+ return 0;
+}
+
+Code_t
+Z_InsertZcodeChecksum(krb5_keyblock *keyblock, ZNotice_t *notice,
+ char *buffer, char *cksum_start, int cksum_len,
+ char *cstart, char *cend, int buffer_len,
+ int *length_adjust)
+{
+ int plain_len; /* length of part not to be checksummed */
+ int cksum0_len; /* length of part before checksum */
+ int cksum1_len; /* length of part after checksum */
+ krb5_data cksumbuf;
+ krb5_data cksum;
+ char *key_data;
+ int key_len;
+ krb5_enctype enctype;
+ krb5_cksumtype cksumtype;
+ Code_t result;
+
+ key_data = Z_keydata(keyblock);
+ key_len = Z_keylen(keyblock);
+ result = Z_ExtractEncCksum(keyblock, &enctype, &cksumtype);
+ if (result)
+ return (ZAUTH_FAILED);
+
+ /* Assemble the things to be checksummed */
+ plain_len = cksum_start - buffer;
+ cksum0_len = cstart - cksum_start;
+ cksum1_len = (cksum_start + cksum_len) - cend;
+ memset(&cksumbuf, 0, sizeof(cksumbuf));
+ cksumbuf.length = cksum0_len + cksum1_len + notice->z_message_len;
+ cksumbuf.data = malloc(cksumbuf.length);
+ if (!cksumbuf.data)
+ return ENOMEM;
+ memcpy(cksumbuf.data, cksum_start, cksum0_len);
+ memcpy(cksumbuf.data + cksum0_len, cend, cksum1_len);
+ memcpy(cksumbuf.data + cksum0_len + cksum1_len,
+ notice->z_message, notice->z_message_len);
+ /* compute the checksum */
+ result = Z_Checksum(&cksumbuf, keyblock, cksumtype,
+ (char **)&cksum.data, &cksum.length);
+ if (result) {
+ free(cksumbuf.data);
+ return result;
+ }
+
+ /*
+ * OK.... we can zcode to a space starting at 'cstart',
+ * with a length of buffer_len - (plain_len + cksum_len).
+ * Then we tack on the end part, which is located at
+ * cksumbuf.data + cksum0_len and has length cksum1_len
+ */
+
+ result = ZMakeZcode(cstart, buffer_len - (plain_len + cksum_len),
+ cksum.data, cksum.length);
+ free(cksum.data);
+ if (!result) {
+ int zcode_len = strlen(cstart) + 1;
+ memcpy(cstart + zcode_len, cksumbuf.data + cksum0_len, cksum1_len);
+ *length_adjust = zcode_len - cksum_len + (cksum0_len + cksum1_len);
+ }
+ free(cksumbuf.data);
+ return result;
+}
+
+Code_t
+Z_ExtractEncCksum(krb5_keyblock *keyblock, krb5_enctype *enctype,
+ krb5_cksumtype *cksumtype) {
+ *enctype = Z_enctype(keyblock);
+ return Z_krb5_lookup_cksumtype(*enctype, cksumtype);
+}
+#endif
+
+#ifdef HAVE_KRB5
+/* returns 0 if invalid or losing, 1 if valid, *sigh* */
+int
+Z_krb5_verify_cksum(krb5_keyblock *keyblock, krb5_data *cksumbuf,
+ krb5_cksumtype cksumtype, char *asn1_data,
+ int asn1_len) {
+ krb5_error_code result;
+#if HAVE_KRB5_C_MAKE_CHECKSUM
+ krb5_checksum checksum;
+ krb5_boolean valid;
+#else
+ krb5_crypto cryptctx;
+ Checksum checksum;
+ size_t xlen;
+#endif
+
+ memset(&checksum, 0, sizeof(checksum));
+#if HAVE_KRB5_C_MAKE_CHECKSUM
+ /* Verify the checksum -- MIT crypto API */
+ checksum.length = asn1_len;
+ checksum.contents = asn1_data;
+ checksum.checksum_type = cksumtype;
+ result = krb5_c_verify_checksum(Z_krb5_ctx,
+ keyblock, Z_KEYUSAGE_SRV_CKSUM,
+ cksumbuf, &checksum, &valid);
+ if (!result && valid)
+ return 1;
+ else
+ return 0;
+#else
+ checksum.checksum.length = asn1_len;
+ checksum.checksum.data = asn1_data;
+ checksum.cksumtype = cksumtype;
+
+ result = krb5_crypto_init(Z_krb5_ctx, keyblock, keyblock->keytype, &cryptctx);
+ if (result)
+ return result;
+
+ /* HOLDING: cryptctx */
+ result = krb5_verify_checksum(Z_krb5_ctx, cryptctx,
+ Z_KEYUSAGE_SRV_CKSUM,
+ cksumbuf->data, cksumbuf->length,
+ &checksum);
+ krb5_crypto_destroy(Z_krb5_ctx, cryptctx);
+ if (result)
+ return 0;
+ else
+ return 1;
+#endif
+}
+#endif
Modified: trunk/athena/lib/zephyr/server/bdump.c
===================================================================
--- trunk/athena/lib/zephyr/server/bdump.c 2008-04-03 17:32:17 UTC (rev 22813)
+++ trunk/athena/lib/zephyr/server/bdump.c 2008-04-03 17:51:46 UTC (rev 22814)
@@ -66,6 +66,12 @@
static void shutdown_file_pointers __P((void));
static void cleanup __P((Server *server));
+#ifdef HAVE_KRB5
+static long ticket5_time;
+#define TKT5LIFETIME 8*60*60
+#define tkt5_lifetime(val) (val)
+#endif
+
#ifdef HAVE_KRB4
static long ticket_time;
@@ -82,6 +88,9 @@
static int live_socket = -1;
static FILE *input, *output;
static struct sockaddr_in bdump_sin;
+#ifdef HAVE_KRB5
+static krb5_auth_context bdump_ac;
+#endif
#ifdef notdef
static int cancel_outgoing_dump;
#endif
@@ -89,6 +98,7 @@
int bdumping;
int bdump_concurrent;
extern char *bdump_version;
+extern int bdump_auth_proto;
/*
* Functions for performing a brain dump between servers.
@@ -110,9 +120,9 @@
#if 1
zdbug((LOG_DEBUG, "bdump_offer"));
#endif
-#ifdef HAVE_KRB4
+#if defined(HAVE_KRB4) || defined(HAVE_KRB5)
/*
- * when using HAVE_KRB4 server-server authentication, we can
+ * when using kerberos server-server authentication, we can
* use any random local address
*/
bdump_socket = socket(AF_INET, SOCK_STREAM, 0);
@@ -211,11 +221,25 @@
#ifdef _POSIX_VERSION
struct sigaction action;
#endif
-
+#if defined(HAVE_KRB4) || defined(HAVE_KRB5)
+ char *data = NULL;
+ int len = 0;
+ int proto = 0;
+#endif
#ifdef HAVE_KRB4
KTEXT_ST ticket;
AUTH_DAT kdata;
-#else
+ /* may be moved into kstuff.c */
+ char instance [INST_SZ];
+#endif
+#ifdef HAVE_KRB5
+ /* may be moved into kstuff.c */
+ krb5_principal principal;
+ krb5_data k5data;
+ krb5_ap_rep_enc_part *rep;
+ krb5_keytab kt;
+#endif
+#if !defined(HAVE_KRB4) && !defined(HAVE_KRB5)
unsigned short fromport;
#endif /* HAVE_KRB4 */
@@ -270,48 +294,164 @@
bdump_socket = -1;
timer_reset(bdump_timer);
}
-
+
/* Now begin the brain dump. */
-
-#ifdef HAVE_KRB4
- /* receive the authenticator */
- retval = GetKerberosData(live_socket, from.sin_addr, &kdata,
- SERVER_SERVICE, srvtab_file);
- if (retval != KSUCCESS) {
- syslog(LOG_ERR, "bdump_send: getkdata: %s",
+#if defined(HAVE_KRB5) || defined(HAVE_KRB4)
+ retval = ReadKerberosData(live_socket, &len, &data, &proto);
+
+ if (retval != 0) {
+ syslog(LOG_ERR, "bdump_send: ReadKerberosData: %s",
krb_get_err_text(retval));
cleanup(server);
return;
}
+
+ syslog(LOG_INFO, "bdump_send: got %d bytes of authenticator for protocol %d", len, proto);
+
if (get_tgt()) {
+ syslog(LOG_ERR, "bdump_send: get_tgt failed");
cleanup(server);
return;
}
- if (strcmp(kdata.pname, SERVER_SERVICE) ||
- strcmp(kdata.pinst, SERVER_INSTANCE) ||
- strcmp(kdata.prealm, ZGetRealm())) {
- syslog(LOG_ERR, "bdump_send: peer not zephyr: %s.%s@%s",
- kdata.pname, kdata.pinst, kdata.prealm);
- cleanup(server);
- return;
+
+ switch(proto) {
+#ifdef HAVE_KRB5
+ case 5:
+ /* "server" side */
+ retval = krb5_build_principal(Z_krb5_ctx, &principal,
+ strlen(ZGetRealm()),
+ ZGetRealm(),
+ SERVER_KRB5_SERVICE, SERVER_INSTANCE,
+ 0);
+ if (retval) {
+ syslog(LOG_ERR, "bdump_send: krb5_build_principal: %s", error_message(retval));
+ cleanup(server);
+ return;
+ }
+
+
+ retval = krb5_auth_con_init(Z_krb5_ctx, &bdump_ac);
+ if (retval) {
+ syslog(LOG_ERR, "bdump_send: krb5_auth_con_init: %s", error_message(retval));
+ cleanup(server);
+ return;
+ }
+
+ retval = krb5_auth_con_setflags(Z_krb5_ctx, bdump_ac, KRB5_AUTH_CONTEXT_DO_SEQUENCE);
+ if (retval) {
+ syslog(LOG_ERR, "bdump_send: krb5_auth_con_setflags: %s", error_message(retval));
+ cleanup(server);
+ return;
+ }
+
+ retval = krb5_auth_con_genaddrs(Z_krb5_ctx, bdump_ac, live_socket,
+ KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR|KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR);
+ if (retval) {
+ syslog(LOG_ERR, "bdump_send: krb5_auth_con_genaddrs: %s", error_message(retval));
+ cleanup(server);
+ return;
+ }
+
+ /* Get the "client" krb_ap_req */
+
+ memset((char *)&k5data, 0, sizeof(krb5_data));
+ k5data.length = len;
+ k5data.data = data;
+ if (retval) {
+ syslog(LOG_ERR, "bdump_send: cannot get auth response: %s",
+ error_message(retval));
+ cleanup(server);
+ return;
+ }
+
+ /* resolve keytab */
+ retval = krb5_kt_resolve(Z_krb5_ctx, keytab_file, &kt);
+ if (retval) {
+ syslog(LOG_ERR, "bdump_send: cannot resolve keytab: %s",
+ error_message(retval));
+ krb5_kt_close(Z_krb5_ctx, kt);
+ cleanup(server);
+ return;
+ }
+
+ retval = krb5_rd_req(Z_krb5_ctx, &bdump_ac, &k5data, principal, kt, NULL, NULL);
+ krb5_free_principal(Z_krb5_ctx, principal);
+ krb5_kt_close(Z_krb5_ctx, kt);
+ free(k5data.data);
+ memset((char *)&k5data, 0, sizeof(krb5_data));
+ if (retval) {
+ syslog(LOG_ERR, "bdump_send: mutual authentication failed: %s",
+ error_message(retval));
+ cleanup(server);
+ return;
+ }
+
+ /* Now send back our auth packet */
+
+ retval = krb5_mk_rep(Z_krb5_ctx, bdump_ac, &k5data);
+ if (retval) {
+ syslog(LOG_ERR, "bdump_send: krb5_mk_rep: %s", error_message(retval));
+ cleanup(server);
+ return;
+ }
+ retval = SendKrb5Data(live_socket, &k5data);
+ if (retval) {
+ syslog(LOG_ERR, "bdump_send: cannot send authenticator: %s",
+ error_message(retval));
+ krb5_free_data_contents(Z_krb5_ctx, &k5data);
+ cleanup(server);
+ return;
+ }
+ krb5_free_data_contents(Z_krb5_ctx, &k5data);
+ break;
+#endif /* HAVE_KRB5 */
+#ifdef HAVE_KRB4
+ case 4:
+ /* here to krb_rd_req from GetKerberosData candidate for refactoring
+ back into kstuff.c */
+ (void) strcpy(instance, "*"); /* let Kerberos fill it in */
+
+ ticket.length = len;
+ memcpy(&ticket.dat, data, MIN(len, sizeof(ticket.dat)));
+ retval = krb_rd_req(&ticket, SERVER_SERVICE, instance,
+ from.sin_addr.s_addr, &kdata, srvtab_file);
+ /*
+ retval = GetKerberosData(live_socket, from.sin_addr, &kdata,
+ SERVER_SERVICE, srvtab_file);
+ */
+ if (retval != KSUCCESS) {
+ syslog(LOG_ERR, "bdump_send: getkdata: %s",
+ krb_get_err_text(retval));
+ cleanup(server);
+ return;
+ }
+ if (strcmp(kdata.pname, SERVER_SERVICE) ||
+ strcmp(kdata.pinst, SERVER_INSTANCE) ||
+ strcmp(kdata.prealm, ZGetRealm())) {
+ syslog(LOG_ERR, "bdump_send: peer not zephyr: %s.%s@%s",
+ kdata.pname, kdata.pinst, kdata.prealm);
+ cleanup(server);
+ return;
+ }
+ /* authenticate back */
+ retval = SendKerberosData(live_socket, &ticket, SERVER_SERVICE,
+ SERVER_INSTANCE);
+ if (retval != 0) {
+ syslog(LOG_ERR,"bdump_send: SendKerberosData: %s",
+ error_message (retval));
+ cleanup(server);
+ return;
+ }
+ break;
+#endif /* HAVE_KRB4 */
}
- /* authenticate back */
- retval = SendKerberosData(live_socket, &ticket, SERVER_SERVICE,
- SERVER_INSTANCE);
- if (retval != 0) {
- syslog(LOG_ERR,"bdump_send: SendKerberosData: %s",
- error_message (retval));
- cleanup(server);
- return;
- }
-#else /* !HAVE_KRB4 */
+#else /* HAVE_KRB4 || HAVE_KRB5 */
if (fromport > IPPORT_RESERVED || fromport < IPPORT_RESERVED / 2) {
syslog(LOG_ERR, "bdump_send: bad port from peer: %d", fromport);
cleanup(server);
return;
}
-#endif /* HAVE_KRB4 */
-
+#endif /* HAVE_KRB4 || HAVE_KRB5 */
retval = setup_file_pointers();
if (retval != 0) {
syslog (LOG_WARNING, "bdump_send: can't set up file pointers: %s",
@@ -374,12 +514,21 @@
#ifdef _POSIX_VERSION
struct sigaction action;
#endif
+#if defined(HAVE_KRB4) || defined(HAVE_KRB5)
+#ifdef HAVE_KRB5
+ krb5_creds creds;
+ krb5_creds *credsp;
+ krb5_principal principal;
+ krb5_data data;
+ krb5_ap_rep_enc_part *rep;
+#endif
#ifdef HAVE_KRB4
KTEXT_ST ticket;
AUTH_DAT kdata;
-#else /* !HAVE_KRB4 */
+#endif
+#else /* !HAVE_KRB4 && !HAVE_KRB5 */
int reserved_port = IPPORT_RESERVED - 1;
-#endif /* HAVE_KRB4 */
+#endif /* !HAVE_KRB4 && !HAVE_KRB5 */
bdumping = 1;
server->dumping = 1;
@@ -419,7 +568,7 @@
server->dumping = 0;
return;
}
-#ifndef HAVE_KRB4
+#if !defined(HAVE_KRB4) && !defined(HAVE_KRB5)
if (ntohs(from.sin_port) > IPPORT_RESERVED ||
ntohs(from.sin_port) < IPPORT_RESERVED / 2) {
syslog(LOG_ERR, "bdump_get: port not reserved: %d",
@@ -428,9 +577,9 @@
return;
}
live_socket = rresvport(&reserved_port);
-#else /* !HAVE_KRB4 */
+#else /* !HAVE_KRB4 && !HAVE_KRB5 */
live_socket = socket(AF_INET, SOCK_STREAM, 0);
-#endif /* HAVE_KRB4 */
+#endif /* !HAVE_KRB4 && !HAVE_KRB5 */
if (live_socket < 0) {
syslog(LOG_ERR, "bdump_get: socket: %m");
cleanup(server);
@@ -449,42 +598,150 @@
#endif
/* Now begin the brain dump. */
-
-#ifdef HAVE_KRB4
- /* send an authenticator */
+#if defined(HAVE_KRB4) || defined(HAVE_KRB5)
if (get_tgt()) {
+ syslog(LOG_ERR, "bdump_get: get_tgt failed");
cleanup(server);
return;
}
- retval = SendKerberosData(live_socket, &ticket, SERVER_SERVICE,
- SERVER_INSTANCE);
- if (retval != 0) {
- syslog(LOG_ERR,"bdump_get: %s", error_message(retval));
- cleanup(server);
- return;
- }
-#if 1
- zdbug((LOG_DEBUG, "bdump_get: SendKerberosData ok"));
+ switch(bdump_auth_proto) {
+#ifdef HAVE_KRB5
+ case 5: /* "client" side */
+ memset((char *)&creds, 0, sizeof(creds));
+
+ retval = krb5_build_principal(Z_krb5_ctx, &principal,
+ strlen(ZGetRealm()),
+ ZGetRealm(),
+ SERVER_KRB5_SERVICE, SERVER_INSTANCE,
+ 0);
+ if (retval) {
+ syslog(LOG_ERR, "bdump_get: krb5_build_principal: %s", error_message(retval));
+ cleanup(server);
+ return;
+ }
+
+ retval = krb5_copy_principal(Z_krb5_ctx, principal, &creds.server);
+ if (retval) {
+ syslog(LOG_ERR, "bdump_get: krb5_copy_principal (server): %s", error_message(retval));
+ krb5_free_principal(Z_krb5_ctx, principal);
+ cleanup(server);
+ return;
+ }
+
+ retval = krb5_copy_principal(Z_krb5_ctx, principal, &creds.client);
+ krb5_free_principal(Z_krb5_ctx, principal);
+ if (retval) {
+ syslog(LOG_ERR, "bdump_get: krb5_copy_principal (client): %s", error_message(retval));
+ krb5_free_cred_contents(Z_krb5_ctx, &creds);
+ cleanup(server);
+ return;
+ }
+
+ retval = krb5_get_credentials(Z_krb5_ctx, 0, Z_krb5_ccache,
+ &creds, &credsp);
+ krb5_free_cred_contents(Z_krb5_ctx, &creds);
+ if (retval) {
+ syslog(LOG_ERR, "bdump_get: krb5_get_credentials: %s", error_message(retval));
+ cleanup(server);
+ return;
+ }
+
+ retval = krb5_auth_con_init(Z_krb5_ctx, &bdump_ac);
+ if (retval) {
+ syslog(LOG_ERR, "bdump_get: krb5_auth_con_init: %s", error_message(retval));
+ krb5_free_creds(Z_krb5_ctx, credsp);
+ cleanup(server);
+ return;
+ }
+
+ retval = krb5_auth_con_setflags(Z_krb5_ctx, bdump_ac, KRB5_AUTH_CONTEXT_DO_SEQUENCE);
+ if (retval) {
+ syslog(LOG_ERR, "bdump_get: krb5_auth_con_setflags: %s", error_message(retval));
+ krb5_free_creds(Z_krb5_ctx, credsp);
+ cleanup(server);
+ return;
+ }
+
+ retval = krb5_auth_con_genaddrs(Z_krb5_ctx, bdump_ac, live_socket,
+ KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR|KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR);
+ if (retval) {
+ syslog(LOG_ERR, "bdump_get: krb5_auth_con_genaddrs: %s", error_message(retval));
+ krb5_free_creds(Z_krb5_ctx, credsp);
+ cleanup(server);
+ return;
+ }
+
+ memset((char *)&data, 0, sizeof(krb5_data));
+ retval = krb5_mk_req_extended(Z_krb5_ctx, &bdump_ac, AP_OPTS_MUTUAL_REQUIRED|AP_OPTS_USE_SUBKEY,
+ NULL, credsp, &data);
+ if (retval) {
+ syslog(LOG_ERR, "bdump_get: krb5_mk_req_ext: %s", error_message(retval));
+ krb5_free_creds(Z_krb5_ctx, credsp);
+ cleanup(server);
+ return;
+ }
+ retval = SendKrb5Data(live_socket, &data);
+ krb5_free_creds(Z_krb5_ctx, credsp);
+ if (retval) {
+ syslog(LOG_ERR, "bdump_get: cannot send authenticator: %s",
+ error_message(retval));
+ krb5_free_data_contents(Z_krb5_ctx, &data);
+ cleanup(server);
+ return;
+ }
+ krb5_free_data_contents(Z_krb5_ctx, &data);
+ memset((char *)&data, 0, sizeof(krb5_data));
+ retval = GetKrb5Data(live_socket, &data);
+ if (retval) {
+ syslog(LOG_ERR, "bdump_get: cannot get auth response: %s",
+ error_message(retval));
+ cleanup(server);
+ return;
+ }
+ retval = krb5_rd_rep(Z_krb5_ctx, bdump_ac, &data, &rep);
+ free(data.data);
+ memset((char *)&data, 0, sizeof(krb5_data));
+ if (retval) {
+ syslog(LOG_ERR, "bdump_get: mutual authentication failed: %s",
+ error_message(retval));
+ cleanup(server);
+ return;
+ }
+ break;
#endif
-
- /* get his authenticator */
- retval = GetKerberosData(live_socket, from.sin_addr, &kdata,
- SERVER_SERVICE, srvtab_file);
- if (retval != KSUCCESS) {
- syslog(LOG_ERR, "bdump_get getkdata: %s",krb_get_err_text(retval));
- cleanup(server);
- return;
- }
+#ifdef HAVE_KRB4
+ case 4:
+ /* send an authenticator */
+ retval = SendKerberosData(live_socket, &ticket, SERVER_SERVICE,
+ SERVER_INSTANCE);
+ if (retval != 0) {
+ syslog(LOG_ERR,"bdump_get: %s", error_message(retval));
+ cleanup(server);
+ return;
+ }
+ zdbug((LOG_DEBUG, "bdump_get: SendKerberosData ok"));
+
+ /* get his authenticator */
+ retval = GetKerberosData(live_socket, from.sin_addr, &kdata,
+ SERVER_SERVICE, srvtab_file);
+ if (retval != KSUCCESS) {
+ syslog(LOG_ERR, "bdump_get getkdata: %s",krb_get_err_text(retval));
+ cleanup(server);
+ return;
+ }
- if (strcmp(kdata.pname, SERVER_SERVICE) ||
- strcmp(kdata.pinst, SERVER_INSTANCE) ||
- strcmp(kdata.prealm, ZGetRealm())) {
- syslog(LOG_ERR, "bdump_get: peer not zephyr in lrealm: %s.%s@%s",
- kdata.pname, kdata.pinst,kdata.prealm);
- cleanup(server);
- return;
+ if (strcmp(kdata.pname, SERVER_SERVICE) ||
+ strcmp(kdata.pinst, SERVER_INSTANCE) ||
+ strcmp(kdata.prealm, ZGetRealm())) {
+ syslog(LOG_ERR, "bdump_get: peer not zephyr in lrealm: %s.%s@%s",
+ kdata.pname, kdata.pinst,kdata.prealm);
+ cleanup(server);
+ return;
+ }
+ break;
+#endif /* HAVE_KRB4 */
}
-#endif /* HAVE_KRB4 */
+#endif /* defined(HAVE_KRB4) || defined(HAVE_KRB5) */
retval = setup_file_pointers();
if (retval != 0) {
syslog(LOG_WARNING, "bdump_get: can't set up file pointers: %s",
@@ -499,9 +756,7 @@
cleanup(server);
return;
}
-#if 1
zdbug((LOG_DEBUG,"bdump_get: gbdl ok"));
-#endif
retval = bdump_send_loop(server);
if (retval != ZERR_NONE) {
syslog(LOG_WARNING, "bdump_send_loop failed: %s",
@@ -605,7 +860,30 @@
retval = ZFormatNoticeList(¬ice, lyst, num, &pack, &packlen, ZNOAUTH);
if (retval != ZERR_NONE)
return retval;
-
+
+#ifdef HAVE_KRB5
+ if (bdump_ac) {
+ krb5_data indata, outmsg;
+ indata.length=packlen;
+ indata.data=pack;
+ memset(&outmsg, 0, sizeof(krb5_data));
+ retval = krb5_mk_priv(Z_krb5_ctx, bdump_ac, &indata, &outmsg, NULL);
+ if (retval != ZERR_NONE)
+ return retval;
+ if (outmsg.length > Z_MAXPKTLEN) {
+ syslog(LOG_ERR, "bsl: encrypted packet is too large");
+ return ZERR_PKTLEN;
+ }
+ packlen = outmsg.length;
+ free(pack);
+ pack=malloc(packlen);
+ if (!pack)
+ return ENOMEM;
+ memcpy(pack, outmsg.data, packlen);
+ krb5_free_data_contents(Z_krb5_ctx, &outmsg);
+ }
+#endif
+
length = htons((u_short) packlen);
count = net_write(output, (char *) &length, sizeof(length));
@@ -650,6 +928,11 @@
if (live_socket >= 0) {
close(live_socket);
live_socket = -1;
+#ifdef HAVE_KRB5
+ if (bdump_ac)
+ krb5_auth_con_free(Z_krb5_ctx, bdump_ac);
+ bdump_ac = NULL;
+#endif
}
}
@@ -694,7 +977,7 @@
#ifndef NOENCRYPTION
Sched *s;
#endif
-
+
/* have they expired ? */
if (ticket_time < NOW - tkt_lifetime(TKTLIFETIME) + (15L * 60L)) {
/* +15 for leeway */
@@ -728,6 +1011,54 @@
des_key_sched(serv_key, serv_ksched.s);
#endif /* !NOENCRYPTION */
}
+#ifdef HAVE_KRB5
+ /* XXX */
+ if (ticket5_time < NOW - tkt5_lifetime(TKT5LIFETIME) + (15L * 60L)) {
+ krb5_keytab kt;
+ krb5_get_init_creds_opt opt;
+ krb5_creds cred;
+ krb5_principal principal;
+
+ memset(&cred, 0, sizeof(cred));
+
+ retval = krb5_build_principal(Z_krb5_ctx, &principal,
+ strlen(ZGetRealm()),
+ ZGetRealm(),
+ SERVER_KRB5_SERVICE, SERVER_INSTANCE,
+ 0);
+ if (retval) {
+ krb5_free_principal(Z_krb5_ctx, principal);
+ return(1);
+ }
+
+ krb5_get_init_creds_opt_init (&opt);
+ krb5_get_init_creds_opt_set_tkt_life (&opt, TKT5LIFETIME);
+
+ retval = krb5_kt_resolve(Z_krb5_ctx, keytab_file, &kt);
+ if (retval) return(1);
+
+ retval = krb5_get_init_creds_keytab (Z_krb5_ctx,
+ &cred,
+ principal,
+ kt,
+ 0,
+ NULL,
+ &opt);
+ krb5_free_principal(Z_krb5_ctx, principal);
+ krb5_kt_close(Z_krb5_ctx, kt);
+ if (retval) return(1);
+
+ retval = krb5_cc_initialize (Z_krb5_ctx, Z_krb5_ccache, cred.client);
+ if (retval) return(1);
+
+ retval = krb5_cc_store_cred (Z_krb5_ctx, Z_krb5_ccache, &cred);
+ if (retval) return(1);
+
+ ticket5_time = NOW;
+
+ krb5_free_cred_contents (Z_krb5_ctx, &cred);
+ }
+#endif
return(0);
}
#endif /* HAVE_KRB4 */
@@ -771,8 +1102,14 @@
Code_t retval;
Client *client = NULL;
struct sockaddr_in who;
+#ifdef HAVE_KRB5
+ char buf[512];
+ int blen;
+#endif
+#if defined(HAVE_KRB4) || defined(HAVE_KRB5)
+ char *cp;
+#endif
#ifdef HAVE_KRB4
- char *cp;
C_Block cblock;
#endif /* HAVE_KRB4 */
ZRealm *realm = NULL;
@@ -798,6 +1135,23 @@
return retval;
}
+#if HAVE_KRB5
+ if (bdump_ac) {
+ krb5_data in, out;
+ in.length = len;
+ in.data = packet;
+ memset(&out, 0, sizeof(krb5_data));
+ retval = krb5_rd_priv(Z_krb5_ctx, bdump_ac, &in, &out, NULL);
+ if (retval != ZERR_NONE) {
+ syslog(LOG_ERR, "brl krb5 rd priv: %s", error_message(retval));
+ return retval;
+ }
+ memcpy(packet, out.data, out.length);
+ len = out.length;
+ krb5_free_data_contents(Z_krb5_ctx, &out);
+ }
+#endif
+
retval = ZParseNotice(packet, len, ¬ice);
if (retval != ZERR_NONE) {
syslog(LOG_ERR, "brl notice parse: %s", error_message(retval));
@@ -853,6 +1207,52 @@
syslog(LOG_ERR,"brl failed: %s", error_message(retval));
return retval;
}
+#ifdef HAVE_KRB5
+ client->session_keyblock = NULL;
+ if (*notice.z_class_inst) {
+ /* check out this session key I found */
+ cp = notice.z_message + strlen(notice.z_message) + 1;
+ if (*cp == '0') {
+ /* ****ing netascii; this is an encrypted DES keyblock
+ XXX this code should be conditionalized for server
+ transitions */
+ retval = Z_krb5_init_keyblock(Z_krb5_ctx, ENCTYPE_DES_CBC_CRC,
+ sizeof(C_Block),
+ &client->session_keyblock);
+ if (retval) {
+ syslog(LOG_ERR, "brl failed to allocate DES keyblock: %s",
+ error_message(retval));
+ return retval;
+ }
+ retval = ZReadAscii(cp, strlen(cp), cblock, sizeof(C_Block));
+ if (retval != ZERR_NONE) {
+ syslog(LOG_ERR,"brl bad cblk read: %s (%s)",
+ error_message(retval), cp);
+ } else {
+ des_ecb_encrypt(cblock, Z_keydata(client->session_keyblock),
+ serv_ksched.s, DES_DECRYPT);
+ }
+ } else if (*cp == 'Z') { /* Zcode! Long live the new flesh! */
+ retval = ZReadZcode(cp, buf, sizeof(buf), &blen);
+ if (retval != ZERR_NONE) {
+ syslog(LOG_ERR,"brl bad cblk read: %s (%s)",
+ error_message(retval), cp);
+ } else {
+ retval = Z_krb5_init_keyblock(Z_krb5_ctx,
+ ntohl(*(krb5_enctype *)&buf[0]),
+ ntohl(*(u_int32_t *)&buf[4]),
+ &client->session_keyblock);
+ if (retval) {
+ syslog(LOG_ERR, "brl failed to allocate keyblock: %s",
+ error_message(retval));
+ return retval;
+ }
+ memcpy(Z_keydata(client->session_keyblock), &buf[8],
+ Z_keylen(client->session_keyblock));
+ }
+ }
+ }
+#else
#ifdef HAVE_KRB4
memset(client->session_key, 0, sizeof(C_Block));
if (*notice.z_class_inst) {
@@ -872,6 +1272,7 @@
}
}
#endif /* HAVE_KRB4 */
+#endif
} else if (strcmp(notice.z_opcode, CLIENT_SUBSCRIBE) == 0) {
/* a subscription packet */
if (!client) {
@@ -1025,6 +1426,29 @@
return retval;
}
+#ifdef HAVE_KRB5
+ if (bdump_ac) {
+ krb5_data indata, outmsg;
+ indata.length=packlen;
+ indata.data=pack;
+ memset(&outmsg, 0, sizeof(krb5_data));
+ retval = krb5_mk_priv(Z_krb5_ctx, bdump_ac, &indata, &outmsg, NULL);
+ if (retval != ZERR_NONE)
+ return retval;
+ if (outmsg.length > Z_MAXPKTLEN) {
+ syslog(LOG_ERR, "sn: encrypted packet is too large");
+ return ZERR_PKTLEN;
+ }
+ packlen = outmsg.length;
+ free(pack);
+ pack=malloc(packlen);
+ if (!pack)
+ return ENOMEM;
+ memcpy(pack, outmsg.data, packlen);
+ krb5_free_data_contents(Z_krb5_ctx, &outmsg);
+ }
+#endif
+
length = htons((u_short) packlen);
count = net_write(output, (char *) &length, sizeof(length));
@@ -1138,7 +1562,13 @@
errno = 0;
cc = fread(buf, 1, len, f);
if (cc == 0)
+ {
+ if (feof(f))
+ return len2;
+ if (errno == 0)
+ errno = EIO;
return -1;
+ }
buf += cc;
len2 += cc;
len -= cc;
Modified: trunk/athena/lib/zephyr/server/client.c
===================================================================
--- trunk/athena/lib/zephyr/server/client.c 2008-04-03 17:32:17 UTC (rev 22813)
+++ trunk/athena/lib/zephyr/server/client.c 2008-04-03 17:51:46 UTC (rev 22814)
@@ -84,9 +84,13 @@
if (!client)
return ENOMEM;
memset(&client->addr, 0, sizeof(struct sockaddr_in));
-#ifdef KERBEROS
+#ifdef HAVE_KRB5
+ client->session_keyblock = NULL;
+#else
+#ifdef HAVE_KRB4
memset(&client->session_key, 0, sizeof(client->session_key));
#endif
+#endif
client->last_send = 0;
client->last_ack = NOW;
client->addr.sin_family = AF_INET;
@@ -122,6 +126,10 @@
nack_release(client);
subscr_cancel_client(client);
free_string(client->principal);
+#ifdef HAVE_KRB5
+ if (client->session_keyblock)
+ krb5_free_keyblock(Z_krb5_ctx, client->session_keyblock);
+#endif
if (flush)
uloc_flush_client(&client->addr);
free(client);
Modified: trunk/athena/lib/zephyr/server/dispatch.c
===================================================================
--- trunk/athena/lib/zephyr/server/dispatch.c 2008-04-03 17:32:17 UTC (rev 22813)
+++ trunk/athena/lib/zephyr/server/dispatch.c 2008-04-03 17:51:46 UTC (rev 22814)
@@ -14,6 +14,7 @@
#include <zephyr/mit-copyright.h>
#include "zserver.h"
#include <sys/socket.h>
+#include <com_err.h>
#ifndef lint
#ifndef SABER
@@ -582,14 +583,23 @@
we are distributing authentic and
we have a pointer to auth info
*/
-#ifdef HAVE_KRB4
- retval = ZFormatAuthenticNotice(notice, noticepack, packlen, &packlen,
- client->session_key);
- if (retval != ZERR_NONE) {
- syslog(LOG_ERR, "xmit auth format: %s", error_message(retval));
- free(noticepack);
- return;
- }
+#ifdef HAVE_KRB5
+ retval = ZFormatAuthenticNoticeV5(notice, noticepack, packlen,
+ &packlen, client->session_keyblock);
+ if (retval != ZERR_NONE) {
+ syslog(LOG_ERR, "xmit auth format: %s", error_message(retval));
+ free(noticepack);
+ return;
+ }
+#else
+#if defined(HAVE_KRB4)
+ retval = ZFormatAuthenticNotice(notice, noticepack, packlen,
+ &packlen, client->session_key);
+ if (retval != ZERR_NONE) {
+ syslog(LOG_ERR, "xmit auth format: %s", error_message(retval));
+ free(noticepack);
+ return;
+ }
#else /* !HAVE_KRB4 */
notice->z_auth = 1;
retval = ZFormatSmallRawNotice(notice, noticepack, &packlen);
@@ -599,6 +609,7 @@
return;
}
#endif /* HAVE_KRB4 */
+#endif /* HAVE_KRB5 */
} else {
notice->z_auth = 0;
notice->z_authent_len = 0;
@@ -1126,10 +1137,28 @@
clt_ack(notice, who, AUTH_FAILED);
return ZERR_NONE;
}
+#ifdef HAVE_KRB5
+ if (client->session_keyblock) {
+ krb5_free_keyblock_contents(Z_krb5_ctx, client->session_keyblock);
+ retval = krb5_copy_keyblock_contents(Z_krb5_ctx, ZGetSession(),
+ client->session_keyblock);
+ } else {
+ retval = krb5_copy_keyblock(Z_krb5_ctx, ZGetSession(),
+ &client->session_keyblock);
+ }
+ if (retval) {
+ syslog(LOG_WARNING, "keyblock copy failed in subscr: %s",
+ error_message(retval));
+ if (server == me_server)
+ nack(notice, who);
+ return ZERR_NONE;
+ }
+#else
#ifdef HAVE_KRB4
/* in case it's changed */
memcpy(client->session_key, ZGetSession(), sizeof(C_Block));
#endif
+#endif
retval = subscr_subscribe(client, notice, server);
if (retval != ZERR_NONE) {
syslog(LOG_WARNING, "subscr failed: %s", error_message(retval));
Modified: trunk/athena/lib/zephyr/server/kstuff.c
===================================================================
--- trunk/athena/lib/zephyr/server/kstuff.c 2008-04-03 17:32:17 UTC (rev 22813)
+++ trunk/athena/lib/zephyr/server/kstuff.c 2008-04-03 17:51:46 UTC (rev 22814)
@@ -22,30 +22,6 @@
#ifdef HAVE_KRB4
-/* Keep a hash table mapping tickets to session keys, so we can do a fast
- * check of the cryptographic checksum without doing and DES decryptions.
- * Also remember the expiry time of the ticket, so that we can sweep the
- * table periodically. */
-
-#define HASHTAB_SIZE 4091
-
-typedef struct hash_entry Hash_entry;
-
-/* The ticket comes at the end, in a variable-length array. */
-struct hash_entry {
- C_Block session_key;
- time_t expires;
- char srcprincipal[ANAME_SZ+INST_SZ+REALM_SZ+4];
- Hash_entry *next;
- int ticket_len;
- unsigned char ticket[1];
-};
-
-Hash_entry *hashtab[HASHTAB_SIZE];
-
-static int hash_ticket __P((unsigned char *, int));
-static void add_session_key __P((KTEXT, C_Block, char *, time_t));
-static int find_session_key __P((KTEXT, C_Block, char *));
static ZChecksum_t compute_checksum __P((ZNotice_t *, C_Block));
static ZChecksum_t compute_rlm_checksum __P((ZNotice_t *, C_Block));
@@ -113,6 +89,10 @@
* get the ticket and write it to the file descriptor
*/
+#if !defined(krb_err_base) && defined(ERROR_TABLE_BASE_krb)
+#define krb_err_base ERROR_TABLE_BASE_krb
+#endif
+
Code_t
SendKerberosData(fd, ticket, service, host)
int fd; /* file descriptor to write onto */
@@ -142,21 +122,157 @@
#endif /* HAVE_KRB4 */
+#if defined(HAVE_KRB5) || defined(HAVE_KRB4)
Code_t
+ReadKerberosData(int fd, int *size, char **data, int *proto) {
+ char p[20];
+ int i;
+ unsigned char *dst;
+ Code_t retval;
+ int len = 0;
+
+ for (i=0; i<20; i++) {
+ if (read(fd, &p[i], 1) != 1) {
+ p[i] = 0;
+ syslog(LOG_WARNING,"ReadKerberosData: bad read reply len @%d (got \"%s\"", i, p);
+ return(KFAILURE);
+ }
+ if (p[i] == ' ') {
+ p[i] = '\0';
+ break;
+ }
+ }
+
+ if (i == 20) {
+ syslog(LOG_WARNING, "ReadKerberosData: read reply len exceeds buffer");
+ return KFAILURE;
+ }
+
+ if (!strncmp(p, "V5-", 3) && (len = atoi(p+3)) > 0)
+ *proto = 5;
+ else if ((len = atoi(p)) > 0)
+ *proto = 4;
+
+ if (*proto < 4 | *proto > 5) {
+ syslog(LOG_WARNING, "ReadKerberosData: error parsing authenticator length (\"%s\")", p);
+ return KFAILURE;
+ }
+
+ if (len <= 0) {
+ syslog(LOG_WARNING, "ReadKerberosData: read reply len = %d", len);
+ return KFAILURE;
+ }
+
+ *data = malloc(len);
+ if (! *data) {
+ syslog(LOG_WARNING, "ReadKerberosData: failure allocating %d bytes: %m", len);
+ return errno;
+ }
+
+ dst=*data;
+ for (i=0; i < len; i++) {
+ if (read(fd, dst++, 1) != 1) {
+ free(*data);
+ *data = NULL;
+ *size = 0;
+ syslog(LOG_WARNING,"ReadKerberosData: bad read reply string");
+ return ZSRV_PKSHORT;
+ }
+ }
+ *size = len;
+ return 0;
+}
+#endif
+
+#ifdef HAVE_KRB5
+Code_t
+GetKrb5Data(int fd, krb5_data *data) {
+ char p[20];
+ int i;
+ unsigned char *dst;
+ Code_t retval;
+
+ for (i=0; i<20; i++) {
+ if (read(fd, &p[i], 1) != 1) {
+ p[i] = 0;
+ syslog(LOG_WARNING,"bad read reply len @%d (got \"%s\")", i, p);
+ return(KFAILURE);
+ }
+ if (p[i] == ' ') {
+ p[i] = '\0';
+ break;
+ }
+ }
+ if (i == 20 || strncmp(p, "V5-", 3) || !atoi(p+3)) {
+ syslog(LOG_WARNING,"bad reply len");
+ return ZSRV_PKSHORT;
+ }
+ data->length = atoi(p+3);
+ data->data = malloc(data->length);
+ if (! data->data) {
+ data->length = 0;
+ return errno;
+ }
+ dst=data->data;
+ for (i=0; i < data->length; i++) {
+ if (read(fd, dst++, 1) != 1) {
+ free(data->data);
+ memset((char *)data, 0, sizeof(krb5_data));
+ syslog(LOG_WARNING,"bad read reply string");
+ return ZSRV_PKSHORT;
+ }
+ }
+ return 0;
+}
+
+Code_t
+SendKrb5Data(int fd, krb5_data *data) {
+ char p[32];
+ int written, size_to_write;
+ sprintf(p, "V5-%d ", data->length);
+ size_to_write = strlen (p);
+ if (size_to_write != (written = write(fd, p, size_to_write)) ||
+ data->length != (written = write(fd, data->data, data->length))) {
+ return (written < 0) ? errno : ZSRV_PKSHORT;
+ }
+ return 0;
+}
+#endif
+
+Code_t
ZCheckRealmAuthentication(notice, from, realm)
ZNotice_t *notice;
struct sockaddr_in *from;
char *realm;
{
-#ifdef HAVE_KRB4
- int result;
- char rlmprincipal[ANAME_SZ+INST_SZ+REALM_SZ+4];
- char srcprincipal[ANAME_SZ+INST_SZ+REALM_SZ+4];
- KTEXT_ST authent, ticket;
- AUTH_DAT dat;
- ZChecksum_t checksum;
- CREDENTIALS cred;
- C_Block session_key;
+#ifdef HAVE_KRB5
+ char *authbuf;
+ char rlmprincipal[ANAME_SZ+INST_SZ+REALM_SZ+4+1024];
+ krb5_principal princ;
+ krb5_data packet;
+ krb5_ticket *tkt;
+ char *name;
+ krb5_error_code result;
+ krb5_principal server;
+ krb5_keytab keytabid = 0;
+ krb5_auth_context authctx;
+ krb5_keyblock *keyblock;
+ krb5_enctype enctype;
+ krb5_cksumtype cksumtype;
+ krb5_data cksumbuf;
+ int valid;
+ char *cksum0_base, *cksum1_base, *cksum2_base;
+ char *svcinst, *x, *y;
+ char *asn1_data, *key_data;
+ int asn1_len, key_len, cksum0_len, cksum1_len, cksum2_len;
+#ifdef KRB5_AUTH_CON_GETAUTHENTICATOR_TAKES_DOUBLE_POINTER
+ krb5_authenticator *authenticator;
+#define KRB5AUTHENT authenticator
+#else
+ krb5_authenticator authenticator;
+#define KRB5AUTHENT &authenticator
+#endif
+ int len;
if (!notice->z_auth)
return ZAUTH_NO;
@@ -165,52 +281,537 @@
if (notice->z_authent_len <= 0)
return ZAUTH_FAILED;
+ len = strlen(notice->z_ascii_authent)+1;
+ authbuf=malloc(len);
+
/* Read in the authentication data. */
- if (ZReadAscii(notice->z_ascii_authent,
- strlen(notice->z_ascii_authent)+1,
- (unsigned char *)authent.dat,
- notice->z_authent_len) == ZERR_BADFIELD) {
+ if (ZReadZcode(notice->z_ascii_authent,
+ authbuf,
+ len, &len) == ZERR_BADFIELD) {
return ZAUTH_FAILED;
}
- authent.length = notice->z_authent_len;
- (void) sprintf(rlmprincipal, "%s.%s@%s", SERVER_SERVICE,
+ (void) sprintf(rlmprincipal, "%s/%s@%s", SERVER_SERVICE,
SERVER_INSTANCE, realm);
- result = krb_rd_req(&authent, SERVER_SERVICE, SERVER_INSTANCE,
- from->sin_addr.s_addr, &dat, srvtab_file);
- if (result == RD_AP_OK) {
- sprintf(srcprincipal, "%s%s%s@%s", dat.pname, dat.pinst[0] ? "." : "",
- dat.pinst, dat.prealm);
- if (strcmp(rlmprincipal, srcprincipal))
- return ZAUTH_FAILED;
- } else {
- return ZAUTH_FAILED; /* didn't decode correctly */
+ packet.length = len;
+ packet.data = authbuf;
+
+ result = krb5_kt_resolve(Z_krb5_ctx,
+ keytab_file, &keytabid);
+ if (result) {
+ free(authbuf);
+ return (result);
}
- /* Check the cryptographic checksum. */
-#ifdef NOENCRYPTION
- checksum = 0;
+ /* HOLDING: authbuf, keytabid */
+ /* Create the auth context */
+ result = krb5_auth_con_init(Z_krb5_ctx, &authctx);
+ if (result) {
+ krb5_kt_close(Z_krb5_ctx, keytabid);
+ free(authbuf);
+ return (result);
+ }
+
+ /* HOLDING: authbuf, authctx */
+ result = krb5_build_principal(Z_krb5_ctx, &server, strlen(__Zephyr_realm),
+ __Zephyr_realm, SERVER_SERVICE,
+ SERVER_INSTANCE, NULL);
+ if (!result) {
+ result = krb5_rd_req(Z_krb5_ctx, &authctx, &packet, server,
+ keytabid, 0, &tkt);
+ krb5_free_principal(Z_krb5_ctx, server);
+ }
+ krb5_kt_close(Z_krb5_ctx, keytabid);
+
+ if (result) {
+ if (result == KRB5KRB_AP_ERR_REPEAT)
+ syslog(LOG_DEBUG, "ZCheckRealmAuthentication: k5 auth failed: %s", error_message(result));
+ else
+ syslog(LOG_WARNING,"ZCheckRealmAuthentication: k5 auth failed: %s", error_message(result));
+ free(authbuf);
+ krb5_auth_con_free(Z_krb5_ctx, authctx);
+ return ZAUTH_FAILED;
+ }
+
+ /* HOLDING: authbuf, authctx, tkt */
+
+ if (tkt == 0 || !Z_tktprincp(tkt)) {
+ if (tkt)
+ krb5_free_ticket(Z_krb5_ctx, tkt);
+ free(authbuf);
+ krb5_auth_con_free(Z_krb5_ctx, authctx);
+ return ZAUTH_FAILED;
+ }
+
+ princ = Z_tktprinc(tkt);
+
+ if (princ == 0) {
+ krb5_free_ticket(Z_krb5_ctx, tkt);
+ free(authbuf);
+ krb5_auth_con_free(Z_krb5_ctx, authctx);
+ return ZAUTH_FAILED;
+ }
+
+ /* HOLDING: authbuf, authctx, tkt */
+ result = krb5_unparse_name(Z_krb5_ctx, princ, &name);
+ if (result) {
+ syslog(LOG_WARNING, "k5 unparse_name failed: %s",
+ error_message(result));
+ free(authbuf);
+ krb5_auth_con_free(Z_krb5_ctx, authctx);
+ krb5_free_ticket(Z_krb5_ctx, tkt);
+ return ZAUTH_FAILED;
+ }
+
+ krb5_free_ticket(Z_krb5_ctx, tkt);
+
+ /* HOLDING: authbuf, authctx, name */
+ if (strcmp(name, rlmprincipal)) {
+ syslog(LOG_WARNING, "k5 name mismatch: '%s' vs '%s'",
+ name, rlmprincipal);
+ krb5_auth_con_free(Z_krb5_ctx, authctx);
+ free(name);
+ free(authbuf);
+ return ZAUTH_FAILED;
+ }
+ free(name);
+ free(authbuf);
+
+ /* HOLDING: authctx */
+ /* Get an authenticator so we can get the keyblock */
+ result = krb5_auth_con_getauthenticator (Z_krb5_ctx, authctx,
+ &authenticator);
+ if(result) {
+ krb5_auth_con_free(Z_krb5_ctx, authctx);
+ return result;
+ }
+
+ /* HOLDING: authctx, authenticator */
+ result = krb5_auth_con_getkey(Z_krb5_ctx, authctx, &keyblock);
+ if (result) {
+ krb5_auth_con_free(Z_krb5_ctx, authctx);
+ krb5_free_authenticator(Z_krb5_ctx, KRB5AUTHENT);
+ return (ZAUTH_FAILED);
+ }
+
+ /* HOLDING: authctx, authenticator, keyblock */
+ /* Figure out what checksum type to use */
+ key_data = Z_keydata(keyblock);
+ key_len = Z_keylen(keyblock);
+ result = Z_ExtractEncCksum(keyblock, &enctype, &cksumtype);
+ if (result) {
+ krb5_free_keyblock(Z_krb5_ctx, keyblock);
+ krb5_auth_con_free(Z_krb5_ctx, authctx);
+ krb5_free_authenticator(Z_krb5_ctx, KRB5AUTHENT);
+ return (ZAUTH_FAILED);
+ }
+ /* HOLDING: authctx, authenticator, keyblock */
+
+ /* Assemble the things to be checksummed */
+ /* first part is from start of packet through z_default_format:
+ * - z_version
+ * - z_num_other_fields
+ * - z_kind
+ * - z_uid
+ * - z_port
+ * - z_auth
+ * - z_authent_len
+ * - z_ascii_authent
+ * - z_class
+ * - z_class_inst
+ * - z_opcode
+ * - z_sender
+ * - z_recipient
+ * - z_default_format
+ */
+ cksum0_base = notice->z_packet;
+ x = notice->z_default_format;
+ cksum0_len = x + strlen(x) + 1 - cksum0_base;
+ /* second part is from z_multinotice through other fields:
+ * - z_multinotice
+ * - z_multiuid
+ * - z_other_fields[]
+ */
+ cksum1_base = notice->z_multinotice;
+ if (notice->z_num_other_fields)
+ x = notice->z_other_fields[notice->z_num_other_fields];
+ else
+ x = cksum1_base + strlen(cksum1_base) + 1; /* multiuid */
+ cksum1_len = x + strlen(x) + 1 - cksum1_base;
+
+ /* last part is the message body */
+ cksum2_base = notice->z_message;
+ cksum2_len = notice->z_message_len;
+
+ if ((!notice->z_ascii_checksum || *notice->z_ascii_checksum != 'Z') &&
+ key_len == 8 &&
+ (enctype == ENCTYPE_DES_CBC_CRC ||
+ enctype == ENCTYPE_DES_CBC_MD4 ||
+ enctype == ENCTYPE_DES_CBC_MD5)) {
+ /* try old-format checksum (covers cksum0 only) */
+
+ ZChecksum_t our_checksum;
+
+ our_checksum = compute_rlm_checksum(notice, key_data);
+
+ krb5_free_keyblock(Z_krb5_ctx, keyblock);
+ krb5_auth_con_free(Z_krb5_ctx, authctx);
+ krb5_free_authenticator(Z_krb5_ctx, KRB5AUTHENT);
+
+ if (our_checksum == notice->z_checksum) {
+ return ZAUTH_YES;
+ } else
+ return ZAUTH_FAILED;
+ }
+
+ /* HOLDING: authctx, authenticator */
+
+ cksumbuf.length = cksum0_len + cksum1_len + cksum2_len;
+ cksumbuf.data = malloc(cksumbuf.length);
+ if (!cksumbuf.data) {
+ krb5_free_keyblock(Z_krb5_ctx, keyblock);
+ krb5_auth_con_free(Z_krb5_ctx, authctx);
+ krb5_free_authenticator(Z_krb5_ctx, KRB5AUTHENT);
+ return ZAUTH_FAILED;
+ }
+ /* HOLDING: authctx, authenticator, cksumbuf.data */
+
+ memcpy(cksumbuf.data, cksum0_base, cksum0_len);
+ memcpy(cksumbuf.data + cksum0_len, cksum1_base, cksum1_len);
+ memcpy(cksumbuf.data + cksum0_len + cksum1_len,
+ cksum2_base, cksum2_len);
+
+ /* decode zcoded checksum */
+ /* The encoded form is always longer than the original */
+ asn1_len = strlen(notice->z_ascii_checksum) + 1;
+ asn1_data = malloc(asn1_len);
+ if (!asn1_data) {
+ krb5_free_keyblock(Z_krb5_ctx, keyblock);
+ krb5_auth_con_free(Z_krb5_ctx, authctx);
+ krb5_free_authenticator(Z_krb5_ctx, KRB5AUTHENT);
+ free(cksumbuf.data);
+ return ZAUTH_FAILED;
+ }
+ /* HOLDING: authctx, authenticator, cksumbuf.data, asn1_data */
+ result = ZReadZcode(notice->z_ascii_checksum,
+ asn1_data, asn1_len, &asn1_len);
+ if (result != ZERR_NONE) {
+ krb5_free_keyblock(Z_krb5_ctx, keyblock);
+ krb5_auth_con_free(Z_krb5_ctx, authctx);
+ krb5_free_authenticator(Z_krb5_ctx, KRB5AUTHENT);
+ free(asn1_data);
+ free(cksumbuf.data);
+ return ZAUTH_FAILED;
+ }
+ /* HOLDING: asn1_data, cksumbuf.data */
+
+ valid = Z_krb5_verify_cksum(keyblock, &cksumbuf, cksumtype, asn1_data, asn1_len);
+
+ free(asn1_data);
+ krb5_auth_con_free(Z_krb5_ctx, authctx);
+ krb5_free_authenticator(Z_krb5_ctx, KRB5AUTHENT);
+ krb5_free_keyblock(Z_krb5_ctx, keyblock);
+ free(cksumbuf.data);
+
+ if (valid)
+ return (ZAUTH_YES);
+ else
+ return (ZAUTH_FAILED);
#else
- checksum = compute_rlm_checksum(notice, dat.session);
+ return (notice->z_auth) ? ZAUTH_YES : ZAUTH_NO;
#endif
- if (checksum != notice->z_checksum) {
-#ifndef NOENCRYPTION
- checksum = compute_checksum(notice, dat.session);
- if (checksum != notice->z_checksum)
+}
+
+Code_t
+ZCheckAuthentication(notice, from)
+ ZNotice_t *notice;
+ struct sockaddr_in *from;
+{
+#ifdef HAVE_KRB5
+ char *authbuf;
+ krb5_principal princ;
+ krb5_data packet;
+ krb5_ticket *tkt;
+ char *name;
+ krb5_error_code result;
+ krb5_principal server;
+ krb5_keytab keytabid = 0;
+ krb5_auth_context authctx;
+ krb5_keyblock *keyblock;
+ krb5_enctype enctype;
+ krb5_cksumtype cksumtype;
+ krb5_data cksumbuf;
+ int valid;
+ char *cksum0_base, *cksum1_base, *cksum2_base;
+ char *svcinst, *x, *y;
+ char *asn1_data, *key_data;
+ int asn1_len, key_len, cksum0_len, cksum1_len, cksum2_len;
+#ifdef KRB5_AUTH_CON_GETAUTHENTICATOR_TAKES_DOUBLE_POINTER
+ krb5_authenticator *authenticator;
+#define KRB5AUTHENT authenticator
+#else
+ krb5_authenticator authenticator;
+#define KRB5AUTHENT &authenticator
#endif
+ int len;
+
+ if (!notice->z_auth)
+ return ZAUTH_NO;
+
+ /* Check for bogus authentication data length. */
+ if (notice->z_authent_len <= 1)
return ZAUTH_FAILED;
+
+#ifdef HAVE_KRB4
+ if (notice->z_ascii_authent[0] != 'Z')
+ return ZCheckAuthentication4(notice, from);
+#endif
+
+ len = strlen(notice->z_ascii_authent)+1;
+ authbuf=malloc(len);
+
+ /* Read in the authentication data. */
+ if (ZReadZcode(notice->z_ascii_authent,
+ authbuf,
+ len, &len) == ZERR_BADFIELD) {
+ return ZAUTH_FAILED;
}
- return ZAUTH_YES;
+ packet.length = len;
+ packet.data = authbuf;
-#else /* !HAVE_KRB4 */
+ result = krb5_kt_resolve(Z_krb5_ctx,
+ keytab_file, &keytabid);
+ if (result) {
+ free(authbuf);
+ return (result);
+ }
+
+ /* HOLDING: authbuf, keytabid */
+ /* Create the auth context */
+ result = krb5_auth_con_init(Z_krb5_ctx, &authctx);
+ if (result) {
+ krb5_kt_close(Z_krb5_ctx, keytabid);
+ free(authbuf);
+ return (result);
+ }
+
+ /* HOLDING: authbuf, authctx */
+ result = krb5_build_principal(Z_krb5_ctx, &server, strlen(__Zephyr_realm),
+ __Zephyr_realm, SERVER_SERVICE,
+ SERVER_INSTANCE, NULL);
+ if (!result) {
+ result = krb5_rd_req(Z_krb5_ctx, &authctx, &packet, server,
+ keytabid, 0, &tkt);
+ krb5_free_principal(Z_krb5_ctx, server);
+ }
+ krb5_kt_close(Z_krb5_ctx, keytabid);
+
+ if (result) {
+ if (result == KRB5KRB_AP_ERR_REPEAT)
+ syslog(LOG_DEBUG, "ZCheckAuthentication: k5 auth failed: %s", error_message(result));
+ else
+ syslog(LOG_WARNING,"ZCheckAuthentication: k5 auth failed: %s", error_message(result));
+ free(authbuf);
+ krb5_auth_con_free(Z_krb5_ctx, authctx);
+ return ZAUTH_FAILED;
+ }
+
+ /* HOLDING: authbuf, authctx, tkt */
+
+ if (tkt == 0 || !Z_tktprincp(tkt)) {
+ if (tkt)
+ krb5_free_ticket(Z_krb5_ctx, tkt);
+ free(authbuf);
+ krb5_auth_con_free(Z_krb5_ctx, authctx);
+ return ZAUTH_FAILED;
+ }
+ princ = Z_tktprinc(tkt);
+
+ if (princ == 0) {
+ krb5_free_ticket(Z_krb5_ctx, tkt);
+ free(authbuf);
+ krb5_auth_con_free(Z_krb5_ctx, authctx);
+ return ZAUTH_FAILED;
+ }
+
+ /* HOLDING: authbuf, authctx, tkt */
+ result = krb5_unparse_name(Z_krb5_ctx, princ, &name);
+ if (result) {
+ syslog(LOG_WARNING, "k5 unparse_name failed: %s",
+ error_message(result));
+ free(authbuf);
+ krb5_auth_con_free(Z_krb5_ctx, authctx);
+ krb5_free_ticket(Z_krb5_ctx, tkt);
+ return ZAUTH_FAILED;
+ }
+
+ krb5_free_ticket(Z_krb5_ctx, tkt);
+
+ /* HOLDING: authbuf, authctx, name */
+ if (strcmp(name, notice->z_sender)) {
+ syslog(LOG_WARNING, "k5 name mismatch: '%s' vs '%s'",
+ name, notice->z_sender);
+ krb5_auth_con_free(Z_krb5_ctx, authctx);
+ free(name);
+ free(authbuf);
+ return ZAUTH_FAILED;
+ }
+ free(name);
+ free(authbuf);
+
+ /* HOLDING: authctx */
+ /* Get an authenticator so we can get the keyblock */
+ result = krb5_auth_con_getauthenticator (Z_krb5_ctx, authctx,
+ &authenticator);
+ if(result) {
+ krb5_auth_con_free(Z_krb5_ctx, authctx);
+ return result;
+ }
+
+ /* HOLDING: authctx, authenticator */
+ result = krb5_auth_con_getkey(Z_krb5_ctx, authctx, &keyblock);
+ if (result) {
+ krb5_auth_con_free(Z_krb5_ctx, authctx);
+ krb5_free_authenticator(Z_krb5_ctx, KRB5AUTHENT);
+ return (ZAUTH_FAILED);
+ }
+
+ /* HOLDING: authctx, authenticator, keyblock */
+ /* Figure out what checksum type to use */
+ key_data = Z_keydata(keyblock);
+ key_len = Z_keylen(keyblock);
+ result = Z_ExtractEncCksum(keyblock, &enctype, &cksumtype);
+ if (result) {
+ krb5_free_keyblock(Z_krb5_ctx, keyblock);
+ krb5_auth_con_free(Z_krb5_ctx, authctx);
+ krb5_free_authenticator(Z_krb5_ctx, KRB5AUTHENT);
+ return (ZAUTH_FAILED);
+ }
+ /* HOLDING: authctx, authenticator, keyblock */
+
+ ZSetSession(keyblock);
+
+ /* Assemble the things to be checksummed */
+ /* first part is from start of packet through z_default_format:
+ * - z_version
+ * - z_num_other_fields
+ * - z_kind
+ * - z_uid
+ * - z_port
+ * - z_auth
+ * - z_authent_len
+ * - z_ascii_authent
+ * - z_class
+ * - z_class_inst
+ * - z_opcode
+ * - z_sender
+ * - z_recipient
+ * - z_default_format
+ */
+ cksum0_base = notice->z_packet;
+ x = notice->z_default_format;
+ cksum0_len = x + strlen(x) + 1 - cksum0_base;
+ /* second part is from z_multinotice through other fields:
+ * - z_multinotice
+ * - z_multiuid
+ * - z_other_fields[]
+ */
+ cksum1_base = notice->z_multinotice;
+ if (notice->z_num_other_fields)
+ x = notice->z_other_fields[notice->z_num_other_fields];
+ else
+ x = cksum1_base + strlen(cksum1_base) + 1; /* multiuid */
+ cksum1_len = x + strlen(x) + 1 - cksum1_base;
+
+ /* last part is the message body */
+ cksum2_base = notice->z_message;
+ cksum2_len = notice->z_message_len;
+
+ if ((!notice->z_ascii_checksum || *notice->z_ascii_checksum != 'Z') &&
+ key_len == 8 &&
+ (enctype == ENCTYPE_DES_CBC_CRC ||
+ enctype == ENCTYPE_DES_CBC_MD4 ||
+ enctype == ENCTYPE_DES_CBC_MD5)) {
+ /* try old-format checksum (covers cksum0 only) */
+
+ ZChecksum_t our_checksum;
+
+ our_checksum = compute_checksum(notice, key_data);
+
+ krb5_free_keyblock(Z_krb5_ctx, keyblock);
+ krb5_auth_con_free(Z_krb5_ctx, authctx);
+ krb5_free_authenticator(Z_krb5_ctx, KRB5AUTHENT);
+
+ if (our_checksum == notice->z_checksum)
+ return ZAUTH_YES;
+ else
+ return ZAUTH_FAILED;
+ }
+
+ /* HOLDING: authctx, authenticator */
+
+ cksumbuf.length = cksum0_len + cksum1_len + cksum2_len;
+ cksumbuf.data = malloc(cksumbuf.length);
+ if (!cksumbuf.data) {
+ krb5_free_keyblock(Z_krb5_ctx, keyblock);
+ krb5_auth_con_free(Z_krb5_ctx, authctx);
+ krb5_free_authenticator(Z_krb5_ctx, KRB5AUTHENT);
+ return ZAUTH_FAILED;
+ }
+ /* HOLDING: authctx, authenticator, cksumbuf.data */
+
+ memcpy(cksumbuf.data, cksum0_base, cksum0_len);
+ memcpy(cksumbuf.data + cksum0_len, cksum1_base, cksum1_len);
+ memcpy(cksumbuf.data + cksum0_len + cksum1_len,
+ cksum2_base, cksum2_len);
+
+ /* decode zcoded checksum */
+ /* The encoded form is always longer than the original */
+ asn1_len = strlen(notice->z_ascii_checksum) + 1;
+ asn1_data = malloc(asn1_len);
+ if (!asn1_data) {
+ krb5_free_keyblock(Z_krb5_ctx, keyblock);
+ krb5_auth_con_free(Z_krb5_ctx, authctx);
+ krb5_free_authenticator(Z_krb5_ctx, KRB5AUTHENT);
+ free(cksumbuf.data);
+ return ZAUTH_FAILED;
+ }
+ /* HOLDING: authctx, authenticator, cksumbuf.data, asn1_data */
+ result = ZReadZcode(notice->z_ascii_checksum,
+ asn1_data, asn1_len, &asn1_len);
+ if (result != ZERR_NONE) {
+ krb5_free_keyblock(Z_krb5_ctx, keyblock);
+ krb5_auth_con_free(Z_krb5_ctx, authctx);
+ krb5_free_authenticator(Z_krb5_ctx, KRB5AUTHENT);
+ free(asn1_data);
+ free(cksumbuf.data);
+ return ZAUTH_FAILED;
+ }
+ /* HOLDING: asn1_data, cksumbuf.data, authctx, authenticator */
+
+ valid = Z_krb5_verify_cksum(keyblock, &cksumbuf, cksumtype, asn1_data, asn1_len);
+
+ free(asn1_data);
+ krb5_auth_con_free(Z_krb5_ctx, authctx);
+ krb5_free_authenticator(Z_krb5_ctx, KRB5AUTHENT);
+ krb5_free_keyblock(Z_krb5_ctx, keyblock);
+ free(cksumbuf.data);
+
+ if (valid)
+ return (ZAUTH_YES);
+ else
+ return (ZAUTH_FAILED);
+#else
return (notice->z_auth) ? ZAUTH_YES : ZAUTH_NO;
#endif
}
+#undef KRB5AUTHENT
+
Code_t
-ZCheckAuthentication(notice, from)
+ZCheckAuthentication4(notice, from)
ZNotice_t *notice;
struct sockaddr_in *from;
{
@@ -221,6 +822,7 @@
AUTH_DAT dat;
ZChecksum_t checksum;
C_Block session_key;
+ char instance[INST_SZ+1];
if (!notice->z_auth)
return ZAUTH_NO;
@@ -238,10 +840,12 @@
}
authent.length = notice->z_authent_len;
- result = krb_rd_req(&authent, SERVER_SERVICE, SERVER_INSTANCE,
+ strcpy(instance, SERVER_INSTANCE);
+
+ result = krb_rd_req(&authent, SERVER_SERVICE, instance,
from->sin_addr.s_addr, &dat, srvtab_file);
if (result == RD_AP_OK) {
- memcpy(__Zephyr_session, dat.session, sizeof(C_Block));
+ ZSetSessionDES(&dat.session);
sprintf(srcprincipal, "%s%s%s@%s", dat.pname, dat.pinst[0] ? "." : "",
dat.pinst, dat.prealm);
if (strcmp(srcprincipal, notice->z_sender))
@@ -266,76 +870,8 @@
#endif
}
+
#ifdef HAVE_KRB4
-
-static int hash_ticket(p, len)
- unsigned char *p;
- int len;
-{
- unsigned long hashval = 0, g;
-
- for (; len > 0; p++, len--) {
- hashval = (hashval << 4) + *p;
- g = hashval & 0xf0000000;
- if (g) {
- hashval ^= g >> 24;
- hashval ^= g;
- }
- }
- return hashval % HASHTAB_SIZE;
-}
-
-static void add_session_key(ticket, session_key, srcprincipal, expires)
- KTEXT ticket;
- C_Block session_key;
- char *srcprincipal;
- time_t expires;
-{
- Hash_entry *entry;
- int hashval;
-
- /* If we can't allocate memory for the hash table entry, just forget
- * about it. */
- entry = (Hash_entry *) malloc(sizeof(Hash_entry) - 1 + ticket->length);
- if (!entry)
- return;
-
- /* Initialize the new entry. */
- memcpy(entry->session_key, session_key, sizeof(entry->session_key));
- strcpy(entry->srcprincipal, srcprincipal);
- entry->expires = expires;
- entry->ticket_len = ticket->length;
- memcpy(entry->ticket, ticket->dat, ticket->length * sizeof(unsigned char));
-
- /* Insert the new entry in the hash table. */
- hashval = hash_ticket(ticket->dat, ticket->length);
- entry->next = hashtab[hashval];
- hashtab[hashval] = entry;
-}
-
-static int find_session_key(ticket, key, srcprincipal)
- KTEXT ticket;
- C_Block key;
- char *srcprincipal;
-{
- unsigned char *dat;
- int hashval, len;
- Hash_entry *entry;
-
- dat = ticket->dat;
- len = ticket->length;
- hashval = hash_ticket(dat, len);
-
- for (entry = hashtab[hashval]; entry; entry = entry->next) {
- if (entry->ticket_len == len && memcmp(entry->ticket, dat, len) == 0) {
- memcpy(key, entry->session_key, sizeof(entry->session_key));
- strcpy(srcprincipal, entry->srcprincipal);
- return 0;
- }
- }
- return -1;
-}
-
static ZChecksum_t compute_checksum(notice, session_key)
ZNotice_t *notice;
C_Block session_key;
@@ -373,26 +909,87 @@
#endif
}
-void sweep_ticket_hash_table(arg)
- void *arg;
+#ifdef HAVE_KRB5
+krb5_error_code
+Z_krb5_init_keyblock(krb5_context context,
+ krb5_enctype type,
+ size_t size,
+ krb5_keyblock **key)
{
- int i;
- Hash_entry **ptr, *entry;
+#ifdef HAVE_KRB5_CREDS_KEYBLOCK_ENCTYPE
+ return krb5_init_keyblock(context, type, size, key);
+#else
+ krb5_error_code ret;
+ krb5_keyblock *tmp, tmp_ss;
+ tmp = &tmp_ss;
- for (i = 0; i < HASHTAB_SIZE; i++) {
- ptr = &hashtab[i];
- while (*ptr) {
- entry = *ptr;
- if (entry->expires < NOW) {
- *ptr = entry->next;
- free(entry);
- } else {
- ptr = &(*ptr)->next;
- }
- }
+ *key = NULL;
+ Z_enctype(tmp) = type;
+ Z_keylen(tmp) = size;
+ Z_keydata(tmp) = malloc(size);
+ if (!Z_keydata(tmp))
+ return ENOMEM;
+ ret = krb5_copy_keyblock(context, tmp, key);
+ free(Z_keydata(tmp));
+ return ret;
+#endif
+}
+
+#if 0
+void ZLogKey(char *label, krb5_keyblock *keyblock) {
+ char *p, *buf;
+ unsigned char *k;
+ int i;
+ buf = malloc(5 *Z_keylen(keyblock)+1);
+
+ k=Z_keydata(keyblock);
+ for (i=0,p=buf; i < Z_keylen(keyblock); i++,p+=strlen(p))
+ sprintf(p, " 0x%02x", k[i]);
+ syslog(LOG_ERR, "key %s is type %d, %d bytes, %s", label, Z_enctype(keyblock), Z_keylen(keyblock), buf);
+ free(buf);
+}
+#endif
+
+void
+ZSetSession(krb5_keyblock *keyblock) {
+#if 1
+ krb5_error_code result;
+
+ if (__Zephyr_keyblock) {
+ krb5_free_keyblock_contents(Z_krb5_ctx, __Zephyr_keyblock);
+ result = krb5_copy_keyblock_contents(Z_krb5_ctx, keyblock, __Zephyr_keyblock);
+ } else {
+ result = krb5_copy_keyblock(Z_krb5_ctx, keyblock, &__Zephyr_keyblock);
}
- timer_set_rel(SWEEP_INTERVAL, sweep_ticket_hash_table, NULL);
+
+ if (result) /*XXX we're out of memory? */
+ ;
+#else
+ memcpy(__Zephyr_session, Z_keydata(keyblock), sizeof(C_Block));
+#endif
}
+#endif
+#ifdef HAVE_KRB4
+void
+ZSetSessionDES(C_Block *key) {
+#ifdef HAVE_KRB5
+ Code_t result;
+ if (__Zephyr_keyblock) {
+ krb5_free_keyblock(Z_krb5_ctx, __Zephyr_keyblock);
+ __Zephyr_keyblock=NULL;
+ }
+ result = Z_krb5_init_keyblock(Z_krb5_ctx, ENCTYPE_DES_CBC_CRC,
+ sizeof(C_Block),
+ &__Zephyr_keyblock);
+ if (result) /*XXX we're out of memory? */
+ return;
+ memcpy(Z_keydata(__Zephyr_keyblock), key, sizeof(C_Block));
+#else
+ memcpy(__Zephyr_session, key, sizeof(C_Block));
+#endif
+}
+#endif
+
#endif /* HAVE_KRB4 */
Modified: trunk/athena/lib/zephyr/server/main.c
===================================================================
--- trunk/athena/lib/zephyr/server/main.c 2008-04-03 17:32:17 UTC (rev 22813)
+++ trunk/athena/lib/zephyr/server/main.c 2008-04-03 17:51:46 UTC (rev 22814)
@@ -92,6 +92,10 @@
char myname[MAXHOSTNAMELEN]; /* my host name */
char list_file[128];
+#ifdef HAVE_KRB5
+char keytab_file[128];
+static char tkt5_file[256];
+#endif
#ifdef HAVE_KRB4
char srvtab_file[128];
char my_realm[REALM_SZ];
@@ -120,6 +124,25 @@
struct in_addr my_addr;
char *bdump_version = "1.2";
+#ifdef HAVE_KRB5
+int bdump_auth_proto = 5;
+#else /* HAVE_KRB5 */
+#ifdef HAVE_KRB4
+int bdump_auth_proto = 4;
+#else /* HAVE_KRB4 */
+int bdump_auth_proto = 0;
+#endif /* HAVE_KRB4 */
+#endif /* HAVE_KRB5 */
+
+#ifdef HAVE_KRB5
+krb5_ccache Z_krb5_ccache;
+krb5_keyblock *__Zephyr_keyblock;
+#else
+#ifdef HAVE_KRB4
+C_Block __Zephyr_session;
+#endif
+#endif
+
int
main(argc, argv)
int argc;
@@ -142,6 +165,10 @@
sprintf(srvtab_file, "%s/zephyr/%s", SYSCONFDIR, ZEPHYR_SRVTAB);
sprintf(tkt_file, "%s/zephyr/%s", SYSCONFDIR, ZEPHYR_TKFILE);
#endif
+#ifdef HAVE_KRB5
+ sprintf(keytab_file, "%s/zephyr/%s", SYSCONFDIR, ZEPHYR_KEYTAB);
+ sprintf(tkt5_file, "FILE:%s/zephyr/%s", SYSCONFDIR, ZEPHYR_TK5FILE);
+#endif
sprintf(acl_dir, "%s/zephyr/%s", SYSCONFDIR, ZEPHYR_ACL_DIR);
sprintf(subs_file, "%s/zephyr/%s", SYSCONFDIR, DEFAULT_SUBS_FILE);
@@ -150,7 +177,7 @@
programname = (programname) ? programname + 1 : argv[0];
/* process arguments */
- while ((optchar = getopt(argc, argv, "dsnv:f:k:")) != EOF) {
+ while ((optchar = getopt(argc, argv, "dsnv4f:k:")) != EOF) {
switch(optchar) {
case 'd':
zdebug = 1;
@@ -175,6 +202,9 @@
init_from_dump = 0;
dumpfile = optarg;
break;
+ case '4':
+ bdump_auth_proto = 4;
+ break;
case '?':
default:
usage();
@@ -293,9 +323,6 @@
/* Reinitialize t_local now that initialization is done. */
gettimeofday(&t_local, NULL);
uptime = NOW;
-#ifdef HAVE_KRB4
- timer_set_rel(SWEEP_INTERVAL, sweep_ticket_hash_table, NULL);
-#endif
realm_wakeup();
#ifdef DEBUG_MALLOC
@@ -381,6 +408,20 @@
ZSetServerState(1);
ZInitialize(); /* set up the library */
+#ifdef HAVE_KRB5
+ krb5_cc_resolve(Z_krb5_ctx, tkt5_file, &Z_krb5_ccache);
+#ifdef HAVE_KRB5_CC_SET_DEFAULT_NAME
+ krb5_cc_set_default_name(Z_krb5_ctx, tkt5_file);
+#else
+ {
+ /* Hack to make krb5_cc_default do something reasonable */
+ char *env=(char *)malloc(strlen(tkt5_file)+12);
+ if (!env) return(1);
+ sprintf(env, "KRB5CCNAME=%s", tkt5_file);
+ putenv(env);
+ }
+#endif
+#endif
#ifdef HAVE_KRB4
/* Override what Zinitialize set for ZGetRealm() */
if (*my_realm)
Modified: trunk/athena/lib/zephyr/server/realm.c
===================================================================
--- trunk/athena/lib/zephyr/server/realm.c 2008-04-03 17:32:17 UTC (rev 22813)
+++ trunk/athena/lib/zephyr/server/realm.c 2008-04-03 17:51:46 UTC (rev 22814)
@@ -61,7 +61,7 @@
*
*/
static void realm_sendit __P((ZNotice_t *notice, struct sockaddr_in *who, int auth, ZRealm *realm, int ack_to_sender));
-static void realm_sendit_auth __P((ZNotice_t *notice, struct sockaddr_in *who, int auth, ZRealm *realm, int ack_to_sender));
+static Code_t realm_sendit_auth __P((ZNotice_t *notice, struct sockaddr_in *who, int auth, ZRealm *realm, int ack_to_sender));
static void rlm_ack __P((ZNotice_t *notice, Unacked *nacked));
static void rlm_nack_cancel __P((ZNotice_t *notice, struct sockaddr_in *who));
static void rlm_new_ticket __P(());
@@ -72,7 +72,6 @@
#ifdef HAVE_KRB4
static Code_t ticket_retrieve __P((ZRealm *realm));
static int ticket_lookup __P((char *realm));
-static int ticket_expired __P((CREDENTIALS *cred));
#endif
static int
@@ -229,6 +228,7 @@
}
*rlm_list[nused].name = '\0';
+ fclose(fp);
return(rlm_list);
}
@@ -240,6 +240,7 @@
if (retval = (subscr_send_realm_subs(&otherrealms[cnt])) != ZERR_NONE)
return(retval);
}
+ return ZERR_NONE;
}
int
@@ -282,7 +283,7 @@
return 0;
}
-sender_in_realm(notice)
+int sender_in_realm(notice)
ZNotice_t *notice;
{
char *realm;
@@ -557,9 +558,13 @@
abort();
}
memset(&client->addr, 0, sizeof(struct sockaddr_in));
+#ifdef HAVE_KRB5
+ client->session_keyblock = NULL;
+#else
#ifdef HAVE_KRB4
memset(&client->session_key, 0, sizeof(client->session_key));
#endif
+#endif
sprintf(rlmprinc, "%s.%s@%s", SERVER_SERVICE, SERVER_INSTANCE,
rlm->name);
client->principal = make_string(rlmprinc, 0);
@@ -619,14 +624,16 @@
zdbug((LOG_DEBUG, "rlm_deathgram: suggesting %s to %s",
(server) ? server->addr_str : "nothing", realm->name));
+#ifdef HAVE_KRB5
if (!ticket_lookup(realm->name))
if ((retval = ticket_retrieve(realm)) != ZERR_NONE) {
syslog(LOG_WARNING, "rlm_deathgram failed: %s",
error_message(retval));
return;
}
+#endif
- if ((retval = ZFormatNotice(&snotice, &pack, &packlen, ZAUTH))
+ if ((retval = ZFormatNotice(&snotice, &pack, &packlen, ZCAUTH))
!= ZERR_NONE)
{
syslog(LOG_WARNING, "rlm_deathgram format: %s",
@@ -683,12 +690,14 @@
snotice.z_message = NULL;
snotice.z_message_len = 0;
+#ifdef HAVE_KRB5
if (!ticket_lookup(realm->name))
if ((retval = ticket_retrieve(realm)) != ZERR_NONE) {
syslog(LOG_WARNING, "rlm_wakeup failed: %s",
error_message(retval));
continue;
}
+#endif
if ((retval = ZFormatNotice(&snotice, &pack, &packlen, ZAUTH))
!= ZERR_NONE)
@@ -893,7 +902,7 @@
ZRealm *realm;
int ack_to_sender;
{
-#ifdef HAVE_KRB4
+#ifdef HAVE_KRB5
Code_t retval;
if (!auth) {
@@ -913,7 +922,7 @@
zdbug((LOG_DEBUG, "realm_sendit to realm %s auth %d", realm->name, auth));
/* valid ticket available now, send the message */
- realm_sendit_auth(notice, who, auth, realm, ack_to_sender);
+ retval = realm_sendit_auth(notice, who, auth, realm, ack_to_sender);
#else /* HAVE_KRB4 */
realm_sendit(notice, who, auth, realm, ack_to_sender);
#endif /* HAVE_KRB4 */
@@ -1095,8 +1104,8 @@
}
}
-#ifdef HAVE_KRB4
-static void
+#ifdef HAVE_KRB5
+static Code_t
realm_sendit_auth(notice, who, auth, realm, ack_to_sender)
ZNotice_t *notice;
int auth;
@@ -1111,33 +1120,27 @@
Code_t retval;
Unacked *nacked;
char buf[1024], multi[64];
- CREDENTIALS cred;
- KTEXT_ST authent;
ZNotice_t partnotice, newnotice;
offset = 0;
- /* build an authent. first, make sure we have the ticket available */
- retval = krb_get_cred(SERVER_SERVICE, SERVER_INSTANCE, realm->name, &cred);
- if (retval != GC_OK) {
- syslog(LOG_WARNING, "rlm_sendit_auth get_cred: %s",
- error_message(retval+krb_err_base));
- return;
+ buffer = (char *) malloc(sizeof(ZPacket_t));
+ if (!buffer) {
+ syslog(LOG_ERR, "realm_sendit_auth malloc");
+ return ENOMEM; /* DON'T put on nack list */
}
- retval = krb_mk_req(&authent, SERVER_SERVICE, SERVER_INSTANCE,
- realm->name, 1);
- if (retval != MK_AP_OK) {
- syslog(LOG_WARNING, "rlm_sendit_auth mk_req: %s",
- error_message(retval+krb_err_base));
- return;
- }
+ buffer_len = sizeof(ZPacket_t);
- retval = ZMakeAscii(buf, sizeof(buf), authent.dat, authent.length);
+ newnotice = *notice;
+
+ hdrlen = 0;
+ retval = ZMakeZcodeRealmAuthentication(&newnotice, buffer, buffer_len,
+ &hdrlen, realm->name);
if (retval != ZERR_NONE) {
- syslog(LOG_WARNING, "rlm_sendit_auth mk_ascii: %s",
+ syslog(LOG_WARNING, "rlm_sendit_auth make zcksum: %s",
error_message(retval));
- return;
+ return (retval);
}
/* set the dest addr */
@@ -1145,46 +1148,8 @@
if (retval != ZERR_NONE) {
syslog(LOG_WARNING, "rlm_sendit_auth set addr: %s",
error_message(retval));
- return;
+ return (retval);
}
-
- /* now format the notice, refragmenting if needed */
- newnotice = *notice;
- newnotice.z_auth = 1;
- newnotice.z_ascii_authent = buf;
- newnotice.z_authent_len = authent.length;
-
- buffer = (char *) malloc(sizeof(ZPacket_t));
- if (!buffer) {
- syslog(LOG_ERR, "realm_sendit_auth malloc");
- return; /* DON'T put on nack list */
- }
-
- buffer_len = sizeof(ZPacket_t);
-
- retval = Z_FormatRawHeader(&newnotice, buffer, buffer_len, &hdrlen, &ptr,
- NULL);
- if (retval != ZERR_NONE) {
- syslog(LOG_WARNING, "rlm_sendit_auth raw: %s", error_message(retval));
- free(buffer);
- return;
- }
-
-#ifdef NOENCRYPTION
- newnotice.z_checksum = 0;
-#else
- newnotice.z_checksum =
- (ZChecksum_t)des_quad_cksum(buffer, NULL, ptr - buffer, 0,
- cred.session);
-#endif
-
- retval = Z_FormatRawHeader(&newnotice, buffer, buffer_len, &hdrlen,
- NULL, NULL);
- if (retval != ZERR_NONE) {
- syslog(LOG_WARNING, "rlm_sendit_auth raw: %s", error_message(retval));
- free(buffer);
- return;
- }
/* This is not terribly pretty, but it does do its job.
* If a packet we get that needs to get sent off to another realm is
@@ -1195,17 +1160,14 @@
* but only the server uses it.
*/
- if ((newnotice.z_message_len+hdrlen > buffer_len) ||
- (newnotice.z_message_len+hdrlen > Z_MAXPKTLEN)) {
- /* Deallocate buffer, use a local one */
+ if ((notice->z_message_len+hdrlen > buffer_len) ||
+ (notice->z_message_len+hdrlen > Z_MAXPKTLEN)) {
+
+ /* Reallocate buffers inside the refragmenter */
free(buffer);
-
+
partnotice = *notice;
- partnotice.z_auth = 1;
- partnotice.z_ascii_authent = buf;
- partnotice.z_authent_len = authent.length;
-
origoffset = 0;
origlen = notice->z_message_len;
@@ -1213,7 +1175,7 @@
if (sscanf(notice->z_multinotice, "%d/%d", &origoffset,
&origlen) != 2) {
syslog(LOG_WARNING, "rlm_sendit_auth frag: parse failed");
- return;
+ return ZERR_BADFIELD;
}
#if 0
@@ -1227,8 +1189,8 @@
(void) sprintf(multi, "%d/%d", offset+origoffset, origlen);
partnotice.z_multinotice = multi;
if (offset > 0) {
- (void) gettimeofday(&partnotice.z_uid.tv,
- (struct timezone *)0);
+ (void) Z_gettimeofday(&partnotice.z_uid.tv,
+ (struct timezone *)0);
partnotice.z_uid.tv.tv_sec = htonl((u_long)
partnotice.z_uid.tv.tv_sec);
partnotice.z_uid.tv.tv_usec =
@@ -1248,35 +1210,21 @@
buffer = (char *) malloc(sizeof(ZPacket_t));
if (!buffer) {
syslog(LOG_ERR, "realm_sendit_auth malloc");
- return; /* DON'T put on nack list */
+ return ENOMEM; /* DON'T put on nack list */
}
+
+ buffer_len = sizeof(ZPacket_t);
- retval = Z_FormatRawHeader(&partnotice, buffer, buffer_len,
- &hdrlen, &ptr, NULL);
+ retval = ZMakeZcodeRealmAuthentication(&partnotice, buffer,
+ buffer_len, &hdrlen,
+ realm->name);
if (retval != ZERR_NONE) {
- syslog(LOG_WARNING, "rlm_sendit_auth raw: %s",
+ syslog(LOG_WARNING, "rlm_sendit_auth set addr: %s",
error_message(retval));
free(buffer);
- return;
+ return (retval);
}
-#ifdef NOENCRYPTION
- partnotice.z_checksum = 0;
-#else
- partnotice.z_checksum =
- (ZChecksum_t)des_quad_cksum(buffer, NULL, ptr - buffer, 0,
- cred.session);
-#endif
-
- retval = Z_FormatRawHeader(&partnotice, buffer, buffer_len,
- &hdrlen, NULL, NULL);
- if (retval != ZERR_NONE) {
- syslog(LOG_WARNING, "rlm_sendit_auth raw: %s",
- error_message(retval));
- free(buffer);
- return;
- }
-
ptr = buffer+hdrlen;
(void) memcpy(ptr, partnotice.z_message, partnotice.z_message_len);
@@ -1288,14 +1236,14 @@
syslog(LOG_WARNING, "rlm_sendit_auth xmit: %s",
error_message(retval));
free(buffer);
- return;
+ return(retval);
}
if (!(nacked = (Unacked *)malloc(sizeof(Unacked)))) {
/* no space: just punt */
syslog(LOG_ERR, "rlm_sendit_auth nack malloc");
free(buffer);
- return;
+ return ENOMEM;
}
nacked->rexmits = 0;
@@ -1322,35 +1270,30 @@
if (!notice->z_message_len)
break;
}
-#if 0
- zdbug((LOG_DEBUG, "rlm_sendit_auth frag message sent"));
-#endif
- } else {
+ }
+ else {
/* This is easy, no further fragmentation needed */
ptr = buffer+hdrlen;
(void) memcpy(ptr, newnotice.z_message, newnotice.z_message_len);
- buffer_len = hdrlen+newnotice.z_message_len;
+ buffer_len = hdrlen+newnotice.z_message_len;
/* now send */
if ((retval = ZSendPacket(buffer, buffer_len, 0)) != ZERR_NONE) {
syslog(LOG_WARNING, "rlm_sendit_auth xmit: %s",
error_message(retval));
free(buffer);
- return;
+ return(retval);
}
-#if 0
- zdbug((LOG_DEBUG, "rlm_sendit_auth message sent"));
-#endif
/* now we've sent it, mark it as not ack'ed */
if (!(nacked = (Unacked *)malloc(sizeof(Unacked)))) {
/* no space: just punt */
syslog(LOG_ERR, "rlm_sendit_auth nack malloc");
free(buffer);
- return;
+ return 0;
}
nacked->rexmits = 0;
@@ -1371,33 +1314,52 @@
/* chain in */
LIST_INSERT(&rlm_nacklist, nacked);
}
- return;
+ return 0;
}
static int
-ticket_expired(cred)
-CREDENTIALS *cred;
-{
-#ifdef HAVE_KRB_LIFE_TO_TIME
- return (krb_life_to_time(cred->issue_date, cred->lifetime) < NOW);
-#else /* HAVE_KRB_LIFE_TO_TIME */
- return (cred->issue_date + cred->lifetime*5*60 < NOW);
-#endif /* HAVE_KRB_LIFE_TO_TIME */
-}
-
-static int
ticket_lookup(realm)
char *realm;
{
- CREDENTIALS cred;
- KTEXT_ST authent;
- int retval;
+ krb5_error_code result;
+ krb5_timestamp sec;
+ krb5_ccache ccache;
+ krb5_creds creds_in, *creds;
- retval = krb_get_cred(SERVER_SERVICE, SERVER_INSTANCE, realm, &cred);
- if (retval == GC_OK && !ticket_expired(&cred))
- /* good ticket */
- return(1);
+ result = krb5_cc_default(Z_krb5_ctx, &ccache);
+ if (result)
+ return 0;
+ memset(&creds_in, 0, sizeof(creds_in));
+
+ result = krb5_cc_get_principal(Z_krb5_ctx, ccache, &creds_in.client);
+ if (result) {
+ krb5_cc_close(Z_krb5_ctx, ccache);
+ return 0;
+ }
+
+ result = krb5_build_principal(Z_krb5_ctx, &creds_in.server,
+ strlen(realm),
+ realm,
+ SERVER_KRB5_SERVICE, SERVER_INSTANCE, 0);
+ if (result) {
+ krb5_cc_close(Z_krb5_ctx, ccache);
+ return 0;
+ }
+
+ result = krb5_get_credentials(Z_krb5_ctx, 0 /* flags */, ccache,
+ &creds_in, &creds);
+ krb5_cc_close(Z_krb5_ctx, ccache);
+ /* good ticket? */
+
+ krb5_timeofday (Z_krb5_ctx, &sec);
+ krb5_free_cred_contents(Z_krb5_ctx, &creds_in); /* hope this is OK */
+ if ((result == 0) && (sec < creds->times.endtime)) {
+ krb5_free_creds(Z_krb5_ctx, creds);
+ return (1);
+ }
+ if (!result) krb5_free_creds(Z_krb5_ctx, creds);
+
return (0);
}
@@ -1405,27 +1367,50 @@
ticket_retrieve(realm)
ZRealm *realm;
{
- int pid, retval = 0;
- KTEXT_ST authent;
+ int pid;
+ krb5_ccache ccache;
+ krb5_error_code result;
+ krb5_auth_context authctx;
+ krb5_creds creds_in, *creds;
get_tgt();
if (realm->child_pid)
/* Right idea. Basically, we haven't gotten it yet */
- return KRBET_KDC_AUTH_EXP;
+ return KRB5KRB_AP_ERR_TKT_EXPIRED;
- /* For Putrify */
- memset(&authent.dat,0,MAX_KTXT_LEN);
- authent.mbz=0;
+ if (realm->have_tkt) {
+ /* Get a pointer to the default ccache. We don't need to free this. */
+ result = krb5_cc_default(Z_krb5_ctx, &ccache);
- if (realm->have_tkt) {
- retval = krb_mk_req(&authent, SERVER_SERVICE, SERVER_INSTANCE,
- realm->name, 0);
- if (retval == KSUCCESS) {
- return retval;
+ /* GRRR. There's no allocator or constructor for krb5_creds */
+ /* GRRR. It would be nice if this API were documented at all */
+ memset(&creds_in, 0, sizeof(creds_in));
+
+ if (!result)
+ result = krb5_cc_get_principal(Z_krb5_ctx, ccache, &creds_in.client);
+ /* construct the service principal */
+ if (!result)
+ result = krb5_build_principal(Z_krb5_ctx, &creds_in.server,
+ strlen(realm->name), realm->name,
+ SERVER_KRB5_SERVICE, SERVER_INSTANCE,
+ 0);
+
+ /* HOLDING: creds_in.server */
+
+ /* look up or get the credentials we need */
+ if (!result)
+ result = krb5_get_credentials(Z_krb5_ctx, 0 /* flags */, ccache,
+ &creds_in, &creds);
+ krb5_cc_close(Z_krb5_ctx, ccache);
+ krb5_free_cred_contents(Z_krb5_ctx, &creds_in); /* hope this is OK */
+ if (!result) {
+ krb5_free_creds(Z_krb5_ctx, creds);
+ return 0;
}
} else {
syslog(LOG_ERR, "tkt_rtrv: don't have ticket, but have no child");
+ result = KRB5KRB_AP_ERR_TKT_EXPIRED;
}
pid = fork();
@@ -1463,11 +1448,37 @@
#endif
#endif
+ syslog(LOG_INFO, "tkt_rtrv running for %s", realm->name);
while (1) {
- retval = krb_mk_req(&authent, SERVER_SERVICE, SERVER_INSTANCE,
- realm->name, 0);
- if (retval == KSUCCESS)
+ /* Get a pointer to the default ccache. We don't need to free this. */
+ result = krb5_cc_default(Z_krb5_ctx, &ccache);
+
+ /* GRRR. There's no allocator or constructor for krb5_creds */
+ /* GRRR. It would be nice if this API were documented at all */
+ memset(&creds_in, 0, sizeof(creds_in));
+
+ if (!result)
+ result = krb5_cc_get_principal(Z_krb5_ctx, ccache, &creds_in.client);
+ /* construct the service principal */
+ if (!result)
+ result = krb5_build_principal(Z_krb5_ctx, &creds_in.server,
+ strlen(realm->name), realm->name,
+ SERVER_KRB5_SERVICE, SERVER_INSTANCE,
+ 0);
+
+ /* HOLDING: creds_in.server */
+
+ /* look up or get the credentials we need */
+ if (!result)
+ result = krb5_get_credentials(Z_krb5_ctx, 0 /* flags */, ccache,
+ &creds_in, &creds);
+ krb5_cc_close(Z_krb5_ctx, ccache);
+ krb5_free_cred_contents(Z_krb5_ctx, &creds_in); /* hope this is OK */
+ if (!result) {
+ krb5_free_creds(Z_krb5_ctx, creds);
+ syslog(LOG_INFO, "tkt_rtrv succeeded for %s", realm->name);
exit(0);
+ }
/* Sleep a little while before retrying */
sleep(30);
@@ -1475,11 +1486,11 @@
} else {
realm->child_pid = pid;
realm->have_tkt = 0;
-
- syslog(LOG_WARNING, "tkt_rtrv: %s: %s", realm->name,
- krb_err_txt[retval]);
- return (retval+krb_err_base);
+
+ syslog(LOG_WARNING, "tkt_rtrv: %s: %d", realm->name,
+ result);
+ return (result);
}
}
-#endif /* HAVE_KRB4 */
+#endif /* HAVE_KRB5 */
Modified: trunk/athena/lib/zephyr/server/server.c
===================================================================
--- trunk/athena/lib/zephyr/server/server.c 2008-04-03 17:32:17 UTC (rev 22813)
+++ trunk/athena/lib/zephyr/server/server.c 2008-04-03 17:51:46 UTC (rev 22814)
@@ -1405,7 +1405,7 @@
syslog(LOG_CRIT, "srv_fwd malloc");
abort();
}
- retval = ZFormatSmallRawNotice(notice, pack, &packlen);
+ retval = ZNewFormatSmallRawNotice(notice, pack, &packlen);
if (retval != ZERR_NONE) {
syslog(LOG_WARNING, "srv_fwd format: %s", error_message(retval));
continue;
Modified: trunk/athena/lib/zephyr/server/subscr.c
===================================================================
--- trunk/athena/lib/zephyr/server/subscr.c 2008-04-03 17:32:17 UTC (rev 22813)
+++ trunk/athena/lib/zephyr/server/subscr.c 2008-04-03 17:51:46 UTC (rev 22814)
@@ -187,18 +187,13 @@
}
}
if (realm && !bdumping) {
- if (server && server == me_server) {
- retval = subscr_realm_sendit(who, subs, notice, realm);
- if (retval != ZERR_NONE) {
- free_subscriptions(subs);
- free_string(sender);
- return(retval);
- } else {
- /* free this one, will get from ADD */
- free_subscription(subs);
- }
+ retval = subscr_realm_sendit(who, subs, notice, realm);
+ if (retval != ZERR_NONE) {
+ free_subscription(subs);
+ continue; /* the for loop */
} else {
- /* Indicates we leaked traffic back to our realm */
+ /* Indicates we leaked traffic back to our realm */
+ free_subscription(subs); /* free this one, wil get from ADD */
}
} else {
retval = triplet_register(who, &subs->dest, NULL);
@@ -842,10 +837,15 @@
{
int i = 0;
Destlist *subs;
+#ifdef HAVE_KRB5
+ char buf[512];
+ char *bufp;
+#else
#ifdef HAVE_KRB4
char buf[512];
C_Block cblock;
#endif /* HAVE_KRB4 */
+#endif
char buf2[512];
char *list[7 * NUM_FIELDS];
int num = 0;
@@ -858,14 +858,45 @@
list[num++] = buf2;
+#ifdef HAVE_KRB5
+#ifdef HAVE_KRB4 /* XXX make this optional for server transition time */
+ if (Z_enctype(client->session_keyblock) == ENCTYPE_DES_CBC_CRC) {
+ bufp = malloc(Z_keylen(client->session_keyblock));
+ if (bufp == NULL) {
+ syslog(LOG_WARNING, "subscr_send_subs: cannot allocate memory for DES keyblock: %m");
+ return errno;
+ }
+ des_ecb_encrypt(Z_keydata(client->session_keyblock), bufp, serv_ksched.s, DES_ENCRYPT);
+ retval = ZMakeAscii(buf, sizeof(buf), bufp, Z_keylen(client->session_keyblock));
+ } else {
+#endif
+ bufp = malloc(Z_keylen(client->session_keyblock) + 8); /* + enctype
+ + length */
+ if (bufp == NULL) {
+ syslog(LOG_WARNING, "subscr_send_subs: cannot allocate memory for keyblock: %m");
+ return errno;
+ }
+ *(krb5_enctype *)&bufp[0] = htonl(Z_enctype(client->session_keyblock));
+ *(u_int32_t *)&bufp[4] = htonl(Z_keylen(client->session_keyblock));
+ memcpy(&bufp[8], Z_keydata(client->session_keyblock), Z_keylen(client->session_keyblock));
+
+ retval = ZMakeZcode(buf, sizeof(buf), bufp, Z_keylen(client->session_keyblock) + 8);
#ifdef HAVE_KRB4
+ }
+#endif /* HAVE_KRB4 */
+#else /* HAVE_KRB5 */
+#ifdef HAVE_KRB4
#ifdef NOENCRYPTION
memcpy(cblock, client->session_key, sizeof(C_Block));
-#else
+#else /* NOENCRYPTION */
des_ecb_encrypt(client->session_key, cblock, serv_ksched.s, DES_ENCRYPT);
-#endif
+#endif /* NOENCRYPTION */
retval = ZMakeAscii(buf, sizeof(buf), cblock, sizeof(C_Block));
+#endif /* HAVE_KRB4 */
+#endif /* HAVE_KRB5 */
+
+#if defined(HAVE_KRB4) || defined(HAVE_KRB5)
if (retval != ZERR_NONE) {
#if 0
zdbug((LOG_DEBUG,"zmakeascii failed: %s", error_message(retval)));
@@ -876,7 +907,7 @@
zdbug((LOG_DEBUG, "cblock %s", buf));
#endif
}
-#endif /* HAVE_KRB4 */
+#endif /* HAVE_KRB4 || HAVE_KRB5*/
retval = bdump_send_list_tcp(SERVACK, &client->addr, ZEPHYR_ADMIN_CLASS,
num > 1 ? "CBLOCK" : "", ADMIN_NEWCLT,
client->principal->string, "", list, num);
Modified: trunk/athena/lib/zephyr/server/uloc.c
===================================================================
--- trunk/athena/lib/zephyr/server/uloc.c 2008-04-03 17:32:17 UTC (rev 22813)
+++ trunk/athena/lib/zephyr/server/uloc.c 2008-04-03 17:51:46 UTC (rev 22814)
@@ -241,7 +241,12 @@
login_sendit(notice, auth, who, 1);
}
} else {
- syslog(LOG_ERR, "unknown ulog opcode %s", notice->z_opcode);
+ if (!strcmp(notice->z_opcode, LOGIN_USER_LOGIN)) {
+ zdbug((LOG_DEBUG, "ulog opcode from unknown foreign realm %s",
+ notice->z_opcode));
+ } else {
+ syslog(LOG_ERR, "unknown ulog opcode %s", notice->z_opcode);
+ }
if (server == me_server)
nack(notice, who);
return ZERR_NONE;
@@ -441,6 +446,7 @@
default:
syslog(LOG_ERR,"broken location state %s/%d",
loc->user->string, (int) loc->exposure);
+ exposure_level = EXPOSE_OPSTAFF;
break;
}
retval = bdump_send_list_tcp(ACKED, &loc->addr, LOGIN_CLASS,
@@ -1085,6 +1091,11 @@
lnotice = *notice;
lnotice.z_opcode = LOCATE_LOCATE;
lnotice.z_kind = ACKED;
+ lnotice.z_auth = 0;
+ lnotice.z_authent_len = 0;
+ lnotice.z_ascii_authent = "";
+ lnotice.z_checksum = 0;
+ lnotice.z_ascii_checksum = "";
if ((retval = ZFormatRawNotice(&lnotice, &pack, &packlen)) != ZERR_NONE) {
syslog(LOG_WARNING, "ulog_relay_loc format: %s",
Modified: trunk/athena/lib/zephyr/server/zserver.h
===================================================================
--- trunk/athena/lib/zephyr/server/zserver.h 2008-04-03 17:32:17 UTC (rev 22813)
+++ trunk/athena/lib/zephyr/server/zserver.h 2008-04-03 17:51:46 UTC (rev 22814)
@@ -17,6 +17,9 @@
#include <zephyr/mit-copyright.h>
#include <internal.h>
+
+#include <com_err.h>
+
#include <arpa/inet.h>
#include "zsrv_err.h"
@@ -28,10 +31,21 @@
#include "access.h"
#include "acl.h"
-#ifdef HAVE_KRB4
+#if defined(HAVE_KRB5) || defined(HAVE_KRB4)
/* Kerberos-specific library interfaces used only by the server. */
+#ifdef HAVE_KRB5
+extern krb5_keyblock *__Zephyr_keyblock;
+#define ZGetSession() (__Zephyr_keyblock)
+void ZSetSession(krb5_keyblock *keyblock);
+Code_t ZFormatAuthenticNoticeV5 __P((ZNotice_t*, char*, int, int*, krb5_keyblock *));
+krb5_error_code Z_krb5_init_keyblock(krb5_context, krb5_enctype, size_t,
+ krb5_keyblock **);
+#else
extern C_Block __Zephyr_session;
#define ZGetSession() (__Zephyr_session)
+#endif
+void ZSetSessionDES(C_Block *key);
+
Code_t ZFormatAuthenticNotice __P((ZNotice_t*, char*, int, int*, C_Block));
#endif
@@ -120,9 +134,13 @@
struct _Client {
struct sockaddr_in addr; /* ipaddr/port of client */
Destlist *subs ; /* subscriptions */
+#ifdef HAVE_KRB5
+ krb5_keyblock *session_keyblock;
+#else
#ifdef HAVE_KRB4
C_Block session_key; /* session key for this client */
#endif /* HAVE_KRB4 */
+#endif
String *principal; /* krb principal of user */
int last_send; /* Counter for last sent packet. */
time_t last_ack; /* Time of last received ack */
@@ -268,9 +286,6 @@
#ifndef NOENCRYPTION
Sched *check_key_sched_cache __P((des_cblock key));
void add_to_key_sched_cache __P((des_cblock key, Sched *sched));
-int krb_set_key __P((char *key, int cvt));
-int krb_rd_req __P((KTEXT authent, char *service, char *instance,
- unsigned KRB_INT32 from_addr, AUTH_DAT *ad, char *fn));
int krb_find_ticket __P((KTEXT authent, KTEXT ticket));
int krb_get_lrealm __P((char *r, int n));
#endif
@@ -355,6 +370,10 @@
extern int zdebug;
extern char myname[]; /* domain name of this host */
extern char list_file[];
+#ifdef HAVE_KRB5
+extern char keytab_file[];
+extern krb5_ccache Z_krb5_ccache;
+#endif
#ifdef HAVE_KRB4
extern char srvtab_file[];
extern char my_realm[];
Modified: trunk/athena/lib/zephyr/server/zsrv_conf.h
===================================================================
--- trunk/athena/lib/zephyr/server/zsrv_conf.h 2008-04-03 17:32:17 UTC (rev 22813)
+++ trunk/athena/lib/zephyr/server/zsrv_conf.h 2008-04-03 17:51:46 UTC (rev 22814)
@@ -18,6 +18,10 @@
#define SERVER_LIST_FILE "server.list"
#define REALM_LIST_FILE "realm.list"
+#ifdef HAVE_KRB5
+#define ZEPHYR_KEYTAB "krb5.keytab"
+#define ZEPHYR_TK5FILE "z5tkts"
+#endif
#ifdef HAVE_KRB4
#define ZEPHYR_SRVTAB "srvtab"
#define ZEPHYR_TKFILE "ztkts"
Modified: trunk/athena/lib/zephyr/zhm/zhm_client.c
===================================================================
--- trunk/athena/lib/zephyr/zhm/zhm_client.c 2008-04-03 17:32:17 UTC (rev 22813)
+++ trunk/athena/lib/zephyr/zhm/zhm_client.c 2008-04-03 17:51:46 UTC (rev 22814)
@@ -74,7 +74,7 @@
Zperr(ret);
com_err("hm", ret, "setting destination");
}
- if ((ret = send_outgoing(notice)) != ZERR_NONE) {
+ if ((ret = ZSendPacket(packet, pak_len, 0)) != ZERR_NONE) {
Zperr(ret);
com_err("hm", ret, "while sending raw notice");
}