From 1a0e03eb19998ab496a6ea845ff2c42d9a02df0b Mon Sep 17 00:00:00 2001 From: Karl Ramm Date: Tue, 25 Dec 2007 00:56:08 +0000 Subject: applied athena-update-branch patch --- acconfig.h | 33 +++ configure.in | 58 +++- debian/control | 2 +- debian/rules | 14 +- h/config.h.in | 263 +++++++++++------ h/internal.h | 56 ++++ h/zephyr/zephyr.h | 10 + lib/Makefile.in | 3 +- lib/ZCkAuth.c | 36 ++- lib/ZFmtAuth.c | 70 ++++- lib/ZFmtNotice.c | 26 ++ lib/ZFmtSmRaw.c | 23 ++ lib/ZGetSender.c | 45 ++- lib/ZInit.c | 45 +++ lib/ZMkAuth.c | 188 ++++++++++++- lib/ZParseNot.c | 21 +- lib/Zinternal.c | 518 +++++++++++++++++++++++++++++++++- server/bdump.c | 229 ++++++++++++++- server/class.c | 12 +- server/client.c | 10 +- server/dispatch.c | 60 +++- server/kstuff.c | 811 +++++++++++++++++++++++++++++++++++++++++++---------- server/main.c | 44 ++- server/realm.c | 384 ++++++++++++------------- server/server.c | 8 +- server/subscr.c | 88 ++++-- server/uloc.c | 17 +- server/zserver.h | 68 +++-- server/zsrv_conf.h | 4 + server/zsrv_err.et | 2 +- zhm/zhm_client.c | 2 +- 31 files changed, 2600 insertions(+), 550 deletions(-) diff --git a/acconfig.h b/acconfig.h index 96eb3d1..b4ec827 100644 --- a/acconfig.h +++ b/acconfig.h @@ -4,6 +4,39 @@ /* Define to compile with Kerberos support. */ #undef HAVE_KRB4 +/* Define to compile with Kerberos v5 support. */ +#undef HAVE_KRB5 + +/* Define to 1 if `enc_part2' is member of `krb5_ticket'. */ +#undef HAVE_KRB5_TICKET_ENC_PART2 + +/* Define to 1 if `keyblock.enctype' is member of `krb5_creds'. */ +#undef HAVE_KRB5_CREDS_KEYBLOCK_ENCTYPE + +/* Define to 1 if you have the `krb5_c_make_checksum' function. */ +#undef HAVE_KRB5_C_MAKE_CHECKSUM + +/* Define to 1 if you have the `krb5_cc_set_default_name' function. */ +#undef HAVE_KRB5_CC_SET_DEFAULT_NAME + +/* Define to 1 if `krb5_auth_con_getauthenticator' takes a double pointer third arg. */ +#undef KRB5_AUTH_CON_GETAUTHENTICATOR_TAKES_DOUBLE_POINTER + +/* Define to 1 if you have the header file. */ +#undef HAVE_KRB5_ERR_H + +/* Define to 1 if you have the `krb5_free_data' function. */ +#undef HAVE_KRB5_FREE_DATA + +/* Define to 1 if you have the header file. */ +#undef HAVE_KRB5_SS_H + +/* Define to 1 if you have the `krb_get_err_text' function. */ +#undef HAVE_KRB_GET_ERR_TEXT + +/* Define to 1 if you have the `krb_log' function. */ +#undef HAVE_KRB_LOG + /* Define to compile with ares support. */ #undef HAVE_ARES diff --git a/configure.in b/configure.in index c894ab8..7985dae 100644 --- a/configure.in +++ b/configure.in @@ -37,7 +37,7 @@ AC_HEADER_STDC 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(RLIB) 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,6 +101,59 @@ AC_FUNC_GETPGRP 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_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_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_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 diff --git a/debian/control b/debian/control index a7d5058..df8502e 100644 --- a/debian/control +++ b/debian/control @@ -20,7 +20,7 @@ Description: The original "Instant Message" system libraries without Kerberos Package: libzephyr3-krb Section: libs Architecture: any -Depends: ${shlibs:Depends}, krb4-config +Depends: ${shlibs:Depends}, krb5-config Conflicts: libzephyr3 Provides: libzephyr3 Description: The original "Instant Message" system libraries with Kerberos diff --git a/debian/rules b/debian/rules index ffab880..41be8c0 100755 --- a/debian/rules +++ b/debian/rules @@ -51,9 +51,9 @@ configure-stamp: dh_testdir # Add here commands to configure the package. -mkdir krb - cd krb&&../configure --with-krb4=/usr $(CONFIGURE_ROOT) + cd krb&& CFLAGS=-g ../configure --with-krb4=/usr --with-krb5=/usr $(CONFIGURE_ROOT) -mkdir no-krb - cd no-krb&&../configure $(CONFIGURE_ROOT) + cd no-krb&& CFLAGS=-g ../configure $(CONFIGURE_ROOT) touch configure-stamp build: configure-stamp build-stamp @@ -126,20 +126,11 @@ binary-arch: build install dh_movefiles --sourcedir=debian/tmp-krb -plibzephyr3-krb -pzephyr-server-krb dh_installdebconf dh_installdocs -# dh_installexamples -# dh_installmenu -# dh_installemacsen -# dh_installpam dh_installinit -pzephyr-clients --init-script=zhm --no-start dh_installinit -pzephyr-server-krb --init-script=zephyrd dh_installinit -pzephyr-server --init-script=zephyrd -# dh_installcron -# dh_installmanpages -# dh_installinfo -# dh_undocumented dh_installchangelogs dh_strip -# dh_link dh_compress dh_fixperms # You may want to make some executables suid here. @@ -148,7 +139,6 @@ binary-arch: build install cp debian/libzephyr3/DEBIAN/shlibs debian/libzephyr3-krb/DEBIAN/shlibs dh_shlibdeps dh_installdeb -# dh_perl dh_gencontrol dh_md5sums dh_builddeb diff --git a/h/config.h.in b/h/config.h.in index 1a3dd61..c962a5d 100644 --- a/h/config.h.in +++ b/h/config.h.in @@ -1,40 +1,42 @@ -/* h/config.h.in. Generated automatically from configure.in by autoheader. */ +/* h/config.h.in. Generated from configure.in by autoheader. */ +/* Define to compile with Hesiod support. */ +#undef HAVE_HESIOD -/* Define if the `getpgrp' function takes no argument. */ -#undef GETPGRP_VOID +/* Define to compile with Kerberos support. */ +#undef HAVE_KRB4 -/* Define to `int' if doesn't define. */ -#undef gid_t +/* Define to compile with Kerberos v5 support. */ +#undef HAVE_KRB5 -/* Define if you don't have vprintf but do have _doprnt. */ -#undef HAVE_DOPRNT +/* Define to 1 if `enc_part2' is member of `krb5_ticket'. */ +#undef HAVE_KRB5_TICKET_ENC_PART2 -/* Define if you have that is POSIX.1 compatible. */ -#undef HAVE_SYS_WAIT_H +/* Define to 1 if `keyblock.enctype' is member of `krb5_creds'. */ +#undef HAVE_KRB5_CREDS_KEYBLOCK_ENCTYPE -/* Define if you have the vprintf function. */ -#undef HAVE_VPRINTF +/* Define to 1 if you have the `krb5_c_make_checksum' function. */ +#undef HAVE_KRB5_C_MAKE_CHECKSUM -/* Define as the return type of signal handlers (int or void). */ -#undef RETSIGTYPE +/* Define to 1 if you have the `krb5_cc_set_default_name' function. */ +#undef HAVE_KRB5_CC_SET_DEFAULT_NAME -/* Define if the `setpgrp' function takes no argument. */ -#undef SETPGRP_VOID +/* Define to 1 if `krb5_auth_con_getauthenticator' takes a double pointer third arg. */ +#undef KRB5_AUTH_CON_GETAUTHENTICATOR_TAKES_DOUBLE_POINTER -/* Define if you have the ANSI C header files. */ -#undef STDC_HEADERS +/* Define to 1 if you have the header file. */ +#undef HAVE_KRB5_ERR_H -/* Define to `int' if doesn't define. */ -#undef uid_t +/* Define to 1 if you have the `krb5_free_data' function. */ +#undef HAVE_KRB5_FREE_DATA -/* Define if the X Window System is missing or not being used. */ -#undef X_DISPLAY_MISSING +/* Define to 1 if you have the header file. */ +#undef HAVE_KRB5_SS_H -/* Define to compile with Hesiod support. */ -#undef HAVE_HESIOD +/* Define to 1 if you have the `krb_get_err_text' function. */ +#undef HAVE_KRB_GET_ERR_TEXT -/* Define to compile with Kerberos support. */ -#undef HAVE_KRB4 +/* Define to 1 if you have the `krb_log' function. */ +#undef HAVE_KRB_LOG /* Define to compile with ares support. */ #undef HAVE_ARES @@ -45,122 +47,223 @@ /* Define if you have the System Resource Controller library. */ #undef HAVE_SRC +/* Define to "unsigned long" if your system headers don't. */ +#undef ulong + /* Define to a temporary directory on your system. */ #define FOUND_TMP "/var/tmp" /* Define to the type of the host system. */ #define MACHINE_TYPE "unknown" -/* The number of bytes in a int. */ -#undef SIZEOF_INT +/* Define if `regcomp' exists and works. */ +#undef HAVE_REGCOMP -/* The number of bytes in a long. */ -#undef SIZEOF_LONG -/* The number of bytes in a short. */ -#undef SIZEOF_SHORT +/* Define to 1 if the `getpgrp' function requires zero arguments. */ +#undef GETPGRP_VOID -/* Define if you have the gethostid function. */ +/* Define to 1 if you have the header file. */ +#undef HAVE_DLFCN_H + +/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */ +#undef HAVE_DOPRNT + +/* Define to 1 if you have the header file. */ +#undef HAVE_FCNTL_H + +/* Define to 1 if you have the `gethostid' function. */ #undef HAVE_GETHOSTID -/* Define if you have the getlogin function. */ +/* Define to 1 if you have the `getlogin' function. */ #undef HAVE_GETLOGIN -/* Define if you have the getpgid function. */ +/* Define to 1 if you have the `getpgid' function. */ #undef HAVE_GETPGID -/* Define if you have the getsid function. */ +/* Define to 1 if you have the `getsid' function. */ #undef HAVE_GETSID -/* Define if you have the krb_get_err_text function. */ +/* Define to 1 if you have the header file. */ +#undef HAVE_INTTYPES_H + +/* Define to 1 if you have the `krb5_cc_set_default_name' function. */ +#undef HAVE_KRB5_CC_SET_DEFAULT_NAME + +/* Define to 1 if you have the `krb5_c_make_checksum' function. */ +#undef HAVE_KRB5_C_MAKE_CHECKSUM + +/* Define to 1 if you have the header file. */ +#undef HAVE_KRB5_ERR_H + +/* Define to 1 if you have the `krb5_free_data' function. */ +#undef HAVE_KRB5_FREE_DATA + +/* Define to 1 if you have the `krb_get_err_text' function. */ #undef HAVE_KRB_GET_ERR_TEXT -/* Define if you have the krb_log function. */ +/* Define to 1 if you have the `krb_log' function. */ #undef HAVE_KRB_LOG -/* Define if you have the lrand48 function. */ +/* Define to 1 if you have the `44bsd' library (-l44bsd). */ +#undef HAVE_LIB44BSD + +/* Define to 1 if you have the `curses' library (-lcurses). */ +#undef HAVE_LIBCURSES + +/* Define to 1 if you have the `dl' library (-ldl). */ +#undef HAVE_LIBDL + +/* Define to 1 if you have the `gen' library (-lgen). */ +#undef HAVE_LIBGEN + +/* Define to 1 if you have the `nsl' library (-lnsl). */ +#undef HAVE_LIBNSL + +/* Define to 1 if you have the `readline' library (-lreadline). */ +#undef HAVE_LIBREADLINE + +/* Define to 1 if you have the `resolv' library (-lresolv). */ +#undef HAVE_LIBRESOLV + +/* Define to 1 if you have the `socket' library (-lsocket). */ +#undef HAVE_LIBSOCKET + +/* Define to 1 if you have the `w' library (-lw). */ +#undef HAVE_LIBW + +/* Define to 1 if you have the `lrand48' function. */ #undef HAVE_LRAND48 -/* Define if you have the memcpy function. */ +/* Define to 1 if you have the header file. */ +#undef HAVE_MALLOC_H + +/* Define to 1 if you have the `memcpy' function. */ #undef HAVE_MEMCPY -/* Define if you have the memmove function. */ +/* Define to 1 if you have the `memmove' function. */ #undef HAVE_MEMMOVE -/* Define if you have the putenv function. */ +/* Define to 1 if you have the header file. */ +#undef HAVE_MEMORY_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_PATHS_H + +/* Define to 1 if you have the `putenv' function. */ #undef HAVE_PUTENV -/* Define if you have the random function. */ +/* Define to 1 if you have the `random' function. */ #undef HAVE_RANDOM -/* Define if you have the strchr function. */ -#undef HAVE_STRCHR +/* Define to 1 if you have the header file. */ +#undef HAVE_SGTTY_H -/* Define if you have the strerror function. */ -#undef HAVE_STRERROR +/* Define to 1 if you have the header file. */ +#undef HAVE_STDINT_H -/* Define if you have the waitpid function. */ -#undef HAVE_WAITPID +/* Define to 1 if you have the header file. */ +#undef HAVE_STDLIB_H -/* Define if you have the header file. */ -#undef HAVE_FCNTL_H +/* Define to 1 if you have the `strchr' function. */ +#undef HAVE_STRCHR -/* Define if you have the header file. */ -#undef HAVE_MALLOC_H +/* Define to 1 if you have the `strerror' function. */ +#undef HAVE_STRERROR -/* Define if you have the header file. */ -#undef HAVE_PATHS_H +/* Define to 1 if you have the header file. */ +#undef HAVE_STRINGS_H -/* Define if you have the header file. */ -#undef HAVE_SGTTY_H +/* Define to 1 if you have the header file. */ +#undef HAVE_STRING_H -/* Define if you have the header file. */ +/* Define to 1 if you have the header file. */ #undef HAVE_SYS_CDEFS_H -/* Define if you have the header file. */ +/* Define to 1 if you have the header file. */ #undef HAVE_SYS_FILE_H -/* Define if you have the header file. */ +/* Define to 1 if you have the header file. */ #undef HAVE_SYS_FILIO_H -/* Define if you have the header file. */ +/* Define to 1 if you have the header file. */ #undef HAVE_SYS_IOCTL_H -/* Define if you have the header file. */ +/* Define to 1 if you have the header file. */ #undef HAVE_SYS_MSGBUF_H -/* Define if you have the header file. */ +/* Define to 1 if you have the header file. */ #undef HAVE_SYS_SELECT_H -/* Define if you have the header file. */ +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ #undef HAVE_SYS_TIME_H -/* Define if you have the header file. */ +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have the header file. */ #undef HAVE_SYS_UTSNAME_H -/* Define if you have the header file. */ +/* Define to 1 if you have that is POSIX.1 compatible. */ +#undef HAVE_SYS_WAIT_H + +/* Define to 1 if you have the header file. */ #undef HAVE_TERMIOS_H -/* Define if you have the header file. */ +/* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H -/* Define if you have the 44bsd library (-l44bsd). */ -#undef HAVE_LIB44BSD +/* Define to 1 if you have the `vprintf' function. */ +#undef HAVE_VPRINTF -/* Define if you have the dl library (-ldl). */ -#undef HAVE_LIBDL +/* Define to 1 if you have the `waitpid' function. */ +#undef HAVE_WAITPID -/* Define if you have the gen library (-lgen). */ -#undef HAVE_LIBGEN +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT -/* Define if you have the nsl library (-lnsl). */ -#undef HAVE_LIBNSL +/* Define to the full name of this package. */ +#undef PACKAGE_NAME -/* Define if you have the resolv library (-lresolv). */ -#undef HAVE_LIBRESOLV +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING -/* Define if you have the socket library (-lsocket). */ -#undef HAVE_LIBSOCKET +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME -/* Define if you have the w library (-lw). */ -#undef HAVE_LIBW +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* Define as the return type of signal handlers (`int' or `void'). */ +#undef RETSIGTYPE + +/* Define to 1 if the `setpgrp' function takes no argument. */ +#undef SETPGRP_VOID + +/* The size of `int', as computed by sizeof. */ +#undef SIZEOF_INT + +/* The size of `long', as computed by sizeof. */ +#undef SIZEOF_LONG + +/* The size of `short', as computed by sizeof. */ +#undef SIZEOF_SHORT + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Define to 1 if the X Window System is missing or not being used. */ +#undef X_DISPLAY_MISSING + +/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a + `char[]'. */ +#undef YYTEXT_POINTER + +/* Define to `int' if doesn't define. */ +#undef gid_t + +/* Define to `int' if doesn't define. */ +#undef uid_t diff --git a/h/internal.h b/h/internal.h index f0b482c..403e85c 100644 --- a/h/internal.h +++ b/h/internal.h @@ -11,6 +11,10 @@ #include #endif +#ifdef HAVE_KRB5 +#include +#endif + #ifdef HAVE_HESIOD #include #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 __Zephyr_open; /* 0 if FD opened, 1 otherwise */ 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,6 +113,46 @@ Code_t Z_WaitForNotice __P((ZNotice_t *notice, 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) +#else +#define Z_keydata(keyblock) ((keyblock)->keyvalue.data) +#define Z_keylen(keyblock) ((keyblock)->keyvalue.length) +#define Z_credskey(creds) (&(creds)->session) +#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__ */ diff --git a/h/zephyr/zephyr.h b/h/zephyr/zephyr.h index 713e261..429663e 100644 --- a/h/zephyr/zephyr.h +++ b/h/zephyr/zephyr.h @@ -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 @@ -98,6 +99,7 @@ typedef struct _ZNotice_t { 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; @@ -139,6 +141,8 @@ int ZCompareMultiUIDPred ZP((ZNotice_t *, void *)); /* 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 *)); @@ -152,6 +156,7 @@ Code_t ZParseNotice ZP((char*, int, ZNotice_t *)); 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 (*)())); @@ -175,8 +180,12 @@ Code_t ZSrvSendRawList ZP((ZNotice_t*, char*[], int, 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)); @@ -253,6 +262,7 @@ void ZSetDebug ZP((void (*)(ZCONST char *, va_list, void *), void *)); #define SRV_TIMEOUT 30 #define ZAUTH (ZMakeAuthentication) +#define ZCAUTH (ZMakeZcodeAuthentication) #define ZNOAUTH ((Z_AuthProc)0) /* Packet strings */ diff --git a/lib/Makefile.in b/lib/Makefile.in index 5415797..40abb6e 100644 --- a/lib/Makefile.in +++ b/lib/Makefile.in @@ -39,7 +39,8 @@ OBJS = zephyr_err.lo ZAsyncLocate.lo ZCkAuth.lo ZCkIfNot.lo ZClosePort.lo \ 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.o \ + ZReadZcode.o ZCkZaut.o .SUFFIXES: .lo diff --git a/lib/ZCkAuth.c b/lib/ZCkAuth.c index 17fdc2b..4c83e6a 100644 --- a/lib/ZCkAuth.c +++ b/lib/ZCkAuth.c @@ -17,6 +17,10 @@ static char rcsid_ZCheckAuthentication_c[] = #include +#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 @@ static char rcsid_ZCheckAuthentication_c[] = 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 @@ Code_t ZCheckAuthentication(notice, from) #else return (notice->z_auth ? ZAUTH_YES : ZAUTH_NO); #endif +#else + ZCheckZcodeAuthentication(notice, from); +#endif } diff --git a/lib/ZFmtAuth.c b/lib/ZFmtAuth.c index c2d8a00..97a70f2 100644 --- a/lib/ZFmtAuth.c +++ b/lib/ZFmtAuth.c @@ -16,7 +16,7 @@ static char rcsid_ZFormatAuthenticNotice_c[] = "$Id$"; #include -#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 @@ Code_t ZFormatAuthenticNotice(notice, buffer, buffer_len, len, session) 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 diff --git a/lib/ZFmtNotice.c b/lib/ZFmtNotice.c index d7876d7..0b9ca39 100644 --- a/lib/ZFmtNotice.c +++ b/lib/ZFmtNotice.c @@ -41,3 +41,29 @@ Code_t ZFormatNotice(notice, buffer, ret_len, cert_routine) 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); +} diff --git a/lib/ZFmtSmRaw.c b/lib/ZFmtSmRaw.c index a9ce79d..0fcd74c 100644 --- a/lib/ZFmtSmRaw.c +++ b/lib/ZFmtSmRaw.c @@ -37,3 +37,26 @@ Code_t ZFormatSmallRawNotice(notice, buffer, ret_len) 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); +} diff --git a/lib/ZGetSender.c b/lib/ZGetSender.c index df5f3e2..c495cec 100644 --- a/lib/ZGetSender.c +++ b/lib/ZGetSender.c @@ -22,24 +22,53 @@ static const char rcsid_ZGetSender_c[] = 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) { +#if 0 + krb5_unparse_name(Z_krb5_ctx, principal, &prname); + sender = strdup(prname); +#else + krb5_524_conv_principal(Z_krb5_ctx, principal, pname, 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); +#endif + krb5_free_principal(Z_krb5_ctx, principal); + } + 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 @@ -47,6 +76,8 @@ char *ZGetSender() 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); } diff --git a/lib/ZInit.c b/lib/ZInit.c index 401f6db..16d266e 100644 --- a/lib/ZInit.c +++ b/lib/ZInit.c @@ -21,6 +21,12 @@ static char rcsid_ZInitialize_c[] = #ifdef HAVE_KRB4 #include #endif +#ifdef HAVE_KRB5 +#include +#endif +#ifdef HAVE_KRB5_ERR_H +#include +#endif #ifndef INADDR_NONE #define INADDR_NONE 0xffffffff @@ -36,13 +42,22 @@ Code_t ZInitialize() 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 @@ Code_t ZInitialize() __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,8 +105,14 @@ Code_t ZInitialize() 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) @@ -95,6 +121,24 @@ Code_t ZInitialize() 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); @@ -105,6 +149,7 @@ Code_t ZInitialize() } #else strcpy(__Zephyr_realm, "local-realm"); +#endif #endif __My_addr.s_addr = INADDR_NONE; diff --git a/lib/ZMkAuth.c b/lib/ZMkAuth.c index 5a6749c..92d0bd3 100644 --- a/lib/ZMkAuth.c +++ b/lib/ZMkAuth.c @@ -20,6 +20,10 @@ static const char rcsid_ZMakeAuthentication_c[] = "$Id$"; #include #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 @@ Code_t ZMakeAuthentication(notice, buffer, buffer_len, len) 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 @@ Code_t ZMakeAuthentication(notice, buffer, buffer_len, len) 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 @@ Code_t ZMakeAuthentication(notice, buffer, buffer_len, len) 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 @@ Code_t ZMakeAuthentication(notice, buffer, buffer_len, len) 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 diff --git a/lib/ZParseNot.c b/lib/ZParseNot.c index 7950e96..a198845 100644 --- a/lib/ZParseNot.c +++ b/lib/ZParseNot.c @@ -209,11 +209,22 @@ Code_t ZParseNotice(buffer, len, notice) 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; diff --git a/lib/Zinternal.c b/lib/Zinternal.c index 0efcc56..4440dfe 100644 --- a/lib/Zinternal.c +++ b/lib/Zinternal.c @@ -44,9 +44,60 @@ int __subscriptions_num; 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 */, 12 /* 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 */, 10 /* hmac-sha1-96-aes128 */ }, + { 18 /* aes256-cts-hmac-sha1-96 */, 11 /* 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 @@ void *__Z_debug_print_closure; 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 @@ -633,6 +686,52 @@ Code_t Z_FormatHeader(notice, buffer, buffer_len, len, cert_routine) 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; @@ -652,6 +751,210 @@ Code_t Z_FormatAuthHeader(notice, buffer, buffer_len, len, cert_routine) 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;iz_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; @@ -742,7 +1045,7 @@ Code_t Z_FormatRawHeader(notice, buffer, buffer_len, len, cstart, cend) 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; @@ -995,3 +1298,210 @@ void ZSetDebug(proc, arg) } #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) { +#if HAVE_KRB5_CREDS_KEYBLOCK_ENCTYPE + *enctype = keyblock->enctype; + return Z_krb5_lookup_cksumtype(*enctype, cksumtype); +#else + unsigned int len; + ENCTYPE *val; + int i = 0; + Code_t result; + + result = krb5_keytype_to_enctypes(Z_krb5_ctx, keyblock->keytype, + &len, &val); + if (result) + return result; + + do { + if (i == len) break; + result = Z_krb5_lookup_cksumtype(val[i], cksumtype); + i++; + } while (result != 0); + + if (result) + return result; + + *enctype = val[i-1]; +#endif + return 0; +} +#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 diff --git a/server/bdump.c b/server/bdump.c index 22bf518..d997672 100644 --- a/server/bdump.c +++ b/server/bdump.c @@ -66,6 +66,12 @@ static int setup_file_pointers __P((void)); 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; @@ -272,7 +278,12 @@ bdump_send() } /* Now begin the brain dump. */ - +#ifdef HAVE_KRB5 + { /* "server" side */ + krb5_auth_context actx; + + } +#else /* HAVE_KRB5 */ #ifdef HAVE_KRB4 /* receive the authenticator */ retval = GetKerberosData(live_socket, from.sin_addr, &kdata, @@ -311,6 +322,7 @@ bdump_send() return; } #endif /* HAVE_KRB4 */ +#endif /* HAVE_KRB5 */ retval = setup_file_pointers(); if (retval != 0) { @@ -450,6 +462,109 @@ bdump_get_v12 (notice, auth, who, server) /* Now begin the brain dump. */ +#ifdef HAVE_KRB5 + if (get_tgt()) { + cleanup(server); + return; + } + { /* "client" side */ + krb5_auth_context actx; + krb5_creds creds; + krb5_creds *credsp; + krb5_principal principal; + krb5_data data; + krb5_ap_rep_enc_part *rep; + + 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, &actx); + 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; + } + + memset((char *)&data, 0, sizeof(krb5_data)); + retval = krb5_mk_req_extended(Z_krb5_ctx, &actx, 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_auth_con_free(Z_krb5_ctx, actx); + 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); + krb5_auth_con_free(Z_krb5_ctx, actx); + 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)); + krb5_auth_con_free(Z_krb5_ctx, actx); + cleanup(server); + return; + } + retval = krb5_rd_rep(Z_krb5_ctx, actx, &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)); + krb5_auth_con_free(Z_krb5_ctx, actx); + cleanup(server); + return; + } + + } +#else #ifdef HAVE_KRB4 /* send an authenticator */ if (get_tgt()) { @@ -485,6 +600,7 @@ bdump_get_v12 (notice, auth, who, server) return; } #endif /* HAVE_KRB4 */ +#endif retval = setup_file_pointers(); if (retval != 0) { syslog(LOG_WARNING, "bdump_get: can't set up file pointers: %s", @@ -728,6 +844,54 @@ get_tgt() 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,11 +935,17 @@ bdump_recv_loop(server) Code_t retval; Client *client = NULL; struct sockaddr_in who; -#ifdef HAVE_KRB4 +#ifdef HAVE_KRB5 + char buf[512]; + int blen; +#endif +#if defined(HAVE_KRB4) || defined(HAVE_KRB5) char *cp; +#endif +#ifdef HAVE_KRB4 C_Block cblock; #endif /* HAVE_KRB4 */ - Realm *realm = NULL; + ZRealm *realm = NULL; #if 1 zdbug((LOG_DEBUG, "bdump recv loop")); @@ -853,6 +1023,52 @@ bdump_recv_loop(server) 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 = 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, client->session_keyblock->contents, + 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 = krb5_init_keyblock(Z_krb5_ctx, + ntohl(*(krb5_enctype *)&buf[0]), + ntohl(*(krb5_ui_4 *)&buf[4]), + &client->session_keyblock); + if (retval) { + syslog(LOG_ERR, "brl failed to allocate keyblock: %s", + error_message(retval)); + return retval; + } + memcpy(client->session_keyblock->contents, &buf[8], + client->session_keyblock->length); + } + } + } +#else #ifdef HAVE_KRB4 memset(client->session_key, 0, sizeof(C_Block)); if (*notice.z_class_inst) { @@ -872,6 +1088,7 @@ bdump_recv_loop(server) } } #endif /* HAVE_KRB4 */ +#endif } else if (strcmp(notice.z_opcode, CLIENT_SUBSCRIBE) == 0) { /* a subscription packet */ if (!client) { @@ -1138,7 +1355,13 @@ net_read(f, buf, len) 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; diff --git a/server/class.c b/server/class.c index 6ccacae..0ce5da3 100644 --- a/server/class.c +++ b/server/class.c @@ -81,9 +81,9 @@ static const char rcsid_class_c[] = static Triplet *triplet_bucket[HASHSIZE]; /* the hash table of pointers */ static Code_t remove_client __P((Triplet *triplet, Client *client, - Realm *realm)); + ZRealm *realm)); static Code_t insert_client __P((Triplet *triplet, Client *client, - Realm *realm)); + ZRealm *realm)); static Triplet *triplet_alloc __P((String *classname, String *inst, String *recipient)); static void free_triplet __P((Triplet *)); @@ -117,7 +117,7 @@ Code_t triplet_register(client, dest, realm) Client *client; Destination *dest; - Realm *realm; + ZRealm *realm; { Triplet *triplet; unsigned long hashval; @@ -140,7 +140,7 @@ Code_t triplet_deregister(client, dest, realm) Client *client; Destination *dest; - Realm *realm; + ZRealm *realm; { Triplet *triplet; int retval; @@ -304,7 +304,7 @@ static Code_t insert_client(triplet, client, realm) Triplet *triplet; Client *client; - Realm *realm; + ZRealm *realm; { Client **clientp, **newclients; int new_size; @@ -348,7 +348,7 @@ insert_client(triplet, client, realm) static Code_t remove_client(triplet, client, realm) Triplet *triplet; Client *client; - Realm *realm; + ZRealm *realm; { Client **clientp; diff --git a/server/client.c b/server/client.c index 85918e7..9098ac0 100644 --- a/server/client.c +++ b/server/client.c @@ -84,8 +84,12 @@ client_register(notice, host, client_p, wantdefaults) 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; @@ -122,6 +126,10 @@ client_deregister(client, flush) 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); diff --git a/server/dispatch.c b/server/dispatch.c index 493fcd4..09fa0c1 100644 --- a/server/dispatch.c +++ b/server/dispatch.c @@ -14,6 +14,7 @@ #include #include "zserver.h" #include +#include #ifndef lint #ifndef SABER @@ -134,7 +135,7 @@ handle_packet() int authentic; /* authentic flag */ Pending *pending; /* pending packet */ int from_server; /* packet is from another server */ - Realm *realm; /* foreign realm ptr */ + ZRealm *realm; /* foreign realm ptr */ #ifdef DEBUG static int first_time = 1; #endif @@ -201,8 +202,8 @@ handle_packet() } else { if (realm = realm_which_realm(&input_sin)) { authentic = ZCheckRealmAuthentication(&new_notice, - &input_sin, - realm->name); + &input_sin, + realm->name); } else authentic = ZCheckAuthentication(&new_notice, &input_sin); } @@ -223,6 +224,7 @@ handle_packet() } } +#if 0 if (whoisit.sin_port != hm_port && whoisit.sin_port != hm_srv_port && strcasecmp(new_notice.z_class, ZEPHYR_ADMIN_CLASS) != 0 && whoisit.sin_port != srv_addr.sin_port && @@ -231,6 +233,7 @@ handle_packet() ntohs(whoisit.sin_port)); return; } +#endif message_notices.val++; dispatch(&new_notice, authentic, &whoisit, from_server); @@ -251,7 +254,7 @@ dispatch(notice, auth, who, from_server) String *notice_class; struct sockaddr_in who2; int authflag; - Realm *realm; + ZRealm *realm; char *cp; #ifdef DEBUG char dbg_buf[BUFSIZ]; @@ -353,7 +356,7 @@ sendit(notice, auth, who, external) class = make_string(notice->z_class, 1); if (realm_bound_for_realm(ZGetRealm(), notice->z_recipient)) { - Realm *rlm; + ZRealm *rlm; acl = class_get_acl(class); if (acl != NULL) { @@ -586,6 +589,7 @@ xmit_frag(notice, buf, len, waitforack) return(ZERR_NONE); } + /* * Send the notice to the client. After transmitting, put it onto the * not ack'ed list. @@ -619,14 +623,23 @@ xmit(notice, dest, auth, client) 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); @@ -636,6 +649,7 @@ xmit(notice, dest, auth, client) return; } #endif /* HAVE_KRB4 */ +#endif /* HAVE_KRB5 */ } else { notice->z_auth = 0; notice->z_authent_len = 0; @@ -1095,7 +1109,7 @@ control_dispatch(notice, auth, who, server) Client *client; Code_t retval; int wantdefs; - Realm *realm; + ZRealm *realm; struct sockaddr_in newwho; /* @@ -1163,9 +1177,27 @@ control_dispatch(notice, auth, who, server) 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) { diff --git a/server/kstuff.c b/server/kstuff.c index eff445d..b4b48d7 100644 --- a/server/kstuff.c +++ b/server/kstuff.c @@ -22,30 +22,6 @@ static const char rcsid_kstuff_c[] = "$Id$"; #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 @@ GetKerberosData(fd, haddr, kdata, service, srvtab) * 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,93 @@ SendKerberosData(fd, ticket, service, host) #endif /* HAVE_KRB4 */ +#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) { + syslog(LOG_WARNING,"bad read reply len"); + 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 +217,537 @@ ZCheckRealmAuthentication(notice, from, realm) 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_NO; + } + /* 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_NO; + } + /* 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 +758,7 @@ ZCheckAuthentication(notice, from) AUTH_DAT dat; ZChecksum_t checksum; C_Block session_key; + char instance[INST_SZ+1]; if (!notice->z_auth) return ZAUTH_NO; @@ -238,10 +776,13 @@ ZCheckAuthentication(notice, from) } authent.length = notice->z_authent_len; - result = krb_rd_req(&authent, SERVER_SERVICE, SERVER_INSTANCE, + strcpy(instance, SERVER_INSTANCE); + + /* We don't have the session key cached; do it the long way. */ + 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 +807,8 @@ ZCheckAuthentication(notice, from) #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; -} +#ifdef HAVE_KRB4 static ZChecksum_t compute_checksum(notice, session_key) ZNotice_t *notice; C_Block session_key; @@ -373,26 +846,68 @@ static ZChecksum_t compute_rlm_checksum(notice, session_key) #endif } -void sweep_ticket_hash_table(arg) - void *arg; -{ - int i; - Hash_entry **ptr, *entry; - - 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; - } - } +#ifdef HAVE_KRB5 +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; +#ifdef HAVE_KRB5_INIT_KEYBLOCK + if (__Zephyr_keyblock) { + krb5_free_keyblock(__Zephyr_keyblock); + __Zephyr_keyblock=NULL; + } + result = 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 + krb5_keyblock *tmp, tmp_ss; + tmp = &tmp_ss; + Z_keylen(tmp)=sizeof(C_Block); + Z_keydata(tmp)=key; +#if HAVE_KRB5_CREDS_KEYBLOCK_ENCTYPE + tmp->enctype = ENCTYPE_DES_CBC_CRC; +#else + tmp->keytype = KEYTYPE_DES; +#endif + if (__Zephyr_keyblock) { + krb5_free_keyblock_contents(Z_krb5_ctx, __Zephyr_keyblock); + result = krb5_copy_keyblock_contents(Z_krb5_ctx, tmp, + __Zephyr_keyblock); + } else { + result = krb5_copy_keyblock(Z_krb5_ctx, tmp, &__Zephyr_keyblock); + } + if (result) /*XXX we're out of memory? */ + ; +#endif +#else + memcpy(__Zephyr_session, key, sizeof(C_Block)); +#endif +} +#endif #endif /* HAVE_KRB4 */ diff --git a/server/main.c b/server/main.c index e160929..0f2aa4c 100644 --- a/server/main.c +++ b/server/main.c @@ -92,6 +92,10 @@ char *programname; /* set to the basename of argv[0] */ 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,15 @@ static int nofork; struct in_addr my_addr; char *bdump_version = "1.2"; +#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; @@ -141,6 +154,10 @@ main(argc, argv) #ifdef HAVE_KRB4 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); @@ -293,9 +310,6 @@ main(argc, argv) /* 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 @@ -369,6 +383,7 @@ main(argc, argv) static int initialize() { + int zero = 0; if (do_net_setup()) return(1); @@ -381,6 +396,20 @@ initialize() 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) @@ -447,6 +476,13 @@ do_net_setup() if (srv_socket < 0) { syslog(LOG_ERR, "client_sock failed: %m"); return 1; + } else { +#ifdef SO_BSDCOMPAT + int on = 1; + + /* Prevent Linux from giving us socket errors we don't care about. */ + setsockopt(srv_socket, SOL_SOCKET, SO_BSDCOMPAT, &on, sizeof(on)); +#endif } if (bind(srv_socket, (struct sockaddr *) &srv_addr, sizeof(srv_addr)) < 0) { @@ -633,7 +669,7 @@ reap(sig) { int pid, i = 0; int oerrno = errno; - Realm *rlm; + ZRealm *rlm; #ifdef _POSIX_VERSION int waitb; #else diff --git a/server/realm.c b/server/realm.c index ecef9eb..ddfd057 100644 --- a/server/realm.c +++ b/server/realm.c @@ -3,17 +3,17 @@ Unacked *rlm_nacklist = NULL; /* not acked list for realm-realm packets */ -Realm *otherrealms; /* points to an array of the known +ZRealm *otherrealms; /* points to an array of the known servers */ int nrealms = 0; /* number of other realms */ /* * External Routines: * - * Realm *realm_which_realm(struct sockaddr_in *who) + * ZRealm *realm_which_realm(struct sockaddr_in *who) * figures out if this packet came from another realm's server * - * Realm *realm_get_realm_by_pid(int pid) + * ZRealm *realm_get_realm_by_pid(int pid) * figures out which realm a child handler was for * * void kill_realm_pids() @@ -31,7 +31,7 @@ int nrealms = 0; /* number of other realms */ * int realm_sender_in_realm(char *realm, char *sender) * figures out if sender is in realm * - * Realm *realm_get_realm_by_name(char *name) + * ZRealm *realm_get_realm_by_name(char *name) * finds a realm struct from the realm array by name, tries expansion * * Code_t realm_dispatch(ZNotice_t *notice, int auth, struct sockaddr_in *who, @@ -49,35 +49,34 @@ int nrealms = 0; /* number of other realms */ * * Code_t realm_control_dispatch(ZNotice_t *notice, int auth, * struct sockaddr_in *who, Server *server, - * Realm *realm) + * ZRealm *realm) * dispatches a foreign realm control message * * void realm_handoff(ZNotice_t *notice, int auth, struct sockaddr_in *who, - * Realm *realm, int ack_to_sender) + * ZRealm *realm, int ack_to_sender) * hands off a message to another realm * * void realm_dump_realms(File *fp) * do a database dump of foreign realm info * */ -static void realm_sendit __P((ZNotice_t *notice, struct sockaddr_in *who, int auth, Realm *realm, int ack_to_sender)); -static void realm_sendit_auth __P((ZNotice_t *notice, struct sockaddr_in *who, int auth, Realm *realm, int ack_to_sender)); +static void realm_sendit __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(()); static void rlm_rexmit __P((void *arg)); -static Code_t realm_ulocate_dispatch __P((ZNotice_t *notice,int auth,struct sockaddr_in *who,Server *server,Realm *realm)); -static Code_t realm_new_server __P((struct sockaddr_in *, ZNotice_t *, Realm *)); -static Code_t realm_set_server __P((struct sockaddr_in *, Realm *)); +static Code_t realm_ulocate_dispatch __P((ZNotice_t *notice,int auth,struct sockaddr_in *who,Server *server,ZRealm *realm)); +static Code_t realm_new_server __P((struct sockaddr_in *, ZNotice_t *, ZRealm *)); +static Code_t realm_set_server __P((struct sockaddr_in *, ZRealm *)); #ifdef HAVE_KRB4 -static Code_t ticket_retrieve __P((Realm *realm)); +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 realm_get_idx_by_addr(realm, who) - Realm *realm; + ZRealm *realm; struct sockaddr_in *who; { struct sockaddr_in *addr; @@ -95,7 +94,7 @@ char * realm_expand_realm(realmname) char *realmname; { - Realm *realm; + ZRealm *realm; int a; /* First, look for an exact match (case insensitive) */ @@ -120,11 +119,11 @@ char *realmname; return(realmname); } -Realm * +ZRealm * realm_get_realm_by_pid(pid) int pid; { - Realm *realm; + ZRealm *realm; int a; for (realm = otherrealms, a = 0; a < nrealms; a++, realm++) @@ -137,7 +136,7 @@ realm_get_realm_by_pid(pid) void kill_realm_pids() { - Realm *realm; + ZRealm *realm; int a; for (realm = otherrealms, a = 0; a < nrealms; a++, realm++) @@ -147,11 +146,11 @@ kill_realm_pids() return; } -Realmname * +ZRealmname * get_realm_lists(file) char *file; { - Realmname *rlm_list, *rlm; + ZRealmname *rlm_list, *rlm; int ii, nused, ntotal; FILE *fp; char buf[REALM_SZ + MAXHOSTNAMELEN + 1]; /* one for newline */ @@ -159,11 +158,11 @@ get_realm_lists(file) nused = 0; if (!(fp = fopen(file, "r"))) - return((Realmname *)0); + return((ZRealmname *)0); /* start with 16, realloc if necessary */ ntotal = 16; - rlm_list = (Realmname *)malloc(ntotal * sizeof(Realmname)); + rlm_list = (ZRealmname *)malloc(ntotal * sizeof(ZRealmname)); if (!rlm_list) { syslog(LOG_CRIT, "get_realm_lists malloc"); abort(); @@ -197,9 +196,9 @@ get_realm_lists(file) /* new realm */ if (nused + 1 >= ntotal) { /* make more space */ - rlm_list = (Realmname *)realloc((char *)rlm_list, + rlm_list = (ZRealmname *)realloc((char *)rlm_list, (unsigned)ntotal * 2 * - sizeof(Realmname)); + sizeof(ZRealmname)); if (!rlm_list) { syslog(LOG_CRIT, "get_realm_lists realloc"); abort(); @@ -219,9 +218,9 @@ get_realm_lists(file) } } if (nused + 1 >= ntotal) { - rlm_list = (Realmname *)realloc((char *)rlm_list, + rlm_list = (ZRealmname *)realloc((char *)rlm_list, (unsigned)(ntotal + 1) * - sizeof(Realmname)); + sizeof(ZRealmname)); if (!rlm_list) { syslog(LOG_CRIT, "get_realm_lists realloc"); abort(); @@ -229,6 +228,7 @@ get_realm_lists(file) } *rlm_list[nused].name = '\0'; + fclose(fp); return(rlm_list); } @@ -282,7 +282,7 @@ realm_sender_in_realm(realm, sender) return 0; } -sender_in_realm(notice) +int sender_in_realm(notice) ZNotice_t *notice; { char *realm; @@ -295,11 +295,11 @@ sender_in_realm(notice) return 0; } -Realm * +ZRealm * realm_which_realm(who) struct sockaddr_in *who; { - Realm *realm; + ZRealm *realm; struct sockaddr_in *addr; int a, b; @@ -316,12 +316,12 @@ realm_which_realm(who) return 0; } -Realm * +ZRealm * realm_get_realm_by_name(name) char *name; { int a; - Realm *realm; + ZRealm *realm; /* First, look for an exact match (case insensitive) */ for (realm = otherrealms, a = 0; a < nrealms; a++, realm++) @@ -341,7 +341,7 @@ rlm_nack_cancel(notice, who) register ZNotice_t *notice; struct sockaddr_in *who; { - register Realm *which = realm_which_realm(who); + register ZRealm *which = realm_which_realm(who); register Unacked *nacked, *next; ZPacket_t retval; @@ -424,7 +424,7 @@ realm_dispatch(notice, auth, who, server) struct sockaddr_in *who; Server *server; { - Realm *realm; + ZRealm *realm; struct sockaddr_in newwho; Code_t status = ZERR_NONE; char rlm_recipient[REALM_SZ + 1]; @@ -490,8 +490,8 @@ void realm_init() { Client *client; - Realmname *rlmnames; - Realm *rlm; + ZRealmname *rlmnames; + ZRealm *rlm; int ii, jj, found; struct in_addr *addresses; struct hostent *hp; @@ -508,7 +508,7 @@ realm_init() for (nrealms = 0; *rlmnames[nrealms].name; nrealms++); - otherrealms = (Realm *)malloc(nrealms * sizeof(Realm)); + otherrealms = (ZRealm *)malloc(nrealms * sizeof(ZRealm)); if (!otherrealms) { syslog(LOG_CRIT, "malloc failed in realm_init"); abort(); @@ -557,8 +557,12 @@ realm_init() 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); @@ -589,7 +593,7 @@ void realm_deathgram(server) Server *server; { - Realm *realm; + ZRealm *realm; char rlm_recipient[REALM_SZ + 1]; int jj = 0; @@ -628,7 +632,7 @@ realm_deathgram(server) } #endif - if ((retval = ZFormatNotice(&snotice, &pack, &packlen, ZAUTH)) + if ((retval = ZFormatNotice(&snotice, &pack, &packlen, ZCAUTH)) != ZERR_NONE) { syslog(LOG_WARNING, "rlm_deathgram format: %s", @@ -651,7 +655,7 @@ void realm_wakeup() { int jj, found = 0; - Realm *realm; + ZRealm *realm; char rlm_recipient[REALM_SZ + 1]; for (jj = 1; jj < nservers; jj++) { /* skip limbo server */ @@ -721,7 +725,7 @@ realm_ulocate_dispatch(notice, auth, who, server, realm) int auth; struct sockaddr_in *who; Server *server; - Realm *realm; + ZRealm *realm; { register char *opcode = notice->z_opcode; Code_t status; @@ -761,7 +765,7 @@ realm_control_dispatch(notice, auth, who, server, realm) int auth; struct sockaddr_in *who; Server *server; - Realm *realm; + ZRealm *realm; { register char *opcode = notice->z_opcode; Code_t status; @@ -841,12 +845,12 @@ static Code_t realm_new_server(sin, notice, realm) struct sockaddr_in *sin; ZNotice_t *notice; - Realm *realm; + ZRealm *realm; { struct hostent *hp; char suggested_server[MAXHOSTNAMELEN]; unsigned long addr; - Realm *rlm; + ZRealm *rlm; struct sockaddr_in sinaddr; int srvidx; @@ -877,9 +881,9 @@ realm_new_server(sin, notice, realm) static Code_t realm_set_server(sin, realm) struct sockaddr_in *sin; - Realm *realm; + ZRealm *realm; { - Realm *rlm; + ZRealm *rlm; rlm = realm_which_realm(sin); /* Not exactly */ @@ -894,7 +898,7 @@ realm_handoff(notice, auth, who, realm, ack_to_sender) ZNotice_t *notice; int auth; struct sockaddr_in *who; - Realm *realm; + ZRealm *realm; int ack_to_sender; { #ifdef HAVE_KRB4 @@ -917,7 +921,7 @@ realm_handoff(notice, auth, who, realm, ack_to_sender) 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 */ @@ -928,7 +932,7 @@ realm_sendit(notice, who, auth, realm, ack_to_sender) ZNotice_t *notice; struct sockaddr_in *who; int auth; - Realm *realm; + ZRealm *realm; int ack_to_sender; { caddr_t pack; @@ -1009,7 +1013,7 @@ rlm_rexmit(arg) { Unacked *nackpacket = (Unacked *) arg; Code_t retval; - register Realm *realm; + register ZRealm *realm; int new_srv_idx; zdbug((LOG_DEBUG,"rlm_rexmit")); @@ -1100,12 +1104,12 @@ realm_dump_realms(fp) } #ifdef HAVE_KRB4 -static void +static Code_t realm_sendit_auth(notice, who, auth, realm, ack_to_sender) ZNotice_t *notice; int auth; struct sockaddr_in *who; - Realm *realm; + ZRealm *realm; int ack_to_sender; { char *buffer, *ptr; @@ -1115,33 +1119,27 @@ realm_sendit_auth(notice, who, auth, realm, ack_to_sender) 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); + + newnotice = *notice; - retval = ZMakeAscii(buf, sizeof(buf), authent.dat, authent.length); + 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 set addr: %s", error_message(retval)); - return; + return (retval); } /* set the dest addr */ @@ -1149,45 +1147,7 @@ realm_sendit_auth(notice, who, auth, realm, ack_to_sender) if (retval != ZERR_NONE) { syslog(LOG_WARNING, "rlm_sendit_auth set addr: %s", error_message(retval)); - return; - } - - /* 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; + return (retval); } /* This is not terribly pretty, but it does do its job. @@ -1199,16 +1159,13 @@ realm_sendit_auth(notice, who, auth, realm, ack_to_sender) * 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; + partnotice = *notice; origoffset = 0; origlen = notice->z_message_len; @@ -1217,7 +1174,7 @@ realm_sendit_auth(notice, who, auth, realm, ack_to_sender) 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 @@ -1252,33 +1209,19 @@ realm_sendit_auth(notice, who, auth, realm, ack_to_sender) 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 */ } - - retval = Z_FormatRawHeader(&partnotice, 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 - 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); + buffer_len = sizeof(ZPacket_t); + + 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); } ptr = buffer+hdrlen; @@ -1292,14 +1235,14 @@ realm_sendit_auth(notice, who, auth, realm, ack_to_sender) 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; @@ -1326,35 +1269,30 @@ realm_sendit_auth(notice, who, auth, realm, ack_to_sender) 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; @@ -1375,61 +1313,103 @@ realm_sendit_auth(notice, who, auth, realm, ack_to_sender) /* chain in */ LIST_INSERT(&rlm_nacklist, nacked); } - return; -} - -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 */ + return 0; } 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); } static Code_t ticket_retrieve(realm) - Realm *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; - - /* For Putrify */ - memset(&authent.dat,0,MAX_KTXT_LEN); - authent.mbz=0; + return KRB5KRB_AP_ERR_TKT_EXPIRED; if (realm->have_tkt) { - retval = krb_mk_req(&authent, SERVER_SERVICE, SERVER_INSTANCE, - realm->name, 0); - if (retval == KSUCCESS) { - return retval; + /* 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); + return 0; } } else { syslog(LOG_ERR, "tkt_rtrv: don't have ticket, but have no child"); + result = KRB5KRB_AP_ERR_TKT_EXPIRED; } pid = fork(); @@ -1467,11 +1447,37 @@ ticket_retrieve(realm) #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); @@ -1479,10 +1485,10 @@ ticket_retrieve(realm) } 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 */ diff --git a/server/server.c b/server/server.c index 5cce0ff..c2c6421 100644 --- a/server/server.c +++ b/server/server.c @@ -880,7 +880,7 @@ send_stats(who) char **responses; int num_resp; char *vers, *pkts, *upt; - Realm *realm; + ZRealm *realm; int extrafields = 0; #define NUM_FIXED 3 /* 3 fixed fields, plus server info */ @@ -1381,7 +1381,11 @@ server_forward(notice, auth, who) syslog(LOG_CRIT, "srv_fwd malloc"); abort(); } - retval = ZFormatSmallRawNotice(notice, pack, &packlen); + if (realm_which_realm(who)) { + retval = ZNewFormatSmallRawNotice(notice, pack, &packlen); + } else { + retval = ZFormatSmallRawNotice(notice, pack, &packlen); + } if (retval != ZERR_NONE) { syslog(LOG_WARNING, "srv_fwd format: %s", error_message(retval)); continue; diff --git a/server/subscr.c b/server/subscr.c index b5da880..49d3211 100644 --- a/server/subscr.c +++ b/server/subscr.c @@ -95,10 +95,10 @@ static char **subscr_marshal_subs __P((ZNotice_t *notice, int auth, int *found)); static Destlist *subscr_copy_def_subs __P((char *person)); static Code_t subscr_realm_sendit __P((Client *who, Destlist *subs, - ZNotice_t *notice, Realm *realm)); + ZNotice_t *notice, ZRealm *realm)); static void subscr_unsub_realms __P((Destlist *newsubs)); static void subscr_unsub_sendit __P((Client *who, Destlist *subs, - Realm *realm)); + ZRealm *realm)); static int cl_match __P((Destlist*, Client *)); static int defaults_read = 0; /* set to 1 if the default subs @@ -140,7 +140,7 @@ add_subscriptions(who, subs, notice, server) Code_t retval; Acl *acl; String *sender; - Realm *realm = NULL; + ZRealm *realm = NULL; if (!subs) return ZERR_NONE; /* no subscr -> no error */ @@ -187,18 +187,14 @@ add_subscriptions(who, subs, notice, server) } } 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); - } + continue; /* the for loop */ } else { /* 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); @@ -333,7 +329,7 @@ subscr_cancel(sin, notice) struct sockaddr_in *sin; ZNotice_t *notice; { - Realm *realm; + ZRealm *realm; Client *who; Destlist *cancel_subs, *subs, *cancel_next, *client_subs, *client_next; Code_t retval; @@ -396,7 +392,7 @@ Code_t subscr_realm_cancel(sin, notice, realm) struct sockaddr_in *sin; ZNotice_t *notice; - Realm *realm; + ZRealm *realm; { Client *who; Destlist *cancel_subs, *subs, *client_subs, *next, *next2; @@ -452,7 +448,7 @@ subscr_cancel_client(client) { Destlist *subs, *next; Code_t retval; - Realm *realm; + ZRealm *realm; #if 0 zdbug((LOG_DEBUG,"subscr_cancel_client %s", @@ -557,7 +553,7 @@ subscr_marshal_subs(notice, auth, who, found) zdbug((LOG_DEBUG, "subscr_marshal")); #endif *found = 0; - + /* Note that the following code is an incredible crock! */ /* We cannot send multiple packets as acknowledgements to the client, @@ -842,10 +838,15 @@ subscr_send_subs(client) { 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 +859,45 @@ subscr_send_subs(client) list[num++] = buf2; +#ifdef HAVE_KRB5 +#ifdef HAVE_KRB4 /* XXX make this optional for server transition time */ + if (client->session_keyblock->enctype == ENCTYPE_DES_CBC_CRC) { + bufp = malloc(client->session_keyblock->length); + if (bufp == NULL) { + syslog(LOG_WARNING, "subscr_send_subs: cannot allocate memory for DES keyblock: %m"); + return errno; + } + des_ecb_encrypt(client->session_keyblock->contents, bufp, serv_ksched.s, DES_ENCRYPT); + retval = ZMakeAscii(buf, sizeof(buf), bufp, client->session_keyblock->length); + } else { +#endif + bufp = malloc(client->session_keyblock->length + 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(client->session_keyblock->enctype); + *(krb5_ui_4 *)&bufp[4] = htonl(client->session_keyblock->length); + memcpy(&bufp[8], client->session_keyblock->contents, client->session_keyblock->length); + + retval = ZMakeZcode(buf, sizeof(buf), bufp, client->session_keyblock->length + 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 +908,7 @@ subscr_send_subs(client) 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); @@ -1047,7 +1079,7 @@ subscr_realm_sendit(who, subs, notice, realm) Client *who; Destlist *subs; ZNotice_t *notice; - Realm *realm; + ZRealm *realm; { ZNotice_t snotice; char *pack; @@ -1132,7 +1164,7 @@ subscr_realm_sendit(who, subs, notice, realm) static Code_t subscr_add_raw(client, realm, newsubs) Client *client; - Realm *realm; + ZRealm *realm; Destlist *newsubs; { Destlist *subs, *subs2, *subs3, **head; @@ -1162,7 +1194,7 @@ subscr_add_raw(client, realm, newsubs) } } else { if (!realm) { - Realm *remrealm = + ZRealm *remrealm = realm_get_realm_by_name(subs->dest.recip->string + 1); if (remrealm) { Destlist *sub = (Destlist *) malloc(sizeof(Destlist)); @@ -1190,7 +1222,7 @@ subscr_add_raw(client, realm, newsubs) /* Called from bdump_recv_loop to decapsulate realm subs */ Code_t subscr_realm(realm, notice) - Realm *realm; + ZRealm *realm; ZNotice_t *notice; { Destlist *newsubs; @@ -1210,7 +1242,7 @@ static void subscr_unsub_sendit(who, subs, realm) Client *who; Destlist *subs; - Realm *realm; + ZRealm *realm; { ZNotice_t unotice; Code_t retval; @@ -1275,7 +1307,7 @@ subscr_unsub_sendit(who, subs, realm) /* Called from bump_send_loop by way of realm_send_realms */ Code_t subscr_send_realm_subs(realm) - Realm *realm; + ZRealm *realm; { int i = 0; Destlist *subs, *next; @@ -1342,7 +1374,7 @@ subscr_send_realm_subs(realm) Code_t subscr_realm_subs(realm) - Realm *realm; + ZRealm *realm; { int i = 0; Destlist *subs, *next; @@ -1431,7 +1463,7 @@ subscr_check_foreign_subs(notice, who, server, realm, newsubs) ZNotice_t *notice; struct sockaddr_in *who; Server *server; - Realm *realm; + ZRealm *realm; Destlist *newsubs; { Destlist *subs, *subs2, *next; @@ -1470,7 +1502,7 @@ subscr_check_foreign_subs(notice, who, server, realm, newsubs) found = 0; for (subs = newsubs; subs; subs = next) { - Realm *rlm; + ZRealm *rlm; next=subs->next; if (subs->dest.recip->string[0] != '\0') { rlm = realm_which_realm(who); @@ -1566,7 +1598,7 @@ Code_t subscr_foreign_user(notice, who, server, realm) ZNotice_t *notice; struct sockaddr_in *who; Server *server; - Realm *realm; + ZRealm *realm; { Destlist *newsubs, *temp; Acl *acl; @@ -1640,7 +1672,7 @@ Code_t subscr_foreign_user(notice, who, server, realm) temp->dest.recip = make_string(rlm_recipient, 0); } - status = subscr_add_raw(client, (Realm *)0, newsubs); + status = subscr_add_raw(client, (ZRealm *)0, newsubs); } else if (!strcmp(snotice.z_opcode, REALM_REQ_SUBSCRIBE)) { zdbug((LOG_DEBUG, "subscr_foreign_user REQ %s/%s", tp0, tp1)); status = subscr_check_foreign_subs(notice, who, server, realm, newsubs); diff --git a/server/uloc.c b/server/uloc.c index 0d7ea8e..66071cf 100644 --- a/server/uloc.c +++ b/server/uloc.c @@ -106,7 +106,7 @@ static int ul_equiv __P((Location *l1, Location *l2)); static void free_loc __P((Location *loc)); static void ulogin_locate_forward __P((ZNotice_t *notice, - struct sockaddr_in *who, Realm *realm)); + struct sockaddr_in *who, ZRealm *realm)); static Location *locations = NULL; /* ptr to first in array */ static int num_locs = 0; /* number in array */ @@ -241,7 +241,11 @@ ulogin_dispatch(notice, auth, who, server) 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; @@ -282,7 +286,7 @@ ulocate_dispatch(notice, auth, who, server) Server *server; { char *cp; - Realm *realm; + ZRealm *realm; if (!strcmp(notice->z_opcode, LOCATE_LOCATE)) { /* we are talking to a current-rev client; send an ack */ @@ -294,7 +298,7 @@ ulocate_dispatch(notice, auth, who, server) ulogin_locate(notice, who, auth); return ZERR_NONE; } else { - syslog(LOG_ERR, "unknown uloc opcode %s", notice->z_opcode); + syslog(LOG_ERR, "unknown uloc opcode %s", notice->z_opcode); if (server == me_server) nack(notice, who); return ZERR_NONE; @@ -441,6 +445,7 @@ uloc_send_locations() 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, @@ -1004,7 +1009,7 @@ static void ulogin_locate_forward(notice, who, realm) ZNotice_t *notice; struct sockaddr_in *who; - Realm *realm; + ZRealm *realm; { ZNotice_t lnotice; @@ -1018,7 +1023,7 @@ void ulogin_realm_locate(notice, who, realm) ZNotice_t *notice; struct sockaddr_in *who; - Realm *realm; + ZRealm *realm; { char **answer; int found; diff --git a/server/zserver.h b/server/zserver.h index 221e26b..981a000 100644 --- a/server/zserver.h +++ b/server/zserver.h @@ -17,6 +17,9 @@ #include #include + +#include + #include #include "zsrv_err.h" @@ -28,10 +31,19 @@ #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 *)); +#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 @@ -67,9 +79,9 @@ typedef struct { typedef struct _Destination Destination; typedef struct _Destlist Destlist; -typedef struct _Realm Realm; -typedef struct _Realmname Realmname; -typedef enum _Realm_state Realm_state; +typedef struct _ZRealm ZRealm; +typedef struct _ZRealmname ZRealmname; +typedef enum _ZRealm_state ZRealm_state; typedef struct _Client Client; typedef struct _Triplet Triplet; typedef enum _Server_state Server_state; @@ -90,14 +102,14 @@ struct _Destlist { struct _Destlist *next, **prev_p; }; -enum _Realm_state { - REALM_UP, /* Realm is up */ - REALM_TARDY, /* Realm due for a hello XXX */ - REALM_DEAD, /* Realm is considered dead */ - REALM_STARTING /* Realm is between dead and up */ +enum _ZRealm_state { + REALM_UP, /* ZRealm is up */ + REALM_TARDY, /* ZRealm due for a hello XXX */ + REALM_DEAD, /* ZRealm is considered dead */ + REALM_STARTING /* ZRealm is between dead and up */ }; -struct _Realm { +struct _ZRealm { char name[REALM_SZ]; int count; struct sockaddr_in *addrs; @@ -107,10 +119,10 @@ struct _Realm { Client *client; int child_pid; int have_tkt; - Realm_state state; + ZRealm_state state; }; -struct _Realmname { +struct _ZRealmname { char name[REALM_SZ]; char **servers; int nused; @@ -120,13 +132,17 @@ struct _Realmname { 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 */ - Realm *realm; + ZRealm *realm; struct _Client *next, **prev_p; }; @@ -215,9 +231,9 @@ int get_tgt __P((void)); extern String *class_control, *class_admin, *class_hm; extern String *class_ulogin, *class_ulocate; int ZDest_eq __P((Destination *d1, Destination *d2)); -Code_t triplet_register __P((Client *client, Destination *dest, Realm *realm)); +Code_t triplet_register __P((Client *client, Destination *dest, ZRealm *realm)); Code_t triplet_deregister __P((Client *client, Destination *dest, - Realm *realm)); + ZRealm *realm)); Code_t class_restrict __P((char *class, Acl *acl)); Code_t class_setup_restricted __P((char *class, Acl *acl)); Client **triplet_lookup __P((Destination *dest)); @@ -268,7 +284,7 @@ void sweep_ticket_hash_table __P((void *)); #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_set_key __P((void *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)); @@ -297,7 +313,7 @@ Code_t server_adispatch __P((ZNotice_t *notice, int auth, struct sockaddr_in *who, Server *server)); /* found in subscr.c */ -Code_t subscr_foreign_user __P((ZNotice_t *, struct sockaddr_in *, Server *, Realm *)); +Code_t subscr_foreign_user __P((ZNotice_t *, struct sockaddr_in *, Server *, ZRealm *)); Code_t subscr_cancel __P((struct sockaddr_in *sin, ZNotice_t *notice)); Code_t subscr_subscribe __P((Client *who, ZNotice_t *notice, Server *server)); Code_t subscr_send_subs __P((Client *client)); @@ -321,16 +337,16 @@ Code_t uloc_send_locations __P((void)); /* found in realm.c */ int realm_sender_in_realm __P((char *realm, char *sender)); int realm_bound_for_realm __P((char *realm, char *recip)); -Realm *realm_which_realm __P((struct sockaddr_in *who)); -Realm *realm_get_realm_by_name __P((char *name)); -Realm *realm_get_realm_by_pid __P((int)); -void realm_handoff(ZNotice_t *, int, struct sockaddr_in *, Realm *, int); +ZRealm *realm_which_realm __P((struct sockaddr_in *who)); +ZRealm *realm_get_realm_by_name __P((char *name)); +ZRealm *realm_get_realm_by_pid __P((int)); +void realm_handoff(ZNotice_t *, int, struct sockaddr_in *, ZRealm *, int); char *realm_expand_realm(char *); void realm_init __P((void)); -Code_t ZCheckRealmAuthentication __P((ZNotice_t *, struct sockaddr_in *, +Code_t ZCheckZRealmAuthentication __P((ZNotice_t *, struct sockaddr_in *, char *)); Code_t realm_control_dispatch __P((ZNotice_t *, int, struct sockaddr_in *, - Server *, Realm *)); + Server *, ZRealm *)); void realm_shutdown __P((void)); void realm_deathgram __P((Server *)); @@ -355,6 +371,10 @@ extern int nfds; /* number to look at in select() */ 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[]; @@ -385,7 +405,7 @@ extern int nservers; /* number of other servers*/ extern String *empty; extern String *wildcard_instance; -extern Realm *otherrealms; +extern ZRealm *otherrealms; extern int nrealms; extern struct in_addr my_addr; /* my inet address */ diff --git a/server/zsrv_conf.h b/server/zsrv_conf.h index 7b663da..5508e3a 100644 --- a/server/zsrv_conf.h +++ b/server/zsrv_conf.h @@ -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" diff --git a/server/zsrv_err.et b/server/zsrv_err.et index de48f21..36d6a3f 100644 --- a/server/zsrv_err.et +++ b/server/zsrv_err.et @@ -13,7 +13,7 @@ ec ZSRV_NOCLT, ec ZSRV_NOSUB, "No such subscription" ec ZSRV_NOCLASS, - "Class unkown" + "Class unknown" ec ZSRV_CLASSXISTS, "Class already registered" ec ZSRV_CLASSRESTRICTED, diff --git a/zhm/zhm_client.c b/zhm/zhm_client.c index 6ee448b..0da6bee 100644 --- a/zhm/zhm_client.c +++ b/zhm/zhm_client.c @@ -74,7 +74,7 @@ void transmission_tower(notice, packet, pak_len) 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"); } -- cgit v1.2.3