diff options
author | markm <markm@FreeBSD.org> | 2000-01-09 20:58:00 +0000 |
---|---|---|
committer | markm <markm@FreeBSD.org> | 2000-01-09 20:58:00 +0000 |
commit | 4ecbd6db44d79348bc815f31096e53104f50838b (patch) | |
tree | 36fa73706fa0587a390c45a3fbf17c9523cb0e35 /crypto/heimdal/kdc | |
download | FreeBSD-src-4ecbd6db44d79348bc815f31096e53104f50838b.zip FreeBSD-src-4ecbd6db44d79348bc815f31096e53104f50838b.tar.gz |
Import KTH Heimdal, which will be the core of our Kerberos5.
Userland to follow.
Diffstat (limited to 'crypto/heimdal/kdc')
26 files changed, 7528 insertions, 0 deletions
diff --git a/crypto/heimdal/kdc/524.c b/crypto/heimdal/kdc/524.c new file mode 100644 index 0000000..fb188de --- /dev/null +++ b/crypto/heimdal/kdc/524.c @@ -0,0 +1,183 @@ +/* + * Copyright (c) 1997-1999 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "kdc_locl.h" + +RCSID("$Id: 524.c,v 1.10 1999/12/02 17:04:58 joda Exp $"); + +#ifdef KRB4 + +krb5_error_code +do_524(Ticket *t, krb5_data *reply, const char *from, struct sockaddr *addr) +{ + krb5_error_code ret = 0; + krb5_principal sprinc = NULL; + krb5_crypto crypto; + hdb_entry *server; + Key *skey; + krb5_data et_data; + EncTicketPart et; + EncryptedData ticket; + krb5_storage *sp; + char *spn = NULL; + unsigned char buf[MAX_KTXT_LEN + 4 * 4]; + size_t len; + + principalname2krb5_principal(&sprinc, t->sname, t->realm); + krb5_unparse_name(context, sprinc, &spn); + server = db_fetch(sprinc); + if(server == NULL){ + kdc_log(0, "Request to convert ticket from %s for unknown principal %s", + from, spn); + goto out; + } + ret = hdb_enctype2key(context, server, t->enc_part.etype, &skey); + if(ret){ + kdc_log(0, "No suitable key found for server (%s) " + "when converting ticket from ", spn, from); + goto out; + } + krb5_crypto_init(context, &skey->key, 0, &crypto); + ret = krb5_decrypt_EncryptedData (context, + crypto, + KRB5_KU_TICKET, + &t->enc_part, + &et_data); + krb5_crypto_destroy(context, crypto); + if(ret){ + kdc_log(0, "Failed to decrypt ticket from %s for %s", from, spn); + goto out; + } + ret = krb5_decode_EncTicketPart(context, et_data.data, et_data.length, + &et, &len); + krb5_data_free(&et_data); + if(ret){ + kdc_log(0, "Failed to decode ticket from %s for %s", from, spn); + goto out; + } + { + krb5_principal client; + char *cpn; + principalname2krb5_principal(&client, et.cname, et.crealm); + krb5_unparse_name(context, client, &cpn); + kdc_log(1, "524-REQ %s from %s for %s", cpn, from, spn); + free(cpn); + krb5_free_principal(context, client); + } + + if(et.endtime < kdc_time){ + kdc_log(0, "Ticket expired (%s)", spn); + free_EncTicketPart(&et); + ret = KRB5KRB_AP_ERR_TKT_EXPIRED; + goto out; + } + if(et.flags.invalid){ + kdc_log(0, "Ticket not valid (%s)", spn); + free_EncTicketPart(&et); + ret = KRB5KRB_AP_ERR_TKT_NYV; + goto out; + } + { + krb5_addresses *save_caddr, new_addr; + krb5_address v4_addr; + + ret = krb5_sockaddr2address(addr, &v4_addr); + if(ret) { + kdc_log(0, "Failed to convert address (%s)", spn); + free_EncTicketPart(&et); + goto out; + } + + if (et.caddr && !krb5_address_search (context, &v4_addr, et.caddr)) { + kdc_log(0, "Incorrect network address (%s)", spn); + free_EncTicketPart(&et); + krb5_free_address(context, &v4_addr); + ret = KRB5KRB_AP_ERR_BADADDR; + goto out; + } + if(v4_addr.addr_type == KRB5_ADDRESS_INET) { + /* we need to collapse the addresses in the ticket to a + single address; best guess is to use the address the + connection came from */ + save_caddr = et.caddr; + new_addr.len = 1; + new_addr.val = &v4_addr; + et.caddr = &new_addr; + } + ret = encode_v4_ticket(buf + sizeof(buf) - 1, sizeof(buf), + &et, &t->sname, &len); + if(v4_addr.addr_type == KRB5_ADDRESS_INET) + et.caddr = save_caddr; + } + free_EncTicketPart(&et); + if(ret){ + kdc_log(0, "Failed to encode v4 ticket (%s)", spn); + goto out; + } + ret = get_des_key(server, &skey); + if(ret){ + kdc_log(0, "No DES key for server (%s)", spn); + goto out; + } + ret = encrypt_v4_ticket(buf + sizeof(buf) - len, len, + skey->key.keyvalue.data, &ticket); + if(ret){ + kdc_log(0, "Failed to encrypt v4 ticket (%s)", spn); + goto out; + } +out: + /* make reply */ + memset(buf, 0, sizeof(buf)); + sp = krb5_storage_from_mem(buf, sizeof(buf)); + krb5_store_int32(sp, ret); + if(ret == 0){ + krb5_store_int32(sp, server->kvno); /* is this right? */ + krb5_store_data(sp, ticket.cipher); + /* Aargh! This is coded as a KTEXT_ST. */ + sp->seek(sp, MAX_KTXT_LEN - ticket.cipher.length, SEEK_CUR); + krb5_store_int32(sp, 0); /* mbz */ + free_EncryptedData(&ticket); + } + ret = krb5_storage_to_data(sp, reply); + krb5_storage_free(sp); + + if(spn) + free(spn); + if(sprinc) + krb5_free_principal(context, sprinc); + hdb_free_entry(context, server); + free(server); + return ret; +} + +#endif diff --git a/crypto/heimdal/kdc/Makefile.am b/crypto/heimdal/kdc/Makefile.am new file mode 100644 index 0000000..3e3df20 --- /dev/null +++ b/crypto/heimdal/kdc/Makefile.am @@ -0,0 +1,62 @@ +# $Id: Makefile.am,v 1.33 1999/05/13 23:32:35 assar Exp $ + +include $(top_srcdir)/Makefile.am.common + +INCLUDES += $(INCLUDE_krb4) + +bin_PROGRAMS = string2key + +sbin_PROGRAMS = kstash + +libexec_PROGRAMS = hprop hpropd kdc + +man_MANS = kdc.8 kstash.8 hprop.8 hpropd.8 + +hprop_SOURCES = hprop.c hprop-common.c hprop.h kadb.h +hpropd_SOURCES = hpropd.c hprop-common.c hprop.h + +kstash_SOURCES = kstash.c headers.h + +string2key_SOURCES = string2key.c headers.h + +kdc_SOURCES = \ + 524.c \ + config.c \ + connect.c \ + kaserver.c \ + kdc_locl.h \ + kerberos4.c \ + kerberos4.h \ + kerberos5.c \ + log.c \ + main.c \ + misc.c \ + rx.h + + +hprop_LDADD = \ + $(top_builddir)/lib/hdb/libhdb.la \ + $(top_builddir)/lib/krb5/libkrb5.la \ + $(LIB_kdb) $(LIB_krb4) \ + $(top_builddir)/lib/des/libdes.la \ + $(top_builddir)/lib/asn1/libasn1.la \ + $(LIB_roken) \ + $(DBLIB) + +hpropd_LDADD = \ + $(top_builddir)/lib/hdb/libhdb.la \ + $(top_builddir)/lib/krb5/libkrb5.la \ + $(LIB_kdb) $(LIB_krb4) \ + $(top_builddir)/lib/des/libdes.la \ + $(top_builddir)/lib/asn1/libasn1.la \ + $(LIB_roken) \ + $(DBLIB) + +LDADD = $(top_builddir)/lib/hdb/libhdb.la \ + $(top_builddir)/lib/krb5/libkrb5.la \ + $(LIB_krb4) \ + $(top_builddir)/lib/des/libdes.la \ + $(top_builddir)/lib/asn1/libasn1.la \ + $(LIB_roken) \ + $(DBLIB) + diff --git a/crypto/heimdal/kdc/Makefile.in b/crypto/heimdal/kdc/Makefile.in new file mode 100644 index 0000000..6ba90e1 --- /dev/null +++ b/crypto/heimdal/kdc/Makefile.in @@ -0,0 +1,799 @@ +# Makefile.in generated automatically by automake 1.4 from Makefile.am + +# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +# $Id: Makefile.am,v 1.33 1999/05/13 23:32:35 assar Exp $ + + +# $Id: Makefile.am.common,v 1.3 1999/04/01 14:58:43 joda Exp $ + + +# $Id: Makefile.am.common,v 1.13 1999/11/01 03:19:58 assar Exp $ + + +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +DESTDIR = + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = .. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS) +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +transform = @program_transform_name@ + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +host_alias = @host_alias@ +host_triplet = @host@ +AFS_EXTRA_LD = @AFS_EXTRA_LD@ +AIX_EXTRA_KAFS = @AIX_EXTRA_KAFS@ +AWK = @AWK@ +CANONICAL_HOST = @CANONICAL_HOST@ +CATMAN = @CATMAN@ +CATMANEXT = @CATMANEXT@ +CC = @CC@ +DBLIB = @DBLIB@ +EXEEXT = @EXEEXT@ +EXTRA_LIB45 = @EXTRA_LIB45@ +GROFF = @GROFF@ +INCLUDE_ = @INCLUDE_@ +LD = @LD@ +LEX = @LEX@ +LIBOBJS = @LIBOBJS@ +LIBTOOL = @LIBTOOL@ +LIB_ = @LIB_@ +LIB_AUTH_SUBDIRS = @LIB_AUTH_SUBDIRS@ +LIB_kdb = @LIB_kdb@ +LIB_otp = @LIB_otp@ +LIB_roken = @LIB_roken@ +LIB_security = @LIB_security@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MAKE_X_PROGS_BIN_PROGS = @MAKE_X_PROGS_BIN_PROGS@ +MAKE_X_PROGS_BIN_SCRPTS = @MAKE_X_PROGS_BIN_SCRPTS@ +MAKE_X_PROGS_LIBEXEC_PROGS = @MAKE_X_PROGS_LIBEXEC_PROGS@ +NEED_WRITEAUTH_FALSE = @NEED_WRITEAUTH_FALSE@ +NEED_WRITEAUTH_TRUE = @NEED_WRITEAUTH_TRUE@ +NM = @NM@ +NROFF = @NROFF@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +RANLIB = @RANLIB@ +VERSION = @VERSION@ +VOID_RETSIGTYPE = @VOID_RETSIGTYPE@ +WFLAGS = @WFLAGS@ +WFLAGS_NOIMPLICITINT = @WFLAGS_NOIMPLICITINT@ +WFLAGS_NOUNUSED = @WFLAGS_NOUNUSED@ +YACC = @YACC@ + +AUTOMAKE_OPTIONS = foreign no-dependencies + +SUFFIXES = .et .h .1 .3 .5 .8 .cat1 .cat3 .cat5 .cat8 .x + +INCLUDES = -I$(top_builddir)/include $(INCLUDE_krb4) + +AM_CFLAGS = $(WFLAGS) + +COMPILE_ET = $(top_builddir)/lib/com_err/compile_et + +buildinclude = $(top_builddir)/include + +LIB_XauReadAuth = @LIB_XauReadAuth@ +LIB_crypt = @LIB_crypt@ +LIB_dbm_firstkey = @LIB_dbm_firstkey@ +LIB_dbopen = @LIB_dbopen@ +LIB_dlopen = @LIB_dlopen@ +LIB_dn_expand = @LIB_dn_expand@ +LIB_el_init = @LIB_el_init@ +LIB_getattr = @LIB_getattr@ +LIB_gethostbyname = @LIB_gethostbyname@ +LIB_getpwent_r = @LIB_getpwent_r@ +LIB_getpwnam_r = @LIB_getpwnam_r@ +LIB_getsockopt = @LIB_getsockopt@ +LIB_logout = @LIB_logout@ +LIB_logwtmp = @LIB_logwtmp@ +LIB_odm_initialize = @LIB_odm_initialize@ +LIB_readline = @LIB_readline@ +LIB_res_search = @LIB_res_search@ +LIB_setpcred = @LIB_setpcred@ +LIB_setsockopt = @LIB_setsockopt@ +LIB_socket = @LIB_socket@ +LIB_syslog = @LIB_syslog@ +LIB_tgetent = @LIB_tgetent@ + +HESIODLIB = @HESIODLIB@ +HESIODINCLUDE = @HESIODINCLUDE@ +INCLUDE_hesiod = @INCLUDE_hesiod@ +LIB_hesiod = @LIB_hesiod@ + +INCLUDE_krb4 = @INCLUDE_krb4@ +LIB_krb4 = @LIB_krb4@ + +INCLUDE_readline = @INCLUDE_readline@ + +LEXLIB = @LEXLIB@ + +cat1dir = $(mandir)/cat1 +cat3dir = $(mandir)/cat3 +cat5dir = $(mandir)/cat5 +cat8dir = $(mandir)/cat8 + +MANRX = \(.*\)\.\([0-9]\) +CATSUFFIX = @CATSUFFIX@ + +NROFF_MAN = groff -mandoc -Tascii + +@KRB4_TRUE@LIB_kafs = $(top_builddir)/lib/kafs/libkafs.la $(AIX_EXTRA_KAFS) + +@KRB5_TRUE@LIB_krb5 = $(top_builddir)/lib/krb5/libkrb5.la $(top_builddir)/lib/asn1/libasn1.la +@KRB5_TRUE@LIB_gssapi = $(top_builddir)/lib/gssapi/libgssapi.la + +CHECK_LOCAL = $(PROGRAMS) + +bin_PROGRAMS = string2key + +sbin_PROGRAMS = kstash + +libexec_PROGRAMS = hprop hpropd kdc + +man_MANS = kdc.8 kstash.8 hprop.8 hpropd.8 + +hprop_SOURCES = hprop.c hprop-common.c hprop.h kadb.h +hpropd_SOURCES = hpropd.c hprop-common.c hprop.h + +kstash_SOURCES = kstash.c headers.h + +string2key_SOURCES = string2key.c headers.h + +kdc_SOURCES = 524.c config.c connect.c kaserver.c kdc_locl.h kerberos4.c kerberos4.h kerberos5.c log.c main.c misc.c rx.h + + +hprop_LDADD = $(top_builddir)/lib/hdb/libhdb.la $(top_builddir)/lib/krb5/libkrb5.la $(LIB_kdb) $(LIB_krb4) $(top_builddir)/lib/des/libdes.la $(top_builddir)/lib/asn1/libasn1.la $(LIB_roken) $(DBLIB) + + +hpropd_LDADD = $(top_builddir)/lib/hdb/libhdb.la $(top_builddir)/lib/krb5/libkrb5.la $(LIB_kdb) $(LIB_krb4) $(top_builddir)/lib/des/libdes.la $(top_builddir)/lib/asn1/libasn1.la $(LIB_roken) $(DBLIB) + + +LDADD = $(top_builddir)/lib/hdb/libhdb.la $(top_builddir)/lib/krb5/libkrb5.la $(LIB_krb4) $(top_builddir)/lib/des/libdes.la $(top_builddir)/lib/asn1/libasn1.la $(LIB_roken) $(DBLIB) + +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = ../include/config.h +CONFIG_CLEAN_FILES = +bin_PROGRAMS = string2key$(EXEEXT) +libexec_PROGRAMS = hprop$(EXEEXT) hpropd$(EXEEXT) kdc$(EXEEXT) +sbin_PROGRAMS = kstash$(EXEEXT) +PROGRAMS = $(bin_PROGRAMS) $(libexec_PROGRAMS) $(sbin_PROGRAMS) + + +DEFS = @DEFS@ -I. -I$(srcdir) -I../include +CPPFLAGS = @CPPFLAGS@ +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ +X_CFLAGS = @X_CFLAGS@ +X_LIBS = @X_LIBS@ +X_EXTRA_LIBS = @X_EXTRA_LIBS@ +X_PRE_LIBS = @X_PRE_LIBS@ +string2key_OBJECTS = string2key.$(OBJEXT) +string2key_LDADD = $(LDADD) +string2key_DEPENDENCIES = $(top_builddir)/lib/hdb/libhdb.la \ +$(top_builddir)/lib/krb5/libkrb5.la $(top_builddir)/lib/des/libdes.la \ +$(top_builddir)/lib/asn1/libasn1.la +string2key_LDFLAGS = +hprop_OBJECTS = hprop.$(OBJEXT) hprop-common.$(OBJEXT) +hprop_DEPENDENCIES = $(top_builddir)/lib/hdb/libhdb.la \ +$(top_builddir)/lib/krb5/libkrb5.la $(top_builddir)/lib/des/libdes.la \ +$(top_builddir)/lib/asn1/libasn1.la +hprop_LDFLAGS = +hpropd_OBJECTS = hpropd.$(OBJEXT) hprop-common.$(OBJEXT) +hpropd_DEPENDENCIES = $(top_builddir)/lib/hdb/libhdb.la \ +$(top_builddir)/lib/krb5/libkrb5.la $(top_builddir)/lib/des/libdes.la \ +$(top_builddir)/lib/asn1/libasn1.la +hpropd_LDFLAGS = +kdc_OBJECTS = 524.$(OBJEXT) config.$(OBJEXT) connect.$(OBJEXT) \ +kaserver.$(OBJEXT) kerberos4.$(OBJEXT) kerberos5.$(OBJEXT) \ +log.$(OBJEXT) main.$(OBJEXT) misc.$(OBJEXT) +kdc_LDADD = $(LDADD) +kdc_DEPENDENCIES = $(top_builddir)/lib/hdb/libhdb.la \ +$(top_builddir)/lib/krb5/libkrb5.la $(top_builddir)/lib/des/libdes.la \ +$(top_builddir)/lib/asn1/libasn1.la +kdc_LDFLAGS = +kstash_OBJECTS = kstash.$(OBJEXT) +kstash_LDADD = $(LDADD) +kstash_DEPENDENCIES = $(top_builddir)/lib/hdb/libhdb.la \ +$(top_builddir)/lib/krb5/libkrb5.la $(top_builddir)/lib/des/libdes.la \ +$(top_builddir)/lib/asn1/libasn1.la +kstash_LDFLAGS = +CFLAGS = @CFLAGS@ +COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ +man8dir = $(mandir)/man8 +MANS = $(man_MANS) +DIST_COMMON = Makefile.am Makefile.in + + +DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) + +TAR = tar +GZIP_ENV = --best +SOURCES = $(string2key_SOURCES) $(hprop_SOURCES) $(hpropd_SOURCES) $(kdc_SOURCES) $(kstash_SOURCES) +OBJECTS = $(string2key_OBJECTS) $(hprop_OBJECTS) $(hpropd_OBJECTS) $(kdc_OBJECTS) $(kstash_OBJECTS) + +all: all-redirect +.SUFFIXES: +.SUFFIXES: .1 .3 .5 .8 .S .c .cat1 .cat3 .cat5 .cat8 .et .h .lo .o .obj .s .x +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) $(top_srcdir)/Makefile.am.common $(top_srcdir)/cf/Makefile.am.common + cd $(top_srcdir) && $(AUTOMAKE) --foreign kdc/Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + + +mostlyclean-binPROGRAMS: + +clean-binPROGRAMS: + -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS) + +distclean-binPROGRAMS: + +maintainer-clean-binPROGRAMS: + +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(bindir) + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + if test -f $$p; then \ + echo " $(LIBTOOL) --mode=install $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`"; \ + $(LIBTOOL) --mode=install $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \ + else :; fi; \ + done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + list='$(bin_PROGRAMS)'; for p in $$list; do \ + rm -f $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \ + done + +mostlyclean-libexecPROGRAMS: + +clean-libexecPROGRAMS: + -test -z "$(libexec_PROGRAMS)" || rm -f $(libexec_PROGRAMS) + +distclean-libexecPROGRAMS: + +maintainer-clean-libexecPROGRAMS: + +install-libexecPROGRAMS: $(libexec_PROGRAMS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(libexecdir) + @list='$(libexec_PROGRAMS)'; for p in $$list; do \ + if test -f $$p; then \ + echo " $(LIBTOOL) --mode=install $(INSTALL_PROGRAM) $$p $(DESTDIR)$(libexecdir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`"; \ + $(LIBTOOL) --mode=install $(INSTALL_PROGRAM) $$p $(DESTDIR)$(libexecdir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \ + else :; fi; \ + done + +uninstall-libexecPROGRAMS: + @$(NORMAL_UNINSTALL) + list='$(libexec_PROGRAMS)'; for p in $$list; do \ + rm -f $(DESTDIR)$(libexecdir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \ + done + +mostlyclean-sbinPROGRAMS: + +clean-sbinPROGRAMS: + -test -z "$(sbin_PROGRAMS)" || rm -f $(sbin_PROGRAMS) + +distclean-sbinPROGRAMS: + +maintainer-clean-sbinPROGRAMS: + +install-sbinPROGRAMS: $(sbin_PROGRAMS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(sbindir) + @list='$(sbin_PROGRAMS)'; for p in $$list; do \ + if test -f $$p; then \ + echo " $(LIBTOOL) --mode=install $(INSTALL_PROGRAM) $$p $(DESTDIR)$(sbindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`"; \ + $(LIBTOOL) --mode=install $(INSTALL_PROGRAM) $$p $(DESTDIR)$(sbindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \ + else :; fi; \ + done + +uninstall-sbinPROGRAMS: + @$(NORMAL_UNINSTALL) + list='$(sbin_PROGRAMS)'; for p in $$list; do \ + rm -f $(DESTDIR)$(sbindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \ + done + +.c.o: + $(COMPILE) -c $< + +# FIXME: We should only use cygpath when building on Windows, +# and only if it is available. +.c.obj: + $(COMPILE) -c `cygpath -w $<` + +.s.o: + $(COMPILE) -c $< + +.S.o: + $(COMPILE) -c $< + +mostlyclean-compile: + -rm -f *.o core *.core + -rm -f *.$(OBJEXT) + +clean-compile: + +distclean-compile: + -rm -f *.tab.c + +maintainer-clean-compile: + +.c.lo: + $(LIBTOOL) --mode=compile $(COMPILE) -c $< + +.s.lo: + $(LIBTOOL) --mode=compile $(COMPILE) -c $< + +.S.lo: + $(LIBTOOL) --mode=compile $(COMPILE) -c $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +distclean-libtool: + +maintainer-clean-libtool: + +string2key$(EXEEXT): $(string2key_OBJECTS) $(string2key_DEPENDENCIES) + @rm -f string2key$(EXEEXT) + $(LINK) $(string2key_LDFLAGS) $(string2key_OBJECTS) $(string2key_LDADD) $(LIBS) + +hprop$(EXEEXT): $(hprop_OBJECTS) $(hprop_DEPENDENCIES) + @rm -f hprop$(EXEEXT) + $(LINK) $(hprop_LDFLAGS) $(hprop_OBJECTS) $(hprop_LDADD) $(LIBS) + +hpropd$(EXEEXT): $(hpropd_OBJECTS) $(hpropd_DEPENDENCIES) + @rm -f hpropd$(EXEEXT) + $(LINK) $(hpropd_LDFLAGS) $(hpropd_OBJECTS) $(hpropd_LDADD) $(LIBS) + +kdc$(EXEEXT): $(kdc_OBJECTS) $(kdc_DEPENDENCIES) + @rm -f kdc$(EXEEXT) + $(LINK) $(kdc_LDFLAGS) $(kdc_OBJECTS) $(kdc_LDADD) $(LIBS) + +kstash$(EXEEXT): $(kstash_OBJECTS) $(kstash_DEPENDENCIES) + @rm -f kstash$(EXEEXT) + $(LINK) $(kstash_LDFLAGS) $(kstash_OBJECTS) $(kstash_LDADD) $(LIBS) + +install-man8: + $(mkinstalldirs) $(DESTDIR)$(man8dir) + @list='$(man8_MANS)'; \ + l2='$(man_MANS)'; for i in $$l2; do \ + case "$$i" in \ + *.8*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \ + else file=$$i; fi; \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " $(INSTALL_DATA) $$file $(DESTDIR)$(man8dir)/$$inst"; \ + $(INSTALL_DATA) $$file $(DESTDIR)$(man8dir)/$$inst; \ + done + +uninstall-man8: + @list='$(man8_MANS)'; \ + l2='$(man_MANS)'; for i in $$l2; do \ + case "$$i" in \ + *.8*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " rm -f $(DESTDIR)$(man8dir)/$$inst"; \ + rm -f $(DESTDIR)$(man8dir)/$$inst; \ + done +install-man: $(MANS) + @$(NORMAL_INSTALL) + $(MAKE) $(AM_MAKEFLAGS) install-man8 +uninstall-man: + @$(NORMAL_UNINSTALL) + $(MAKE) $(AM_MAKEFLAGS) uninstall-man8 + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + here=`pwd` && cd $(srcdir) \ + && mkid -f$$here/ID $$unique $(LISP) + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ + || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS) + +mostlyclean-tags: + +clean-tags: + +distclean-tags: + -rm -f TAGS ID + +maintainer-clean-tags: + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) + +subdir = kdc + +distdir: $(DISTFILES) + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + if test -d $$d/$$file; then \ + cp -pr $$/$$file $(distdir)/$$file; \ + else \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file || :; \ + fi; \ + done + $(MAKE) $(AM_MAKEFLAGS) top_distdir="$(top_distdir)" distdir="$(distdir)" dist-hook +info-am: +info: info-am +dvi-am: +dvi: dvi-am +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) check-local +check: check-am +installcheck-am: +installcheck: installcheck-am +install-exec-am: install-binPROGRAMS install-libexecPROGRAMS \ + install-sbinPROGRAMS + @$(NORMAL_INSTALL) + $(MAKE) $(AM_MAKEFLAGS) install-exec-hook +install-exec: install-exec-am + +install-data-am: install-man install-data-local +install-data: install-data-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am +install: install-am +uninstall-am: uninstall-binPROGRAMS uninstall-libexecPROGRAMS \ + uninstall-sbinPROGRAMS uninstall-man +uninstall: uninstall-am +all-am: Makefile $(PROGRAMS) $(MANS) all-local +all-redirect: all-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install +installdirs: + $(mkinstalldirs) $(DESTDIR)$(bindir) $(DESTDIR)$(libexecdir) \ + $(DESTDIR)$(sbindir) $(DESTDIR)$(mandir)/man8 + + +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + +maintainer-clean-generic: +mostlyclean-am: mostlyclean-binPROGRAMS mostlyclean-libexecPROGRAMS \ + mostlyclean-sbinPROGRAMS mostlyclean-compile \ + mostlyclean-libtool mostlyclean-tags \ + mostlyclean-generic + +mostlyclean: mostlyclean-am + +clean-am: clean-binPROGRAMS clean-libexecPROGRAMS clean-sbinPROGRAMS \ + clean-compile clean-libtool clean-tags clean-generic \ + mostlyclean-am + +clean: clean-am + +distclean-am: distclean-binPROGRAMS distclean-libexecPROGRAMS \ + distclean-sbinPROGRAMS distclean-compile \ + distclean-libtool distclean-tags distclean-generic \ + clean-am + -rm -f libtool + +distclean: distclean-am + +maintainer-clean-am: maintainer-clean-binPROGRAMS \ + maintainer-clean-libexecPROGRAMS \ + maintainer-clean-sbinPROGRAMS maintainer-clean-compile \ + maintainer-clean-libtool maintainer-clean-tags \ + maintainer-clean-generic distclean-am + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +maintainer-clean: maintainer-clean-am + +.PHONY: mostlyclean-binPROGRAMS distclean-binPROGRAMS clean-binPROGRAMS \ +maintainer-clean-binPROGRAMS uninstall-binPROGRAMS install-binPROGRAMS \ +mostlyclean-libexecPROGRAMS distclean-libexecPROGRAMS \ +clean-libexecPROGRAMS maintainer-clean-libexecPROGRAMS \ +uninstall-libexecPROGRAMS install-libexecPROGRAMS \ +mostlyclean-sbinPROGRAMS distclean-sbinPROGRAMS clean-sbinPROGRAMS \ +maintainer-clean-sbinPROGRAMS uninstall-sbinPROGRAMS \ +install-sbinPROGRAMS mostlyclean-compile distclean-compile \ +clean-compile maintainer-clean-compile mostlyclean-libtool \ +distclean-libtool clean-libtool maintainer-clean-libtool install-man8 \ +uninstall-man8 install-man uninstall-man tags mostlyclean-tags \ +distclean-tags clean-tags maintainer-clean-tags distdir info-am info \ +dvi-am dvi check-local check check-am installcheck-am installcheck \ +install-exec-am install-exec install-data-local install-data-am \ +install-data install-am install uninstall-am uninstall all-local \ +all-redirect all-am all installdirs mostlyclean-generic \ +distclean-generic clean-generic maintainer-clean-generic clean \ +mostlyclean distclean maintainer-clean + + +install-suid-programs: + @foo='$(bin_SUIDS)'; \ + for file in $$foo; do \ + x=$(DESTDIR)$(bindir)/$$file; \ + if chown 0:0 $$x && chmod u+s $$x; then :; else \ + chmod 0 $$x; fi; done + +install-exec-hook: install-suid-programs + +install-build-headers:: $(include_HEADERS) $(build_HEADERZ) + @foo='$(include_HEADERS) $(build_HEADERZ)'; \ + for f in $$foo; do \ + f=`basename $$f`; \ + if test -f "$(srcdir)/$$f"; then file="$(srcdir)/$$f"; \ + else file="$$f"; fi; \ + if cmp -s $$file $(buildinclude)/$$f 2> /dev/null ; then \ + : ; else \ + echo " cp $$file $(buildinclude)/$$f"; \ + cp $$file $(buildinclude)/$$f; \ + fi ; \ + done + +all-local: install-build-headers +#NROFF_MAN = nroff -man +.1.cat1: + $(NROFF_MAN) $< > $@ +.3.cat3: + $(NROFF_MAN) $< > $@ +.5.cat5: + $(NROFF_MAN) $< > $@ +.8.cat8: + $(NROFF_MAN) $< > $@ + +dist-cat1-mans: + @foo='$(man1_MANS)'; \ + bar='$(man_MANS)'; \ + for i in $$bar; do \ + case $$i in \ + *.1) foo="$$foo $$i";; \ + esac; done ;\ + for i in $$foo; do \ + x=`echo $$i | sed 's/\.[^.]*$$/.cat1/'`; \ + echo "$(NROFF_MAN) $(srcdir)/$$i > $(distdir)/$$x"; \ + $(NROFF_MAN) $(srcdir)/$$i > $(distdir)/$$x; \ + done + +dist-cat3-mans: + @foo='$(man3_MANS)'; \ + bar='$(man_MANS)'; \ + for i in $$bar; do \ + case $$i in \ + *.3) foo="$$foo $$i";; \ + esac; done ;\ + for i in $$foo; do \ + x=`echo $$i | sed 's/\.[^.]*$$/.cat3/'`; \ + echo "$(NROFF_MAN) $(srcdir)/$$i > $(distdir)/$$x"; \ + $(NROFF_MAN) $(srcdir)/$$i > $(distdir)/$$x; \ + done + +dist-cat5-mans: + @foo='$(man5_MANS)'; \ + bar='$(man_MANS)'; \ + for i in $$bar; do \ + case $$i in \ + *.5) foo="$$foo $$i";; \ + esac; done ;\ + for i in $$foo; do \ + x=`echo $$i | sed 's/\.[^.]*$$/.cat5/'`; \ + echo "$(NROFF_MAN) $(srcdir)/$$i > $(distdir)/$$x"; \ + $(NROFF_MAN) $(srcdir)/$$i > $(distdir)/$$x; \ + done + +dist-cat8-mans: + @foo='$(man8_MANS)'; \ + bar='$(man_MANS)'; \ + for i in $$bar; do \ + case $$i in \ + *.8) foo="$$foo $$i";; \ + esac; done ;\ + for i in $$foo; do \ + x=`echo $$i | sed 's/\.[^.]*$$/.cat8/'`; \ + echo "$(NROFF_MAN) $(srcdir)/$$i > $(distdir)/$$x"; \ + $(NROFF_MAN) $(srcdir)/$$i > $(distdir)/$$x; \ + done + +dist-hook: dist-cat1-mans dist-cat3-mans dist-cat5-mans dist-cat8-mans + +install-cat1-mans: + @ext=1;\ + foo='$(man1_MANS)'; \ + bar='$(man_MANS)'; \ + for i in $$bar; do \ + case $$i in \ + *.1) foo="$$foo $$i";; \ + esac; done; \ + if test "$$foo"; then \ + $(mkinstalldirs) $(DESTDIR)$(cat1dir); \ + for x in $$foo; do \ + f=`echo $$x | sed 's/\.[^.]*$$/.cat1/'`; \ + if test -f "$(srcdir)/$$f"; then \ + b=`echo $$x | sed 's!$(MANRX)!\1!'`; \ + echo "$(INSTALL_DATA) $(srcdir)/$$f $(DESTDIR)$(cat1dir)/$$b.$(CATSUFFIX)";\ + $(INSTALL_DATA) $(srcdir)/$$g $(DESTDIR)$(cat1dir)/$$b.$(CATSUFFIX);\ + fi; \ + done ;\ + fi + +install-cat3-mans: + @ext=3;\ + foo='$(man3_MANS)'; \ + bar='$(man_MANS)'; \ + for i in $$bar; do \ + case $$i in \ + *.3) foo="$$foo $$i";; \ + esac; done; \ + if test "$$foo"; then \ + $(mkinstalldirs) $(DESTDIR)$(cat3dir); \ + for x in $$foo; do \ + f=`echo $$x | sed 's/\.[^.]*$$/.cat3/'`; \ + if test -f "$(srcdir)/$$f"; then \ + b=`echo $$x | sed 's!$(MANRX)!\1!'`; \ + echo "$(INSTALL_DATA) $(srcdir)/$$f $(DESTDIR)$(cat3dir)/$$b.$(CATSUFFIX)";\ + $(INSTALL_DATA) $(srcdir)/$$g $(DESTDIR)$(cat3dir)/$$b.$(CATSUFFIX);\ + fi; \ + done ;\ + fi + +install-cat5-mans: + @ext=5;\ + foo='$(man5_MANS)'; \ + bar='$(man_MANS)'; \ + for i in $$bar; do \ + case $$i in \ + *.5) foo="$$foo $$i";; \ + esac; done; \ + if test "$$foo"; then \ + $(mkinstalldirs) $(DESTDIR)$(cat5dir); \ + for x in $$foo; do \ + f=`echo $$x | sed 's/\.[^.]*$$/.cat5/'`; \ + if test -f "$(srcdir)/$$f"; then \ + b=`echo $$x | sed 's!$(MANRX)!\1!'`; \ + echo "$(INSTALL_DATA) $(srcdir)/$$f $(DESTDIR)$(cat5dir)/$$b.$(CATSUFFIX)";\ + $(INSTALL_DATA) $(srcdir)/$$g $(DESTDIR)$(cat5dir)/$$b.$(CATSUFFIX);\ + fi; \ + done ;\ + fi + +install-cat8-mans: + @ext=8;\ + foo='$(man8_MANS)'; \ + bar='$(man_MANS)'; \ + for i in $$bar; do \ + case $$i in \ + *.8) foo="$$foo $$i";; \ + esac; done; \ + if test "$$foo"; then \ + $(mkinstalldirs) $(DESTDIR)$(cat8dir); \ + for x in $$foo; do \ + f=`echo $$x | sed 's/\.[^.]*$$/.cat8/'`; \ + if test -f "$(srcdir)/$$f"; then \ + b=`echo $$x | sed 's!$(MANRX)!\1!'`; \ + echo "$(INSTALL_DATA) $(srcdir)/$$f $(DESTDIR)$(cat8dir)/$$b.$(CATSUFFIX)";\ + $(INSTALL_DATA) $(srcdir)/$$g $(DESTDIR)$(cat8dir)/$$b.$(CATSUFFIX);\ + fi; \ + done ;\ + fi + +install-cat-mans: install-cat1-mans install-cat3-mans install-cat5-mans install-cat8-mans + +install-data-local: install-cat-mans + +.et.h: + $(COMPILE_ET) $< +.et.c: + $(COMPILE_ET) $< + +.x.c: + @cmp -s $< $@ 2> /dev/null || cp $< $@ + +check-local:: + @foo='$(CHECK_LOCAL)'; \ + if test "$$foo"; then \ + failed=0; all=0; \ + for i in $$foo; do \ + all=`expr $$all + 1`; \ + if ./$$i --version > /dev/null 2>&1; then \ + echo "PASS: $$i"; \ + else \ + echo "FAIL: $$i"; \ + failed=`expr $$failed + 1`; \ + fi; \ + done; \ + if test "$$failed" -eq 0; then \ + banner="All $$all tests passed"; \ + else \ + banner="$$failed of $$all tests failed"; \ + fi; \ + dashes=`echo "$$banner" | sed s/./=/g`; \ + echo "$$dashes"; \ + echo "$$banner"; \ + echo "$$dashes"; \ + test "$$failed" -eq 0; \ + fi + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/crypto/heimdal/kdc/config.c b/crypto/heimdal/kdc/config.c new file mode 100644 index 0000000..ba76432 --- /dev/null +++ b/crypto/heimdal/kdc/config.c @@ -0,0 +1,309 @@ +/* + * Copyright (c) 1997-1999 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "kdc_locl.h" +#include <getarg.h> +#include <parse_bytes.h> + +RCSID("$Id: config.c,v 1.28 1999/12/02 17:04:58 joda Exp $"); + +static char *config_file; +int require_preauth = -1; +char *keyfile; +static char *max_request_str; +size_t max_request; +time_t kdc_warn_pwexpire; +struct dbinfo *databases; +HDB **db; +int num_db; +char *port_str; +int enable_http = -1; +krb5_boolean encode_as_rep_as_tgs_rep; /* bug compatibility */ + +krb5_boolean check_ticket_addresses; +krb5_boolean allow_null_ticket_addresses; + +#ifdef KRB4 +char *v4_realm; +#endif +#ifdef KASERVER +krb5_boolean enable_kaserver = -1; +#endif + +static int help_flag; +static int version_flag; + +static struct getargs args[] = { + { + "config-file", 'c', arg_string, &config_file, + "location of config file", "file" + }, + { + "require-preauth", 'p', arg_negative_flag, &require_preauth, + "don't require pa-data in as-reqs" + }, + { + "key-file", 'k', arg_string, &keyfile, + "location of master key file", "file" + }, + { + "max-request", 0, arg_string, &max_request, + "max size for a kdc-request", "size" + }, +#if 0 + { + "database", 'd', arg_string, &databases, + "location of database", "database" + }, +#endif + { "enable-http", 'H', arg_flag, &enable_http, "turn on HTTP support" }, +#ifdef KRB4 + { + "v4-realm", 'r', arg_string, &v4_realm, + "realm to serve v4-requests for" + }, +#endif +#ifdef KASERVER + { + "kaserver", 'K', arg_negative_flag, &enable_kaserver, + "turn off kaserver support" + }, +#endif + { "ports", 'P', arg_string, &port_str, + "ports to listen to" + }, + { "help", 'h', arg_flag, &help_flag }, + { "version", 'v', arg_flag, &version_flag } +}; + +static int num_args = sizeof(args) / sizeof(args[0]); + +static void +usage(int ret) +{ + arg_printusage (args, num_args, NULL, ""); + exit (ret); +} + +static void +get_dbinfo(krb5_config_section *cf) +{ + krb5_config_binding *top_binding = NULL; + krb5_config_binding *db_binding; + krb5_config_binding *default_binding = NULL; + struct dbinfo *di, **dt; + const char *default_dbname = HDB_DEFAULT_DB; + const char *default_mkey = HDB_DB_DIR "/m-key"; + const char *p; + + databases = NULL; + dt = &databases; + while((db_binding = (krb5_config_binding *) + krb5_config_get_next(context, cf, &top_binding, + krb5_config_list, + "kdc", + "database", + NULL))) { + p = krb5_config_get_string(context, db_binding, "realm", NULL); + if(p == NULL) { + if(default_binding) { + krb5_warnx(context, "WARNING: more than one realm-less " + "database specification"); + krb5_warnx(context, "WARNING: using the first encountered"); + } else + default_binding = db_binding; + continue; + } + di = calloc(1, sizeof(*di)); + di->realm = strdup(p); + p = krb5_config_get_string(context, db_binding, "dbname", NULL); + if(p) + di->dbname = strdup(p); + p = krb5_config_get_string(context, db_binding, "mkey_file", NULL); + if(p) + di->mkey_file = strdup(p); + *dt = di; + dt = &di->next; + } + if(default_binding) { + di = calloc(1, sizeof(*di)); + p = krb5_config_get_string(context, default_binding, "dbname", NULL); + if(p) { + di->dbname = strdup(p); + default_dbname = p; + } + p = krb5_config_get_string(context, default_binding, "mkey_file", NULL); + if(p) { + di->mkey_file = strdup(p); + default_mkey = p; + } + *dt = di; + dt = &di->next; + } else { + di = calloc(1, sizeof(*di)); + di->dbname = strdup(default_dbname); + di->mkey_file = strdup(default_mkey); + *dt = di; + dt = &di->next; + } + for(di = databases; di; di = di->next) { + if(di->dbname == NULL) + di->dbname = strdup(default_dbname); + if(di->mkey_file == NULL) { + p = strrchr(di->dbname, '.'); + if(p == NULL || strchr(p, '/') != NULL) + asprintf(&di->mkey_file, "%s.mkey", di->dbname); + else + asprintf(&di->mkey_file, "%.*s.mkey", + (int)(p - di->dbname), di->dbname); + } + } +} + +void +configure(int argc, char **argv) +{ + krb5_config_section *cf = NULL; + int optind = 0; + int e; + const char *p; + + while((e = getarg(args, num_args, argc, argv, &optind))) + warnx("error at argument `%s'", argv[optind]); + + if(help_flag) + usage (0); + + if (version_flag) { + print_version(NULL); + exit(0); + } + + argc -= optind; + argv += optind; + + if (argc != 0) + usage(1); + + if(config_file == NULL) + config_file = HDB_DB_DIR "/kdc.conf"; + + if(krb5_config_parse_file(config_file, &cf)) + cf = NULL; + + if(keyfile == NULL){ + p = krb5_config_get_string (context, cf, + "kdc", + "key-file", + NULL); + if(p) + keyfile = strdup(p); + } + + + get_dbinfo(cf); + + if(max_request_str){ + max_request = parse_bytes(max_request_str, NULL); + } + + if(max_request == 0){ + p = krb5_config_get_string (context, + cf, + "kdc", + "max-request", + NULL); + if(p) + max_request = parse_bytes(p, NULL); + } + + if(require_preauth == -1) + require_preauth = krb5_config_get_bool(context, cf, "kdc", + "require-preauth", NULL); + + if(port_str == NULL){ + p = krb5_config_get_string(context, cf, "kdc", "ports", NULL); + if (p != NULL) + port_str = strdup(p); + } + if(enable_http == -1) + enable_http = krb5_config_get_bool(context, cf, "kdc", + "enable-http", NULL); + check_ticket_addresses = + krb5_config_get_bool(context, cf, "kdc", + "check-ticket-addresses", NULL); + allow_null_ticket_addresses = + krb5_config_get_bool(context, cf, "kdc", + "allow-null-ticket-addresses", NULL); +#ifdef KRB4 + if(v4_realm == NULL){ + p = krb5_config_get_string (context, cf, + "kdc", + "v4-realm", + NULL); + if(p) + v4_realm = strdup(p); + } +#endif +#ifdef KASERVER + if (enable_kaserver == -1) + enable_kaserver = krb5_config_get_bool_default(context, cf, TRUE, + "kdc", + "enable-kaserver", + NULL); +#endif + + encode_as_rep_as_tgs_rep = krb5_config_get_bool(context, cf, "kdc", + "encode_as_rep_as_tgs_rep", + NULL); + + kdc_warn_pwexpire = krb5_config_get_time (context, cf, + "kdc", + "kdc_warn_pwexpire", + NULL); + kdc_openlog(cf); + if(cf) + krb5_config_file_free (context, cf); + if(max_request == 0) + max_request = 64 * 1024; + if(require_preauth == -1) + require_preauth = 1; + if (port_str == NULL) + port_str = "+"; +#ifdef KRB4 + if(v4_realm == NULL){ + v4_realm = malloc(40); /* REALM_SZ */ + krb_get_lrealm(v4_realm, 1); + } +#endif +} diff --git a/crypto/heimdal/kdc/connect.c b/crypto/heimdal/kdc/connect.c new file mode 100644 index 0000000..62b5bea --- /dev/null +++ b/crypto/heimdal/kdc/connect.c @@ -0,0 +1,727 @@ +/* + * Copyright (c) 1997-1999 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "kdc_locl.h" + +RCSID("$Id: connect.c,v 1.68 1999/12/02 17:04:58 joda Exp $"); + +struct port_desc{ + int family; + int type; + int port; +}; + +static struct port_desc *ports; +static int num_ports; + +static void +add_port(int family, int port, const char *protocol) +{ + int type; + int i; + + if(strcmp(protocol, "udp") == 0) + type = SOCK_DGRAM; + else if(strcmp(protocol, "tcp") == 0) + type = SOCK_STREAM; + else + return; + for(i = 0; i < num_ports; i++){ + if(ports[i].type == type + && ports[i].port == port + && ports[i].family == family) + return; + } + ports = realloc(ports, (num_ports + 1) * sizeof(*ports)); + ports[num_ports].family = family; + ports[num_ports].type = type; + ports[num_ports].port = port; + num_ports++; +} + +static void +add_port_service(int family, const char *service, int port, + const char *protocol) +{ + port = krb5_getportbyname (context, service, protocol, port); + add_port (family, port, protocol); +} + +static void +add_port_string (int family, const char *port_str, const char *protocol) +{ + struct servent *sp; + int port; + + sp = roken_getservbyname (port_str, protocol); + if (sp != NULL) { + port = sp->s_port; + } else { + char *end; + + port = htons(strtol(port_str, &end, 0)); + if (end == port_str) + return; + } + add_port (family, port, protocol); +} + +static void +add_standard_ports (int family) +{ + add_port_service(family, "kerberos", 88, "udp"); + add_port_service(family, "kerberos", 88, "tcp"); + add_port_service(family, "kerberos-sec", 88, "udp"); + add_port_service(family, "kerberos-sec", 88, "tcp"); + add_port_service(family, "kerberos-iv", 750, "udp"); + add_port_service(family, "kerberos-iv", 750, "tcp"); + if(enable_http) + add_port_service(family, "http", 80, "tcp"); +#ifdef KASERVER + if (enable_kaserver) + add_port_service(family, "afs3-kaserver", 7004, "udp"); +#endif +} + +static void +parse_ports(const char *str) +{ + char *pos = NULL; + char *p; + char *str_copy = strdup (str); + + p = strtok_r(str_copy, " \t", &pos); + while(p != NULL) { + if(strcmp(p, "+") == 0) { +#ifdef HAVE_IPV6 + add_standard_ports(AF_INET6); +#endif + add_standard_ports(AF_INET); + } else { + char *q = strchr(p, '/'); + if(q){ + *q++ = 0; +#ifdef HAVE_IPV6 + add_port_string(AF_INET6, p, q); +#endif + add_port_string(AF_INET, p, q); + }else { +#ifdef HAVE_IPV6 + add_port_string(AF_INET6, p, "udp"); + add_port_string(AF_INET6, p, "tcp"); +#endif + add_port_string(AF_INET, p, "udp"); + add_port_string(AF_INET, p, "tcp"); + } + } + + p = strtok_r(NULL, " \t", &pos); + } + free (str_copy); +} + +struct descr { + int s; + int type; + unsigned char *buf; + size_t size; + size_t len; + time_t timeout; +}; + +/* + * Create the socket (family, type, port) in `d' + */ + +static void +init_socket(struct descr *d, krb5_address *a, int family, int type, int port) +{ + krb5_error_code ret; + struct sockaddr_storage __ss; + struct sockaddr *sa = (struct sockaddr *)&__ss; + int sa_size; + + memset(d, 0, sizeof(*d)); + d->s = -1; + + ret = krb5_addr2sockaddr (a, sa, &sa_size, port); + if (ret) { + krb5_warn(context, ret, "krb5_anyaddr"); + close(d->s); + d->s = -1; + return; + } + + if (sa->sa_family != family) + return; + + d->s = socket(family, type, 0); + if(d->s < 0){ + krb5_warn(context, errno, "socket(%d, %d, 0)", family, type); + d->s = -1; + return; + } +#if defined(HAVE_SETSOCKOPT) && defined(SOL_SOCKET) && defined(SO_REUSEADDR) + { + int one = 1; + setsockopt(d->s, SOL_SOCKET, SO_REUSEADDR, (void *)&one, sizeof(one)); + } +#endif + d->type = type; + + if(bind(d->s, sa, sa_size) < 0){ + krb5_warn(context, errno, "bind(%d)", ntohs(port)); + close(d->s); + d->s = -1; + return; + } + if(type == SOCK_STREAM && listen(d->s, SOMAXCONN) < 0){ + krb5_warn(context, errno, "listen"); + close(d->s); + return; + } +} + +/* + * Allocate descriptors for all the sockets that we should listen on + * and return the number of them. + */ + +static int +init_sockets(struct descr **desc) +{ + krb5_error_code ret; + int i, j; + struct descr *d; + int num = 0; + krb5_addresses addresses; + + ret = krb5_get_all_server_addrs (context, &addresses); + if (ret) + krb5_err (context, 1, ret, "krb5_get_all_server_addrs"); + parse_ports(port_str); + d = malloc(addresses.len * num_ports * sizeof(*d)); + if (d == NULL) + krb5_errx(context, 1, "malloc(%u) failed", num_ports * sizeof(*d)); + + for (i = 0; i < num_ports; i++){ + for (j = 0; j < addresses.len; ++j) { + init_socket(&d[num], &addresses.val[j], + ports[i].family, ports[i].type, ports[i].port); + if(d[num].s != -1){ + char a_str[80]; + size_t len; + + krb5_print_address (&addresses.val[j], a_str, + sizeof(a_str), &len); + + kdc_log(5, "listening on %s port %u/%s", + a_str, + ntohs(ports[i].port), + (ports[i].type == SOCK_STREAM) ? "tcp" : "udp"); + /* XXX */ + num++; + } + } + } + krb5_free_addresses (context, &addresses); + d = realloc(d, num * sizeof(*d)); + if (d == NULL && num != 0) + krb5_errx(context, 1, "realloc(%u) failed", num * sizeof(*d)); + *desc = d; + return num; +} + + +static int +process_request(unsigned char *buf, + size_t len, + krb5_data *reply, + int *sendlength, + const char *from, + struct sockaddr *addr) +{ + KDC_REQ req; +#ifdef KRB4 + Ticket ticket; +#endif + krb5_error_code ret; + size_t i; + + gettimeofday(&now, NULL); + if(decode_AS_REQ(buf, len, &req, &i) == 0){ + ret = as_rep(&req, reply, from, addr); + free_AS_REQ(&req); + return ret; + }else if(decode_TGS_REQ(buf, len, &req, &i) == 0){ + ret = tgs_rep(&req, reply, from, addr); + free_TGS_REQ(&req); + return ret; + } +#ifdef KRB4 + else if(maybe_version4(buf, len)){ + *sendlength = 0; /* elbitapmoc sdrawkcab XXX */ + do_version4(buf, len, reply, from, (struct sockaddr_in*)addr); + return 0; + }else if(decode_Ticket(buf, len, &ticket, &i) == 0){ + ret = do_524(&ticket, reply, from, addr); + free_Ticket(&ticket); + return ret; + } +#endif +#ifdef KASERVER + else if (enable_kaserver) { + ret = do_kaserver (buf, len, reply, from, (struct sockaddr_in*)addr); + return ret; + } +#endif + + return -1; +} + +static void +addr_to_string(struct sockaddr *addr, size_t addr_len, char *str, size_t len) +{ + krb5_address a; + krb5_sockaddr2address(addr, &a); + if(krb5_print_address(&a, str, len, &len) == 0) { + krb5_free_address(context, &a); + return; + } + krb5_free_address(context, &a); + snprintf(str, len, "<family=%d>", addr->sa_family); +} + +static void +do_request(void *buf, size_t len, int sendlength, + int socket, struct sockaddr *from, size_t from_len) +{ + krb5_error_code ret; + krb5_data reply; + char addr[128]; + + addr_to_string(from, from_len, addr, sizeof(addr)); + + reply.length = 0; + ret = process_request(buf, len, &reply, &sendlength, addr, from); + if(reply.length){ + kdc_log(5, "sending %d bytes to %s", reply.length, addr); + if(sendlength){ + unsigned char len[4]; + len[0] = (reply.length >> 24) & 0xff; + len[1] = (reply.length >> 16) & 0xff; + len[2] = (reply.length >> 8) & 0xff; + len[3] = reply.length & 0xff; + if(sendto(socket, len, sizeof(len), 0, from, from_len) < 0) { + kdc_log (0, "sendto(%s): %s", addr, strerror(errno)); + krb5_data_free(&reply); + return; + } + } + if(sendto(socket, reply.data, reply.length, 0, from, from_len) < 0) { + kdc_log (0, "sendto(%s): %s", addr, strerror(errno)); + krb5_data_free(&reply); + return; + } + krb5_data_free(&reply); + } + if(ret) + kdc_log(0, "Failed processing %lu byte request from %s", + (unsigned long)len, addr); +} + +static void +handle_udp(struct descr *d) +{ + unsigned char *buf; + struct sockaddr_storage __ss; + struct sockaddr *sa = (struct sockaddr *)&__ss; + int from_len; + int n; + + buf = malloc(max_request); + if(buf == NULL){ + kdc_log(0, "Failed to allocate %u bytes", max_request); + return; + } + + from_len = sizeof(__ss); + n = recvfrom(d->s, buf, max_request, 0, + sa, &from_len); + if(n < 0){ + krb5_warn(context, errno, "recvfrom"); + goto out; + } + if(n == 0) { + goto out; + } + do_request(buf, n, 0, d->s, sa, from_len); +out: + free (buf); +} + +static void +clear_descr(struct descr *d) +{ + if(d->buf) + memset(d->buf, 0, d->size); + d->len = 0; + if(d->s != -1) + close(d->s); + d->s = -1; +} + + +/* remove HTTP %-quoting from buf */ +static int +de_http(char *buf) +{ + char *p, *q; + for(p = q = buf; *p; p++, q++) { + if(*p == '%') { + unsigned int x; + if(sscanf(p + 1, "%2x", &x) != 1) + return -1; + *q = x; + p += 2; + } else + *q = *p; + } + *q = '\0'; + return 0; +} + +#define TCP_TIMEOUT 4 + +/* + * accept a new TCP connection on `d[index]' + */ + +static void +add_new_tcp (struct descr *d, int index, int min_free) +{ + struct sockaddr_storage __ss; + struct sockaddr *sa = (struct sockaddr *)&__ss; + int s; + int from_len; + + from_len = sizeof(__ss); + s = accept(d[index].s, sa, &from_len); + if(s < 0){ + krb5_warn(context, errno, "accept"); + return; + } + if(min_free == -1){ + close(s); + return; + } + + d[min_free].s = s; + d[min_free].timeout = time(NULL) + TCP_TIMEOUT; + d[min_free].type = SOCK_STREAM; +} + +/* + * Grow `d' to handle at least `n'. + * Return != 0 if fails + */ + +static int +grow_descr (struct descr *d, size_t n) +{ + if (d->size - d->len < n) { + unsigned char *tmp; + + d->size += max(1024, d->len + n); + if (d->size >= max_request) { + kdc_log(0, "Request exceeds max request size (%u bytes).", + d->size); + clear_descr(d); + return -1; + } + tmp = realloc (d->buf, d->size); + if (tmp == NULL) { + kdc_log(0, "Failed to re-allocate %u bytes.", d->size); + clear_descr(d); + return -1; + } + d->buf = tmp; + } + return 0; +} + +/* + * Try to handle the TCP data at `d->buf, d->len'. + * Return -1 if failed, 0 if succesful, and 1 if data is complete. + */ + +static int +handle_vanilla_tcp (struct descr *d) +{ + krb5_storage *sp; + int32_t len; + + sp = krb5_storage_from_mem(d->buf, d->len); + if (sp == NULL) { + kdc_log (0, "krb5_storage_from_mem failed"); + return -1; + } + krb5_ret_int32(sp, &len); + krb5_storage_free(sp); + if(d->len - 4 >= len) { + memcpy(d->buf, d->buf + 4, d->len - 4); + return 1; + } + return 0; +} + +/* + * Try to handle the TCP/HTTP data at `d->buf, d->len'. + * Return -1 if failed, 0 if succesful, and 1 if data is complete. + */ + +static int +handle_http_tcp (struct descr *d, const char *addr) +{ + char *s, *p, *t; + void *data; + char *proto; + int len; + + s = (char *)d->buf; + + p = strstr(s, "\r\n"); + if (p == NULL) { + kdc_log(0, "Malformed HTTP request from %s", addr); + return -1; + } + *p = 0; + + p = NULL; + t = strtok_r(s, " \t", &p); + if (t == NULL) { + kdc_log(0, "Malformed HTTP request from %s", addr); + return -1; + } + t = strtok_r(NULL, " \t", &p); + if(t == NULL) { + kdc_log(0, "Malformed HTTP request from %s", addr); + return -1; + } + data = malloc(strlen(t)); + if (data == NULL) { + kdc_log(0, "Failed to allocate %u bytes", strlen(t)); + return -1; + } + if(*t == '/') + t++; + if(de_http(t) != 0) { + kdc_log(0, "Malformed HTTP request from %s", addr); + kdc_log(5, "Request: %s", t); + free(data); + return -1; + } + proto = strtok_r(NULL, " \t", &p); + if (proto == NULL) { + kdc_log(0, "Malformed HTTP request from %s", addr); + free(data); + return -1; + } + len = base64_decode(t, data); + if(len <= 0){ + const char *msg = + " 404 Not found\r\n" + "Server: Heimdal/" VERSION "\r\n" + "Content-type: text/html\r\n" + "Content-transfer-encoding: 8bit\r\n\r\n" + "<TITLE>404 Not found</TITLE>\r\n" + "<H1>404 Not found</H1>\r\n" + "That page doesn't exist, maybe you are looking for " + "<A HREF=\"http://www.pdc.kth.se/heimdal\">Heimdal</A>?\r\n"; + write(d->s, proto, strlen(proto)); + write(d->s, msg, strlen(msg)); + kdc_log(0, "HTTP request from %s is non KDC request", addr); + kdc_log(5, "Request: %s", t); + free(data); + return -1; + } + { + const char *msg = + " 200 OK\r\n" + "Server: Heimdal/" VERSION "\r\n" + "Content-type: application/octet-stream\r\n" + "Content-transfer-encoding: binary\r\n\r\n"; + write(d->s, proto, strlen(proto)); + write(d->s, msg, strlen(msg)); + } + memcpy(d->buf, data, len); + d->len = len; + free(data); + return 1; +} + +/* + * Handle incoming data to the TCP socket in `d[index]' + */ + +static void +handle_tcp(struct descr *d, int index, int min_free) +{ + unsigned char buf[1024]; + char addr[32]; + struct sockaddr_storage __ss; + struct sockaddr *sa = (struct sockaddr *)&__ss; + int from_len; + int n; + int ret = 0; + + if (d[index].timeout == 0) { + add_new_tcp (d, index, min_free); + return; + } + + /* + * We can't trust recvfrom to return an address so we always call + * getpeername. + */ + + n = recvfrom(d[index].s, buf, sizeof(buf), 0, NULL, NULL); + if(n < 0){ + krb5_warn(context, errno, "recvfrom"); + return; + } + from_len = sizeof(__ss); + if (getpeername(d[index].s, sa, &from_len) < 0) { + krb5_warn(context, errno, "getpeername"); + return; + } + addr_to_string(sa, from_len, addr, sizeof(addr)); + if (grow_descr (&d[index], n)) + return; + memcpy(d[index].buf + d[index].len, buf, n); + d[index].len += n; + if(d[index].len > 4 && d[index].buf[0] == 0) { + ret = handle_vanilla_tcp (&d[index]); + } else if(enable_http && + d[index].len >= 4 && + strncmp((char *)d[index].buf, "GET ", 4) == 0 && + strncmp((char *)d[index].buf + d[index].len - 4, + "\r\n\r\n", 4) == 0) { + ret = handle_http_tcp (&d[index], addr); + if (ret < 0) + clear_descr (d + index); + } else if (d[index].len > 4) { + kdc_log (0, "TCP data of strange type from %s", addr); + return; + } + if (ret < 0) + return; + else if (ret == 1) { + do_request(d[index].buf, d[index].len, 1, + d[index].s, sa, from_len); + clear_descr(d + index); + } +} + +void +loop(void) +{ + struct descr *d; + int ndescr; + + ndescr = init_sockets(&d); + if(ndescr <= 0) + krb5_errx(context, 1, "No sockets!"); + while(exit_flag == 0){ + struct timeval tmout; + fd_set fds; + int min_free = -1; + int max_fd = 0; + int i; + FD_ZERO(&fds); + for(i = 0; i < ndescr; i++){ + if(d[i].s >= 0){ + if(d[i].type == SOCK_STREAM && + d[i].timeout && d[i].timeout < time(NULL)){ + struct sockaddr sa; + int salen = sizeof(sa); + char addr[32]; + + getpeername(d[i].s, &sa, &salen); + addr_to_string(&sa, salen, addr, sizeof(addr)); + kdc_log(1, "TCP-connection from %s expired after %u bytes", + addr, d[i].len); + clear_descr(&d[i]); + continue; + } + if(max_fd < d[i].s) + max_fd = d[i].s; + FD_SET(d[i].s, &fds); + }else if(min_free < 0 || i < min_free) + min_free = i; + } + if(min_free == -1){ + struct descr *tmp; + tmp = realloc(d, (ndescr + 4) * sizeof(*d)); + if(tmp == NULL) + krb5_warnx(context, "No memory"); + else{ + d = tmp; + memset(d + ndescr, 0, 4 * sizeof(*d)); + for(i = ndescr; i < ndescr + 4; i++) + d[i].s = -1; + min_free = ndescr; + ndescr += 4; + } + } + + tmout.tv_sec = TCP_TIMEOUT; + tmout.tv_usec = 0; + switch(select(max_fd + 1, &fds, 0, 0, &tmout)){ + case 0: + break; + case -1: + krb5_warn(context, errno, "select"); + break; + default: + for(i = 0; i < ndescr; i++) + if(d[i].s >= 0 && FD_ISSET(d[i].s, &fds)) { + if(d[i].type == SOCK_DGRAM) + handle_udp(&d[i]); + else if(d[i].type == SOCK_STREAM) + handle_tcp(d, i, min_free); + } + } + } + free (d); +} diff --git a/crypto/heimdal/kdc/headers.h b/crypto/heimdal/kdc/headers.h new file mode 100644 index 0000000..f9c3eb8 --- /dev/null +++ b/crypto/heimdal/kdc/headers.h @@ -0,0 +1,96 @@ +/* + * Copyright (c) 1997, 1998 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id: headers.h,v 1.5 1999/12/02 17:04:59 joda Exp $ + */ + +#ifndef __HEADERS_H__ +#define __HEADERS_H__ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <signal.h> +#include <stdarg.h> +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#ifdef HAVE_FCNTL_H +#include <fcntl.h> +#endif +#ifdef HAVE_SYS_SELECT_H +#include <sys/select.h> +#endif +#ifdef HAVE_SYS_SOCKET_H +#include <sys/socket.h> +#endif +#ifdef HAVE_NETINET_IN_H +#include <netinet/in.h> +#endif +#ifdef HAVE_NETINET_IN6_H +#include <netinet/in6.h> +#endif +#ifdef HAVE_NETINET6_IN6_H +#include <netinet6/in6.h> +#endif +#ifdef HAVE_ARPA_INET_H +#include <arpa/inet.h> +#endif +#ifdef HAVE_NETDB_H +#include <netdb.h> +#endif +#include <err.h> +#include <roken.h> +#include <getarg.h> +#include <base64.h> +#include <parse_units.h> +#include <krb5.h> +#include <hdb.h> +#include <hdb_err.h> +#include <der.h> /* copy_octet_string */ + +#ifdef KRB4 +#include <krb.h> +#include <prot.h> +#define Principal Principal4 +#include <krb_db.h> +#endif + +#define ALLOC(X) ((X) = malloc(sizeof(*(X)))) + +#endif /* __HEADERS_H__ */ diff --git a/crypto/heimdal/kdc/hprop-common.c b/crypto/heimdal/kdc/hprop-common.c new file mode 100644 index 0000000..660725f --- /dev/null +++ b/crypto/heimdal/kdc/hprop-common.c @@ -0,0 +1,83 @@ +/* + * Copyright (c) 1997, 1998 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "hprop.h" + +RCSID("$Id: hprop-common.c,v 1.7 1999/12/02 17:04:59 joda Exp $"); + +krb5_error_code +send_priv(krb5_context context, krb5_auth_context ac, + krb5_data *data, int fd) +{ + krb5_data packet; + krb5_error_code ret; + + ret = krb5_mk_priv (context, + ac, + data, + &packet, + NULL); + if (ret) + return ret; + + ret = krb5_write_message (context, &fd, &packet); + krb5_data_free(&packet); + return ret; +} + +krb5_error_code +recv_priv(krb5_context context, krb5_auth_context ac, int fd, krb5_data *out) +{ + krb5_error_code ret; + krb5_data data; + + ret = krb5_read_message (context, &fd, &data); + if (ret) + return ret; + + ret = krb5_rd_priv(context, ac, &data, out, NULL); + krb5_data_free (&data); + return ret; +} + +krb5_error_code +send_clear(krb5_context context, int fd, krb5_data data) +{ + return krb5_write_message (context, &fd, &data); +} + +krb5_error_code +recv_clear(krb5_context context, int fd, krb5_data *out) +{ + return krb5_read_message (context, &fd, out); +} diff --git a/crypto/heimdal/kdc/hprop.8 b/crypto/heimdal/kdc/hprop.8 new file mode 100644 index 0000000..d700577 --- /dev/null +++ b/crypto/heimdal/kdc/hprop.8 @@ -0,0 +1,66 @@ +.\" $Id: hprop.8,v 1.3 1997/09/03 20:33:04 joda Exp $ +.\" +.Dd September 3, 1997 +.Dt HPROP 8 +.Os HEIMDAL +.Sh NAME +.Nm hprop +.Nd +propagate the KDC database +.Sh SYNOPSIS +.Nm +.Op Fl 4DEhnv +.Op Fl d Ar file +.Op Fl -database= Ns Ar file +.Op Fl -decrypt +.Op Fl -encrypt +.Op Fl -help +.Op Fl k +.Op Fl -keytab= Ns Ar file +.Op Fl m Ar file +.Op Fl -master-key= Ns Ar file +.Op Fl -stdout +.Op Fl -v4-db +.Op Fl -verbose +.Op Fl -version +.Ar host ... +.Sh DESCRIPTION +.Nm +propagates the database from a master KDC to a slave. It connects to +all +.Ar hosts +specified on the command by opening a TCP connection to port 754 +(service hprop) and sends the database in encrypted form. +.Pp +Options supported: +.Bl -tag -width Ds +.It Fl d Ar file +.It Fl -database= Ns Ar file +The database to be propagated. +.It Fl D +.It Fl -decrypt +The encryption keys in the database can either be in clear, or +encrypted with a master key. This option thansmits the database with +unencrypted keys. +.It Fl E +.It Fl -encrypt +This option thansmits the database with encrypted keys. +.It Fl k +.It Fl -keytab= Ns Ar file +The keytab to use for fetching the key to be used for authenticating +to the propagation daemon(s). The key +.Pa kadmin/hprop +is used from this keytab. +.It Fl m Ar file +.It Fl -master-key= Ns Ar file +Where to find the master key to encrypt or decrypt keys with. +.It Fl n +.It Fl -stdout +Dump the database on stdout, in a format that can be fed to hpropd. +.It Fl 4 +.It Fl -v4-db +Use a version 4 database. This option is only available if the code is +compiled with Kerberos 4 support. +.El +.Sh SEE ALSO +.Xr hpropd 8 diff --git a/crypto/heimdal/kdc/hprop.c b/crypto/heimdal/kdc/hprop.c new file mode 100644 index 0000000..3be6a6f --- /dev/null +++ b/crypto/heimdal/kdc/hprop.c @@ -0,0 +1,676 @@ +/* + * Copyright (c) 1997, 1998, 1999 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "hprop.h" + +RCSID("$Id: hprop.c,v 1.40 1999/12/04 18:02:18 assar Exp $"); + +static int version_flag; +static int help_flag; +static char *ktname = HPROP_KEYTAB; +static char *database; +static char *mkeyfile; +static int to_stdout; +static int verbose_flag; +static int encrypt_flag; +static int decrypt_flag; +static EncryptionKey mkey5; +static krb5_data msched5; + +static int v4_db; +static int ka_db; +static char *afs_cell; + +#ifdef KRB4 +static char *realm; + +#ifdef KASERVER_DB +static int kaspecials_flag; +#endif +#endif + +static int +open_socket(krb5_context context, const char *hostname) +{ + struct addrinfo *ai, *a; + struct addrinfo hints; + int error; + char portstr[NI_MAXSERV]; + + memset (&hints, 0, sizeof(hints)); + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + + snprintf (portstr, sizeof(portstr), + "%u", + ntohs(krb5_getportbyname (context, "hprop", "tcp", HPROP_PORT))); + + error = getaddrinfo (hostname, portstr, &hints, &ai); + if (error) { + warnx ("%s: %s", hostname, gai_strerror(error)); + return -1; + } + + for (a = ai; a != NULL; a = a->ai_next) { + int s; + + s = socket (a->ai_family, a->ai_socktype, a->ai_protocol); + if (s < 0) + continue; + if (connect (s, a->ai_addr, a->ai_addrlen) < 0) { + warn ("connect(%s)", hostname); + close (s); + continue; + } + freeaddrinfo (ai); + return s; + } + warnx ("failed to contact %s", hostname); + freeaddrinfo (ai); + return -1; +} + +struct prop_data{ + krb5_context context; + krb5_auth_context auth_context; + int sock; +}; + +int hdb_entry2value(krb5_context, hdb_entry*, krb5_data*); + +static krb5_error_code +v5_prop(krb5_context context, HDB *db, hdb_entry *entry, void *appdata) +{ + krb5_error_code ret; + struct prop_data *pd = appdata; + krb5_data data; + + if(encrypt_flag) + _hdb_seal_keys_int(entry, 0, msched5); + if(decrypt_flag) + _hdb_unseal_keys_int(entry, 0, msched5); + + ret = hdb_entry2value(context, entry, &data); + if(ret) return ret; + + if(to_stdout) + ret = send_clear(context, STDOUT_FILENO, data); + else + ret = send_priv(context, pd->auth_context, &data, pd->sock); + krb5_data_free(&data); + return ret; +} + +#ifdef KRB4 +static des_cblock mkey4; +static des_key_schedule msched4; +static char realm_buf[REALM_SZ]; + +static int +v4_prop(void *arg, Principal *p) +{ + struct prop_data *pd = arg; + hdb_entry ent; + krb5_error_code ret; + + memset(&ent, 0, sizeof(ent)); + + ret = krb5_425_conv_principal(pd->context, p->name, p->instance, realm, + &ent.principal); + if(ret){ + krb5_warn(pd->context, ret, + "krb5_425_conv_principal %s.%s@%s", + p->name, p->instance, realm); + return 0; + } + + if(verbose_flag) { + char *s; + krb5_unparse_name_short(pd->context, ent.principal, &s); + krb5_warnx(pd->context, "%s.%s -> %s", p->name, p->instance, s); + free(s); + } + + ent.kvno = p->key_version; + ent.keys.len = 3; + ent.keys.val = malloc(ent.keys.len * sizeof(*ent.keys.val)); + ent.keys.val[0].mkvno = NULL; +#if 0 + ent.keys.val[0].mkvno = malloc (sizeof(*ent.keys.val[0].mkvno)); + *(ent.keys.val[0].mkvno) = p->kdc_key_ver; /* XXX */ +#endif + ent.keys.val[0].salt = calloc(1, sizeof(*ent.keys.val[0].salt)); + ent.keys.val[0].salt->type = pa_pw_salt; + ent.keys.val[0].key.keytype = ETYPE_DES_CBC_MD5; + krb5_data_alloc(&ent.keys.val[0].key.keyvalue, sizeof(des_cblock)); + + { + unsigned char *key = ent.keys.val[0].key.keyvalue.data; + unsigned char null_key[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + memcpy(key, &p->key_low, 4); + memcpy(key + 4, &p->key_high, 4); + kdb_encrypt_key((des_cblock*)key, (des_cblock*)key, + &mkey4, msched4, DES_DECRYPT); + if(memcmp(key, null_key, sizeof(null_key)) == 0) { + free_Key(&ent.keys.val[0]); + ent.keys.val = 0; + ent.flags.invalid = 1; + } + } + copy_Key(&ent.keys.val[0], &ent.keys.val[1]); + ent.keys.val[1].key.keytype = ETYPE_DES_CBC_MD4; + copy_Key(&ent.keys.val[0], &ent.keys.val[2]); + ent.keys.val[2].key.keytype = ETYPE_DES_CBC_CRC; + + ALLOC(ent.max_life); + *ent.max_life = krb_life_to_time(0, p->max_life); + if(*ent.max_life == NEVERDATE){ + free(ent.max_life); + ent.max_life = NULL; + } + + ALLOC(ent.pw_end); + *ent.pw_end = p->exp_date; + ret = krb5_make_principal(pd->context, &ent.created_by.principal, + realm, + "kadmin", + "hprop", + NULL); + if(ret){ + krb5_warn(pd->context, ret, "krb5_make_principal"); + ret = 0; + goto out; + } + ent.created_by.time = time(NULL); + ALLOC(ent.modified_by); + ret = krb5_425_conv_principal(pd->context, p->mod_name, p->mod_instance, + realm, &ent.modified_by->principal); + if(ret){ + krb5_warn(pd->context, ret, "%s.%s@%s", p->name, p->instance, realm); + ent.modified_by->principal = NULL; + ret = 0; + goto out; + } + ent.modified_by->time = p->mod_date; + + ent.flags.forwardable = 1; + ent.flags.renewable = 1; + ent.flags.proxiable = 1; + ent.flags.postdate = 1; + ent.flags.client = 1; + ent.flags.server = 1; + + /* special case password changing service */ + if(strcmp(p->name, "changepw") == 0 && + strcmp(p->instance, "kerberos") == 0) { + ent.flags.forwardable = 0; + ent.flags.renewable = 0; + ent.flags.proxiable = 0; + ent.flags.postdate = 0; + ent.flags.initial = 1; + ent.flags.change_pw = 1; + } + + ret = v5_prop(pd->context, NULL, &ent, pd); + + if (strcmp (p->name, "krbtgt") == 0 + && strcmp (realm, p->instance) != 0) { + krb5_free_principal (pd->context, ent.principal); + ret = krb5_425_conv_principal (pd->context, p->name, + realm, p->instance, + &ent.principal); + if (ret == 0) + ret = v5_prop (pd->context, NULL, &ent, pd); + } + +out: + hdb_free_entry(pd->context, &ent); + return ret; +} + +#ifdef KASERVER_DB + +#include "kadb.h" + +/* read a `ka_entry' from `fd' at offset `pos' */ +static void +read_block(krb5_context context, int fd, int32_t pos, void *buf, size_t len) +{ + krb5_error_code ret; + if(lseek(fd, 64 + pos, SEEK_SET) == (off_t)-1) + krb5_err(context, 1, errno, "lseek(%u)", 64 + pos); + ret = read(fd, buf, len); + if(ret < 0) + krb5_err(context, 1, errno, "read(%u)", len); + if(ret != len) + krb5_errx(context, 1, "read(%u) = %u", len, ret); +} + +static int +ka_convert(struct prop_data *pd, int fd, struct ka_entry *ent, + const char *cell) +{ + int32_t flags = ntohl(ent->flags); + krb5_error_code ret; + hdb_entry hdb; + + if(!kaspecials_flag + && (flags & KAFNORMAL) == 0) /* remove special entries */ + return 0; + memset(&hdb, 0, sizeof(hdb)); + ret = krb5_425_conv_principal(pd->context, ent->name, ent->instance, realm, + &hdb.principal); + if(ret) { + krb5_warn(pd->context, ret, + "krb5_425_conv_principal (%s.%s@%s)", + ent->name, ent->instance, realm); + return 0; + } + hdb.kvno = ntohl(ent->kvno); + hdb.keys.len = 3; + hdb.keys.val = malloc(hdb.keys.len * sizeof(*hdb.keys.val)); + hdb.keys.val[0].mkvno = NULL; + hdb.keys.val[0].salt = calloc(1, sizeof(*hdb.keys.val[0].salt)); + hdb.keys.val[0].salt->type = hdb_afs3_salt; + hdb.keys.val[0].salt->salt.data = strdup(cell); + hdb.keys.val[0].salt->salt.length = strlen(cell); + + hdb.keys.val[0].key.keytype = ETYPE_DES_CBC_MD5; + krb5_data_copy(&hdb.keys.val[0].key.keyvalue, ent->key, sizeof(ent->key)); + copy_Key(&hdb.keys.val[0], &hdb.keys.val[1]); + hdb.keys.val[1].key.keytype = ETYPE_DES_CBC_MD4; + copy_Key(&hdb.keys.val[0], &hdb.keys.val[2]); + hdb.keys.val[2].key.keytype = ETYPE_DES_CBC_CRC; + + ALLOC(hdb.max_life); + *hdb.max_life = ntohl(ent->max_life); + + if(ntohl(ent->pw_end) != NEVERDATE && ntohl(ent->pw_end) != -1){ + ALLOC(hdb.pw_end); + *hdb.pw_end = ntohl(ent->pw_end); + } + + ret = krb5_make_principal(pd->context, &hdb.created_by.principal, + realm, + "kadmin", + "hprop", + NULL); + hdb.created_by.time = time(NULL); + + if(ent->mod_ptr){ + struct ka_entry mod; + ALLOC(hdb.modified_by); + read_block(pd->context, fd, ntohl(ent->mod_ptr), &mod, sizeof(mod)); + + krb5_425_conv_principal(pd->context, mod.name, mod.instance, realm, + &hdb.modified_by->principal); + hdb.modified_by->time = ntohl(ent->mod_time); + memset(&mod, 0, sizeof(mod)); + } + + hdb.flags.forwardable = 1; + hdb.flags.renewable = 1; + hdb.flags.proxiable = 1; + hdb.flags.postdate = 1; + /* XXX - AFS 3.4a creates krbtgt.REALMOFCELL as NOTGS+NOSEAL */ + if (strcmp(ent->name, "krbtgt") == 0 && + (flags & (KAFNOTGS|KAFNOSEAL)) == (KAFNOTGS|KAFNOSEAL)) + flags &= ~(KAFNOTGS|KAFNOSEAL); + + hdb.flags.client = (flags & KAFNOTGS) == 0; + hdb.flags.server = (flags & KAFNOSEAL) == 0; + + ret = v5_prop(pd->context, NULL, &hdb, pd); + hdb_free_entry(pd->context, &hdb); + return ret; +} + +static int +ka_dump(struct prop_data *pd, const char *file, const char *cell) +{ + struct ka_header header; + int i; + int fd = open(file, O_RDONLY); + + if(fd < 0) + krb5_err(pd->context, 1, errno, "open(%s)", file); + read_block(pd->context, fd, 0, &header, sizeof(header)); + if(header.version1 != header.version2) + krb5_errx(pd->context, 1, "Version mismatch in header: %d/%d", + ntohl(header.version1), ntohl(header.version2)); + if(ntohl(header.version1) != 5) + krb5_errx(pd->context, 1, "Unknown database version %d (expected 5)", + ntohl(header.version1)); + for(i = 0; i < ntohl(header.hashsize); i++){ + int32_t pos = ntohl(header.hash[i]); + while(pos){ + struct ka_entry ent; + read_block(pd->context, fd, pos, &ent, sizeof(ent)); + ka_convert(pd, fd, &ent, cell); + pos = ntohl(ent.next); + } + } + return 0; +} + +#endif /* KASERVER_DB */ + +#endif /* KRB4 */ + + +struct getargs args[] = { + { "master-key", 'm', arg_string, &mkeyfile, "v5 master key file", "file" }, +#ifdef KRB4 +#endif + { "database", 'd', arg_string, &database, "database", "file" }, +#ifdef KRB4 + { "v4-db", '4', arg_flag, &v4_db, "use version 4 database" }, + { "v4-realm", 'r', arg_string, &realm, "v4 realm to use" }, +#endif +#ifdef KASERVER_DB + { "ka-db", 'K', arg_flag, &ka_db, "use kaserver database" }, + { "cell", 'c', arg_string, &afs_cell, "name of AFS cell" }, + { "kaspecials", 'S', arg_flag, &kaspecials_flag, "dump KASPECIAL keys"}, +#endif + { "keytab", 'k', arg_string, &ktname, "keytab to use for authentication", "keytab" }, + { "decrypt", 'D', arg_flag, &decrypt_flag, "decrypt keys" }, + { "encrypt", 'E', arg_flag, &encrypt_flag, "encrypt keys" }, + { "stdout", 'n', arg_flag, &to_stdout, "dump to stdout" }, + { "verbose", 'v', arg_flag, &verbose_flag }, + { "version", 0, arg_flag, &version_flag }, + { "help", 'h', arg_flag, &help_flag } +}; + +static int num_args = sizeof(args) / sizeof(args[0]); + +static void +usage(int ret) +{ + arg_printusage (args, num_args, NULL, "host ..."); + exit (ret); +} + +static void +get_creds(krb5_context context, krb5_ccache *cache) +{ + krb5_keytab keytab; + krb5_principal client; + krb5_error_code ret; + krb5_get_init_creds_opt init_opts; + krb5_preauthtype preauth = KRB5_PADATA_ENC_TIMESTAMP; + krb5_creds creds; + + ret = krb5_kt_resolve(context, ktname, &keytab); + if(ret) krb5_err(context, 1, ret, "krb5_kt_resolve"); + + ret = krb5_make_principal(context, &client, NULL, + "kadmin", HPROP_NAME, NULL); + if(ret) krb5_err(context, 1, ret, "krb5_make_principal"); + + krb5_get_init_creds_opt_init(&init_opts); + krb5_get_init_creds_opt_set_preauth_list(&init_opts, &preauth, 1); + + ret = krb5_get_init_creds_keytab(context, &creds, client, keytab, 0, NULL, &init_opts); + if(ret) krb5_err(context, 1, ret, "krb5_get_init_creds"); + + ret = krb5_kt_close(context, keytab); + if(ret) krb5_err(context, 1, ret, "krb5_kt_close"); + + ret = krb5_cc_gen_new(context, &krb5_mcc_ops, cache); + if(ret) krb5_err(context, 1, ret, "krb5_cc_gen_new"); + + ret = krb5_cc_initialize(context, *cache, client); + if(ret) krb5_err(context, 1, ret, "krb5_cc_initialize"); + + ret = krb5_cc_store_cred(context, *cache, &creds); + if(ret) krb5_err(context, 1, ret, "krb5_cc_store_cred"); +} + +static void +iterate (krb5_context context, + const char *database, + const char *afs_cell, + HDB *db, + int v4_db, int ka_db, + struct prop_data *pd) +{ +#ifdef KRB4 + if(v4_db) { + int e = kerb_db_iterate ((k_iter_proc_t)v4_prop, pd); + if(e) + krb5_errx(context, 1, "kerb_db_iterate: %s", + krb_get_err_text(e)); +#ifdef KASERVER_DB + } else if(ka_db) { + int e = ka_dump(pd, database, afs_cell); + if(e) + krb5_errx(context, 1, "ka_dump: %s", krb_get_err_text(e)); +#endif + } else +#endif + { + krb5_error_code ret = hdb_foreach(context, db, HDB_F_DECRYPT, + v5_prop, pd); + if(ret) + krb5_err(context, 1, ret, "hdb_foreach"); + } +} + +static int +dump_database (krb5_context context, int v4_db, int ka_db, + const char *database, const char *afs_cell, + HDB *db) +{ + struct prop_data pd; + + pd.context = context; + pd.auth_context = NULL; + pd.sock = STDOUT_FILENO; + + iterate (context, database, afs_cell, db, v4_db, ka_db, &pd); + return 0; +} + +static int +propagate_database (krb5_context context, int v4_db, int ka_db, + const char *database, const char *afs_cell, + HDB *db, krb5_ccache ccache, + int optind, int argc, char **argv) +{ + krb5_principal server; + krb5_error_code ret; + int i; + + for(i = optind; i < argc; i++){ + krb5_auth_context auth_context; + int fd; + struct prop_data pd; + krb5_data data; + + fd = open_socket(context, argv[i]); + if(fd < 0) { + krb5_warn (context, errno, "connect %s", argv[i]); + continue; + } + + ret = krb5_sname_to_principal(context, argv[i], + HPROP_NAME, KRB5_NT_SRV_HST, &server); + if(ret) { + krb5_warn(context, ret, "krb5_sname_to_principal(%s)", argv[i]); + close(fd); + continue; + } + + auth_context = NULL; + ret = krb5_sendauth(context, + &auth_context, + &fd, + HPROP_VERSION, + NULL, + server, + AP_OPTS_MUTUAL_REQUIRED, + NULL, /* in_data */ + NULL, /* in_creds */ + ccache, + NULL, + NULL, + NULL); + + if(ret) { + krb5_warn(context, ret, "krb5_sendauth"); + close(fd); + continue; + } + + pd.context = context; + pd.auth_context = auth_context; + pd.sock = fd; + + iterate (context, database, afs_cell, db, + v4_db, ka_db, &pd); + + data.data = NULL; + data.length = 0; + ret = send_priv(context, auth_context, &data, fd); + if(ret) + krb5_warn(context, ret, "send_priv"); + + ret = recv_priv(context, auth_context, fd, &data); + if(ret) + krb5_warn(context, ret, "recv_priv"); + else + krb5_data_free (&data); + + krb5_auth_con_free(context, auth_context); + close(fd); + } + return 0; +} + +int +main(int argc, char **argv) +{ + krb5_error_code ret; + krb5_context context; + krb5_ccache ccache; + HDB *db; + int optind = 0; + + set_progname(argv[0]); + + if(getarg(args, num_args, argc, argv, &optind)) + usage(1); + + if(help_flag) + usage(0); + + if(version_flag){ + print_version(NULL); + exit(0); + } + + ret = krb5_init_context(&context); + if(ret) + exit(1); + + if(encrypt_flag && decrypt_flag) + krb5_errx(context, 1, + "Only one of `--encrypt' and `--decrypt' is meaningful"); + + if(!to_stdout) + get_creds(context, &ccache); + + ret = hdb_read_master_key(context, mkeyfile, &mkey5); + if(ret && ret != ENOENT) + krb5_err(context, 1, ret, "hdb_read_master_key"); + if(ret) { + if(encrypt_flag || decrypt_flag) + krb5_errx(context, 1, "No master key file found"); + } else { + ret = hdb_process_master_key(context, mkey5, &msched5); + if(ret) + krb5_err(context, 1, ret, "hdb_process_master_key"); + } + +#ifdef KRB4 + if (v4_db +#ifdef KASERVER_DB + || ka_db +#endif +) { + int e; + + if (realm == NULL) { + e = krb_get_lrealm(realm_buf, 1); + if(e) + krb5_errx(context, 1, "krb_get_lrealm: %s", + krb_get_err_text(e)); + realm = realm_buf; + } + } + + if(v4_db) { + int e = kerb_db_set_name (database); + if(e) + krb5_errx(context, 1, "kerb_db_set_name: %s", + krb_get_err_text(e)); + e = kdb_get_master_key(0, &mkey4, msched4); + if(e) + krb5_errx(context, 1, "kdb_get_master_key: %s", + krb_get_err_text(e)); + } else +#ifdef KASERVER_DB + if (ka_db) { + /* no preparation required */ + } else +#endif +#endif /* KRB4 */ + { + ret = hdb_create (context, &db, database); + if(ret) + krb5_err(context, 1, ret, "hdb_create: %s", database); + ret = db->open(context, db, O_RDONLY, 0); + if(ret) + krb5_err(context, 1, ret, "db->open"); + } + + if (to_stdout) + dump_database (context, v4_db, ka_db, + database, afs_cell, db); + else + propagate_database (context, v4_db, ka_db, + database, afs_cell, + db, ccache, + optind, argc, argv); + return 0; +} diff --git a/crypto/heimdal/kdc/hprop.h b/crypto/heimdal/kdc/hprop.h new file mode 100644 index 0000000..3802c5d --- /dev/null +++ b/crypto/heimdal/kdc/hprop.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 1997 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $Id: hprop.h,v 1.7 1999/12/02 17:04:59 joda Exp $ */ + +#ifndef __HPROP_H__ +#define __HPROP_H__ + +#include "headers.h" + +#define HPROP_VERSION "hprop-0.0" +#define HPROP_NAME "hprop" +#define HPROP_KEYTAB "FILE:/etc/hprop.keytab" +#define HPROP_PORT 754 + +#ifndef NEVERDATE +#define NEVERDATE ((1U << 31) - 1) +#endif + +krb5_error_code send_priv(krb5_context, krb5_auth_context, krb5_data*, int); +krb5_error_code recv_priv(krb5_context, krb5_auth_context, int, krb5_data*); +krb5_error_code send_clear(krb5_context context, int fd, krb5_data data); +krb5_error_code recv_clear(krb5_context context, int fd, krb5_data *out); + +#endif /* __HPROP_H__ */ diff --git a/crypto/heimdal/kdc/hpropd.8 b/crypto/heimdal/kdc/hpropd.8 new file mode 100644 index 0000000..de4249a --- /dev/null +++ b/crypto/heimdal/kdc/hpropd.8 @@ -0,0 +1,27 @@ +.\" $Id: hpropd.8,v 1.1 1997/08/27 23:42:34 assar Exp $ +.\" +.Dd Aug 27, 1997 +.Dt HPROPD 8 +.Os HEIMDAL +.Sh NAME +.Nm hpropd +.Nd +receive a propagated database +.Sh SYNOPSIS +.Nm +.Op Fl d Ar database +.Op Fl -database= Ns Ar database +.Sh DESCRIPTION +.Nm +receives databases sent by +.Nm hprop . +and writes it as a local database. +.Pp +Options supported: +.Bl -tag -width Ds +.It Fl d Ar database +.It Fl -database= Ns Ar database +the database to create. +.El +.Sh SEE ALSO +.Xr hprop 8 diff --git a/crypto/heimdal/kdc/hpropd.c b/crypto/heimdal/kdc/hpropd.c new file mode 100644 index 0000000..df29240 --- /dev/null +++ b/crypto/heimdal/kdc/hpropd.c @@ -0,0 +1,419 @@ +/* + * Copyright (c) 1997-2000 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "hprop.h" + +RCSID("$Id: hpropd.c,v 1.22 2000/01/06 21:39:24 assar Exp $"); + +#ifdef KRB4 +static des_cblock mkey4; +static des_key_schedule msched4; + +static char * +time2str(time_t t) +{ + static char buf[128]; + strftime(buf, sizeof(buf), "%Y%m%d%H%M", gmtime(&t)); + return buf; +} + +static int +dump_krb4(krb5_context context, hdb_entry *ent, int fd) +{ + char name[ANAME_SZ]; + char instance[INST_SZ]; + char realm[REALM_SZ]; + char buf[1024]; + char *p; + int i; + int ret; + char *princ_name; + Event *modifier; + krb5_realm *realms; + int cmp; + + ret = krb5_524_conv_principal(context, ent->principal, + name, instance, realm); + if (ret) { + krb5_unparse_name(context, ent->principal, &princ_name); + krb5_warn(context, ret, "%s", princ_name); + free(princ_name); + return -1; + } + + ret = krb5_get_default_realms (context, &realms); + if (ret) { + krb5_warn(context, ret, "krb5_get_default_realms"); + return -1; + } + + cmp = strcmp (realms[0], ent->principal->realm); + krb5_free_host_realm (context, realms); + if (cmp != 0) + return -1; + + snprintf (buf, sizeof(buf), "%s %s ", name, + (strlen(instance) != 0) ? instance : "*"); + + if (ent->max_life) { + asprintf(&p, "%d", krb_time_to_life(0, *ent->max_life)); + strcat(buf, p); + free(p); + } else + strcat(buf, "255"); + strcat(buf, " "); + + i = 0; + while (i < ent->keys.len && + ent->keys.val[i].key.keytype != KEYTYPE_DES) + ++i; + + if (i == ent->keys.len) { + krb5_warnx(context, "No DES key for %s.%s", name, instance); + return -1; + } + + if (ent->keys.val[i].mkvno) + asprintf(&p, "%d ", *ent->keys.val[i].mkvno); + else + asprintf(&p, "%d ", 1); + strcat(buf, p); + free(p); + + asprintf(&p, "%d ", ent->kvno); + strcat(buf, p); + free(p); + + asprintf(&p, "%d ", 0); /* Attributes are always 0*/ + strcat(buf, p); + free(p); + + { + u_int32_t *key = ent->keys.val[i].key.keyvalue.data; + kdb_encrypt_key((des_cblock*)key, (des_cblock*)key, + &mkey4, msched4, DES_ENCRYPT); + asprintf(&p, "%x %x ", (int)htonl(*key), (int)htonl(*(key+1))); + strcat(buf, p); + free(p); + } + + if (ent->pw_end == NULL) + strcat(buf, time2str(60*60*24*365*50)); /* passwd will never expire */ + else + strcat(buf, time2str(*ent->pw_end)); + strcat(buf, " "); + + if (ent->modified_by == NULL) + modifier = &ent->created_by; + else + modifier = ent->modified_by; + + ret = krb5_524_conv_principal(context, modifier->principal, + name, instance, realm); + if (ret) { + krb5_unparse_name(context, modifier->principal, &princ_name); + krb5_warn(context, ret, "%s", princ_name); + free(princ_name); + return -1; + } + asprintf(&p, "%s %s %s\n", time2str(modifier->time), + (strlen(name) != 0) ? name : "*", + (strlen(instance) != 0) ? instance : "*"); + strcat(buf, p); + free(p); + + ret = write(fd, buf, strlen(buf)); + if (ret == -1) + krb5_warnx(context, "write"); + return 0; +} +#endif /* KRB4 */ + +static int inetd_flag = -1; +static int help_flag; +static int version_flag; +static int print_dump; +static char *database = HDB_DEFAULT_DB; +static int from_stdin; +#ifdef KRB4 +static int v4dump; +#endif + +struct getargs args[] = { + { "database", 'd', arg_string, &database, "database", "file" }, + { "stdin", 'n', arg_flag, &from_stdin, "read from stdin" }, + { "print", 0, arg_flag, &print_dump, "print dump to stdout" }, + { "inetd", 'i', arg_negative_flag, &inetd_flag, + "Not started from inetd" }, +#ifdef KRB4 + { "v4dump", '4', arg_flag, &v4dump, "create v4 type DB" }, +#endif + { "version", 0, arg_flag, &version_flag, NULL, NULL }, + { "help", 'h', arg_flag, &help_flag, NULL, NULL} +}; + +static int num_args = sizeof(args) / sizeof(args[0]); + +static void +usage(int ret) +{ + arg_printusage (args, num_args, NULL, ""); + exit (ret); +} + +int +main(int argc, char **argv) +{ + krb5_error_code ret; + krb5_context context; + krb5_auth_context ac = NULL; + krb5_principal server; + krb5_principal c1, c2; + krb5_authenticator authent; + krb5_keytab keytab; + int fd; + HDB *db; + char hostname[128]; + int optind = 0; + char *tmp_db; + krb5_log_facility *fac; + int nprincs; +#ifdef KRB4 + int e; + int fd_out; +#endif + + set_progname(argv[0]); + + ret = krb5_init_context(&context); + if(ret) + exit(1); + + ret = krb5_openlog(context, "hpropd", &fac); + if(ret) + ; + krb5_set_warn_dest(context, fac); + + if(getarg(args, num_args, argc, argv, &optind)) + usage(1); + +#ifdef KRB4 + if (v4dump && database == HDB_DEFAULT_DB) + database = "/var/kerberos/524_dump"; +#endif /* KRB4 */ + + if(help_flag) + usage(0); + if(version_flag) { + print_version(NULL); + exit(0); + } + + argc -= optind; + argv += optind; + + if (argc != 0) + usage(1); + + if(from_stdin) + fd = STDIN_FILENO; + else { + struct sockaddr_storage ss; + struct sockaddr *sa = (struct sockaddr *)&ss; + int sin_len = sizeof(ss); + char addr_name[256]; + + fd = STDIN_FILENO; + if (inetd_flag == -1) { + if (getpeername (fd, sa, &sin_len) < 0) + inetd_flag = 0; + else + inetd_flag = 1; + } + if (!inetd_flag) { + mini_inetd (krb5_getportbyname (context, "hprop", "tcp", + HPROP_PORT)); + } + sin_len = sizeof(ss); + if(getpeername(fd, sa, &sin_len) < 0) + krb5_err(context, 1, errno, "getpeername"); + + if (inet_ntop(sa->sa_family, + socket_get_address (sa), + addr_name, + sizeof(addr_name)) == NULL) + strlcpy (addr_name, "unknown address", + sizeof(addr_name)); + + krb5_log(context, fac, 0, "Connection from %s", addr_name); + + gethostname(hostname, sizeof(hostname)); + ret = krb5_sname_to_principal(context, hostname, HPROP_NAME, + KRB5_NT_SRV_HST, &server); + if(ret) + krb5_err(context, 1, ret, "krb5_sname_to_principal"); + + ret = krb5_kt_default(context, &keytab); + if(ret) + krb5_err(context, 1, ret, "krb5_kt_default"); + + ret = krb5_recvauth(context, &ac, &fd, HPROP_VERSION, + server, 0, keytab, NULL); + if(ret) + krb5_err(context, 1, ret, "krb5_recvauth"); + + ret = krb5_auth_getauthenticator(context, ac, &authent); + if(ret) + krb5_err(context, 1, ret, "krb5_auth_getauthenticator"); + + ret = krb5_make_principal(context, &c1, NULL, "kadmin", "hprop", NULL); + if(ret) + krb5_err(context, 1, ret, "krb5_make_principal"); + principalname2krb5_principal(&c2, authent->cname, authent->crealm); + if(!krb5_principal_compare(context, c1, c2)) { + char *s; + krb5_unparse_name(context, c2, &s); + krb5_errx(context, 1, "Unauthorized connection from %s", s); + } + krb5_free_principal(context, c1); + krb5_free_principal(context, c2); + + ret = krb5_kt_close(context, keytab); + if(ret) + krb5_err(context, 1, ret, "krb5_kt_close"); + } + + if(!print_dump) { + asprintf(&tmp_db, "%s~", database); +#ifdef KRB4 + if (v4dump) { + fd_out = open(tmp_db, O_WRONLY | O_CREAT | O_TRUNC, 0600); + if (fd_out == -1) + krb5_errx(context, 1, "%s", strerror(errno)); + } + else +#endif /* KRB4 */ + { + ret = hdb_create(context, &db, tmp_db); + if(ret) + krb5_err(context, 1, ret, "hdb_create(%s)", tmp_db); + ret = db->open(context, db, O_RDWR | O_CREAT | O_TRUNC, 0600); + if(ret) + krb5_err(context, 1, ret, "hdb_open(%s)", tmp_db); + } + } + +#ifdef KRB4 + if (v4dump) { + e = kdb_get_master_key(0, &mkey4, msched4); + if(e) + krb5_errx(context, 1, "kdb_get_master_key: %s", + krb_get_err_text(e)); + } +#endif /* KRB4 */ + + nprincs = 0; + while(1){ + krb5_data data; + hdb_entry entry; + + if(from_stdin){ + ret = recv_clear(context, fd, &data); + if(ret) + krb5_err(context, 1, ret, "recv_clear"); + }else{ + ret = recv_priv(context, ac, fd, &data); + if(ret) + krb5_err(context, 1, ret, "recv_priv"); + } + + if(data.length == 0) { + if(!from_stdin) { + data.data = NULL; + data.length = 0; + send_priv(context, ac, &data, fd); + } + if(!print_dump) { +#ifdef KRB4 + if (v4dump) { + ret = rename(tmp_db, database); + if (ret) + krb5_errx(context, 1, "rename"); + ret = close(fd_out); + if (ret) + krb5_errx(context, 1, "close"); + } else +#endif /* KRB4 */ + { + ret = db->rename(context, db, database); + if(ret) + krb5_err(context, 1, ret, "db_rename"); + ret = db->close(context, db); + if(ret) + krb5_err(context, 1, ret, "db_close"); + } + } + break; + } + ret = hdb_value2entry(context, &data, &entry); + if(ret) + krb5_err(context, 1, ret, "hdb_value2entry"); + if(print_dump) + hdb_print_entry(context, db, &entry, stdout); + else { +#ifdef KRB4 + if (v4dump) { + ret = dump_krb4(context, &entry, fd_out); + if(!ret) nprincs++; + } + else +#endif /* KRB4 */ + { + ret = db->store(context, db, 0, &entry); + if(ret == HDB_ERR_EXISTS) { + char *s; + krb5_unparse_name(context, entry.principal, &s); + krb5_warnx(context, "Entry exists: %s", s); + free(s); + } else if(ret) + krb5_err(context, 1, ret, "db_store"); + else + nprincs++; + } + } + hdb_free_entry(context, &entry); + } + if (!print_dump) + krb5_log(context, fac, 0, "Received %d principals", nprincs); + exit(0); +} diff --git a/crypto/heimdal/kdc/kadb.h b/crypto/heimdal/kdc/kadb.h new file mode 100644 index 0000000..e85dbe2 --- /dev/null +++ b/crypto/heimdal/kdc/kadb.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 1998 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $Id: kadb.h,v 1.2 1999/12/02 17:04:59 joda Exp $ */ + +#ifndef __kadb_h__ +#define __kadb_h__ + +#define HASHSIZE 8191 + +struct ka_header { + int32_t version1; /* file format version, should + match version2 */ + int32_t size; + int32_t free_ptr; + int32_t eof_ptr; + int32_t kvno_ptr; + int32_t stats[8]; + int32_t admin_accounts; + int32_t special_keys_version; + int32_t hashsize; /* allocated size of hash */ + int32_t hash[HASHSIZE]; + int32_t version2; +}; + +struct ka_entry { + int32_t flags; /* see below */ + int32_t next; /* next in hash list */ + int32_t pw_end; /* expiration date */ + int32_t mod_time; /* time last modified */ + int32_t mod_ptr; /* pointer to modifier */ + int32_t pw_change; /* last pw change */ + int32_t max_life; /* max ticket life */ + int32_t kvno; + int32_t foo2[2]; /* huh? */ + char name[64]; + char instance[64]; + char key[8]; +}; + +#define KAFNORMAL (1<<0) +#define KAFADMIN (1<<2) /* an administrator */ +#define KAFNOTGS (1<<3) /* ! allow principal to get or use TGT */ +#define KAFNOSEAL (1<<5) /* ! allow principal as server in GetTicket */ +#define KAFNOCPW (1<<6) /* ! allow principal to change its own key */ +#define KAFSPECIAL (1<<8) /* set if special AuthServer principal */ + +#endif /* __kadb_h__ */ diff --git a/crypto/heimdal/kdc/kaserver.c b/crypto/heimdal/kdc/kaserver.c new file mode 100644 index 0000000..dc155fa --- /dev/null +++ b/crypto/heimdal/kdc/kaserver.c @@ -0,0 +1,794 @@ +/* + * Copyright (c) 1997, 1998, 1999 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "kdc_locl.h" + +RCSID("$Id: kaserver.c,v 1.9 1999/12/02 17:04:59 joda Exp $"); + +#ifdef KASERVER + +#include "kerberos4.h" +#include <rx.h> + +#define KA_AUTHENTICATION_SERVICE 731 +#define KA_TICKET_GRANTING_SERVICE 732 +#define KA_MAINTENANCE_SERVICE 733 + +#define AUTHENTICATE_OLD 1 +#define CHANGEPASSWORD 2 +#define GETTICKET_OLD 3 +#define SETPASSWORD 4 +#define SETFIELDS 5 +#define CREATEUSER 6 +#define DELETEUSER 7 +#define GETENTRY 8 +#define LISTENTRY 9 +#define GETSTATS 10 +#define DEBUG 11 +#define GETPASSWORD 12 +#define GETRANDOMKEY 13 +#define AUTHENTICATE 21 +#define AUTHENTICATE_V2 22 +#define GETTICKET 23 + +/* XXX - Where do we get these? */ + +#define RXGEN_OPCODE (-455) + +#define KADATABASEINCONSISTENT (180480L) +#define KAEXIST (180481L) +#define KAIO (180482L) +#define KACREATEFAIL (180483L) +#define KANOENT (180484L) +#define KAEMPTY (180485L) +#define KABADNAME (180486L) +#define KABADINDEX (180487L) +#define KANOAUTH (180488L) +#define KAANSWERTOOLONG (180489L) +#define KABADREQUEST (180490L) +#define KAOLDINTERFACE (180491L) +#define KABADARGUMENT (180492L) +#define KABADCMD (180493L) +#define KANOKEYS (180494L) +#define KAREADPW (180495L) +#define KABADKEY (180496L) +#define KAUBIKINIT (180497L) +#define KAUBIKCALL (180498L) +#define KABADPROTOCOL (180499L) +#define KANOCELLS (180500L) +#define KANOCELL (180501L) +#define KATOOMANYUBIKS (180502L) +#define KATOOMANYKEYS (180503L) +#define KABADTICKET (180504L) +#define KAUNKNOWNKEY (180505L) +#define KAKEYCACHEINVALID (180506L) +#define KABADSERVER (180507L) +#define KABADUSER (180508L) +#define KABADCPW (180509L) +#define KABADCREATE (180510L) +#define KANOTICKET (180511L) +#define KAASSOCUSER (180512L) +#define KANOTSPECIAL (180513L) +#define KACLOCKSKEW (180514L) +#define KANORECURSE (180515L) +#define KARXFAIL (180516L) +#define KANULLPASSWORD (180517L) +#define KAINTERNALERROR (180518L) +#define KAPWEXPIRED (180519L) +#define KAREUSED (180520L) +#define KATOOSOON (180521L) +#define KALOCKED (180522L) + +static void +decode_rx_header (krb5_storage *sp, + struct rx_header *h) +{ + krb5_ret_int32(sp, &h->epoch); + krb5_ret_int32(sp, &h->connid); + krb5_ret_int32(sp, &h->callid); + krb5_ret_int32(sp, &h->seqno); + krb5_ret_int32(sp, &h->serialno); + krb5_ret_int8(sp, &h->type); + krb5_ret_int8(sp, &h->flags); + krb5_ret_int8(sp, &h->status); + krb5_ret_int8(sp, &h->secindex); + krb5_ret_int16(sp, &h->reserved); + krb5_ret_int16(sp, &h->serviceid); +} + +static void +encode_rx_header (struct rx_header *h, + krb5_storage *sp) +{ + krb5_store_int32(sp, h->epoch); + krb5_store_int32(sp, h->connid); + krb5_store_int32(sp, h->callid); + krb5_store_int32(sp, h->seqno); + krb5_store_int32(sp, h->serialno); + krb5_store_int8(sp, h->type); + krb5_store_int8(sp, h->flags); + krb5_store_int8(sp, h->status); + krb5_store_int8(sp, h->secindex); + krb5_store_int16(sp, h->reserved); + krb5_store_int16(sp, h->serviceid); +} + +static void +init_reply_header (struct rx_header *hdr, + struct rx_header *reply_hdr, + u_char type, + u_char flags) +{ + reply_hdr->epoch = hdr->epoch; + reply_hdr->connid = hdr->connid; + reply_hdr->callid = hdr->callid; + reply_hdr->seqno = 1; + reply_hdr->serialno = 1; + reply_hdr->type = type; + reply_hdr->flags = flags; + reply_hdr->status = 0; + reply_hdr->secindex = 0; + reply_hdr->reserved = 0; + reply_hdr->serviceid = hdr->serviceid; +} + +static void +make_error_reply (struct rx_header *hdr, + u_int32_t ret, + krb5_data *reply) + +{ + krb5_storage *sp; + struct rx_header reply_hdr; + + init_reply_header (hdr, &reply_hdr, HT_ABORT, HF_LAST); + sp = krb5_storage_emem(); + encode_rx_header (&reply_hdr, sp); + krb5_store_int32(sp, ret); + krb5_storage_to_data (sp, reply); + krb5_storage_free (sp); +} + +static krb5_error_code +krb5_ret_xdr_data(krb5_storage *sp, + krb5_data *data) +{ + int ret; + int size; + ret = krb5_ret_int32(sp, &size); + if(ret) + return ret; + data->length = size; + if (size) { + u_char foo[4]; + size_t pad = (4 - size % 4) % 4; + + data->data = malloc(size); + if (data->data == NULL) + return ENOMEM; + ret = sp->fetch(sp, data->data, size); + if(ret != size) + return (ret < 0)? errno : KRB5_CC_END; + if (pad) { + ret = sp->fetch(sp, foo, pad); + if (ret != pad) + return (ret < 0)? errno : KRB5_CC_END; + } + } else + data->data = NULL; + return 0; +} + +static krb5_error_code +krb5_store_xdr_data(krb5_storage *sp, + krb5_data data) +{ + u_char zero[4] = {0, 0, 0, 0}; + int ret; + size_t pad; + + ret = krb5_store_int32(sp, data.length); + if(ret < 0) + return ret; + ret = sp->store(sp, data.data, data.length); + if(ret != data.length){ + if(ret < 0) + return errno; + return KRB5_CC_END; + } + pad = (4 - data.length % 4) % 4; + if (pad) { + ret = sp->store(sp, zero, pad); + if (ret != pad) { + if (ret < 0) + return errno; + return KRB5_CC_END; + } + } + return 0; +} + + +static krb5_error_code +create_reply_ticket (struct rx_header *hdr, + Key *skey, + char *name, char *instance, char *realm, + struct sockaddr_in *addr, + int life, + int kvno, + int32_t max_seq_len, + char *sname, char *sinstance, + u_int32_t challenge, + char *label, + des_cblock *key, + krb5_data *reply) +{ + KTEXT_ST ticket; + des_cblock session; + krb5_storage *sp; + krb5_data enc_data; + des_key_schedule schedule; + struct rx_header reply_hdr; + des_cblock zero; + size_t pad; + unsigned fyrtiosjuelva; + + /* create the ticket */ + + des_new_random_key(&session); + + krb_create_ticket (&ticket, 0, name, instance, realm, + addr->sin_addr.s_addr, + &session, life, kdc_time, + sname, sinstance, skey->key.keyvalue.data); + + /* create the encrypted part of the reply */ + sp = krb5_storage_emem (); + krb5_generate_random_block(&fyrtiosjuelva, sizeof(fyrtiosjuelva)); + fyrtiosjuelva &= 0xffffffff; + krb5_store_int32 (sp, fyrtiosjuelva); +#if 0 + krb5_store_int32 (sp, 4711); /* XXX */ +#endif + krb5_store_int32 (sp, challenge); + sp->store (sp, session, 8); + memset (&session, 0, sizeof(session)); + krb5_store_int32 (sp, kdc_time); + krb5_store_int32 (sp, kdc_time + krb_life_to_time (0, life)); + krb5_store_int32 (sp, kvno); + krb5_store_int32 (sp, ticket.length); + krb5_store_stringz (sp, name); + krb5_store_stringz (sp, instance); +#if 1 /* XXX - Why shouldn't the realm go here? */ + krb5_store_stringz (sp, ""); +#else + krb5_store_stringz (sp, realm); +#endif + krb5_store_stringz (sp, sname); + krb5_store_stringz (sp, sinstance); + sp->store (sp, ticket.dat, ticket.length); + sp->store (sp, label, strlen(label)); + + /* pad to DES block */ + memset (zero, 0, sizeof(zero)); + pad = (8 - sp->seek (sp, 0, SEEK_CUR) % 8) % 8; + sp->store (sp, zero, pad); + + krb5_storage_to_data (sp, &enc_data); + krb5_storage_free (sp); + + if (enc_data.length > max_seq_len) { + krb5_data_free (&enc_data); + make_error_reply (hdr, KAANSWERTOOLONG, reply); + return 0; + } + + /* encrypt it */ + des_set_key (key, schedule); + des_pcbc_encrypt ((des_cblock *)enc_data.data, + (des_cblock *)enc_data.data, + enc_data.length, + schedule, + key, + DES_ENCRYPT); + memset (&schedule, 0, sizeof(schedule)); + + /* create the reply packet */ + init_reply_header (hdr, &reply_hdr, HT_DATA, HF_LAST); + sp = krb5_storage_emem (); + encode_rx_header (&reply_hdr, sp); + krb5_store_int32 (sp, max_seq_len); + krb5_store_xdr_data (sp, enc_data); + krb5_data_free (&enc_data); + krb5_storage_to_data (sp, reply); + krb5_storage_free (sp); + return 0; +} + +static krb5_error_code +unparse_auth_args (krb5_storage *sp, + char **name, + char **instance, + time_t *start_time, + time_t *end_time, + krb5_data *request, + int32_t *max_seq_len) +{ + krb5_data data; + int32_t tmp; + + krb5_ret_xdr_data (sp, &data); + *name = malloc(data.length + 1); + if (*name == NULL) + return ENOMEM; + memcpy (*name, data.data, data.length); + (*name)[data.length] = '\0'; + krb5_data_free (&data); + + krb5_ret_xdr_data (sp, &data); + *instance = malloc(data.length + 1); + if (*instance == NULL) { + free (*name); + return ENOMEM; + } + memcpy (*instance, data.data, data.length); + (*instance)[data.length] = '\0'; + krb5_data_free (&data); + + krb5_ret_int32 (sp, &tmp); + *start_time = tmp; + krb5_ret_int32 (sp, &tmp); + *end_time = tmp; + krb5_ret_xdr_data (sp, request); + krb5_ret_int32 (sp, max_seq_len); + /* ignore the rest */ + return 0; +} + +static void +do_authenticate (struct rx_header *hdr, + krb5_storage *sp, + struct sockaddr_in *addr, + krb5_data *reply) +{ + krb5_error_code ret; + char *name = NULL; + char *instance = NULL; + time_t start_time; + time_t end_time; + krb5_data request; + int32_t max_seq_len; + hdb_entry *client_entry = NULL; + hdb_entry *server_entry = NULL; + Key *ckey = NULL; + Key *skey = NULL; + des_cblock key; + des_key_schedule schedule; + krb5_storage *reply_sp; + time_t max_life; + u_int8_t life; + int32_t chal; + + krb5_data_zero (&request); + + unparse_auth_args (sp, &name, &instance, &start_time, &end_time, + &request, &max_seq_len); + + client_entry = db_fetch4 (name, instance, v4_realm); + if (client_entry == NULL) { + kdc_log(0, "Client not found in database: %s.%s@%s", + name, instance, v4_realm); + make_error_reply (hdr, KANOENT, reply); + goto out; + } + + server_entry = db_fetch4 ("krbtgt", v4_realm, v4_realm); + if (server_entry == NULL) { + kdc_log(0, "Server not found in database: %s.%s@%s", + "krbtgt", v4_realm, v4_realm); + make_error_reply (hdr, KANOENT, reply); + goto out; + } + + /* find a DES key */ + ret = get_des_key(client_entry, &ckey); + if(ret){ + kdc_log(0, "%s", krb5_get_err_text(context, ret)); + make_error_reply (hdr, KANOKEYS, reply); + goto out; + } + + /* find a DES key */ + ret = get_des_key(server_entry, &skey); + if(ret){ + kdc_log(0, "%s", krb5_get_err_text(context, ret)); + make_error_reply (hdr, KANOKEYS, reply); + goto out; + } + + /* try to decode the `request' */ + memcpy (&key, ckey->key.keyvalue.data, sizeof(key)); + des_set_key (&key, schedule); + des_pcbc_encrypt ((des_cblock *)request.data, + (des_cblock *)request.data, + request.length, + schedule, + &key, + DES_DECRYPT); + memset (&schedule, 0, sizeof(schedule)); + + /* check for the magic label */ + if (memcmp ((char *)request.data + 4, "gTGS", 4) != 0) { + make_error_reply (hdr, KABADREQUEST, reply); + goto out; + } + + reply_sp = krb5_storage_from_mem (request.data, 4); + krb5_ret_int32 (reply_sp, &chal); + krb5_storage_free (reply_sp); + + /* life */ + max_life = end_time - kdc_time; + if (client_entry->max_life) + max_life = min(max_life, *client_entry->max_life); + if (server_entry->max_life) + max_life = min(max_life, *server_entry->max_life); + + life = krb_time_to_life(kdc_time, kdc_time + max_life); + + create_reply_ticket (hdr, skey, + name, instance, v4_realm, + addr, life, client_entry->kvno, + max_seq_len, + "krbtgt", v4_realm, + chal + 1, "tgsT", + &key, reply); + memset (&key, 0, sizeof(key)); + +out: + if (request.length) { + memset (request.data, 0, request.length); + krb5_data_free (&request); + } + if (name) + free (name); + if (instance) + free (instance); + if (client_entry) { + hdb_free_entry (context, client_entry); + free (client_entry); + } + if (server_entry) { + hdb_free_entry (context, server_entry); + free (server_entry); + } +} + +static krb5_error_code +unparse_getticket_args (krb5_storage *sp, + int *kvno, + char **auth_domain, + krb5_data *ticket, + char **name, + char **instance, + krb5_data *times, + int32_t *max_seq_len) +{ + krb5_data data; + int32_t tmp; + + krb5_ret_int32 (sp, &tmp); + *kvno = tmp; + + krb5_ret_xdr_data (sp, &data); + *auth_domain = malloc(data.length + 1); + if (*auth_domain == NULL) + return ENOMEM; + memcpy (*auth_domain, data.data, data.length); + (*auth_domain)[data.length] = '\0'; + krb5_data_free (&data); + + krb5_ret_xdr_data (sp, ticket); + + krb5_ret_xdr_data (sp, &data); + *name = malloc(data.length + 1); + if (*name == NULL) { + free (*auth_domain); + return ENOMEM; + } + memcpy (*name, data.data, data.length); + (*name)[data.length] = '\0'; + krb5_data_free (&data); + + krb5_ret_xdr_data (sp, &data); + *instance = malloc(data.length + 1); + if (*instance == NULL) { + free (*auth_domain); + free (*name); + return ENOMEM; + } + memcpy (*instance, data.data, data.length); + (*instance)[data.length] = '\0'; + krb5_data_free (&data); + + krb5_ret_xdr_data (sp, times); + + krb5_ret_int32 (sp, max_seq_len); + /* ignore the rest */ + return 0; +} + +static void +do_getticket (struct rx_header *hdr, + krb5_storage *sp, + struct sockaddr_in *addr, + krb5_data *reply) +{ + krb5_error_code ret; + int kvno; + char *auth_domain = NULL; + krb5_data aticket; + char *name = NULL; + char *instance = NULL; + krb5_data times; + int32_t max_seq_len; + hdb_entry *server_entry = NULL; + hdb_entry *krbtgt_entry = NULL; + Key *kkey = NULL; + Key *skey = NULL; + des_cblock key; + des_key_schedule schedule; + des_cblock session; + time_t max_life; + int8_t life; + time_t start_time, end_time; + char pname[ANAME_SZ]; + char pinst[INST_SZ]; + char prealm[REALM_SZ]; + + krb5_data_zero (&aticket); + krb5_data_zero (×); + + unparse_getticket_args (sp, &kvno, &auth_domain, &aticket, + &name, &instance, ×, &max_seq_len); + + server_entry = db_fetch4 (name, instance, v4_realm); + if (server_entry == NULL) { + kdc_log(0, "Server not found in database: %s.%s@%s", + name, instance, v4_realm); + make_error_reply (hdr, KANOENT, reply); + goto out; + } + + krbtgt_entry = db_fetch4 ("krbtgt", v4_realm, v4_realm); + if (krbtgt_entry == NULL) { + kdc_log(0, "Server not found in database: %s.%s@%s", + "krbtgt", v4_realm, v4_realm); + make_error_reply (hdr, KANOENT, reply); + goto out; + } + + /* find a DES key */ + ret = get_des_key(krbtgt_entry, &kkey); + if(ret){ + kdc_log(0, "%s", krb5_get_err_text(context, ret)); + make_error_reply (hdr, KANOKEYS, reply); + goto out; + } + + /* find a DES key */ + ret = get_des_key(server_entry, &skey); + if(ret){ + kdc_log(0, "%s", krb5_get_err_text(context, ret)); + make_error_reply (hdr, KANOKEYS, reply); + goto out; + } + + /* decrypt the incoming ticket */ + memcpy (&key, kkey->key.keyvalue.data, sizeof(key)); + + /* unpack the ticket */ + { + KTEXT_ST ticket; + u_char flags; + int life; + u_int32_t time_sec; + char sname[ANAME_SZ]; + char sinstance[SNAME_SZ]; + u_int32_t paddress; + + ticket.length = aticket.length; + memcpy (ticket.dat, aticket.data, ticket.length); + + des_set_key (&key, schedule); + decomp_ticket (&ticket, &flags, pname, pinst, prealm, + &paddress, session, &life, &time_sec, + sname, sinstance, + &key, schedule); + + if (strcmp (sname, "krbtgt") != 0 + || strcmp (sinstance, v4_realm) != 0) { + kdc_log(0, "no TGT: %s.%s for %s.%s@%s", + sname, sinstance, + pname, pinst, prealm); + make_error_reply (hdr, KABADTICKET, reply); + goto out; + } + + if (kdc_time > krb_life_to_time(time_sec, life)) { + kdc_log(0, "TGT expired: %s.%s@%s", + pname, pinst, prealm); + make_error_reply (hdr, KABADTICKET, reply); + goto out; + } + } + + /* decrypt the times */ + des_set_key (&session, schedule); + des_ecb_encrypt (times.data, + times.data, + schedule, + DES_DECRYPT); + memset (&schedule, 0, sizeof(schedule)); + + /* and extract them */ + { + krb5_storage *sp; + int32_t tmp; + + sp = krb5_storage_from_mem (times.data, times.length); + krb5_ret_int32 (sp, &tmp); + start_time = tmp; + krb5_ret_int32 (sp, &tmp); + end_time = tmp; + krb5_storage_free (sp); + } + + /* life */ + max_life = end_time - kdc_time; + if (krbtgt_entry->max_life) + max_life = min(max_life, *krbtgt_entry->max_life); + if (server_entry->max_life) + max_life = min(max_life, *server_entry->max_life); + + life = krb_time_to_life(kdc_time, kdc_time + max_life); + + create_reply_ticket (hdr, skey, + pname, pinst, prealm, + addr, life, server_entry->kvno, + max_seq_len, + name, instance, + 0, "gtkt", + &session, reply); + memset (&session, 0, sizeof(session)); + +out: + if (aticket.length) { + memset (aticket.data, 0, aticket.length); + krb5_data_free (&aticket); + } + if (times.length) { + memset (times.data, 0, times.length); + krb5_data_free (×); + } + if (auth_domain) + free (auth_domain); + if (name) + free (name); + if (instance) + free (instance); + if (krbtgt_entry) { + hdb_free_entry (context, krbtgt_entry); + free (krbtgt_entry); + } + if (server_entry) { + hdb_free_entry (context, server_entry); + free (server_entry); + } +} + +krb5_error_code +do_kaserver(unsigned char *buf, + size_t len, + krb5_data *reply, + const char *from, + struct sockaddr_in *addr) +{ + krb5_error_code ret = 0; + struct rx_header hdr; + u_int32_t op; + krb5_storage *sp; + + if (len < RX_HEADER_SIZE) + return -1; + sp = krb5_storage_from_mem (buf, len); + + decode_rx_header (sp, &hdr); + buf += RX_HEADER_SIZE; + len -= RX_HEADER_SIZE; + + switch (hdr.type) { + case HT_DATA : + break; + case HT_ACK : + case HT_BUSY : + case HT_ABORT : + case HT_ACKALL : + case HT_CHAL : + case HT_RESP : + case HT_DEBUG : + default: + /* drop */ + goto out; + } + + + if (hdr.serviceid != KA_AUTHENTICATION_SERVICE + && hdr.serviceid != KA_TICKET_GRANTING_SERVICE) { + ret = -1; + goto out; + } + + krb5_ret_int32(sp, &op); + switch (op) { + case AUTHENTICATE : + do_authenticate (&hdr, sp, addr, reply); + break; + case GETTICKET : + do_getticket (&hdr, sp, addr, reply); + break; + case AUTHENTICATE_OLD : + case CHANGEPASSWORD : + case GETTICKET_OLD : + case SETPASSWORD : + case SETFIELDS : + case CREATEUSER : + case DELETEUSER : + case GETENTRY : + case LISTENTRY : + case GETSTATS : + case DEBUG : + case GETPASSWORD : + case GETRANDOMKEY : + case AUTHENTICATE_V2 : + default : + make_error_reply (&hdr, RXGEN_OPCODE, reply); + break; + } + +out: + krb5_storage_free (sp); + return ret; +} + +#endif /* KASERVER */ diff --git a/crypto/heimdal/kdc/kdc.8 b/crypto/heimdal/kdc/kdc.8 new file mode 100644 index 0000000..8925111 --- /dev/null +++ b/crypto/heimdal/kdc/kdc.8 @@ -0,0 +1,92 @@ +.\" $Id: kdc.8,v 1.3 1997/08/09 00:20:38 joda Exp $ +.\" +.Dd July 27, 1997 +.Dt KDC 8 +.Os HEIMDAL +.Sh NAME +.Nm kdc +.Nd +Kerberos 5 server +.Sh SYNOPSIS +.Nm +.Op Fl c Ar file +.Op Fl -config-file= Ns Ar file +.Op Fl k Ar file +.Op Fl -key-file= Ns Ar file +.Op Fl p +.Op Fl -no-require-preauth +.Op Fl r Ar realm +.Op Fl -v4-realm= Ns Ar realm + +.Sh DESCRIPTION +.Nm +serves requests for tickets. When it starts, it first checks the flags +passed, any options that are not specified with a command line flag is +taken from a config file, or from a default compiled-in value. +.Pp +Options supported: +.Bl -tag -width Ds +.It Fl c Ar file +.It Fl -config-file= Ns Ar file +Specifies the location of the config file, the default is +.Pa /var/heimdal/kdc.conf . +This is the only value that can't be specified in the config file. +.It Fl k Ar file +.It Fl -key-file= Ns Ar file +The location of the master-key file. All keys in the database is +encrypted with this master key. The use of a master key is currently +optional, so there is no default. +.Em "Don't specify a master key file if your database is not encrypted." +.It Fl p +.It Fl -no-require-preauth +Turn off the requirement for pre-autentication in the initial +AS-REQ. The use of pre-authentication makes it more difficult to do +offline password attacks. You might want to turn it off if you have +clients that doesn't do pre-authentication. Since the version 4 +protocol doesn't support any pre-authentication, so serving version 4 +clients is just about the same as not requiring pre-athentication. The +default is to require pre-authentication. +.It Fl r Ar realm +.It Fl -v4-realm= Ns Ar realm +What realm this server should act as when dealing with version 4 +requests. The database can contain any number of realms, but since the +version 4 protocol doesn't contain a realm for the server, it must be +explicitly specified. The default is whatever is returned by +.Fn krb_get_lrealm . +This option is only availabe if the KDC has been compiled with version +4 support. +.El +.Pp +All activities , are logged to one or more destinations, see +.Xr krb5.conf 5 , +and +.Xr krb5_openlog 3 . +The entity used for logging is +.Nm kdc . +.Sh CONFIGURATION FILE +The configuration file has the same syntax as the +.Pa krb5.conf +file (you can actually put the configuration in +.Pa /etc/krb5.conf , +and then start the KDC with +.Fl -config-file= Ns Ar /etc/krb5.conf ) . +All options should be in a section called +.Dq kdc . +Options are called the same as the long option name, and takes the +same arguments. The only difference is the pre-authentication flag, +that has to be specified as: +.Pp +.Dl require-preauth = no +.Pp +(in fact you can specify the option as +.Fl -require-preauth=no ) . +.Pp +An example of a config file: +.Bd -literal -offset indent +[kdc] + require-preauth = no + v4-realm = FOO.SE + key-file = /key-file +.Ed +.Sh SEE ALSO +.Xr kinit 1 diff --git a/crypto/heimdal/kdc/kdc_locl.h b/crypto/heimdal/kdc/kdc_locl.h new file mode 100644 index 0000000..7275576 --- /dev/null +++ b/crypto/heimdal/kdc/kdc_locl.h @@ -0,0 +1,103 @@ +/* + * Copyright (c) 1997-1999 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id: kdc_locl.h,v 1.39 1999/12/02 17:04:59 joda Exp $ + */ + +#ifndef __KDC_LOCL_H__ +#define __KDC_LOCL_H__ + +#include "headers.h" + +extern krb5_context context; + +extern int require_preauth; +extern sig_atomic_t exit_flag; +extern char *keyfile; +extern size_t max_request; +extern time_t kdc_warn_pwexpire; +extern struct dbinfo { + char *realm; + char *dbname; + char *mkey_file; + struct dbinfo *next; +} *databases; +extern HDB **db; +extern int num_db; +extern char *port_str; +extern int enable_http; +extern krb5_boolean encode_as_rep_as_tgs_rep; +extern krb5_boolean check_ticket_addresses; +extern krb5_boolean allow_null_ticket_addresses; + +#ifdef KRB4 +extern char *v4_realm; +#endif +#ifdef KASERVER +extern krb5_boolean enable_kaserver; +#endif + +extern struct timeval now; +#define kdc_time (now.tv_sec) + +krb5_error_code as_rep (KDC_REQ*, krb5_data*, const char*, struct sockaddr*); +void configure (int, char**); +hdb_entry* db_fetch (krb5_principal); +void kdc_log (int, const char*, ...); +char* kdc_log_msg (int, const char*, ...); +char* kdc_log_msg_va (int, const char*, va_list); +void kdc_openlog (krb5_config_section*); +void loop (void); +void set_master_key (EncryptionKey); +krb5_error_code tgs_rep (KDC_REQ*, krb5_data*, const char*, struct sockaddr *); +Key* unseal_key (Key*); + +#ifdef KRB4 +hdb_entry* db_fetch4 (const char*, const char*, const char*); +krb5_error_code do_524 (Ticket*, krb5_data*, const char*, struct sockaddr*); +krb5_error_code do_version4 (unsigned char*, size_t, krb5_data*, const char*, + struct sockaddr_in*); +krb5_error_code encode_v4_ticket (void*, size_t, EncTicketPart*, + PrincipalName*, size_t*); +krb5_error_code encrypt_v4_ticket (void*, size_t, des_cblock*, EncryptedData*); +krb5_error_code get_des_key(hdb_entry*, Key**); +int maybe_version4 (unsigned char*, int); +#endif + +#ifdef KASERVER +krb5_error_code do_kaserver (unsigned char*, size_t, krb5_data*, const char*, + struct sockaddr_in*); +#endif + +#endif /* __KDC_LOCL_H__ */ diff --git a/crypto/heimdal/kdc/kerberos4.c b/crypto/heimdal/kdc/kerberos4.c new file mode 100644 index 0000000..9ff082c --- /dev/null +++ b/crypto/heimdal/kdc/kerberos4.c @@ -0,0 +1,557 @@ +/* + * Copyright (c) 1997 - 1999 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "kdc_locl.h" + +RCSID("$Id: kerberos4.c,v 1.24 1999/12/02 17:04:59 joda Exp $"); + +#ifdef KRB4 + +#include "kerberos4.h" + +#ifndef swap32 +static u_int32_t +swap32(u_int32_t x) +{ + return ((x << 24) & 0xff000000) | + ((x << 8) & 0xff0000) | + ((x >> 8) & 0xff00) | + ((x >> 24) & 0xff); +} +#endif /* swap32 */ + +int +maybe_version4(unsigned char *buf, int len) +{ + return len > 0 && *buf == 4; +} + +static void +make_err_reply(krb5_data *reply, int code, const char *msg) +{ + KTEXT_ST er; + + /* name, instance and realm is not checked in most (all?) version + implementations; msg is also never used, but we send it anyway + (for debugging purposes) */ + + if(msg == NULL) + msg = krb_get_err_text(code); + cr_err_reply(&er, "", "", "", kdc_time, code, (char*)msg); + krb5_data_copy(reply, er.dat, er.length); +} + +static krb5_boolean +valid_princ(krb5_context context, krb5_principal princ) +{ + char *s; + hdb_entry *ent; + krb5_unparse_name(context, princ, &s); + ent = db_fetch(princ); + if(ent == NULL){ + kdc_log(7, "Lookup %s failed", s); + free(s); + return 0; + } + kdc_log(7, "Lookup %s succeeded", s); + free(s); + hdb_free_entry(context, ent); + free(ent); + return 1; +} + +hdb_entry* +db_fetch4(const char *name, const char *instance, const char *realm) +{ + krb5_principal p; + hdb_entry *ent; + krb5_error_code ret; + + ret = krb5_425_conv_principal_ext(context, name, instance, realm, + valid_princ, 0, &p); + if(ret) + return NULL; + ent = db_fetch(p); + krb5_free_principal(context, p); + return ent; +} + +krb5_error_code +get_des_key(hdb_entry *principal, Key **key) +{ + krb5_error_code ret; + + ret = hdb_enctype2key(context, principal, ETYPE_DES_CBC_MD5, key); + if(ret) + ret = hdb_enctype2key(context, principal, ETYPE_DES_CBC_MD4, key); + if(ret) + ret = hdb_enctype2key(context, principal, ETYPE_DES_CBC_CRC, key); + if(ret) + return ret; + if ((*key)->key.keyvalue.length == 0) + return KERB_ERR_NULL_KEY; + return 0; +} + +#define RCHECK(X, L) if(X){make_err_reply(reply, KFAILURE, "Packet too short"); goto L;} + +krb5_error_code +do_version4(unsigned char *buf, + size_t len, + krb5_data *reply, + const char *from, + struct sockaddr_in *addr) +{ + krb5_storage *sp; + krb5_error_code ret; + hdb_entry *client = NULL, *server = NULL; + Key *ckey, *skey; + int8_t pvno; + int8_t msg_type; + int lsb; + char *name = NULL, *inst = NULL, *realm = NULL; + char *sname = NULL, *sinst = NULL; + int32_t req_time; + time_t max_life; + u_int8_t life; + + sp = krb5_storage_from_mem(buf, len); + RCHECK(krb5_ret_int8(sp, &pvno), out); + if(pvno != 4){ + kdc_log(0, "Protocol version mismatch (%d)", pvno); + make_err_reply(reply, KDC_PKT_VER, NULL); + goto out; + } + RCHECK(krb5_ret_int8(sp, &msg_type), out); + lsb = msg_type & 1; + msg_type &= ~1; + switch(msg_type){ + case AUTH_MSG_KDC_REQUEST: + RCHECK(krb5_ret_stringz(sp, &name), out1); + RCHECK(krb5_ret_stringz(sp, &inst), out1); + RCHECK(krb5_ret_stringz(sp, &realm), out1); + RCHECK(krb5_ret_int32(sp, &req_time), out1); + if(lsb) + req_time = swap32(req_time); + RCHECK(krb5_ret_int8(sp, &life), out1); + RCHECK(krb5_ret_stringz(sp, &sname), out1); + RCHECK(krb5_ret_stringz(sp, &sinst), out1); + kdc_log(0, "AS-REQ %s.%s@%s from %s for %s.%s", + name, inst, realm, from, sname, sinst); + + client = db_fetch4(name, inst, realm); + if(client == NULL){ + kdc_log(0, "Client not found in database: %s.%s@%s", + name, inst, realm); + make_err_reply(reply, KERB_ERR_PRINCIPAL_UNKNOWN, NULL); + goto out1; + } + server = db_fetch4(sname, sinst, v4_realm); + if(server == NULL){ + kdc_log(0, "Server not found in database: %s.%s@%s", + sname, sinst, v4_realm); + make_err_reply(reply, KERB_ERR_PRINCIPAL_UNKNOWN, NULL); + goto out1; + } + + ret = get_des_key(client, &ckey); + if(ret){ + kdc_log(0, "%s", krb5_get_err_text(context, ret)); + /* XXX */ + make_err_reply(reply, KDC_NULL_KEY, + "No DES key in database (client)"); + goto out1; + } + +#if 0 + /* this is not necessary with the new code in libkrb */ + /* find a properly salted key */ + while(ckey->salt == NULL || ckey->salt->salt.length != 0) + ret = hdb_next_keytype2key(context, client, KEYTYPE_DES, &ckey); + if(ret){ + kdc_log(0, "No version-4 salted key in database -- %s.%s@%s", + name, inst, realm); + make_err_reply(reply, KDC_NULL_KEY, + "No version-4 salted key in database"); + goto out1; + } +#endif + + ret = get_des_key(server, &skey); + if(ret){ + kdc_log(0, "%s", krb5_get_err_text(context, ret)); + /* XXX */ + make_err_reply(reply, KDC_NULL_KEY, + "No DES key in database (server)"); + goto out1; + } + + max_life = krb_life_to_time(0, life); + if(client->max_life) + max_life = min(max_life, *client->max_life); + if(server->max_life) + max_life = min(max_life, *server->max_life); + + life = krb_time_to_life(kdc_time, kdc_time + max_life); + + { + KTEXT_ST cipher, ticket; + KTEXT r; + des_cblock session; + + des_new_random_key(&session); + + krb_create_ticket(&ticket, 0, name, inst, v4_realm, + addr->sin_addr.s_addr, session, life, kdc_time, + sname, sinst, skey->key.keyvalue.data); + + create_ciph(&cipher, session, sname, sinst, v4_realm, + life, server->kvno, &ticket, kdc_time, + ckey->key.keyvalue.data); + memset(&session, 0, sizeof(session)); + r = create_auth_reply(name, inst, realm, req_time, 0, + client->pw_end ? *client->pw_end : 0, + client->kvno, &cipher); + krb5_data_copy(reply, r->dat, r->length); + memset(&cipher, 0, sizeof(cipher)); + memset(&ticket, 0, sizeof(ticket)); + } + out1: + break; + case AUTH_MSG_APPL_REQUEST: { + int8_t kvno; + int8_t ticket_len; + int8_t req_len; + KTEXT_ST auth; + AUTH_DAT ad; + size_t pos; + krb5_principal tgt_princ = NULL; + hdb_entry *tgt = NULL; + Key *tkey; + + RCHECK(krb5_ret_int8(sp, &kvno), out2); + RCHECK(krb5_ret_stringz(sp, &realm), out2); + + ret = krb5_425_conv_principal(context, "krbtgt", realm, v4_realm, + &tgt_princ); + if(ret){ + kdc_log(0, "Converting krbtgt principal: %s", + krb5_get_err_text(context, ret)); + make_err_reply(reply, KFAILURE, + "Failed to convert v4 principal (krbtgt)"); + goto out2; + } + + tgt = db_fetch(tgt_princ); + if(tgt == NULL){ + char *s; + s = kdc_log_msg(0, "Ticket-granting ticket not " + "found in database: krbtgt.%s@%s", + realm, v4_realm); + make_err_reply(reply, KFAILURE, s); + free(s); + goto out2; + } + + if(tgt->kvno != kvno){ + goto out2; + } + + ret = get_des_key(tgt, &tkey); + if(ret){ + kdc_log(0, "%s", krb5_get_err_text(context, ret)); + /* XXX */ + make_err_reply(reply, KDC_NULL_KEY, + "No DES key in database (krbtgt)"); + goto out2; + } + + RCHECK(krb5_ret_int8(sp, &ticket_len), out2); + RCHECK(krb5_ret_int8(sp, &req_len), out2); + + pos = sp->seek(sp, ticket_len + req_len, SEEK_CUR); + + memset(&auth, 0, sizeof(auth)); + memcpy(&auth.dat, buf, pos); + auth.length = pos; + krb_set_key(tkey->key.keyvalue.data, 0); + ret = krb_rd_req(&auth, "krbtgt", realm, + addr->sin_addr.s_addr, &ad, 0); + if(ret){ + kdc_log(0, "krb_rd_req: %s", krb_get_err_text(ret)); + make_err_reply(reply, ret, NULL); + goto out2; + } + + RCHECK(krb5_ret_int32(sp, &req_time), out2); + if(lsb) + req_time = swap32(req_time); + RCHECK(krb5_ret_int8(sp, &life), out2); + RCHECK(krb5_ret_stringz(sp, &sname), out2); + RCHECK(krb5_ret_stringz(sp, &sinst), out2); + kdc_log(0, "TGS-REQ %s.%s@%s from %s for %s.%s", + ad.pname, ad.pinst, ad.prealm, from, sname, sinst); + + if(strcmp(ad.prealm, realm)){ + kdc_log(0, "Can't hop realms %s -> %s", realm, ad.prealm); + make_err_reply(reply, KERB_ERR_PRINCIPAL_UNKNOWN, + "Can't hop realms"); + goto out2; + } + + if(strcmp(sname, "changepw") == 0){ + kdc_log(0, "Bad request for changepw ticket"); + make_err_reply(reply, KERB_ERR_PRINCIPAL_UNKNOWN, + "Can't authorize password change based on TGT"); + goto out2; + } + +#if 0 + client = db_fetch4(ad.pname, ad.pinst, ad.prealm); + if(client == NULL){ + char *s; + s = kdc_log_msg(0, "Client not found in database: %s.%s@%s", + ad.pname, ad.pinst, ad.prealm); + make_err_reply(reply, KERB_ERR_PRINCIPAL_UNKNOWN, s); + free(s); + goto out2; + } +#endif + + server = db_fetch4(sname, sinst, v4_realm); + if(server == NULL){ + char *s; + s = kdc_log_msg(0, "Server not found in database: %s.%s@%s", + sname, sinst, v4_realm); + make_err_reply(reply, KERB_ERR_PRINCIPAL_UNKNOWN, s); + free(s); + goto out2; + } + + ret = get_des_key(server, &skey); + if(ret){ + kdc_log(0, "%s", krb5_get_err_text(context, ret)); + /* XXX */ + make_err_reply(reply, KDC_NULL_KEY, + "No DES key in database (server)"); + goto out2; + } + + max_life = krb_life_to_time(ad.time_sec, ad.life); + max_life = min(max_life, krb_life_to_time(kdc_time, life)); + life = min(life, krb_time_to_life(kdc_time, max_life)); + max_life = krb_life_to_time(0, life); +#if 0 + if(client->max_life) + max_life = min(max_life, *client->max_life); +#endif + if(server->max_life) + max_life = min(max_life, *server->max_life); + + { + KTEXT_ST cipher, ticket; + KTEXT r; + des_cblock session; + des_new_random_key(&session); + krb_create_ticket(&ticket, 0, ad.pname, ad.pinst, ad.prealm, + addr->sin_addr.s_addr, &session, life, kdc_time, + sname, sinst, skey->key.keyvalue.data); + + create_ciph(&cipher, session, sname, sinst, v4_realm, + life, server->kvno, &ticket, + kdc_time, &ad.session); + + memset(&session, 0, sizeof(session)); + memset(ad.session, 0, sizeof(ad.session)); + + r = create_auth_reply(ad.pname, ad.pinst, ad.prealm, + req_time, 0, 0, 0, &cipher); + krb5_data_copy(reply, r->dat, r->length); + memset(&cipher, 0, sizeof(cipher)); + memset(&ticket, 0, sizeof(ticket)); + } + out2: + if(tgt_princ) + krb5_free_principal(context, tgt_princ); + if(tgt){ + hdb_free_entry(context, tgt); + free(tgt); + } + + break; + } + + case AUTH_MSG_ERR_REPLY: + break; + default: + kdc_log(0, "Unknown message type: %d from %s", + msg_type, from); + + make_err_reply(reply, KFAILURE, "Unknown message type"); + } +out: + if(name) + free(name); + if(inst) + free(inst); + if(realm) + free(realm); + if(sname) + free(sname); + if(sinst) + free(sinst); + if(client){ + hdb_free_entry(context, client); + free(client); + } + if(server){ + hdb_free_entry(context, server); + free(server); + } + krb5_storage_free(sp); + return 0; +} + + +#define ETYPE_DES_PCBC 17 /* XXX */ + +krb5_error_code +encrypt_v4_ticket(void *buf, size_t len, des_cblock *key, EncryptedData *reply) +{ + des_key_schedule schedule; + + reply->etype = ETYPE_DES_PCBC; + reply->kvno = NULL; + reply->cipher.length = len; + reply->cipher.data = malloc(len); + if(len != 0 && reply->cipher.data == NULL) + return ENOMEM; + des_set_key(key, schedule); + des_pcbc_encrypt(buf, + reply->cipher.data, + len, + schedule, + key, + DES_ENCRYPT); + memset(schedule, 0, sizeof(schedule)); + return 0; +} + +krb5_error_code +encode_v4_ticket(void *buf, size_t len, EncTicketPart *et, + PrincipalName *service, size_t *size) +{ + krb5_storage *sp; + krb5_error_code ret; + char name[40], inst[40], realm[40]; + char sname[40], sinst[40]; + + { + krb5_principal princ; + principalname2krb5_principal(&princ, + *service, + et->crealm); + ret = krb5_524_conv_principal(context, + princ, + sname, + sinst, + realm); + krb5_free_principal(context, princ); + if(ret) + return ret; + + principalname2krb5_principal(&princ, + et->cname, + et->crealm); + + ret = krb5_524_conv_principal(context, + princ, + name, + inst, + realm); + krb5_free_principal(context, princ); + } + if(ret) + return ret; + + sp = krb5_storage_emem(); + + krb5_store_int8(sp, 0); /* flags */ + krb5_store_stringz(sp, name); + krb5_store_stringz(sp, inst); + krb5_store_stringz(sp, realm); + { + unsigned char tmp[4] = { 0, 0, 0, 0 }; + int i; + if(et->caddr){ + for(i = 0; i < et->caddr->len; i++) + if(et->caddr->val[i].addr_type == AF_INET && + et->caddr->val[i].address.length == 4){ + memcpy(tmp, et->caddr->val[i].address.data, 4); + break; + } + } + sp->store(sp, tmp, sizeof(tmp)); + } + + if((et->key.keytype != ETYPE_DES_CBC_MD5 && + et->key.keytype != ETYPE_DES_CBC_MD4 && + et->key.keytype != ETYPE_DES_CBC_CRC) || + et->key.keyvalue.length != 8) + return -1; + sp->store(sp, et->key.keyvalue.data, 8); + + { + time_t start = et->starttime ? *et->starttime : et->authtime; + krb5_store_int8(sp, krb_time_to_life(start, et->endtime)); + krb5_store_int32(sp, start); + } + + krb5_store_stringz(sp, sname); + krb5_store_stringz(sp, sinst); + + { + krb5_data data; + krb5_storage_to_data(sp, &data); + krb5_storage_free(sp); + *size = (data.length + 7) & ~7; /* pad to 8 bytes */ + if(*size > len) + return -1; + memset((unsigned char*)buf - *size + 1, 0, *size); + memcpy((unsigned char*)buf - *size + 1, data.data, data.length); + krb5_data_free(&data); + } + return 0; +} + +#endif /* KRB4 */ diff --git a/crypto/heimdal/kdc/kerberos4.h b/crypto/heimdal/kdc/kerberos4.h new file mode 100644 index 0000000..5bf3c2b --- /dev/null +++ b/crypto/heimdal/kdc/kerberos4.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 1997 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $Id: kerberos4.h,v 1.2 1999/12/02 17:04:59 joda Exp $ */ + +#ifndef __KERBEROS4_H__ +#define __KERBEROS4_H__ + +hdb_entry* db_fetch4(const char *name, + const char *instance, + const char *realm); + +#endif /* __KERBEROS4_H__ */ diff --git a/crypto/heimdal/kdc/kerberos5.c b/crypto/heimdal/kdc/kerberos5.c new file mode 100644 index 0000000..1108e6d --- /dev/null +++ b/crypto/heimdal/kdc/kerberos5.c @@ -0,0 +1,1639 @@ +/* + * Copyright (c) 1997-1999 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "kdc_locl.h" + +RCSID("$Id: kerberos5.c,v 1.108 1999/12/02 17:04:59 joda Exp $"); + +#define MAX_TIME ((time_t)((1U << 31) - 1)) + +static void +fix_time(time_t **t) +{ + if(*t == NULL){ + ALLOC(*t); + **t = MAX_TIME; + } + if(**t == 0) **t = MAX_TIME; /* fix for old clients */ +} + +static void +set_salt_padata (METHOD_DATA **m, Salt *salt) +{ + if (salt) { + ALLOC(*m); + (*m)->len = 1; + ALLOC((*m)->val); + (*m)->val->padata_type = salt->type; + copy_octet_string(&salt->salt, + &(*m)->val->padata_value); + } +} + +static PA_DATA* +find_padata(KDC_REQ *req, int *start, int type) +{ + while(*start < req->padata->len){ + (*start)++; + if(req->padata->val[*start - 1].padata_type == type) + return &req->padata->val[*start - 1]; + } + return NULL; +} + +#if 0 + +static krb5_error_code +find_keys(hdb_entry *client, + hdb_entry *server, + Key **ckey, + krb5_enctype *cetype, + Key **skey, + krb5_enctype *setype, + unsigned *etypes, + unsigned num_etypes) +{ + int i; + krb5_error_code ret; + for(i = 0; i < num_etypes; i++) { + if(client){ + ret = hdb_enctype2key(context, client, etypes[i], ckey); + if(ret) + continue; + } + if(server){ + ret = hdb_enctype2key(context, server, etypes[i], skey); + if(ret) + continue; + } + if(etype) + *cetype = *setype = etypes[i]; + return 0; + } + return KRB5KDC_ERR_ETYPE_NOSUPP; +} + +#else + +static krb5_error_code +find_etype(hdb_entry *princ, unsigned *etypes, unsigned len, + Key **key, int *index) +{ + int i; + krb5_error_code ret = KRB5KDC_ERR_ETYPE_NOSUPP; + + for(i = 0; i < len ; i++) { + krb5_error_code tmp; + + tmp = hdb_enctype2key(context, princ, etypes[i], key); + if (tmp == 0) { + if ((*key)->key.keyvalue.length != 0) { + ret = 0; + break; + } else { + ret = KRB5KDC_ERR_NULL_KEY; + } + } + } + if(index) + *index = i; + return ret; +} + +static krb5_error_code +find_keys(hdb_entry *client, + hdb_entry *server, + Key **ckey, + krb5_enctype *cetype, + Key **skey, + krb5_enctype *setype, + int *etypes, + unsigned num_etypes) +{ + int i; + krb5_error_code ret; + if(client){ + /* find client key */ + ret = find_etype(client, etypes, num_etypes, ckey, &i); + if (ret) { + kdc_log(0, "Client has no support for etypes"); + return ret; + } + *cetype = etypes[i]; + } + + if(server){ + /* find server key */ + ret = find_etype(server, etypes, num_etypes, skey, NULL); + if (ret) { + kdc_log(0, "Server has no support for etypes"); + return ret; + } + *setype = (*skey)->key.keytype; + } + return 0; +} +#endif + +static krb5_error_code +encode_reply(KDC_REP *rep, EncTicketPart *et, EncKDCRepPart *ek, + krb5_enctype etype, + int skvno, EncryptionKey *skey, + int ckvno, EncryptionKey *ckey, + krb5_data *reply) +{ + unsigned char buf[8192]; /* XXX The data could be indefinite */ + size_t len; + krb5_error_code ret; + krb5_crypto crypto; + + ret = encode_EncTicketPart(buf + sizeof(buf) - 1, sizeof(buf), et, &len); + if(ret) { + kdc_log(0, "Failed to encode ticket: %s", + krb5_get_err_text(context, ret)); + return ret; + } + + + krb5_crypto_init(context, skey, etype, &crypto); + + krb5_encrypt_EncryptedData(context, + crypto, + KRB5_KU_TICKET, + buf + sizeof(buf) - len, + len, + skvno, + &rep->ticket.enc_part); + + krb5_crypto_destroy(context, crypto); + + if(rep->msg_type == krb_as_rep && !encode_as_rep_as_tgs_rep) + ret = encode_EncASRepPart(buf + sizeof(buf) - 1, sizeof(buf), + ek, &len); + else + ret = encode_EncTGSRepPart(buf + sizeof(buf) - 1, sizeof(buf), + ek, &len); + if(ret) { + kdc_log(0, "Failed to encode KDC-REP: %s", + krb5_get_err_text(context, ret)); + return ret; + } + krb5_crypto_init(context, ckey, 0, &crypto); + if(rep->msg_type == krb_as_rep) { + krb5_encrypt_EncryptedData(context, + crypto, + KRB5_KU_AS_REP_ENC_PART, + buf + sizeof(buf) - len, + len, + ckvno, + &rep->enc_part); + ret = encode_AS_REP(buf + sizeof(buf) - 1, sizeof(buf), rep, &len); + } else { + krb5_encrypt_EncryptedData(context, + crypto, + KRB5_KU_TGS_REP_ENC_PART_SESSION, + buf + sizeof(buf) - len, + len, + ckvno, + &rep->enc_part); + ret = encode_TGS_REP(buf + sizeof(buf) - 1, sizeof(buf), rep, &len); + } + krb5_crypto_destroy(context, crypto); + if(ret) { + kdc_log(0, "Failed to encode KDC-REP: %s", + krb5_get_err_text(context, ret)); + return ret; + } + krb5_data_copy(reply, buf + sizeof(buf) - len, len); + return 0; +} + +static int +realloc_method_data(METHOD_DATA *md) +{ + PA_DATA *pa; + pa = realloc(md->val, (md->len + 1) * sizeof(*md->val)); + if(pa == NULL) + return ENOMEM; + md->val = pa; + md->len++; + return 0; +} + +static krb5_error_code +get_pa_etype_info(METHOD_DATA *md, hdb_entry *client) +{ + krb5_error_code ret = 0; + int i; + ETYPE_INFO pa; + unsigned char *buf; + size_t len; + + + pa.len = client->keys.len; + pa.val = malloc(pa.len * sizeof(*pa.val)); + if(pa.val == NULL) + return ENOMEM; + for(i = 0; i < client->keys.len; i++) { + pa.val[i].etype = client->keys.val[i].key.keytype; + ALLOC(pa.val[i].salttype); + if(client->keys.val[i].salt){ +#if 0 + if(client->keys.val[i].salt->type == hdb_pw_salt) + *pa.val[i].salttype = 0; /* or 1? or NULL? */ + else if(client->keys.val[i].salt->type == hdb_afs3_salt) + *pa.val[i].salttype = 2; + else { + free_ETYPE_INFO(&pa); + kdc_log(0, "unknown salt-type: %d", + client->keys.val[i].salt->type); + return KRB5KRB_ERR_GENERIC; + } + /* according to `the specs', we can't send a salt if + we have AFS3 salted key, but that requires that you + *know* what cell you are using (e.g by assuming + that the cell is the same as the realm in lower + case) */ +#else + *pa.val[i].salttype = client->keys.val[i].salt->type; +#endif + krb5_copy_data(context, &client->keys.val[i].salt->salt, + &pa.val[i].salt); + } else { +#if 0 + *pa.val[i].salttype = 1; /* or 0 with salt? */ +#else + *pa.val[i].salttype = pa_pw_salt; +#endif + pa.val[i].salt = NULL; + } + } + len = length_ETYPE_INFO(&pa); + buf = malloc(len); + if (buf) { + free_ETYPE_INFO(&pa); + return ret; + } + ret = encode_ETYPE_INFO(buf + len - 1, len, &pa, &len); + free_ETYPE_INFO(&pa); + if(ret) { + free(buf); + return ret; + } + ret = realloc_method_data(md); + if(ret) { + free(buf); + return ret; + } + md->val[md->len - 1].padata_type = pa_etype_info; + md->val[md->len - 1].padata_value.length = len; + md->val[md->len - 1].padata_value.data = buf; + return 0; +} + +static int +check_flags(hdb_entry *client, const char *client_name, + hdb_entry *server, const char *server_name, + krb5_boolean is_as_req) +{ + if(client != NULL) { + /* check client */ + if (client->flags.invalid) { + kdc_log(0, "Client (%s) has invalid bit set", client_name); + return KRB5KDC_ERR_POLICY; + } + + if(!client->flags.client){ + kdc_log(0, "Principal may not act as client -- %s", + client_name); + return KRB5KDC_ERR_POLICY; + } + + if (client->valid_start && *client->valid_start > kdc_time) { + kdc_log(0, "Client not yet valid -- %s", client_name); + return KRB5KDC_ERR_CLIENT_NOTYET; + } + + if (client->valid_end && *client->valid_end < kdc_time) { + kdc_log(0, "Client expired -- %s", client_name); + return KRB5KDC_ERR_NAME_EXP; + } + + if (client->pw_end && *client->pw_end < kdc_time + && !server->flags.change_pw) { + kdc_log(0, "Client's key has expired -- %s", client_name); + return KRB5KDC_ERR_KEY_EXPIRED; + } + } + + /* check server */ + + if (server != NULL) { + if (server->flags.invalid) { + kdc_log(0, "Server has invalid flag set -- %s", server_name); + return KRB5KDC_ERR_POLICY; + } + + if(!server->flags.server){ + kdc_log(0, "Principal may not act as server -- %s", + server_name); + return KRB5KDC_ERR_POLICY; + } + + if(!is_as_req && server->flags.initial) { + kdc_log(0, "AS-REQ is required for server -- %s", server_name); + return KRB5KDC_ERR_POLICY; + } + + if (server->valid_start && *server->valid_start > kdc_time) { + kdc_log(0, "Server not yet valid -- %s", server_name); + return KRB5KDC_ERR_SERVICE_NOTYET; + } + + if (server->valid_end && *server->valid_end < kdc_time) { + kdc_log(0, "Server expired -- %s", server_name); + return KRB5KDC_ERR_SERVICE_EXP; + } + + if (server->pw_end && *server->pw_end < kdc_time) { + kdc_log(0, "Server's key has expired -- %s", server_name); + return KRB5KDC_ERR_KEY_EXPIRED; + } + } + return 0; +} + +static krb5_boolean +check_addresses(HostAddresses *addresses, struct sockaddr *from) +{ + krb5_error_code ret; + krb5_address addr; + + if(check_ticket_addresses == 0) + return TRUE; + + if(addresses == NULL) + return allow_null_ticket_addresses; + + ret = krb5_sockaddr2address (from, &addr); + if(ret) + return FALSE; + + return krb5_address_search(context, &addr, addresses); +} + +krb5_error_code +as_rep(KDC_REQ *req, + krb5_data *reply, + const char *from, + struct sockaddr *from_addr) +{ + KDC_REQ_BODY *b = &req->req_body; + AS_REP rep; + KDCOptions f = b->kdc_options; + hdb_entry *client = NULL, *server = NULL; + krb5_enctype cetype, setype; + EncTicketPart et; + EncKDCRepPart ek; + krb5_principal client_princ, server_princ; + char *client_name, *server_name; + krb5_error_code ret = 0; + const char *e_text = NULL; + krb5_crypto crypto; + + Key *ckey, *skey; + + if(b->sname == NULL){ + server_name = "<unknown server>"; + ret = KRB5KRB_ERR_GENERIC; + e_text = "No server in request"; + } else{ + principalname2krb5_principal (&server_princ, *(b->sname), b->realm); + krb5_unparse_name(context, server_princ, &server_name); + } + + if(b->cname == NULL){ + client_name = "<unknown client>"; + ret = KRB5KRB_ERR_GENERIC; + e_text = "No client in request"; + } else { + principalname2krb5_principal (&client_princ, *(b->cname), b->realm); + krb5_unparse_name(context, client_princ, &client_name); + } + kdc_log(0, "AS-REQ %s from %s for %s", + client_name, from, server_name); + + if(ret) + goto out; + + client = db_fetch(client_princ); + if(client == NULL){ + kdc_log(0, "UNKNOWN -- %s", client_name); + ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN; + goto out; + } + + server = db_fetch(server_princ); + + if(server == NULL){ + kdc_log(0, "UNKNOWN -- %s", server_name); + ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN; + goto out; + } + + ret = check_flags(client, client_name, server, server_name, TRUE); + if(ret) + goto out; + + memset(&et, 0, sizeof(et)); + memset(&ek, 0, sizeof(ek)); + + if(req->padata){ + int i = 0; + PA_DATA *pa; + int found_pa = 0; + kdc_log(5, "Looking for pa-data -- %s", client_name); + while((pa = find_padata(req, &i, pa_enc_timestamp))){ + krb5_data ts_data; + PA_ENC_TS_ENC p; + time_t patime; + size_t len; + EncryptedData enc_data; + Key *pa_key; + + found_pa = 1; + + ret = decode_EncryptedData(pa->padata_value.data, + pa->padata_value.length, + &enc_data, + &len); + if (ret) { + ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; + kdc_log(5, "Failed to decode PA-DATA -- %s", + client_name); + goto out; + } + + ret = hdb_enctype2key(context, client, enc_data.etype, &pa_key); + if(ret){ + char *estr; + e_text = "No key matches pa-data"; + ret = KRB5KDC_ERR_PREAUTH_FAILED; + if(krb5_enctype_to_string(context, enc_data.etype, &estr)) + estr = NULL; + if(estr == NULL) + kdc_log(5, "No client key matching pa-data (%d) -- %s", + enc_data.etype, client_name); + else + kdc_log(5, "No client key matching pa-data (%s) -- %s", + estr, client_name); + free(estr); + + free_EncryptedData(&enc_data); + continue; + } + + krb5_crypto_init(context, &pa_key->key, 0, &crypto); + ret = krb5_decrypt_EncryptedData (context, + crypto, + KRB5_KU_PA_ENC_TIMESTAMP, + &enc_data, + &ts_data); + krb5_crypto_destroy(context, crypto); + free_EncryptedData(&enc_data); + if(ret){ + e_text = "Failed to decrypt PA-DATA"; + kdc_log (5, "Failed to decrypt PA-DATA -- %s", + client_name); + ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; + continue; + } + ret = decode_PA_ENC_TS_ENC(ts_data.data, + ts_data.length, + &p, + &len); + krb5_data_free(&ts_data); + if(ret){ + e_text = "Failed to decode PA-ENC-TS-ENC"; + ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; + kdc_log (5, "Failed to decode PA-ENC-TS_ENC -- %s", + client_name); + continue; + } + patime = p.patimestamp; + free_PA_ENC_TS_ENC(&p); + if (abs(kdc_time - p.patimestamp) > context->max_skew) { + ret = KRB5KDC_ERR_PREAUTH_FAILED; + e_text = "Too large time skew"; + kdc_log(0, "Too large time skew -- %s", client_name); + goto out; + } + et.flags.pre_authent = 1; + kdc_log(2, "Pre-authentication succeded -- %s", client_name); + break; + } + if(found_pa == 0 && require_preauth) + goto use_pa; + /* We come here if we found a pa-enc-timestamp, but if there + was some problem with it, other than too large skew */ + if(found_pa && et.flags.pre_authent == 0){ + kdc_log(0, "%s -- %s", e_text, client_name); + e_text = NULL; + goto out; + } + }else if (require_preauth || client->flags.require_preauth || server->flags.require_preauth) { + METHOD_DATA method_data; + PA_DATA *pa; + unsigned char *buf; + size_t len; + krb5_data foo_data; + + use_pa: + method_data.len = 0; + method_data.val = NULL; + + ret = realloc_method_data(&method_data); + pa = &method_data.val[method_data.len-1]; + pa->padata_type = pa_enc_timestamp; + pa->padata_value.length = 0; + pa->padata_value.data = NULL; + + ret = get_pa_etype_info(&method_data, client); /* XXX check ret */ + + len = length_METHOD_DATA(&method_data); + buf = malloc(len); + encode_METHOD_DATA(buf + len - 1, + len, + &method_data, + &len); + free_METHOD_DATA(&method_data); + foo_data.length = len; + foo_data.data = buf; + + ret = KRB5KDC_ERR_PREAUTH_REQUIRED; + krb5_mk_error(context, + ret, + "Need to use PA-ENC-TIMESTAMP", + &foo_data, + client_princ, + server_princ, + 0, + reply); + free(buf); + kdc_log(0, "No PA-ENC-TIMESTAMP -- %s", client_name); + ret = 0; + goto out2; + } + + ret = find_keys(client, server, &ckey, &cetype, &skey, &setype, + b->etype.val, b->etype.len); + if(ret) { + kdc_log(0, "Server/client has no support for etypes"); + goto out; + } + + { + char *cet; + char *set; + krb5_enctype_to_string(context, cetype, &cet); + krb5_enctype_to_string(context, setype, &set); + kdc_log(5, "Using %s/%s", cet, set); + free(cet); + free(set); + } + + + memset(&rep, 0, sizeof(rep)); + rep.pvno = 5; + rep.msg_type = krb_as_rep; + copy_Realm(&b->realm, &rep.crealm); + copy_PrincipalName(b->cname, &rep.cname); + rep.ticket.tkt_vno = 5; + copy_Realm(&b->realm, &rep.ticket.realm); + copy_PrincipalName(b->sname, &rep.ticket.sname); + + { + char str[128]; + unparse_flags(KDCOptions2int(f), KDCOptions_units, str, sizeof(str)); + if(*str) + kdc_log(2, "Requested flags: %s", str); + } + + if(f.renew || f.validate || f.proxy || f.forwarded || f.enc_tkt_in_skey || + f.request_anonymous){ + ret = KRB5KDC_ERR_BADOPTION; + kdc_log(0, "Bad KDC options -- %s", client_name); + goto out; + } + + et.flags.initial = 1; + if(client->flags.forwardable && server->flags.forwardable) + et.flags.forwardable = f.forwardable; + else if (f.forwardable) { + ret = KRB5KDC_ERR_POLICY; + kdc_log(0, "Ticket may not be forwardable -- %s", client_name); + goto out; + } + if(client->flags.proxiable && server->flags.proxiable) + et.flags.proxiable = f.proxiable; + else if (f.proxiable) { + ret = KRB5KDC_ERR_POLICY; + kdc_log(0, "Ticket may not be proxiable -- %s", client_name); + goto out; + } + if(client->flags.postdate && server->flags.postdate) + et.flags.may_postdate = f.allow_postdate; + else if (f.allow_postdate){ + ret = KRB5KDC_ERR_POLICY; + kdc_log(0, "Ticket may not be postdatable -- %s", client_name); + goto out; + } + + /* check for valid set of addresses */ + if(!check_addresses(b->addresses, from_addr)) { + ret = KRB5KRB_AP_ERR_BADADDR; + kdc_log(0, "Bad address list requested -- %s", client_name); + goto out; + } + + krb5_generate_random_keyblock(context, setype, &et.key); + copy_PrincipalName(b->cname, &et.cname); + copy_Realm(&b->realm, &et.crealm); + + { + time_t start; + time_t t; + + start = et.authtime = kdc_time; + + if(f.postdated && req->req_body.from){ + ALLOC(et.starttime); + start = *et.starttime = *req->req_body.from; + et.flags.invalid = 1; + et.flags.postdated = 1; /* XXX ??? */ + } + fix_time(&b->till); + t = *b->till; + if(client->max_life) + t = min(t, start + *client->max_life); + if(server->max_life) + t = min(t, start + *server->max_life); +#if 0 + t = min(t, start + realm->max_life); +#endif + et.endtime = t; + if(f.renewable_ok && et.endtime < *b->till){ + f.renewable = 1; + if(b->rtime == NULL){ + ALLOC(b->rtime); + *b->rtime = 0; + } + if(*b->rtime < *b->till) + *b->rtime = *b->till; + } + if(f.renewable && b->rtime){ + t = *b->rtime; + if(t == 0) + t = MAX_TIME; + if(client->max_renew) + t = min(t, start + *client->max_renew); + if(server->max_renew) + t = min(t, start + *server->max_renew); +#if 0 + t = min(t, start + realm->max_renew); +#endif + ALLOC(et.renew_till); + *et.renew_till = t; + et.flags.renewable = 1; + } + } + + if(b->addresses){ + ALLOC(et.caddr); + copy_HostAddresses(b->addresses, et.caddr); + } + + { + krb5_data empty_string; + + krb5_data_zero(&empty_string); + et.transited.tr_type = DOMAIN_X500_COMPRESS; + et.transited.contents = empty_string; + } + + copy_EncryptionKey(&et.key, &ek.key); + + /* The MIT ASN.1 library (obviously) doesn't tell lengths encoded + * as 0 and as 0x80 (meaning indefinite length) apart, and is thus + * incapable of correctly decoding SEQUENCE OF's of zero length. + * + * To fix this, always send at least one no-op last_req + * + * If there's a pw_end or valid_end we will use that, + * otherwise just a dummy lr. + */ + ek.last_req.val = malloc(2 * sizeof(*ek.last_req.val)); + ek.last_req.len = 0; + if (client->pw_end + && (kdc_warn_pwexpire == 0 + || kdc_time + kdc_warn_pwexpire <= *client->pw_end)) { + ek.last_req.val[ek.last_req.len].lr_type = 6; + ek.last_req.val[ek.last_req.len].lr_value = *client->pw_end; + ++ek.last_req.len; + } + if (client->valid_end) { + ek.last_req.val[ek.last_req.len].lr_type = 7; + ek.last_req.val[ek.last_req.len].lr_value = *client->valid_end; + ++ek.last_req.len; + } + if (ek.last_req.len == 0) { + ek.last_req.val[ek.last_req.len].lr_type = 0; + ek.last_req.val[ek.last_req.len].lr_value = 0; + ++ek.last_req.len; + } + ek.nonce = b->nonce; + if (client->valid_end || client->pw_end) { + ALLOC(ek.key_expiration); + if (client->valid_end) { + if (client->pw_end) + *ek.key_expiration = min(*client->valid_end, *client->pw_end); + else + *ek.key_expiration = *client->valid_end; + } else + *ek.key_expiration = *client->pw_end; + } else + ek.key_expiration = NULL; + ek.flags = et.flags; + ek.authtime = et.authtime; + if (et.starttime) { + ALLOC(ek.starttime); + *ek.starttime = *et.starttime; + } + ek.endtime = et.endtime; + if (et.renew_till) { + ALLOC(ek.renew_till); + *ek.renew_till = *et.renew_till; + } + copy_Realm(&rep.ticket.realm, &ek.srealm); + copy_PrincipalName(&rep.ticket.sname, &ek.sname); + if(et.caddr){ + ALLOC(ek.caddr); + copy_HostAddresses(et.caddr, ek.caddr); + } + + set_salt_padata (&rep.padata, ckey->salt); + ret = encode_reply(&rep, &et, &ek, setype, server->kvno, &skey->key, + client->kvno, &ckey->key, reply); + free_EncTicketPart(&et); + free_EncKDCRepPart(&ek); + free_AS_REP(&rep); +out: + if(ret){ + krb5_mk_error(context, + ret, + e_text, + NULL, + client_princ, + server_princ, + 0, + reply); + ret = 0; + } +out2: + krb5_free_principal(context, client_princ); + free(client_name); + krb5_free_principal(context, server_princ); + free(server_name); + if(client){ + hdb_free_entry(context, client); + free(client); + } + if(server){ + hdb_free_entry(context, server); + free(server); + } + + return ret; +} + + +static krb5_error_code +check_tgs_flags(KDC_REQ_BODY *b, EncTicketPart *tgt, EncTicketPart *et) +{ + KDCOptions f = b->kdc_options; + + if(f.validate){ + if(!tgt->flags.invalid || tgt->starttime == NULL){ + kdc_log(0, "Bad request to validate ticket"); + return KRB5KDC_ERR_BADOPTION; + } + if(*tgt->starttime > kdc_time){ + kdc_log(0, "Early request to validate ticket"); + return KRB5KRB_AP_ERR_TKT_NYV; + } + /* XXX tkt = tgt */ + et->flags.invalid = 0; + }else if(tgt->flags.invalid){ + kdc_log(0, "Ticket-granting ticket has INVALID flag set"); + return KRB5KRB_AP_ERR_TKT_INVALID; + } + + if(f.forwardable){ + if(!tgt->flags.forwardable){ + kdc_log(0, "Bad request for forwardable ticket"); + return KRB5KDC_ERR_BADOPTION; + } + et->flags.forwardable = 1; + } + if(f.forwarded){ + if(!tgt->flags.forwardable){ + kdc_log(0, "Request to forward non-forwardable ticket"); + return KRB5KDC_ERR_BADOPTION; + } + et->flags.forwarded = 1; + et->caddr = b->addresses; + } + if(tgt->flags.forwarded) + et->flags.forwarded = 1; + + if(f.proxiable){ + if(!tgt->flags.proxiable){ + kdc_log(0, "Bad request for proxiable ticket"); + return KRB5KDC_ERR_BADOPTION; + } + et->flags.proxiable = 1; + } + if(f.proxy){ + if(!tgt->flags.proxiable){ + kdc_log(0, "Request to proxy non-proxiable ticket"); + return KRB5KDC_ERR_BADOPTION; + } + et->flags.proxy = 1; + et->caddr = b->addresses; + } + if(tgt->flags.proxy) + et->flags.proxy = 1; + + if(f.allow_postdate){ + if(!tgt->flags.may_postdate){ + kdc_log(0, "Bad request for post-datable ticket"); + return KRB5KDC_ERR_BADOPTION; + } + et->flags.may_postdate = 1; + } + if(f.postdated){ + if(!tgt->flags.may_postdate){ + kdc_log(0, "Bad request for postdated ticket"); + return KRB5KDC_ERR_BADOPTION; + } + if(b->from) + *et->starttime = *b->from; + et->flags.postdated = 1; + et->flags.invalid = 1; + }else if(b->from && *b->from > kdc_time + context->max_skew){ + kdc_log(0, "Ticket cannot be postdated"); + return KRB5KDC_ERR_CANNOT_POSTDATE; + } + + if(f.renewable){ + if(!tgt->flags.renewable){ + kdc_log(0, "Bad request for renewable ticket"); + return KRB5KDC_ERR_BADOPTION; + } + et->flags.renewable = 1; + ALLOC(et->renew_till); + fix_time(&b->rtime); + *et->renew_till = *b->rtime; + } + if(f.renew){ + time_t old_life; + if(!tgt->flags.renewable || tgt->renew_till == NULL){ + kdc_log(0, "Request to renew non-renewable ticket"); + return KRB5KDC_ERR_BADOPTION; + } + old_life = tgt->endtime; + if(tgt->starttime) + old_life -= *tgt->starttime; + else + old_life -= tgt->authtime; + et->endtime = min(*b->till, *et->starttime + old_life); + } + + /* checks for excess flags */ + if(f.request_anonymous){ + kdc_log(0, "Request for anonymous ticket"); + return KRB5KDC_ERR_BADOPTION; + } + return 0; +} + +static krb5_error_code +fix_transited_encoding(TransitedEncoding *tr, + const char *client_realm, + const char *server_realm, + const char *tgt_realm) +{ + krb5_error_code ret = 0; + if(strcmp(client_realm, tgt_realm) && strcmp(server_realm, tgt_realm)){ + char **realms = NULL, **tmp; + int num_realms = 0; + int i; + if(tr->tr_type && tr->contents.length != 0) { + if(tr->tr_type != DOMAIN_X500_COMPRESS){ + kdc_log(0, "Unknown transited type: %u", + tr->tr_type); + return KRB5KDC_ERR_TRTYPE_NOSUPP; + } + ret = krb5_domain_x500_decode(tr->contents, + &realms, + &num_realms, + client_realm, + server_realm); + if(ret){ + krb5_warn(context, ret, "Decoding transited encoding"); + return ret; + } + } + tmp = realloc(realms, (num_realms + 1) * sizeof(*realms)); + if(tmp == NULL){ + ret = ENOMEM; + goto free_realms; + } + realms = tmp; + realms[num_realms] = strdup(tgt_realm); + if(realms[num_realms] == NULL){ + ret = ENOMEM; + goto free_realms; + } + num_realms++; + free_TransitedEncoding(tr); + tr->tr_type = DOMAIN_X500_COMPRESS; + ret = krb5_domain_x500_encode(realms, num_realms, &tr->contents); + if(ret) + krb5_warn(context, ret, "Encoding transited encoding"); + free_realms: + for(i = 0; i < num_realms; i++) + free(realms[i]); + free(realms); + } + return ret; +} + + +static krb5_error_code +tgs_make_reply(KDC_REQ_BODY *b, + EncTicketPart *tgt, + EncTicketPart *adtkt, + AuthorizationData *auth_data, + hdb_entry *server, + hdb_entry *client, + krb5_principal client_principal, + hdb_entry *krbtgt, + krb5_enctype cetype, + krb5_data *reply) +{ + KDC_REP rep; + EncKDCRepPart ek; + EncTicketPart et; + KDCOptions f = b->kdc_options; + krb5_error_code ret; + krb5_enctype etype; + Key *skey; + EncryptionKey *ekey; + + if(adtkt) { + int i; + krb5_keytype kt; + ekey = &adtkt->key; + for(i = 0; i < b->etype.len; i++){ + ret = krb5_enctype_to_keytype(context, b->etype.val[i], &kt); + if(ret) + continue; + if(adtkt->key.keytype == kt) + break; + } + if(i == b->etype.len) + return KRB5KDC_ERR_ETYPE_NOSUPP; + etype = b->etype.val[i]; + }else{ + ret = find_keys(NULL, server, NULL, NULL, &skey, &etype, + b->etype.val, b->etype.len); + if(ret) { + kdc_log(0, "Server has no support for etypes"); + return ret; + } + ekey = &skey->key; + } + + memset(&rep, 0, sizeof(rep)); + memset(&et, 0, sizeof(et)); + memset(&ek, 0, sizeof(ek)); + + rep.pvno = 5; + rep.msg_type = krb_tgs_rep; + + et.authtime = tgt->authtime; + fix_time(&b->till); + et.endtime = min(tgt->endtime, *b->till); + ALLOC(et.starttime); + *et.starttime = kdc_time; + + ret = check_tgs_flags(b, tgt, &et); + if(ret) + return ret; + + copy_TransitedEncoding(&tgt->transited, &et.transited); + ret = fix_transited_encoding(&et.transited, + *krb5_princ_realm(context, client_principal), + *krb5_princ_realm(context, server->principal), + *krb5_princ_realm(context, krbtgt->principal)); + if(ret){ + free_TransitedEncoding(&et.transited); + return ret; + } + + + copy_Realm(krb5_princ_realm(context, server->principal), + &rep.ticket.realm); + krb5_principal2principalname(&rep.ticket.sname, server->principal); + copy_Realm(&tgt->crealm, &rep.crealm); + copy_PrincipalName(&tgt->cname, &rep.cname); + rep.ticket.tkt_vno = 5; + + ek.caddr = et.caddr; + if(et.caddr == NULL) + et.caddr = tgt->caddr; + + { + time_t life; + life = et.endtime - *et.starttime; + if(client && client->max_life) + life = min(life, *client->max_life); + if(server->max_life) + life = min(life, *server->max_life); + et.endtime = *et.starttime + life; + } + if(f.renewable_ok && tgt->flags.renewable && + et.renew_till == NULL && et.endtime < *b->till){ + et.flags.renewable = 1; + ALLOC(et.renew_till); + *et.renew_till = *b->till; + } + if(et.renew_till){ + time_t renew; + renew = *et.renew_till - et.authtime; + if(client && client->max_renew) + renew = min(renew, *client->max_renew); + if(server->max_renew) + renew = min(renew, *server->max_renew); + *et.renew_till = et.authtime + renew; + } + + if(et.renew_till){ + *et.renew_till = min(*et.renew_till, *tgt->renew_till); + *et.starttime = min(*et.starttime, *et.renew_till); + et.endtime = min(et.endtime, *et.renew_till); + } + + *et.starttime = min(*et.starttime, et.endtime); + + if(*et.starttime == et.endtime){ + ret = KRB5KDC_ERR_NEVER_VALID; + goto out; + } + if(et.renew_till && et.endtime == *et.renew_till){ + free(et.renew_till); + et.renew_till = NULL; + et.flags.renewable = 0; + } + + et.flags.pre_authent = tgt->flags.pre_authent; + et.flags.hw_authent = tgt->flags.hw_authent; + + /* XXX Check enc-authorization-data */ + et.authorization_data = auth_data; + + krb5_generate_random_keyblock(context, etype, &et.key); + et.crealm = tgt->crealm; + et.cname = tgt->cname; + + ek.key = et.key; + /* MIT must have at least one last_req */ + ek.last_req.len = 1; + ek.last_req.val = calloc(1, sizeof(*ek.last_req.val)); + ek.nonce = b->nonce; + ek.flags = et.flags; + ek.authtime = et.authtime; + ek.starttime = et.starttime; + ek.endtime = et.endtime; + ek.renew_till = et.renew_till; + ek.srealm = rep.ticket.realm; + ek.sname = rep.ticket.sname; + + /* It is somewhat unclear where the etype in the following + encryption should come from. What we have is a session + key in the passed tgt, and a list of preferred etypes + *for the new ticket*. Should we pick the best possible + etype, given the keytype in the tgt, or should we look + at the etype list here as well? What if the tgt + session key is DES3 and we want a ticket with a (say) + CAST session key. Should the DES3 etype be added to the + etype list, even if we don't want a session key with + DES3? */ + ret = encode_reply(&rep, &et, &ek, etype, adtkt ? 0 : server->kvno, ekey, + 0, &tgt->key, reply); +out: + free_TGS_REP(&rep); + free_TransitedEncoding(&et.transited); + if(et.starttime) + free(et.starttime); + if(et.renew_till) + free(et.renew_till); + free_LastReq(&ek.last_req); + memset(et.key.keyvalue.data, 0, et.key.keyvalue.length); + free_EncryptionKey(&et.key); + return ret; +} + +static krb5_error_code +tgs_check_authenticator(krb5_auth_context ac, + KDC_REQ_BODY *b, + krb5_keyblock *key) +{ + krb5_authenticator auth; + size_t len; + unsigned char buf[8192]; + krb5_error_code ret; + krb5_crypto crypto; + + krb5_auth_getauthenticator(context, ac, &auth); + if(auth->cksum == NULL){ + kdc_log(0, "No authenticator in request"); + ret = KRB5KRB_AP_ERR_INAPP_CKSUM; + goto out; + } + /* + * according to RFC1510 it doesn't need to be keyed, + * but according to the latest draft it needs to. + */ + if ( +#if 0 +!krb5_checksum_is_keyed(context, auth->cksum->cksumtype) + || +#endif + !krb5_checksum_is_collision_proof(context, auth->cksum->cksumtype)) { + kdc_log(0, "Bad checksum type in authenticator: %d", + auth->cksum->cksumtype); + ret = KRB5KRB_AP_ERR_INAPP_CKSUM; + goto out; + } + + /* XXX should not re-encode this */ + ret = encode_KDC_REQ_BODY(buf + sizeof(buf) - 1, sizeof(buf), + b, &len); + if(ret){ + kdc_log(0, "Failed to encode KDC-REQ-BODY: %s", + krb5_get_err_text(context, ret)); + goto out; + } + krb5_crypto_init(context, key, 0, &crypto); + ret = krb5_verify_checksum(context, + crypto, + KRB5_KU_TGS_REQ_AUTH_CKSUM, + buf + sizeof(buf) - len, + len, + auth->cksum); + krb5_crypto_destroy(context, crypto); + if(ret){ + kdc_log(0, "Failed to verify checksum: %s", + krb5_get_err_text(context, ret)); + } +out: + free_Authenticator(auth); + free(auth); + return ret; +} + +static Realm +is_krbtgt(PrincipalName *p) +{ + if(p->name_string.len == 2 && strcmp(p->name_string.val[0], "krbtgt") == 0) + return p->name_string.val[1]; + else + return NULL; +} + +static Realm +find_rpath(Realm r) +{ + const char *new_realm = krb5_config_get_string(context, + NULL, + "libdefaults", + "capath", + r, + NULL); + return (Realm)new_realm; +} + + +static krb5_error_code +tgs_rep2(KDC_REQ_BODY *b, + PA_DATA *tgs_req, + krb5_data *reply, + const char *from, + struct sockaddr *from_addr) +{ + krb5_ap_req ap_req; + krb5_error_code ret; + krb5_principal princ; + krb5_auth_context ac = NULL; + krb5_ticket *ticket = NULL; + krb5_flags ap_req_options; + krb5_flags verify_ap_req_flags; + const char *e_text = NULL; + krb5_crypto crypto; + + hdb_entry *krbtgt = NULL; + EncTicketPart *tgt; + Key *tkey; + krb5_enctype cetype; + krb5_principal cp = NULL; + krb5_principal sp = NULL; + AuthorizationData *auth_data = NULL; + + memset(&ap_req, 0, sizeof(ap_req)); + ret = krb5_decode_ap_req(context, &tgs_req->padata_value, &ap_req); + if(ret){ + kdc_log(0, "Failed to decode AP-REQ: %s", + krb5_get_err_text(context, ret)); + goto out2; + } + + if(!is_krbtgt(&ap_req.ticket.sname)){ + /* XXX check for ticket.sname == req.sname */ + kdc_log(0, "PA-DATA is not a ticket-granting ticket"); + ret = KRB5KDC_ERR_POLICY; /* ? */ + goto out2; + } + + principalname2krb5_principal(&princ, + ap_req.ticket.sname, + ap_req.ticket.realm); + + krbtgt = db_fetch(princ); + + if(krbtgt == NULL) { + char *p; + krb5_unparse_name(context, princ, &p); + kdc_log(0, "Ticket-granting ticket not found in database: %s", p); + free(p); + ret = KRB5KRB_AP_ERR_NOT_US; + goto out2; + } + + if(ap_req.ticket.enc_part.kvno && + *ap_req.ticket.enc_part.kvno != krbtgt->kvno){ + char *p; + + krb5_unparse_name (context, princ, &p); + kdc_log(0, "Ticket kvno = %d, DB kvno = %d (%s)", + *ap_req.ticket.enc_part.kvno, + krbtgt->kvno, + p); + free (p); + ret = KRB5KRB_AP_ERR_BADKEYVER; + goto out2; + } + + ret = hdb_enctype2key(context, krbtgt, ap_req.ticket.enc_part.etype, &tkey); + if(ret){ + char *str; + krb5_enctype_to_string(context, ap_req.ticket.enc_part.etype, &str); + kdc_log(0, "No server key found for %s", str); + free(str); + ret = KRB5KRB_AP_ERR_BADKEYVER; + goto out2; + } + + if (b->kdc_options.validate) + verify_ap_req_flags = KRB5_VERIFY_AP_REQ_IGNORE_INVALID; + else + verify_ap_req_flags = 0; + + ret = krb5_verify_ap_req(context, + &ac, + &ap_req, + princ, + &tkey->key, + verify_ap_req_flags, + &ap_req_options, + &ticket); + + krb5_free_principal(context, princ); + if(ret) { + kdc_log(0, "Failed to verify AP-REQ: %s", + krb5_get_err_text(context, ret)); + goto out2; + } + + cetype = ap_req.authenticator.etype; + + tgt = &ticket->ticket; + + ret = tgs_check_authenticator(ac, b, &tgt->key); + + if (b->enc_authorization_data) { + krb5_keyblock *subkey; + krb5_data ad; + ret = krb5_auth_con_getremotesubkey(context, + ac, + &subkey); + if(ret){ + kdc_log(0, "Failed to get remote subkey: %s", + krb5_get_err_text(context, ret)); + goto out2; + } + if(subkey == NULL){ + ret = krb5_auth_con_getkey(context, ac, &subkey); + if(ret) { + kdc_log(0, "Failed to get session key: %s", + krb5_get_err_text(context, ret)); + goto out2; + } + } + if(subkey == NULL){ + kdc_log(0, "Failed to get key for enc-authorization-data"); + ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */ + goto out2; + } + krb5_crypto_init(context, subkey, 0, &crypto); + ret = krb5_decrypt_EncryptedData (context, + crypto, + KRB5_KU_TGS_REQ_AUTH_DAT_SUBKEY, + b->enc_authorization_data, + &ad); + krb5_crypto_destroy(context, crypto); + if(ret){ + kdc_log(0, "Failed to decrypt enc-authorization-data"); + ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */ + goto out2; + } + krb5_free_keyblock(context, subkey); + ALLOC(auth_data); + ret = decode_AuthorizationData(ad.data, ad.length, auth_data, NULL); + if(ret){ + free(auth_data); + auth_data = NULL; + kdc_log(0, "Failed to decode authorization data"); + ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */ + goto out2; + } + } + + krb5_auth_con_free(context, ac); + + if(ret){ + kdc_log(0, "Failed to verify authenticator: %s", + krb5_get_err_text(context, ret)); + goto out2; + } + + { + PrincipalName *s; + Realm r; + char *spn = NULL, *cpn = NULL; + hdb_entry *server = NULL, *client = NULL; + int loop = 0; + EncTicketPart adtkt; + char opt_str[128]; + + s = b->sname; + r = b->realm; + if(b->kdc_options.enc_tkt_in_skey){ + Ticket *t; + hdb_entry *uu; + krb5_principal p; + Key *tkey; + + if(b->additional_tickets == NULL || + b->additional_tickets->len == 0){ + ret = KRB5KDC_ERR_BADOPTION; /* ? */ + kdc_log(0, "No second ticket present in request"); + goto out; + } + t = &b->additional_tickets->val[0]; + if(!is_krbtgt(&t->sname)){ + kdc_log(0, "Additional ticket is not a ticket-granting ticket"); + ret = KRB5KDC_ERR_POLICY; + goto out2; + } + principalname2krb5_principal(&p, t->sname, t->realm); + uu = db_fetch(p); + krb5_free_principal(context, p); + if(uu == NULL){ + ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN; + goto out; + } + ret = hdb_enctype2key(context, uu, t->enc_part.etype, &tkey); + if(ret){ + ret = KRB5KDC_ERR_ETYPE_NOSUPP; /* XXX */ + goto out; + } + ret = krb5_decrypt_ticket(context, t, &tkey->key, &adtkt, 0); + + if(ret) + goto out; + s = &adtkt.cname; + r = adtkt.crealm; + } + + principalname2krb5_principal(&sp, *s, r); + krb5_unparse_name(context, sp, &spn); + principalname2krb5_principal(&cp, tgt->cname, tgt->crealm); + krb5_unparse_name(context, cp, &cpn); + unparse_flags (KDCOptions2int(b->kdc_options), KDCOptions_units, + opt_str, sizeof(opt_str)); + if(*opt_str) + kdc_log(0, "TGS-REQ %s from %s for %s [%s]", + cpn, from, spn, opt_str); + else + kdc_log(0, "TGS-REQ %s from %s for %s", cpn, from, spn); + server_lookup: + server = db_fetch(sp); + + + if(server == NULL){ + Realm req_rlm, new_rlm; + if(loop++ < 2 && (req_rlm = is_krbtgt(&sp->name))){ + new_rlm = find_rpath(req_rlm); + if(new_rlm) { + kdc_log(5, "krbtgt for realm %s not found, trying %s", + req_rlm, new_rlm); + krb5_free_principal(context, sp); + free(spn); + krb5_make_principal(context, &sp, r, + "krbtgt", new_rlm, NULL); + krb5_unparse_name(context, sp, &spn); + goto server_lookup; + } + } + kdc_log(0, "Server not found in database: %s", spn); + ret = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN; + goto out; + } + + client = db_fetch(cp); + if(client == NULL) + kdc_log(1, "Client not found in database: %s", cpn); +#if 0 + /* XXX check client only if same realm as krbtgt-instance */ + if(client == NULL){ + kdc_log(0, "Client not found in database: %s", cpn); + ret = KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN; + goto out; + } +#endif + + ret = check_flags(client, cpn, server, spn, FALSE); + if(ret) + goto out; + + if((b->kdc_options.validate || b->kdc_options.renew) && + !krb5_principal_compare(context, + krbtgt->principal, + server->principal)){ + kdc_log(0, "Inconsistent request."); + ret = KRB5KDC_ERR_SERVER_NOMATCH; + goto out; + } + + /* check for valid set of addresses */ + if(!check_addresses(tgt->caddr, from_addr)) { + ret = KRB5KRB_AP_ERR_BADADDR; + kdc_log(0, "Request from wrong address"); + goto out; + } + + ret = tgs_make_reply(b, + tgt, + b->kdc_options.enc_tkt_in_skey ? &adtkt : NULL, + auth_data, + server, + client, + cp, + krbtgt, + cetype, + reply); + + out: + free(spn); + free(cpn); + + if(server){ + hdb_free_entry(context, server); + free(server); + } + if(client){ + hdb_free_entry(context, client); + free(client); + } + + } +out2: + if(ret) + krb5_mk_error(context, + ret, + e_text, + NULL, + cp, + sp, + 0, + reply); + krb5_free_principal(context, cp); + krb5_free_principal(context, sp); + if (ticket) { + krb5_free_ticket(context, ticket); + free(ticket); + } + free_AP_REQ(&ap_req); + if(auth_data){ + free_AuthorizationData(auth_data); + free(auth_data); + } + + if(krbtgt){ + hdb_free_entry(context, krbtgt); + free(krbtgt); + } + return ret; +} + + +krb5_error_code +tgs_rep(KDC_REQ *req, + krb5_data *data, + const char *from, + struct sockaddr *from_addr) +{ + krb5_error_code ret; + int i = 0; + PA_DATA *tgs_req = NULL; + + if(req->padata == NULL){ + ret = KRB5KDC_ERR_PREAUTH_REQUIRED; /* XXX ??? */ + kdc_log(0, "TGS-REQ from %s without PA-DATA", from); + goto out; + } + + tgs_req = find_padata(req, &i, pa_tgs_req); + + if(tgs_req == NULL){ + ret = KRB5KDC_ERR_PADATA_TYPE_NOSUPP; + + kdc_log(0, "TGS-REQ from %s without PA-TGS-REQ", from); + goto out; + } + ret = tgs_rep2(&req->req_body, tgs_req, data, from, from_addr); +out: + if(ret && data->data == NULL){ + krb5_mk_error(context, + ret, + NULL, + NULL, + NULL, + NULL, + 0, + data); + } + return 0; +} diff --git a/crypto/heimdal/kdc/kstash.8 b/crypto/heimdal/kdc/kstash.8 new file mode 100644 index 0000000..e9a7502 --- /dev/null +++ b/crypto/heimdal/kdc/kstash.8 @@ -0,0 +1,27 @@ +.\" $Id: kstash.8,v 1.2 2000/01/08 10:57:31 assar Exp $ +.\" +.Dd Aug 27, 1997 +.Dt KSTASH 8 +.Os HEIMDAL +.Sh NAME +.Nm kstash +.Nd +Store the KDC master password in a file +.Sh SYNOPSIS +.Nm +.Op Fl k Ar file +.Op Fl -key-file= Ns Ar file +.Sh DESCRIPTION +.Nm +allows you to the master password and store in a file that will be read +by the KDC. +.Pp +Options supported: +.Bl -tag -width Ds +.It Fl k Ar file +.It Fl -key-file= Ns Ar file +Specify what file the master key is stored in. The default is +.Pa m-key . +.El +.Sh SEE ALSO +.Xr kdc 8 diff --git a/crypto/heimdal/kdc/kstash.c b/crypto/heimdal/kdc/kstash.c new file mode 100644 index 0000000..5b79fd1 --- /dev/null +++ b/crypto/heimdal/kdc/kstash.c @@ -0,0 +1,188 @@ +/* + * Copyright (c) 1997-1999 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "headers.h" + +RCSID("$Id: kstash.c,v 1.10 1999/11/13 04:14:17 assar Exp $"); + +krb5_context context; + +char *keyfile = HDB_DB_DIR "/m-key"; +char *v4_keyfile; +int convert_flag; +int help_flag; +int version_flag; + +struct getargs args[] = { + { "key-file", 'k', arg_string, &keyfile, "master key file", "file" }, + { "version4-key-file", '4', arg_string, &v4_keyfile, + "kerberos 4 master key file", "file" }, + { "convert-file", 0, arg_flag, &convert_flag, + "convert keytype of keyfile" }, + { "help", 'h', arg_flag, &help_flag }, + { "version", 0, arg_flag, &version_flag } +}; + +int num_args = sizeof(args) / sizeof(args[0]); + +static void +write_keyfile(EncryptionKey key) +{ + FILE *f; + char buf[1024]; + size_t len; + +#ifdef HAVE_UMASK + umask(077); +#endif + + f = fopen(keyfile, "w"); + if(f == NULL) + krb5_err(context, 1, errno, "%s", keyfile); + encode_EncryptionKey((unsigned char *)buf + sizeof(buf) - 1, + sizeof(buf), &key, &len); + fwrite(buf + sizeof(buf) - len, len, 1, f); + memset(buf, 0, sizeof(buf)); + if(ferror(f)) { + int e = errno; + unlink(keyfile); + krb5_err(context, 1, e, "%s", keyfile); + } + fclose(f); + chmod(keyfile, 0400); +} + +static int +convert_file(void) +{ + FILE *f; + unsigned char buf[1024]; + char *fn; + size_t len; + EncryptionKey key; + krb5_error_code ret; + + f = fopen(keyfile, "r"); + if(f == NULL) { + krb5_warn(context, errno, "%s", keyfile); + return 1; + } + len = fread(buf, 1, sizeof(buf), f); + if(ferror(f)) { + krb5_warn(context, errno, "fread"); + ret = 1; + goto out1; + } + fclose(f); + ret = decode_EncryptionKey(buf, len, &key, &len); + memset(buf, 0, sizeof(buf)); + if(ret) { + krb5_warn(context, ret, "decode_EncryptionKey"); + goto out2; + } + if(key.keytype == KEYTYPE_DES) + key.keytype = ETYPE_DES_CBC_MD5; + else if(key.keytype == ETYPE_DES_CBC_MD5) { + krb5_warnx(context, "keyfile already converted"); + ret = 0; + goto out2; + } else { + krb5_warnx(context, "bad encryption key type (%d)", key.keytype); + ret = 1; + goto out2; + } + asprintf(&fn, "%s.old", keyfile); + if(fn == NULL) { + krb5_warn(context, ENOMEM, "malloc"); + ret = 1; + goto out1; + } + if(rename(keyfile, fn) < 0) { + krb5_warn(context, errno, "rename"); + ret = 1; + goto out1; + } + write_keyfile(key); + krb5_free_keyblock_contents(context, &key); + return 0; +out1: + memset(buf, 0, sizeof(buf)); + return ret ? 1 : 0; +out2: + krb5_free_keyblock_contents(context, &key); + return ret ? 1 : 0; +} + +int +main(int argc, char **argv) +{ + char buf[1024]; + EncryptionKey key; + FILE *f; + + krb5_program_setup(&context, argc, argv, args, num_args, NULL); + + if(help_flag) + krb5_std_usage(0, args, num_args); + if(version_flag){ + print_version(NULL); + exit(0); + } + + if(convert_flag) + exit(convert_file()); + + key.keytype = ETYPE_DES_CBC_MD5; /* XXX */ + if(v4_keyfile) { + f = fopen(v4_keyfile, "r"); + if(f == NULL) + krb5_err(context, 1, errno, "fopen(%s)", v4_keyfile); + key.keyvalue.length = sizeof(des_cblock); + key.keyvalue.data = malloc(key.keyvalue.length); + fread(key.keyvalue.data, 1, key.keyvalue.length, f); + fclose(f); + } else { + krb5_salt salt; + salt.salttype = KRB5_PW_SALT; + /* XXX better value? */ + salt.saltvalue.data = NULL; + salt.saltvalue.length = 0; + if(des_read_pw_string(buf, sizeof(buf), "Master key: ", 1)) + exit(1); + krb5_string_to_key_salt(context, key.keytype, buf, salt, &key); + } + + write_keyfile(key); + krb5_free_keyblock_contents(context, &key); + exit(0); +} diff --git a/crypto/heimdal/kdc/log.c b/crypto/heimdal/kdc/log.c new file mode 100644 index 0000000..ddbdbee --- /dev/null +++ b/crypto/heimdal/kdc/log.c @@ -0,0 +1,86 @@ +/* + * Copyright (c) 1997, 1998 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "kdc_locl.h" +RCSID("$Id: log.c,v 1.12 1999/12/02 17:05:00 joda Exp $"); + +static krb5_log_facility *logf; + +void +kdc_openlog(krb5_config_section *cf) +{ + char **s = NULL, **p; + krb5_initlog(context, "kdc", &logf); + if(cf) + s = krb5_config_get_strings(context, cf, "kdc", "logging", NULL); + + if(s == NULL) + s = krb5_config_get_strings(context, NULL, "logging", "kdc", NULL); + if(s){ + for(p = s; *p; p++) + krb5_addlog_dest(context, logf, *p); + krb5_config_free_strings(s); + }else + krb5_addlog_dest(context, logf, "0-1/FILE:" HDB_DB_DIR "/kdc.log"); + krb5_set_warn_dest(context, logf); +} + +char* +kdc_log_msg_va(int level, const char *fmt, va_list ap) +{ + char *msg; + krb5_vlog_msg(context, logf, &msg, level, fmt, ap); + return msg; +} + +char* +kdc_log_msg(int level, const char *fmt, ...) +{ + va_list ap; + char *s; + va_start(ap, fmt); + s = kdc_log_msg_va(level, fmt, ap); + va_end(ap); + return s; +} + +void +kdc_log(int level, const char *fmt, ...) +{ + va_list ap; + char *s; + va_start(ap, fmt); + s = kdc_log_msg_va(level, fmt, ap); + if(s) free(s); + va_end(ap); +} diff --git a/crypto/heimdal/kdc/main.c b/crypto/heimdal/kdc/main.c new file mode 100644 index 0000000..46d7aba --- /dev/null +++ b/crypto/heimdal/kdc/main.c @@ -0,0 +1,98 @@ +/* + * Copyright (c) 1997, 1999 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "kdc_locl.h" + +RCSID("$Id: main.c,v 1.21 1999/12/02 17:05:00 joda Exp $"); + +sig_atomic_t exit_flag = 0; +krb5_context context; + +static RETSIGTYPE +sigterm(int sig) +{ + exit_flag = 1; +} + +int +main(int argc, char **argv) +{ + krb5_error_code ret; + set_progname(argv[0]); + + krb5_init_context(&context); + + configure(argc, argv); + + if(databases == NULL) { + db = malloc(sizeof(*db)); + num_db = 1; + ret = hdb_create(context, &db[0], NULL); + if(ret) + krb5_err(context, 1, ret, "hdb_create %s", HDB_DEFAULT_DB); + ret = hdb_set_master_keyfile(context, db[0], NULL); + if (ret) + krb5_err(context, 1, ret, "hdb_set_master_keyfile"); + } else { + struct dbinfo *d; + int i; + /* count databases */ + for(d = databases, i = 0; d; d = d->next, i++); + db = malloc(i * sizeof(*db)); + for(d = databases, num_db = 0; d; d = d->next, num_db++) { + ret = hdb_create(context, &db[num_db], d->dbname); + if(ret) + krb5_err(context, 1, ret, "hdb_create %s", d->dbname); + ret = hdb_set_master_keyfile(context, db[num_db], d->mkey_file); + if (ret) + krb5_err(context, 1, ret, "hdb_set_master_keyfile"); + } + } + +#ifdef HAVE_SIGACTION + { + struct sigaction sa; + + sa.sa_flags = 0; + sa.sa_handler = sigterm; + sigemptyset(&sa.sa_mask); + + sigaction(SIGINT, &sa, NULL); + } +#else + signal(SIGINT, sigterm); +#endif + loop(); + krb5_free_context(context); + return 0; +} diff --git a/crypto/heimdal/kdc/misc.c b/crypto/heimdal/kdc/misc.c new file mode 100644 index 0000000..e476ebc --- /dev/null +++ b/crypto/heimdal/kdc/misc.c @@ -0,0 +1,63 @@ +/* + * Copyright (c) 1997 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "kdc_locl.h" + +RCSID("$Id: misc.c,v 1.18 1999/12/02 17:05:00 joda Exp $"); + +struct timeval now; + +hdb_entry* +db_fetch(krb5_principal principal) +{ + hdb_entry *ent; + krb5_error_code ret; + int i; + ALLOC(ent); + ent->principal = principal; + + for(i = 0; i < num_db; i++) { + ret = db[i]->open(context, db[i], O_RDONLY, 0); + if (ret) { + kdc_log(0, "Failed to open database: %s", + krb5_get_err_text(context, ret)); + continue; + } + ret = db[i]->fetch(context, db[i], HDB_F_DECRYPT, ent); + db[i]->close(context, db[i]); + if(ret == 0) + return ent; + } + free(ent); + return NULL; +} diff --git a/crypto/heimdal/kdc/rx.h b/crypto/heimdal/kdc/rx.h new file mode 100644 index 0000000..ab8ec805 --- /dev/null +++ b/crypto/heimdal/kdc/rx.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 1997 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $Id: rx.h,v 1.4 1999/12/02 17:05:00 joda Exp $ */ + +#ifndef __RX_H__ +#define __RX_H__ + +/* header of a RPC packet */ + +enum rx_header_type { + HT_DATA = 1, + HT_ACK = 2, + HT_BUSY = 3, + HT_ABORT = 4, + HT_ACKALL = 5, + HT_CHAL = 6, + HT_RESP = 7, + HT_DEBUG = 8 +}; + +/* For flags in header */ + +enum rx_header_flag { + HF_CLIENT_INITIATED = 1, + HF_REQ_ACK = 2, + HF_LAST = 4, + HF_MORE = 8 +}; + +struct rx_header { + u_int32_t epoch; + u_int32_t connid; /* And channel ID */ + u_int32_t callid; + u_int32_t seqno; + u_int32_t serialno; + u_char type; + u_char flags; + u_char status; + u_char secindex; + u_int16_t reserved; /* ??? verifier? */ + u_int16_t serviceid; +/* This should be the other way around according to everything but */ +/* tcpdump */ +}; + +#define RX_HEADER_SIZE 28 + +#endif /* __RX_H__ */ diff --git a/crypto/heimdal/kdc/string2key.c b/crypto/heimdal/kdc/string2key.c new file mode 100644 index 0000000..e0cc871 --- /dev/null +++ b/crypto/heimdal/kdc/string2key.c @@ -0,0 +1,179 @@ +/* + * Copyright (c) 1997, 1998, 1999 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "headers.h" +#include <getarg.h> + +RCSID("$Id: string2key.c,v 1.18 1999/12/02 17:05:00 joda Exp $"); + +int version5; +int version4; +int afs; +char *principal; +char *cell; +char *password; +char *keytype_str = "des-cbc-md5"; +int version; +int help; + +struct getargs args[] = { + { "version5", '5', arg_flag, &version5, "Output Kerberos v5 string-to-key" }, + { "version4", '4', arg_flag, &version4, "Output Kerberos v4 string-to-key" }, + { "afs", 'a', arg_flag, &afs, "Output AFS string-to-key" }, + { "cell", 'c', arg_string, &cell, "AFS cell to use", "cell" }, + { "password", 'w', arg_string, &password, "Password to use", "password" }, + { "principal",'p', arg_string, &principal, "Kerberos v5 principal to use", "principal" }, + { "keytype", 'k', arg_string, &keytype_str, "Keytype" }, + { "version", 0, arg_flag, &version, "print version" }, + { "help", 0, arg_flag, &help, NULL } +}; + +int num_args = sizeof(args) / sizeof(args[0]); + +static void +usage(int status) +{ + arg_printusage (args, num_args, NULL, "password"); + exit(status); +} + +static void +tokey(krb5_context context, + krb5_enctype enctype, + const char *password, + krb5_salt salt, + const char *label) +{ + int i; + krb5_keyblock key; + krb5_string_to_key_salt(context, enctype, password, salt, &key); + printf("%s: ", label); + for(i = 0; i < key.keyvalue.length; i++) + printf("%02x", ((unsigned char*)key.keyvalue.data)[i]); + printf("\n"); + krb5_free_keyblock_contents(context, &key); +} + +int +main(int argc, char **argv) +{ + krb5_context context; + krb5_principal princ; + krb5_salt salt; + int optind; + char buf[1024]; + krb5_enctype etype; + krb5_error_code ret; + + optind = krb5_program_setup(&context, argc, argv, args, num_args, NULL); + + if(help) + usage(0); + + if(version){ + print_version (NULL); + return 0; + } + + argc -= optind; + argv += optind; + + if (argc > 1) + usage(1); + + if(!version5 && !version4 && !afs) + version5 = 1; + + ret = krb5_string_to_enctype(context, keytype_str, &etype); +#if 0 + if(ret) { + krb5_keytype keytype; + ret = krb5_string_to_keytype(context, keytype_str, &keytype); + ret = krb5_keytype_to_enctype(context, keytype, &etype); + } +#endif + if(ret) + krb5_err(context, 1, ret, "%s", keytype_str); + + if((etype != ETYPE_DES_CBC_CRC && + etype != ETYPE_DES_CBC_MD4 && + etype != ETYPE_DES_CBC_MD5) && + (afs || version4)) + krb5_errx(context, 1, + "DES is the only valid keytype for AFS and Kerberos 4"); + + + if(version5 && principal == NULL){ + printf("Kerberos v5 principal: "); + if(fgets(buf, sizeof(buf), stdin) == NULL) + return 1; + if(buf[strlen(buf) - 1] == '\n') + buf[strlen(buf) - 1] = '\0'; + principal = estrdup(buf); + } + if(afs && cell == NULL){ + printf("AFS cell: "); + if(fgets(buf, sizeof(buf), stdin) == NULL) + return 1; + if(buf[strlen(buf) - 1] == '\n') + buf[strlen(buf) - 1] = '\0'; + cell = estrdup(buf); + } + if(argv[0]) + password = argv[0]; + if(password == NULL){ + if(des_read_pw_string(buf, sizeof(buf), "Password: ", 0)) + return 1; + password = buf; + } + + if(version5){ + krb5_parse_name(context, principal, &princ); + krb5_get_pw_salt(context, princ, &salt); + tokey(context, etype, password, salt, "Kerberos v5 key"); + krb5_free_salt(context, salt); + } + if(version4){ + salt.salttype = KRB5_PW_SALT; + salt.saltvalue.length = 0; + salt.saltvalue.data = NULL; + tokey(context, ETYPE_DES_CBC_MD5, password, salt, "Kerberos v4 key"); + } + if(afs){ + salt.salttype = KRB5_AFS3_SALT; + salt.saltvalue.length = strlen(cell); + salt.saltvalue.data = cell; + tokey(context, ETYPE_DES_CBC_MD5, password, salt, "AFS key"); + } + return 0; +} |