summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGerald Carter <jerry@samba.org>2004-11-07 20:42:45 +0000
committerGerald Carter <jerry@samba.org>2004-11-07 20:42:45 +0000
commitf0ae41fc1025aa840218545add3fbe2c207cc5bc (patch)
tree3cddf8edcfd08e62c69605d9d5278ccd564384e8
parentf1909f3d5d948d8ef7d47a7b37d53b0121e09346 (diff)
downloadsamba-f0ae41fc1025aa840218545add3fbe2c207cc5bc.tar.gz
samba-f0ae41fc1025aa840218545add3fbe2c207cc5bc.tar.xz
samba-f0ae41fc1025aa840218545add3fbe2c207cc5bc.zip
r3605: * sync up with 3.0 with the exception of volker's recent changes
to the getaliases call
-rw-r--r--packaging/Solaris/makepkg.sh4
-rw-r--r--source/Makefile.in21
-rw-r--r--source/VERSION2
-rw-r--r--source/client/client.c4
-rw-r--r--source/client/smbspool.c8
-rw-r--r--source/configure.in104
-rw-r--r--source/groupdb/mapping.c5
-rw-r--r--source/include/includes.h13
-rw-r--r--source/include/secrets.h3
-rw-r--r--source/lib/account_pol.c5
-rw-r--r--source/libads/kerberos.c600
-rw-r--r--source/libads/kerberos_keytab.c176
-rw-r--r--source/libads/kerberos_verify.c132
-rw-r--r--source/libads/krb5_setpw.c4
-rw-r--r--source/libads/ldap.c52
-rw-r--r--source/libads/util.c58
-rw-r--r--source/libsmb/cliconnect.c2
-rw-r--r--source/libsmb/clikrb5.c96
-rw-r--r--source/libsmb/ntlm_check.c6
-rw-r--r--source/libsmb/smb_signing.c11
-rw-r--r--source/param/loadparm.c12
-rw-r--r--source/python/py_lsa.c4
-rw-r--r--source/python/samba/printerdata.py3
-rw-r--r--source/sam/idmap_rid.c70
-rw-r--r--source/smbd/dosmode.c4
-rw-r--r--source/smbd/posix_acls.c6
-rw-r--r--source/smbd/server.c9
-rw-r--r--source/smbd/trans2.c10
-rw-r--r--source/utils/net_ads.c18
-rw-r--r--source/utils/ntlm_auth.c4
30 files changed, 1161 insertions, 285 deletions
diff --git a/packaging/Solaris/makepkg.sh b/packaging/Solaris/makepkg.sh
index fdf4811a56d..a8195e0755f 100644
--- a/packaging/Solaris/makepkg.sh
+++ b/packaging/Solaris/makepkg.sh
@@ -58,9 +58,6 @@ add_dynamic_entries()
if [ -f lib/pam_winbind.so ]; then
echo f none /usr/lib/security/pam_winbind.so=lib/pam_winbind.so 0755 root other
fi
- if [ -f lib/pam_smbpass.so ]; then
- echo f none /usr/lib/security/pam_pam_smbpass.so=lib/pam_winbind.so 0755 root other
- fi
# Add the manpages
echo "#\n# man pages \n#"
@@ -124,7 +121,6 @@ if [ "x$1" != "xnobuild" ]; then
./configure --prefix=$INSTALL_DIR \
--with-acl-support \
--with-included-popt \
- --with-pam_smbpass \
--localstatedir=/var/lib/samba \
--with-piddir=/var/run \
--with-logfilebase=/var/log/samba \
diff --git a/source/Makefile.in b/source/Makefile.in
index 3a32bab1bab..370017c3ada 100644
--- a/source/Makefile.in
+++ b/source/Makefile.in
@@ -124,7 +124,8 @@ SBIN_PROGS = bin/smbd@EXEEXT@ bin/nmbd@EXEEXT@ bin/swat@EXEEXT@ @EXTRA_SBIN_PROG
BIN_PROGS1 = bin/smbclient@EXEEXT@ bin/net@EXEEXT@ bin/smbspool@EXEEXT@ \
bin/testparm@EXEEXT@ bin/testprns@EXEEXT@ bin/smbstatus@EXEEXT@
BIN_PROGS2 = bin/smbcontrol@EXEEXT@ bin/smbtree@EXEEXT@ bin/tdbbackup@EXEEXT@ \
- bin/nmblookup@EXEEXT@ bin/pdbedit@EXEEXT@ bin/tdbdump@EXEEXT@
+ bin/nmblookup@EXEEXT@ bin/pdbedit@EXEEXT@ bin/tdbdump@EXEEXT@ \
+ bin/tdbtool@EXEEXT@
BIN_PROGS3 = bin/smbpasswd@EXEEXT@ bin/rpcclient@EXEEXT@ bin/smbcacls@EXEEXT@ \
bin/profiles@EXEEXT@ bin/ntlm_auth@EXEEXT@ \
bin/smbcquotas@EXEEXT@
@@ -545,7 +546,7 @@ CUPS_OBJ = client/smbspool.o $(PARAM_OBJ) $(LIBSMB_OBJ) $(UBIQX_OBJ) \
$(LIB_NONSMBD_OBJ) $(KRBCLIENT_OBJ) $(SECRETS_OBJ)
MOUNT_OBJ = client/smbmount.o \
- $(PARAM_OBJ) $(LIBSMB_OBJ) $(KRBCLIENT_OBJ) $(UBIQX_OBJ) $(LIB_NONSMBD_OBJ)
+ $(PARAM_OBJ) $(LIBSMB_OBJ) $(KRBCLIENT_OBJ) $(UBIQX_OBJ) $(LIB_NONSMBD_OBJ) $(SECRETS_OBJ)
MNT_OBJ = client/smbmnt.o $(VERSION_OBJ) $(SNPRINTF_OBJ)
@@ -564,13 +565,13 @@ MASKTEST_OBJ = torture/masktest.o $(PARAM_OBJ) $(LIBSMB_OBJ) $(KRBCLIENT_OBJ) \
$(UBIQX_OBJ) $(LIB_NONSMBD_OBJ)
MSGTEST_OBJ = torture/msgtest.o $(PARAM_OBJ) $(LIBSMB_OBJ) $(KRBCLIENT_OBJ) \
- $(UBIQX_OBJ) $(LIB_NONSMBD_OBJ)
+ $(UBIQX_OBJ) $(LIB_NONSMBD_OBJ) $(SECRETS_OBJ)
LOCKTEST_OBJ = torture/locktest.o $(PARAM_OBJ) $(LOCKING_OBJ) $(KRBCLIENT_OBJ) \
- $(LIBSMB_OBJ) $(UBIQX_OBJ) $(LIB_NONSMBD_OBJ) $(DUMMYROOT_OBJ)
+ $(LIBSMB_OBJ) $(UBIQX_OBJ) $(LIB_NONSMBD_OBJ) $(DUMMYROOT_OBJ) $(SECRETS_OBJ)
NSSTEST_OBJ = torture/nsstest.o $(PARAM_OBJ) $(LIBSMB_OBJ) $(KRBCLIENT_OBJ) \
- $(UBIQX_OBJ) $(LIB_NONSMBD_OBJ)
+ $(UBIQX_OBJ) $(LIB_NONSMBD_OBJ) $(SECRETS_OBJ)
VFSTEST_OBJ = torture/cmd_vfs.o torture/vfstest.o $(SMBD_OBJ_BASE) $(READLINE_OBJ)
@@ -579,7 +580,7 @@ SMBICONV_OBJ = $(PARAM_OBJ) torture/smbiconv.o $(LIB_NONSMBD_OBJ) $(UBIQX_OBJ) $
LOG2PCAP_OBJ = utils/log2pcaphex.o
LOCKTEST2_OBJ = torture/locktest2.o $(PARAM_OBJ) $(LOCKING_OBJ) $(LIBSMB_OBJ) \
- $(KRBCLIENT_OBJ) $(UBIQX_OBJ) $(LIB_NONSMBD_OBJ) $(DUMMYROOT_OBJ)
+ $(KRBCLIENT_OBJ) $(UBIQX_OBJ) $(LIB_NONSMBD_OBJ) $(DUMMYROOT_OBJ) $(SECRETS_OBJ)
SMBCACLS_OBJ = utils/smbcacls.o $(PARAM_OBJ) $(LIBSMB_OBJ) \
$(KRBCLIENT_OBJ) $(UBIQX_OBJ) $(LIB_NONSMBD_OBJ) $(RPC_PARSE_OBJ) \
@@ -605,7 +606,7 @@ RPCTORTURE_OBJ = torture/rpctorture.o \
DEBUG2HTML_OBJ = utils/debug2html.o ubiqx/debugparse.o
-SMBFILTER_OBJ = utils/smbfilter.o $(PARAM_OBJ) $(LIBSMB_OBJ) \
+SMBFILTER_OBJ = utils/smbfilter.o $(PARAM_OBJ) $(LIBSMB_OBJ) $(SECRETS_OBJ) \
$(UBIQX_OBJ) $(LIB_NONSMBD_OBJ) $(KRBCLIENT_OBJ)
PROTO_OBJ = $(SMBD_OBJ_MAIN) \
@@ -677,6 +678,8 @@ POPT_OBJS=popt/findme.o popt/popt.o popt/poptconfig.o \
TDBBACKUP_OBJ = tdb/tdbbackup.o tdb/tdbback.o $(SNPRINTF_OBJ) $(TDBBASE_OBJ)
+TDBTOOL_OBJ = tdb/tdbtool.o $(TDBBASE_OBJ)
+
TDBDUMP_OBJ = tdb/tdbdump.o $(TDBBASE_OBJ)
NTLM_AUTH_OBJ1 = utils/ntlm_auth.o utils/ntlm_auth_diagnostics.o
@@ -1249,6 +1252,10 @@ bin/tdbbackup@EXEEXT@: $(TDBBACKUP_OBJ) bin/.dummy
@echo Linking $@
@$(CC) $(FLAGS) -o $@ $(DYNEXP) $(TDBBACKUP_OBJ)
+bin/tdbtool@EXEEXT@: $(TDBTOOL_OBJ) bin/.dummy
+ @echo Linking $@
+ @$(CC) $(FLAGS) -o $@ $(DYNEXP) $(TDBTOOL_OBJ)
+
bin/tdbdump@EXEEXT@: $(TDBDUMP_OBJ) bin/.dummy
@echo Linking $@
@$(CC) $(FLAGS) -o $@ $(DYNEXP) $(TDBDUMP_OBJ)
diff --git a/source/VERSION b/source/VERSION
index 2a22988fd9d..9cb06979bc7 100644
--- a/source/VERSION
+++ b/source/VERSION
@@ -29,7 +29,7 @@ SAMBA_VERSION_RELEASE=8
# e.g. SAMBA_VERSION_PRE_RELEASE=1 #
# -> "2.2.9pre1" #
########################################################
-SAMBA_VERSION_PRE_RELEASE=2
+SAMBA_VERSION_PRE_RELEASE=
########################################################
# For 'rc' releases the version will be #
diff --git a/source/client/client.c b/source/client/client.c
index c2fec17d7ec..311eaef8f21 100644
--- a/source/client/client.c
+++ b/source/client/client.c
@@ -701,7 +701,7 @@ static int do_get(char *rname, char *lname, BOOL reget)
return 1;
}
- DEBUG(2,("getting file %s of size %.0f as %s ",
+ DEBUG(1,("getting file %s of size %.0f as %s ",
rname, (double)size, lname));
if(!(data = (char *)malloc(read_size))) {
@@ -758,7 +758,7 @@ static int do_get(char *rname, char *lname, BOOL reget)
get_total_time_ms += this_time;
get_total_size += nread;
- DEBUG(2,("(%3.1f kb/s) (average %3.1f kb/s)\n",
+ DEBUG(1,("(%3.1f kb/s) (average %3.1f kb/s)\n",
nread / (1.024*this_time + 1.0e-4),
get_total_size / (1.024*get_total_time_ms)));
}
diff --git a/source/client/smbspool.c b/source/client/smbspool.c
index a67ccadb90b..f838c5de5bf 100644
--- a/source/client/smbspool.c
+++ b/source/client/smbspool.c
@@ -118,13 +118,13 @@ static int smb_print(struct cli_state *, char *, FILE *);
* Find the URI...
*/
- if (strncmp(argv[0], "smb://", 6) == 0)
- strncpy(uri, argv[0], sizeof(uri) - 1);
- else if (getenv("DEVICE_URI") != NULL)
+ if (getenv("DEVICE_URI") != NULL)
strncpy(uri, getenv("DEVICE_URI"), sizeof(uri) - 1);
+ else if (strncmp(argv[0], "smb://", 6) == 0)
+ strncpy(uri, argv[0], sizeof(uri) - 1);
else
{
- fputs("ERROR: No device URI found in argv[0] or DEVICE_URI environment variable!\n", stderr);
+ fputs("ERROR: No device URI found in DEVICE_URI environment variable or argv[0] !\n", stderr);
return (1);
}
diff --git a/source/configure.in b/source/configure.in
index df787655590..170b3c0d1c3 100644
--- a/source/configure.in
+++ b/source/configure.in
@@ -460,7 +460,7 @@ case "$host_os" in
*solaris*)
AC_DEFINE(SYSV, 1, [Whether to enable System V compatibility])
case `uname -r` in
- 5.0*|5.1*|5.2*|5.3*|5.5*)
+ 5.0|5.0.*|5.1|5.1.*|5.2|5.2.*|5.3|5.3.*|5.5|5.5.*)
AC_MSG_RESULT([no large file support])
;;
5.*)
@@ -654,13 +654,13 @@ AC_HEADER_DIRENT
AC_HEADER_TIME
AC_HEADER_SYS_WAIT
AC_CHECK_HEADERS(arpa/inet.h sys/fcntl.h sys/select.h fcntl.h sys/time.h sys/unistd.h)
-AC_CHECK_HEADERS(unistd.h utime.h grp.h sys/id.h limits.h memory.h net/if.h)
+AC_CHECK_HEADERS(unistd.h utime.h grp.h sys/id.h limits.h memory.h)
AC_CHECK_HEADERS(rpc/rpc.h rpcsvc/nis.h rpcsvc/yp_prot.h rpcsvc/ypclnt.h)
AC_CHECK_HEADERS(sys/param.h ctype.h sys/wait.h sys/resource.h sys/ioctl.h sys/ipc.h sys/mode.h)
AC_CHECK_HEADERS(sys/mman.h sys/filio.h sys/priv.h sys/shm.h string.h strings.h stdlib.h sys/socket.h)
AC_CHECK_HEADERS(sys/mount.h sys/vfs.h sys/fs/s5param.h sys/filsys.h termios.h termio.h)
AC_CHECK_HEADERS(sys/termio.h sys/statfs.h sys/dustat.h sys/statvfs.h stdarg.h sys/sockio.h)
-AC_CHECK_HEADERS(sys/sysmacros.h security/pam_modules.h security/_pam_macros.h dlfcn.h)
+AC_CHECK_HEADERS(sys/sysmacros.h security/_pam_macros.h dlfcn.h)
AC_CHECK_HEADERS(sys/syslog.h syslog.h execinfo.h)
AC_CHECK_HEADERS(langinfo.h locale.h)
@@ -687,11 +687,13 @@ case "$host_os" in
fi
;;
esac
-AC_CHECK_HEADERS(shadow.h netinet/ip.h netinet/tcp.h netinet/in_systm.h netinet/in_ip.h)
-AC_CHECK_HEADERS(nss.h nss_common.h nsswitch.h ns_api.h sys/security.h security/pam_appl.h security/pam_modules.h)
+AC_CHECK_HEADERS(shadow.h netinet/tcp.h netinet/in_systm.h netinet/in_ip.h)
+AC_CHECK_HEADERS(nss.h nss_common.h nsswitch.h ns_api.h sys/security.h security/pam_appl.h)
AC_CHECK_HEADERS(stropts.h poll.h)
AC_CHECK_HEADERS(sys/capability.h syscall.h sys/syscall.h)
AC_CHECK_HEADERS(sys/acl.h sys/attributes.h attr/xattr.h sys/xattr.h sys/cdefs.h glob.h)
+# These faile to compile on Solaris so just check for their presence
+AC_CHECK_HEADERS(security/pam_modules.h net/if.h netinet/ip.h, [], [], -)
# For experimental utmp support (lastlog on some BSD-like systems)
AC_CHECK_HEADERS(utmp.h utmpx.h lastlog.h)
@@ -2613,27 +2615,7 @@ if test x"$with_ads_support" != x"no"; then
# Do no harm to the values of CFLAGS and LIBS while testing for
# Kerberos support.
-
- #################################################
- # check for krb5-config from recent MIT and Heimdal kerberos 5
- AC_PATH_PROG(KRB5_CONFIG, krb5-config)
- AC_MSG_CHECKING(for working krb5-config)
- if test -x "$KRB5_CONFIG"; then
- ac_save_CFLAGS=$CFLAGS
- CFLAGS="";export CFLAGS
- ac_save_LDFLAGS=$LDFLAGS
- LDFLAGS="";export LDFLAGS
- KRB5_LIBS="`$KRB5_CONFIG --libs gssapi`"
- KRB5_CFLAGS="`$KRB5_CONFIG --cflags | sed s/@INCLUDE_des@//`"
- KRB5_CPPFLAGS="`$KRB5_CONFIG --cflags | sed s/@INCLUDE_des@//`"
- CFLAGS=$ac_save_CFLAGS;export CFLAGS
- LDFLAGS=$ac_save_LDFLAGS;export LDFLAGS
- FOUND_KRB5=yes
- AC_MSG_RESULT(yes)
- else
- AC_MSG_RESULT(no. Fallback to previous krb5 detection strategy)
- fi
-
+
if test x$FOUND_KRB5 = x"no"; then
#################################################
# check for location of Kerberos 5 install
@@ -2654,12 +2636,36 @@ if test x"$with_ads_support" != x"no"; then
KRB5_CPPFLAGS="-I$withval/include"
KRB5_LDFLAGS="-L$withval/lib"
FOUND_KRB5=yes
+ if test -x "$withval/bin/krb5-config"; then
+ KRB5_CONFIG=$withval/bin/krb5-config
+ fi
;;
esac ],
AC_MSG_RESULT(no krb5-path given)
)
fi
+ #################################################
+ # check for krb5-config from recent MIT and Heimdal kerberos 5
+ AC_PATH_PROG(KRB5_CONFIG, krb5-config)
+ AC_MSG_CHECKING(for working krb5-config)
+ if test -x "$KRB5_CONFIG"; then
+ ac_save_CFLAGS=$CFLAGS
+ CFLAGS="";export CFLAGS
+ ac_save_LDFLAGS=$LDFLAGS
+ LDFLAGS="";export LDFLAGS
+ KRB5_LIBS="`$KRB5_CONFIG --libs gssapi`"
+ KRB5_LDFLAGS="`$KRB5_CONFIG --libs gssapi | sed s/-lgss.*//`"
+ KRB5_CFLAGS="`$KRB5_CONFIG --cflags | sed s/@INCLUDE_des@//`"
+ KRB5_CPPFLAGS="`$KRB5_CONFIG --cflags | sed s/@INCLUDE_des@//`"
+ CFLAGS=$ac_save_CFLAGS;export CFLAGS
+ LDFLAGS=$ac_save_LDFLAGS;export LDFLAGS
+ FOUND_KRB5=yes
+ AC_MSG_RESULT(yes)
+ else
+ AC_MSG_RESULT(no. Fallback to previous krb5 detection strategy)
+ fi
+
if test x$FOUND_KRB5 = x"no"; then
#################################################
# see if this box has the SuSE location for the heimdal krb implementation
@@ -2698,9 +2704,9 @@ if test x"$with_ads_support" != x"no"; then
ac_save_CPPFLAGS=$CPPFLAGS
ac_save_LDFLAGS=$LDFLAGS
- CFLAGS="$CFLAGS $KRB5_CFLAGS"
- CPPFLAGS="$CPPFLAGS $KRB5_CPPFLAGS"
- LDFLAGS="$LDFLAGS $KRB5_LDFLAGS"
+ CFLAGS="$KRB5_CFLAGS $CFLAGS"
+ CPPFLAGS="$KRB5_CPPFLAGS $CPPFLAGS"
+ LDFLAGS="$KRB5_LDFLAGS $LDFLAGS"
KRB5_LIBS="$KRB5_LDFLAGS $KRB5_LIBS"
@@ -2784,9 +2790,23 @@ if test x"$with_ads_support" != x"no"; then
AC_CHECK_FUNC_EXT(krb5_free_keytab_entry_contents, $KRB5_LIBS)
AC_CHECK_FUNC_EXT(krb5_kt_free_entry, $KRB5_LIBS)
AC_CHECK_FUNC_EXT(krb5_krbhst_get_addrinfo, $KRB5_LIBS)
+ AC_CHECK_FUNC_EXT(krb5_c_enctype_compare, $KRB5_LIBS)
+ AC_CHECK_FUNC_EXT(krb5_enctypes_compatible_keys, $KRB5_LIBS)
- LIBS="$LIBS $KRB5_LIBS"
+ LIBS="$KRB5_LIBS $LIBS"
+ AC_CACHE_CHECK([for krb5_encrypt_block type],
+ samba_cv_HAVE_KRB5_ENCRYPT_BLOCK,[
+ AC_TRY_COMPILE([#include <krb5.h>],
+ [krb5_encrypt_block block;],
+ samba_cv_HAVE_KRB5_ENCRYPT_BLOCK=yes,
+ samba_cv_HAVE_KRB5_ENCRYPT_BLOCK=no)])
+
+ if test x"$samba_cv_HAVE_KRB5_ENCRYPT_BLOCK" = x"yes"; then
+ AC_DEFINE(HAVE_KRB5_ENCRYPT_BLOCK,1,
+ [Whether the type krb5_encrypt_block exists])
+ fi
+
AC_CACHE_CHECK([for addrtype in krb5_address],
samba_cv_HAVE_ADDRTYPE_IN_KRB5_ADDRESS,[
AC_TRY_COMPILE([#include <krb5.h>],
@@ -2822,6 +2842,30 @@ if test x"$with_ads_support" != x"no"; then
[Whether the krb5_ticket struct has a enc_part2 property])
fi
+ AC_CACHE_CHECK([for keyblock in krb5_creds],
+ samba_cv_HAVE_KRB5_KEYBLOCK_IN_CREDS,[
+ AC_TRY_COMPILE([#include <krb5.h>],
+ [krb5_creds creds; krb5_keyblock kb; creds.keyblock = kb;],
+ samba_cv_HAVE_KRB5_KEYBLOCK_IN_CREDS=yes,
+ samba_cv_HAVE_KRB5_KEYBLOCK_IN_CREDS=no)])
+
+ if test x"$samba_cv_HAVE_KRB5_KEYBLOCK_IN_CREDS" = x"yes"; then
+ AC_DEFINE(HAVE_KRB5_KEYBLOCK_IN_CREDS,1,
+ [Whether the krb5_creds struct has a keyblock property])
+ fi
+
+ AC_CACHE_CHECK([for session in krb5_creds],
+ samba_cv_HAVE_KRB5_SESSION_IN_CREDS,[
+ AC_TRY_COMPILE([#include <krb5.h>],
+ [krb5_creds creds; krb5_keyblock kb; creds.session = kb;],
+ samba_cv_HAVE_KRB5_SESSION_IN_CREDS=yes,
+ samba_cv_HAVE_KRB5_SESSION_IN_CREDS=no)])
+
+ if test x"$samba_cv_HAVE_KRB5_SESSION_IN_CREDS" = x"yes"; then
+ AC_DEFINE(HAVE_KRB5_SESSION_IN_CREDS,1,
+ [Whether the krb5_creds struct has a session property])
+ fi
+
AC_CACHE_CHECK([for keyvalue in krb5_keyblock],
samba_cv_HAVE_KRB5_KEYBLOCK_KEYVALUE,[
AC_TRY_COMPILE([#include <krb5.h>],
diff --git a/source/groupdb/mapping.c b/source/groupdb/mapping.c
index d189f447d08..50064415f9c 100644
--- a/source/groupdb/mapping.c
+++ b/source/groupdb/mapping.c
@@ -135,11 +135,10 @@ static BOOL default_group_mapping(void)
static BOOL init_group_mapping(void)
{
- static pid_t local_pid;
const char *vstring = "INFO/version";
int32 vers_id;
- if (tdb && local_pid == sys_getpid())
+ if (tdb)
return True;
tdb = tdb_open_log(lock_path("group_mapping.tdb"), 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
if (!tdb) {
@@ -147,8 +146,6 @@ static BOOL init_group_mapping(void)
return False;
}
- local_pid = sys_getpid();
-
/* handle a Samba upgrade */
tdb_lock_bystring(tdb, vstring, 0);
diff --git a/source/include/includes.h b/source/include/includes.h
index d51e4c53f1a..6a1681fe1f1 100644
--- a/source/include/includes.h
+++ b/source/include/includes.h
@@ -455,13 +455,9 @@
#if HAVE_GSSAPI_H
#include <gssapi.h>
-#endif
-
-#if HAVE_GSSAPI_GSSAPI_H
+#elif HAVE_GSSAPI_GSSAPI_H
#include <gssapi/gssapi.h>
-#endif
-
-#if HAVE_GSSAPI_GSSAPI_GENERIC_H
+#elif HAVE_GSSAPI_GSSAPI_GENERIC_H
#include <gssapi/gssapi_generic.h>
#endif
@@ -1340,6 +1336,7 @@ void krb5_free_unparsed_name(krb5_context ctx, char *val);
/* Samba wrapper function for krb5 functionality. */
void setup_kaddr( krb5_address *pkaddr, struct sockaddr *paddr);
int create_kerberos_key_from_string(krb5_context context, krb5_principal host_princ, krb5_data *password, krb5_keyblock *key, krb5_enctype enctype);
+int create_kerberos_key_from_string_direct(krb5_context context, krb5_principal host_princ, krb5_data *password, krb5_keyblock *key, krb5_enctype enctype);
void get_auth_data_from_tkt(DATA_BLOB *auth_data, krb5_ticket *tkt);
krb5_const_principal get_principal_from_tkt(krb5_ticket *tkt);
krb5_error_code krb5_locate_kdc(krb5_context ctx, const krb5_data *realm, struct sockaddr **addr_pp, int *naddrs, int get_masters);
@@ -1347,6 +1344,10 @@ krb5_error_code get_kerberos_allowed_etypes(krb5_context context, krb5_enctype *
void free_kerberos_etypes(krb5_context context, krb5_enctype *enctypes);
BOOL get_krb5_smb_session_key(krb5_context context, krb5_auth_context auth_context, DATA_BLOB *session_key, BOOL remote);
krb5_error_code smb_krb5_kt_free_entry(krb5_context context, krb5_keytab_entry *kt_entry);
+krb5_principal kerberos_fetch_salt_princ_for_host_princ(krb5_context context, krb5_principal host_princ, int enctype);
+void kerberos_set_creds_enctype(krb5_creds *pcreds, int enctype);
+BOOL kerberos_compatible_enctypes(krb5_context context, krb5_enctype enctype1, krb5_enctype enctype2);
+void kerberos_free_data_contents(krb5_context context, krb5_data *pdata);
#endif /* HAVE_KRB5 */
diff --git a/source/include/secrets.h b/source/include/secrets.h
index cb4fbd043a7..4b8d5db66b6 100644
--- a/source/include/secrets.h
+++ b/source/include/secrets.h
@@ -32,6 +32,9 @@
/* this one is for storing trusted domain account password */
#define SECRETS_DOMTRUST_ACCT_PASS "SECRETS/$DOMTRUST.ACC"
+/* Store the principal name used for Kerberos DES key salt under this key name. */
+#define SECRETS_SALTING_PRINCIPAL "SECRETS/SALTING_PRINCIPAL"
+
/* The domain sid and our sid are stored here even though they aren't
really secret. */
#define SECRETS_DOMAIN_SID "SECRETS/SID"
diff --git a/source/lib/account_pol.c b/source/lib/account_pol.c
index 8d5b963da28..c8507f722d1 100644
--- a/source/lib/account_pol.c
+++ b/source/lib/account_pol.c
@@ -30,11 +30,10 @@ static TDB_CONTEXT *tdb; /* used for driver files */
BOOL init_account_policy(void)
{
- static pid_t local_pid;
const char *vstring = "INFO/version";
uint32 version;
- if (tdb && local_pid == sys_getpid())
+ if (tdb)
return True;
tdb = tdb_open_log(lock_path("account_policy.tdb"), 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
if (!tdb) {
@@ -42,8 +41,6 @@ BOOL init_account_policy(void)
return False;
}
- local_pid = sys_getpid();
-
/* handle a Samba upgrade */
tdb_lock_bystring(tdb, vstring,0);
if (!tdb_fetch_uint32(tdb, vstring, &version) || version != DATABASE_VERSION) {
diff --git a/source/libads/kerberos.c b/source/libads/kerberos.c
index 327a76826ef..a38f3c35b1a 100644
--- a/source/libads/kerberos.c
+++ b/source/libads/kerberos.c
@@ -3,8 +3,9 @@
kerberos utility library
Copyright (C) Andrew Tridgell 2001
Copyright (C) Remus Koos 2001
-
-
+ Copyright (C) Nalin Dahyabhai 2004.
+ Copyright (C) Jeremy Allison 2004.
+
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
@@ -24,6 +25,8 @@
#ifdef HAVE_KRB5
+#define LIBADS_CCACHE_NAME "MEMORY:libads"
+
/*
we use a prompter to avoid a crash bug in the kerberos libs when
dealing with empty passwords
@@ -38,7 +41,7 @@ kerb_prompter(krb5_context ctx, void *data,
{
if (num_prompts == 0) return 0;
- memset(prompts[0].reply->data, 0, prompts[0].reply->length);
+ memset(prompts[0].reply->data, '\0', prompts[0].reply->length);
if (prompts[0].reply->length > 0) {
if (data) {
strncpy(prompts[0].reply->data, data, prompts[0].reply->length-1);
@@ -51,10 +54,15 @@ kerb_prompter(krb5_context ctx, void *data,
}
/*
- simulate a kinit, putting the tgt in the default cache location
+ simulate a kinit, putting the tgt in the given cache location. If cache_name == NULL
+ place in default cache location.
remus@snapserver.com
*/
-int kerberos_kinit_password(const char *principal, const char *password, int time_offset, time_t *expire_time)
+int kerberos_kinit_password(const char *principal,
+ const char *password,
+ int time_offset,
+ time_t *expire_time,
+ const char *cache_name)
{
krb5_context ctx = NULL;
krb5_error_code code = 0;
@@ -69,7 +77,8 @@ int kerberos_kinit_password(const char *principal, const char *password, int tim
krb5_set_real_time(ctx, time(NULL) + time_offset, 0);
}
- if ((code = krb5_cc_default(ctx, &cc))) {
+ if ((code = krb5_cc_resolve(ctx, cache_name ?
+ cache_name : krb5_cc_default_name(ctx), &cc))) {
krb5_free_context(ctx);
return code;
}
@@ -129,7 +138,8 @@ int ads_kinit_password(ADS_STRUCT *ads)
return KRB5_LIBOS_CANTREADPWD;
}
- ret = kerberos_kinit_password(s, ads->auth.password, ads->auth.time_offset, &ads->auth.expire);
+ ret = kerberos_kinit_password(s, ads->auth.password, ads->auth.time_offset,
+ &ads->auth.expire, NULL);
if (ret) {
DEBUG(0,("kerberos_kinit_password %s failed: %s\n",
@@ -174,4 +184,580 @@ int ads_kdestroy(const char *cc_name)
return code;
}
+/************************************************************************
+ Routine to fetch the salting principal for a service. Active
+ Directory may use a non-obvious principal name to generate the salt
+ when it determines the key to use for encrypting tickets for a service,
+ and hopefully we detected that when we joined the domain.
+ ************************************************************************/
+
+static char *kerberos_secrets_fetch_salting_principal(const char *service, int enctype)
+{
+ char *key = NULL;
+ char *ret = NULL;
+
+ asprintf(&key, "%s/%s/enctype=%d", SECRETS_SALTING_PRINCIPAL, service, enctype);
+ if (!key) {
+ return NULL;
+ }
+ ret = (char *)secrets_fetch(key, NULL);
+ SAFE_FREE(key);
+ return ret;
+}
+
+/************************************************************************
+ Routine to get the salting principal for this service. Active
+ Directory may use a non-obvious principal name to generate the salt
+ when it determines the key to use for encrypting tickets for a service,
+ and hopefully we detected that when we joined the domain.
+ Caller must free if return is not null.
+ ************************************************************************/
+
+krb5_principal kerberos_fetch_salt_princ_for_host_princ(krb5_context context,
+ krb5_principal host_princ,
+ int enctype)
+{
+ char *unparsed_name = NULL, *salt_princ_s = NULL;
+ krb5_principal ret_princ = NULL;
+
+ if (krb5_unparse_name(context, host_princ, &unparsed_name) != 0) {
+ return (krb5_principal)NULL;
+ }
+
+ if ((salt_princ_s = kerberos_secrets_fetch_salting_principal(unparsed_name, enctype)) == NULL) {
+ krb5_free_unparsed_name(context, unparsed_name);
+ return (krb5_principal)NULL;
+ }
+
+ if (krb5_parse_name(context, salt_princ_s, &ret_princ) != 0) {
+ krb5_free_unparsed_name(context, unparsed_name);
+ SAFE_FREE(salt_princ_s);
+ return (krb5_principal)NULL;
+ }
+ krb5_free_unparsed_name(context, unparsed_name);
+ SAFE_FREE(salt_princ_s);
+ return ret_princ;
+}
+
+/************************************************************************
+ Routine to set the salting principal for this service. Active
+ Directory may use a non-obvious principal name to generate the salt
+ when it determines the key to use for encrypting tickets for a service,
+ and hopefully we detected that when we joined the domain.
+ Setting principal to NULL deletes this entry.
+ ************************************************************************/
+
+ BOOL kerberos_secrets_store_salting_principal(const char *service,
+ int enctype,
+ const char *principal)
+{
+ char *key = NULL;
+ BOOL ret = False;
+ krb5_context context = NULL;
+ krb5_principal princ = NULL;
+ char *princ_s = NULL;
+ char *unparsed_name = NULL;
+
+ krb5_init_context(&context);
+ if (!context) {
+ return False;
+ }
+ if (strchr_m(service, '@')) {
+ asprintf(&princ_s, "%s", service);
+ } else {
+ asprintf(&princ_s, "%s@%s", service, lp_realm());
+ }
+
+ if (krb5_parse_name(context, princ_s, &princ) != 0) {
+ goto out;
+
+ }
+ if (krb5_unparse_name(context, princ, &unparsed_name) != 0) {
+ goto out;
+ }
+
+ asprintf(&key, "%s/%s/enctype=%d", SECRETS_SALTING_PRINCIPAL, unparsed_name, enctype);
+ if (!key) {
+ goto out;
+ }
+
+ if ((principal != NULL) && (strlen(principal) > 0)) {
+ ret = secrets_store(key, principal, strlen(principal) + 1);
+ } else {
+ ret = secrets_delete(key);
+ }
+
+ out:
+
+ SAFE_FREE(key);
+ SAFE_FREE(princ_s);
+
+ if (unparsed_name) {
+ krb5_free_unparsed_name(context, unparsed_name);
+ }
+ if (context) {
+ krb5_free_context(context);
+ }
+
+ return ret;
+}
+
+/************************************************************************
+ Routine to get initial credentials as a service ticket for the local machine.
+ Returns a buffer initialized with krb5_mk_req_extended.
+ ************************************************************************/
+
+static krb5_error_code get_service_ticket(krb5_context ctx,
+ krb5_ccache ccache,
+ const char *service_principal,
+ int enctype,
+ krb5_data *p_outbuf)
+{
+ krb5_creds creds, *new_creds = NULL;
+ char *service_s = NULL;
+ char *machine_account = NULL, *password = NULL;
+ krb5_data in_data;
+ krb5_auth_context auth_context = NULL;
+ krb5_error_code err = 0;
+
+ asprintf(&machine_account, "%s$@%s", global_myname(), lp_realm());
+ if (machine_account == NULL) {
+ goto out;
+ }
+ password = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL);
+ if (password == NULL) {
+ goto out;
+ }
+ if ((err = kerberos_kinit_password(machine_account, password, 0, NULL, LIBADS_CCACHE_NAME)) != 0) {
+ DEBUG(0,("get_service_ticket: kerberos_kinit_password %s@%s failed: %s\n",
+ machine_account,
+ lp_realm(),
+ error_message(err)));
+ goto out;
+ }
+
+ /* Ok - the above call has gotten a TGT. Now we need to get a service
+ ticket to ourselves. */
+
+ /* Set up the enctype and client and server principal fields for krb5_get_credentials. */
+ memset(&creds, '\0', sizeof(creds));
+ kerberos_set_creds_enctype(&creds, enctype);
+
+ if ((err = krb5_cc_get_principal(ctx, ccache, &creds.client))) {
+ DEBUG(3, ("get_service_ticket: krb5_cc_get_principal failed: %s\n",
+ error_message(err)));
+ goto out;
+ }
+
+ if (strchr_m(service_principal, '@')) {
+ asprintf(&service_s, "%s", service_principal);
+ } else {
+ asprintf(&service_s, "%s@%s", service_principal, lp_realm());
+ }
+
+ if ((err = krb5_parse_name(ctx, service_s, &creds.server))) {
+ DEBUG(0,("get_service_ticket: krb5_parse_name %s failed: %s\n",
+ service_s, error_message(err)));
+ goto out;
+ }
+
+ if ((err = krb5_get_credentials(ctx, 0, ccache, &creds, &new_creds))) {
+ DEBUG(5,("get_service_ticket: krb5_get_credentials for %s enctype %d failed: %s\n",
+ service_s, enctype, error_message(err)));
+ goto out;
+ }
+
+ memset(&in_data, '\0', sizeof(in_data));
+ if ((err = krb5_mk_req_extended(ctx, &auth_context, 0, &in_data,
+ new_creds, p_outbuf)) != 0) {
+ DEBUG(0,("get_service_ticket: krb5_mk_req_extended failed: %s\n",
+ error_message(err)));
+ goto out;
+ }
+
+ out:
+
+ if (auth_context) {
+ krb5_auth_con_free(ctx, auth_context);
+ }
+ if (new_creds) {
+ krb5_free_creds(ctx, new_creds);
+ }
+ if (creds.server) {
+ krb5_free_principal(ctx, creds.server);
+ }
+ if (creds.client) {
+ krb5_free_principal(ctx, creds.client);
+ }
+
+ SAFE_FREE(service_s);
+ SAFE_FREE(password);
+ SAFE_FREE(machine_account);
+ return err;
+}
+
+/************************************************************************
+ Check if the machine password can be used in conjunction with the salting_principal
+ to generate a key which will successfully decrypt the AP_REQ already
+ gotten as a message to the local machine.
+ ************************************************************************/
+
+static BOOL verify_service_password(krb5_context ctx,
+ int enctype,
+ const char *salting_principal,
+ krb5_data *in_data)
+{
+ BOOL ret = False;
+ krb5_principal salting_kprinc = NULL;
+ krb5_ticket *ticket = NULL;
+ krb5_keyblock key;
+ krb5_data passdata;
+ char *salting_s = NULL;
+ char *machine_account = NULL, *password = NULL;
+ krb5_auth_context auth_context = NULL;
+ krb5_error_code err;
+
+ memset(&passdata, '\0', sizeof(passdata));
+ memset(&key, '\0', sizeof(key));
+
+ asprintf(&machine_account, "%s$@%s", global_myname(), lp_realm());
+ if (machine_account == NULL) {
+ goto out;
+ }
+ password = secrets_fetch_machine_password(lp_workgroup(), NULL, NULL);
+ if (password == NULL) {
+ goto out;
+ }
+
+ if (strchr_m(salting_principal, '@')) {
+ asprintf(&salting_s, "%s", salting_principal);
+ } else {
+ asprintf(&salting_s, "%s@%s", salting_principal, lp_realm());
+ }
+
+ if ((err = krb5_parse_name(ctx, salting_s, &salting_kprinc))) {
+ DEBUG(0,("verify_service_password: krb5_parse_name %s failed: %s\n",
+ salting_s, error_message(err)));
+ goto out;
+ }
+
+ passdata.length = strlen(password);
+ passdata.data = (char*)password;
+ if ((err = create_kerberos_key_from_string_direct(ctx, salting_kprinc, &passdata, &key, enctype))) {
+ DEBUG(0,("verify_service_password: create_kerberos_key_from_string %d failed: %s\n",
+ enctype, error_message(err)));
+ goto out;
+ }
+
+ if ((err = krb5_auth_con_init(ctx, &auth_context)) != 0) {
+ DEBUG(0,("verify_service_password: krb5_auth_con_init failed %s\n", error_message(err)));
+ goto out;
+ }
+
+ if ((err = krb5_auth_con_setuseruserkey(ctx, auth_context, &key)) != 0) {
+ DEBUG(0,("verify_service_password: krb5_auth_con_setuseruserkey failed %s\n", error_message(err)));
+ goto out;
+ }
+
+ if (!(err = krb5_rd_req(ctx, &auth_context, in_data, NULL, NULL, NULL, &ticket))) {
+ DEBUG(10,("verify_service_password: decrypted message with enctype %u salt %s!\n",
+ (unsigned int)enctype, salting_s));
+ ret = True;
+ }
+
+ out:
+
+ memset(&passdata, 0, sizeof(passdata));
+ krb5_free_keyblock_contents(ctx, &key);
+ if (ticket != NULL) {
+ krb5_free_ticket(ctx, ticket);
+ }
+ if (salting_kprinc) {
+ krb5_free_principal(ctx, salting_kprinc);
+ }
+ SAFE_FREE(salting_s);
+ SAFE_FREE(password);
+ SAFE_FREE(machine_account);
+ return ret;
+}
+
+/************************************************************************
+ *
+ * From the current draft of kerberos-clarifications:
+ *
+ * It is not possible to reliably generate a user's key given a pass
+ * phrase without contacting the KDC, since it will not be known
+ * whether alternate salt or parameter values are required.
+ *
+ * And because our server has a password, we have this exact problem. We
+ * make multiple guesses as to which principal name provides the salt which
+ * the KDC is using.
+ *
+ ************************************************************************/
+
+static void kerberos_derive_salting_principal_for_enctype(const char *service_principal,
+ krb5_context ctx,
+ krb5_ccache ccache,
+ krb5_enctype enctype,
+ krb5_enctype *enctypes)
+{
+ char *salting_principals[3] = {NULL, NULL, NULL}, *second_principal = NULL;
+ krb5_error_code err = 0;
+ krb5_data outbuf;
+ int i, j;
+
+ memset(&outbuf, '\0', sizeof(outbuf));
+
+ /* Check that the service_principal is useful. */
+ if ((service_principal == NULL) || (strlen(service_principal) == 0)) {
+ return;
+ }
+
+ /* Generate our first guess -- the principal as-given. */
+ asprintf(&salting_principals[0], "%s", service_principal);
+ if ((salting_principals[0] == NULL) || (strlen(salting_principals[0]) == 0)) {
+ return;
+ }
+
+ /* Generate our second guess -- the computer's principal, as Win2k3. */
+ asprintf(&second_principal, "host/%s.%s", global_myname(), lp_realm());
+ if (second_principal != NULL) {
+ strlower_m(second_principal);
+ asprintf(&salting_principals[1], "%s@%s", second_principal, lp_realm());
+ SAFE_FREE(second_principal);
+ }
+ if ((salting_principals[1] == NULL) || (strlen(salting_principals[1]) == 0)) {
+ goto out;
+ }
+
+ /* Generate our third guess -- the computer's principal, as Win2k. */
+ asprintf(&second_principal, "HOST/%s", global_myname());
+ if (second_principal != NULL) {
+ strlower_m(second_principal + 5);
+ asprintf(&salting_principals[2], "%s@%s",
+ second_principal, lp_realm());
+ SAFE_FREE(second_principal);
+ }
+ if ((salting_principals[2] == NULL) || (strlen(salting_principals[2]) == 0)) {
+ goto out;
+ }
+
+ /* Get a service ticket for ourselves into our memory ccache. */
+ /* This will commonly fail if there is no principal by that name (and we're trying
+ many names). So don't print a debug 0 error. */
+
+ if ((err = get_service_ticket(ctx, ccache, service_principal, enctype, &outbuf)) != 0) {
+ DEBUG(3, ("verify_service_password: get_service_ticket failed: %s\n",
+ error_message(err)));
+ goto out;
+ }
+
+ /* At this point we have a message to ourselves, salted only the KDC knows how. We
+ have to work out what that salting is. */
+
+ /* Try and find the correct salting principal. */
+ for (i = 0; i < sizeof(salting_principals) / sizeof(salting_principals[i]); i++) {
+ if (verify_service_password(ctx, enctype, salting_principals[i], &outbuf)) {
+ break;
+ }
+ }
+
+ /* If we failed to get a match, return. */
+ if (i >= sizeof(salting_principals) / sizeof(salting_principals[i])) {
+ goto out;
+ }
+
+ /* If we succeeded, store the principal for use for all enctypes which
+ * share the same cipher and string-to-key function. Doing this here
+ * allows servers which just pass a keytab to krb5_rd_req() to work
+ * correctly. */
+ for (j = 0; enctypes[j] != 0; j++) {
+ if (enctype != enctypes[j]) {
+ /* If this enctype isn't compatible with the one which
+ * we used, skip it. */
+
+ if (!kerberos_compatible_enctypes(ctx, enctypes[j], enctype))
+ continue;
+ }
+ /* If the principal which gives us the proper salt is the one
+ * which we would normally guess, don't bother noting anything
+ * in the secrets tdb. */
+ if (strcmp(service_principal, salting_principals[i]) != 0) {
+ kerberos_secrets_store_salting_principal(service_principal,
+ enctypes[j],
+ salting_principals[i]);
+ }
+ }
+
+ out :
+
+ kerberos_free_data_contents(ctx, &outbuf);
+ SAFE_FREE(salting_principals[0]);
+ SAFE_FREE(salting_principals[1]);
+ SAFE_FREE(salting_principals[2]);
+ SAFE_FREE(second_principal);
+}
+
+/************************************************************************
+ Go through all the possible enctypes for this principal.
+ ************************************************************************/
+
+static void kerberos_derive_salting_principal_direct(krb5_context context,
+ krb5_ccache ccache,
+ krb5_enctype *enctypes,
+ char *service_principal)
+{
+ int i;
+
+ /* Try for each enctype separately, because the rules are
+ * different for different enctypes. */
+ for (i = 0; enctypes[i] != 0; i++) {
+ /* Delete secrets entry first. */
+ kerberos_secrets_store_salting_principal(service_principal, 0, NULL);
+#ifdef ENCTYPE_ARCFOUR_HMAC
+ if (enctypes[i] == ENCTYPE_ARCFOUR_HMAC) {
+ /* Of course this'll always work, so just save
+ * ourselves the effort. */
+ continue;
+ }
+#endif
+ /* Try to figure out what's going on with this
+ * principal. */
+ kerberos_derive_salting_principal_for_enctype(service_principal,
+ context,
+ ccache,
+ enctypes[i],
+ enctypes);
+ }
+}
+
+/************************************************************************
+ Wrapper function for the above.
+ ************************************************************************/
+
+BOOL kerberos_derive_salting_principal(char *service_principal)
+{
+ krb5_context context = NULL;
+ krb5_enctype *enctypes = NULL;
+ krb5_ccache ccache = NULL;
+ krb5_error_code ret = 0;
+
+ initialize_krb5_error_table();
+ if ((ret = krb5_init_context(&context)) != 0) {
+ DEBUG(1,("kerberos_derive_cifs_salting_principals: krb5_init_context failed. %s\n",
+ error_message(ret)));
+ return False;
+ }
+ if ((ret = get_kerberos_allowed_etypes(context, &enctypes)) != 0) {
+ DEBUG(1,("kerberos_derive_cifs_salting_principals: get_kerberos_allowed_etypes failed. %s\n",
+ error_message(ret)));
+ goto out;
+ }
+
+ if ((ret = krb5_cc_resolve(context, LIBADS_CCACHE_NAME, &ccache)) != 0) {
+ DEBUG(3, ("get_service_ticket: krb5_cc_resolve for %s failed: %s\n",
+ LIBADS_CCACHE_NAME, error_message(ret)));
+ goto out;
+ }
+
+ kerberos_derive_salting_principal_direct(context, ccache, enctypes, service_principal);
+
+ out:
+ if (enctypes) {
+ free_kerberos_etypes(context, enctypes);
+ }
+ if (ccache) {
+ krb5_cc_destroy(context, ccache);
+ }
+ if (context) {
+ krb5_free_context(context);
+ }
+
+ return ret ? False : True;
+}
+
+/************************************************************************
+ Core function to try and determine what salt is being used for any keytab
+ keys.
+ ************************************************************************/
+
+BOOL kerberos_derive_cifs_salting_principals(void)
+{
+ fstring my_fqdn;
+ char *service = NULL;
+ krb5_context context = NULL;
+ krb5_enctype *enctypes = NULL;
+ krb5_ccache ccache = NULL;
+ krb5_error_code ret = 0;
+ BOOL retval = False;
+
+ initialize_krb5_error_table();
+ if ((ret = krb5_init_context(&context)) != 0) {
+ DEBUG(1,("kerberos_derive_cifs_salting_principals: krb5_init_context failed. %s\n",
+ error_message(ret)));
+ return False;
+ }
+ if ((ret = get_kerberos_allowed_etypes(context, &enctypes)) != 0) {
+ DEBUG(1,("kerberos_derive_cifs_salting_principals: get_kerberos_allowed_etypes failed. %s\n",
+ error_message(ret)));
+ goto out;
+ }
+
+ if ((ret = krb5_cc_resolve(context, LIBADS_CCACHE_NAME, &ccache)) != 0) {
+ DEBUG(3, ("get_service_ticket: krb5_cc_resolve for %s failed: %s\n",
+ LIBADS_CCACHE_NAME, error_message(ret)));
+ goto out;
+ }
+
+ if (asprintf(&service, "%s$", global_myname()) != -1) {
+ strlower_m(service);
+ kerberos_derive_salting_principal_direct(context, ccache, enctypes, service);
+ SAFE_FREE(service);
+ }
+ if (asprintf(&service, "cifs/%s", global_myname()) != -1) {
+ strlower_m(service);
+ kerberos_derive_salting_principal_direct(context, ccache, enctypes, service);
+ SAFE_FREE(service);
+ }
+ if (asprintf(&service, "host/%s", global_myname()) != -1) {
+ strlower_m(service);
+ kerberos_derive_salting_principal_direct(context, ccache, enctypes, service);
+ SAFE_FREE(service);
+ }
+ if (asprintf(&service, "cifs/%s.%s", global_myname(), lp_realm()) != -1) {
+ strlower_m(service);
+ kerberos_derive_salting_principal_direct(context, ccache, enctypes, service);
+ SAFE_FREE(service);
+ }
+ if (asprintf(&service, "host/%s.%s", global_myname(), lp_realm()) != -1) {
+ strlower_m(service);
+ kerberos_derive_salting_principal_direct(context, ccache, enctypes, service);
+ SAFE_FREE(service);
+ }
+ name_to_fqdn(my_fqdn, global_myname());
+ if (asprintf(&service, "cifs/%s", my_fqdn) != -1) {
+ strlower_m(service);
+ kerberos_derive_salting_principal_direct(context, ccache, enctypes, service);
+ SAFE_FREE(service);
+ }
+ if (asprintf(&service, "host/%s", my_fqdn) != -1) {
+ strlower_m(service);
+ kerberos_derive_salting_principal_direct(context, ccache, enctypes, service);
+ SAFE_FREE(service);
+ }
+
+ retval = True;
+
+ out:
+ if (enctypes) {
+ free_kerberos_etypes(context, enctypes);
+ }
+ if (ccache) {
+ krb5_cc_destroy(context, ccache);
+ }
+ if (context) {
+ krb5_free_context(context);
+ }
+ return retval;
+}
#endif
diff --git a/source/libads/kerberos_keytab.c b/source/libads/kerberos_keytab.c
index eec5f104fd9..ec6a8c50780 100644
--- a/source/libads/kerberos_keytab.c
+++ b/source/libads/kerberos_keytab.c
@@ -101,7 +101,34 @@ int ads_keytab_add_entry(ADS_STRUCT *ads, const char *srvPrinc)
/* Construct our principal */
name_to_fqdn(my_fqdn, global_myname());
strlower_m(my_fqdn);
- asprintf(&princ_s, "%s/%s@%s", srvPrinc, my_fqdn, lp_realm());
+
+ if (strchr_m(srvPrinc, '@')) {
+ /* It's a fully-named principal. */
+ asprintf(&princ_s, "%s", srvPrinc);
+ } else if (srvPrinc[strlen(srvPrinc)-1] == '$') {
+ /* It's the machine account, as used by smbclient clients. */
+ asprintf(&princ_s, "%s@%s", srvPrinc, lp_realm());
+ } else {
+ /* It's a normal service principal. Add the SPN now so that we
+ * can obtain credentials for it and double-check the salt value
+ * used to generate the service's keys. */
+ asprintf(&princ_s, "%s/%s@%s", srvPrinc, my_fqdn, lp_realm());
+ /* Update the directory with the SPN */
+ DEBUG(3,("ads_keytab_add_entry: Attempting to add/update '%s'\n", princ_s));
+ if (!ADS_ERR_OK(ads_add_service_principal_name(ads, global_myname(), srvPrinc))) {
+ DEBUG(1,("ads_keytab_add_entry: ads_add_service_principal_name failed.\n"));
+ goto out;
+ }
+ }
+
+ ret = get_kerberos_allowed_etypes(context,&enctypes);
+ if (ret) {
+ DEBUG(1,("ads_keytab_add_entry: get_kerberos_allowed_etypes failed (%s)\n",error_message(ret)));
+ goto out;
+ }
+
+ /* Guess at how the KDC is salting keys for this principal. */
+ kerberos_derive_salting_principal(princ_s);
ret = krb5_parse_name(context, princ_s, &princ);
if (ret) {
@@ -121,7 +148,7 @@ int ads_keytab_add_entry(ADS_STRUCT *ads, const char *srvPrinc)
if (ret != KRB5_KT_END && ret != ENOENT ) {
DEBUG(3,("ads_keytab_add_entry: Will try to delete old keytab entries\n"));
while(!krb5_kt_next_entry(context, keytab, &kt_entry, &cursor)) {
- BOOL compare_ok = False;
+ BOOL compare_name_ok = False;
ret = krb5_unparse_name(context, kt_entry.principal, &ktprinc);
if (ret) {
@@ -139,43 +166,59 @@ int ads_keytab_add_entry(ADS_STRUCT *ads, const char *srvPrinc)
*/
#ifdef HAVE_KRB5_KT_COMPARE
- compare_ok = ((krb5_kt_compare(context, &kt_entry, princ, 0, 0) == True) && (kt_entry.vno != kvno - 1));
+ compare_name_ok = (krb5_kt_compare(context, &kt_entry, princ, 0, 0) == True);
#else
- compare_ok = ((strcmp(ktprinc, princ_s) == 0) && (kt_entry.vno != kvno - 1));
+ compare_name_ok = (strcmp(ktprinc, princ_s) == 0);
#endif
+
+ if (!compare_name_ok) {
+ DEBUG(10,("ads_keytab_add_entry: ignoring keytab entry principal %s, kvno = %d\n",
+ ktprinc, kt_entry.vno));
+ }
+
krb5_free_unparsed_name(context, ktprinc);
ktprinc = NULL;
- if (compare_ok) {
- DEBUG(3,("ads_keytab_add_entry: Found old entry for principal: %s (kvno %d) - trying to remove it.\n",
- princ_s, kt_entry.vno));
- ret = krb5_kt_end_seq_get(context, keytab, &cursor);
- ZERO_STRUCT(cursor);
- if (ret) {
- DEBUG(1,("ads_keytab_add_entry: krb5_kt_end_seq_get() failed (%s)\n",
- error_message(ret)));
- goto out;
- }
- ret = krb5_kt_remove_entry(context, keytab, &kt_entry);
- if (ret) {
- DEBUG(1,("ads_keytab_add_entry: krb5_kt_remove_entry failed (%s)\n",
- error_message(ret)));
- goto out;
- }
- ret = krb5_kt_start_seq_get(context, keytab, &cursor);
- if (ret) {
- DEBUG(1,("ads_keytab_add_entry: krb5_kt_start_seq failed (%s)\n",
- error_message(ret)));
- goto out;
- }
- ret = smb_krb5_kt_free_entry(context, &kt_entry);
- ZERO_STRUCT(kt_entry);
- if (ret) {
- DEBUG(1,("ads_keytab_add_entry: krb5_kt_remove_entry failed (%s)\n",
- error_message(ret)));
- goto out;
+ if (compare_name_ok) {
+ if (kt_entry.vno == kvno - 1) {
+ DEBUG(5,("ads_keytab_add_entry: Saving previous (kvno %d) entry for principal: %s.\n",
+ kvno - 1, princ_s));
+ } else {
+
+ DEBUG(5,("ads_keytab_add_entry: Found old entry for principal: %s (kvno %d) - trying to remove it.\n",
+ princ_s, kt_entry.vno));
+ ret = krb5_kt_end_seq_get(context, keytab, &cursor);
+ ZERO_STRUCT(cursor);
+ if (ret) {
+ DEBUG(1,("ads_keytab_add_entry: krb5_kt_end_seq_get() failed (%s)\n",
+ error_message(ret)));
+ goto out;
+ }
+ ret = krb5_kt_remove_entry(context, keytab, &kt_entry);
+ if (ret) {
+ DEBUG(1,("ads_keytab_add_entry: krb5_kt_remove_entry failed (%s)\n",
+ error_message(ret)));
+ goto out;
+ }
+
+ DEBUG(5,("ads_keytab_add_entry: removed old entry for principal: %s (kvno %d).\n",
+ princ_s, kt_entry.vno));
+
+ ret = krb5_kt_start_seq_get(context, keytab, &cursor);
+ if (ret) {
+ DEBUG(1,("ads_keytab_add_entry: krb5_kt_start_seq failed (%s)\n",
+ error_message(ret)));
+ goto out;
+ }
+ ret = smb_krb5_kt_free_entry(context, &kt_entry);
+ ZERO_STRUCT(kt_entry);
+ if (ret) {
+ DEBUG(1,("ads_keytab_add_entry: krb5_kt_remove_entry failed (%s)\n",
+ error_message(ret)));
+ goto out;
+ }
+ continue;
}
- continue;
}
/* Not a match, just free this entry and continue. */
@@ -201,12 +244,6 @@ int ads_keytab_add_entry(ADS_STRUCT *ads, const char *srvPrinc)
/* If we get here, we have deleted all the old entries with kvno's not equal to the current kvno-1. */
- ret = get_kerberos_allowed_etypes(context,&enctypes);
- if (ret) {
- DEBUG(1,("ads_keytab_add_entry: get_kerberos_allowed_etypes failed (%s)\n",error_message(ret)));
- goto out;
- }
-
/* Now add keytab entries for all encryption types */
for (i = 0; enctypes[i]; i++) {
krb5_keyblock *keyp;
@@ -241,13 +278,6 @@ int ads_keytab_add_entry(ADS_STRUCT *ads, const char *srvPrinc)
krb5_kt_close(context, keytab);
keytab = NULL; /* Done with keytab now. No double free. */
- /* Update the LDAP with the SPN */
- DEBUG(3,("ads_keytab_add_entry: Attempting to add/update '%s'\n", princ_s));
- if (!ADS_ERR_OK(ads_add_service_principal_name(ads, global_myname(), srvPrinc))) {
- DEBUG(1,("ads_keytab_add_entry: ads_add_service_principcal_name failed.\n"));
- goto out;
- }
-
out:
SAFE_FREE(principal);
@@ -410,8 +440,10 @@ int ads_keytab_create_default(ADS_STRUCT *ads)
krb5_kt_cursor cursor;
krb5_keytab_entry kt_entry;
krb5_kvno kvno;
+ fstring my_fqdn, my_Fqdn, my_name, my_NAME;
+ char *p_fqdn;
int i, found = 0;
- char **oldEntries = NULL;
+ char **oldEntries = NULL, *princ_s[18];;
ret = ads_keytab_add_entry(ads, "host");
if (ret) {
@@ -424,6 +456,51 @@ int ads_keytab_create_default(ADS_STRUCT *ads)
return ret;
}
+ fstrcpy(my_name, global_myname());
+ strlower_m(my_name);
+
+ fstrcpy(my_NAME, global_myname());
+ strupper_m(my_NAME);
+
+ my_fqdn[0] = '\0';
+ name_to_fqdn(my_fqdn, global_myname());
+ strlower_m(my_fqdn);
+
+ p_fqdn = strchr_m(my_fqdn, '.');
+ fstrcpy(my_Fqdn, my_NAME);
+ if (p_fqdn) {
+ fstrcat(my_Fqdn, p_fqdn);
+ }
+
+ asprintf(&princ_s[0], "%s$@%s", my_name, lp_realm());
+ asprintf(&princ_s[1], "%s$@%s", my_NAME, lp_realm());
+ asprintf(&princ_s[2], "host/%s@%s", my_name, lp_realm());
+ asprintf(&princ_s[3], "host/%s@%s", my_NAME, lp_realm());
+ asprintf(&princ_s[4], "host/%s@%s", my_fqdn, lp_realm());
+ asprintf(&princ_s[5], "host/%s@%s", my_Fqdn, lp_realm());
+ asprintf(&princ_s[6], "HOST/%s@%s", my_name, lp_realm());
+ asprintf(&princ_s[7], "HOST/%s@%s", my_NAME, lp_realm());
+ asprintf(&princ_s[8], "HOST/%s@%s", my_fqdn, lp_realm());
+ asprintf(&princ_s[9], "HOST/%s@%s", my_Fqdn, lp_realm());
+ asprintf(&princ_s[10], "cifs/%s@%s", my_name, lp_realm());
+ asprintf(&princ_s[11], "cifs/%s@%s", my_NAME, lp_realm());
+ asprintf(&princ_s[12], "cifs/%s@%s", my_fqdn, lp_realm());
+ asprintf(&princ_s[13], "cifs/%s@%s", my_Fqdn, lp_realm());
+ asprintf(&princ_s[14], "CIFS/%s@%s", my_name, lp_realm());
+ asprintf(&princ_s[15], "CIFS/%s@%s", my_NAME, lp_realm());
+ asprintf(&princ_s[16], "CIFS/%s@%s", my_fqdn, lp_realm());
+ asprintf(&princ_s[17], "CIFS/%s@%s", my_Fqdn, lp_realm());
+
+ for (i = 0; i < sizeof(princ_s) / sizeof(princ_s[0]); i++) {
+ if (princ_s[i] != NULL) {
+ ret = ads_keytab_add_entry(ads, princ_s[i]);
+ if (ret != 0) {
+ DEBUG(1,("ads_keytab_create_default: ads_keytab_add_entry failed while adding '%s'.\n", princ_s[i]));
+ }
+ SAFE_FREE(princ_s[i]);
+ }
+ }
+
kvno = (krb5_kvno) ads_get_kvno(ads, global_myname());
if (kvno == -1) {
DEBUG(1,("ads_keytab_create_default: ads_get_kvno failed to determine the system's kvno.\n"));
@@ -495,6 +572,11 @@ int ads_keytab_create_default(ADS_STRUCT *ads)
* or mb strings into account. Maybe this is because they assume utf8 ?
* In this case we may need to convert from utf8 to mb charset here ? JRA.
*/
+ p = strchr_m(ktprinc, '@');
+ if (p) {
+ *p = '\0';
+ }
+
p = strchr_m(ktprinc, '/');
if (p) {
*p = '\0';
diff --git a/source/libads/kerberos_verify.c b/source/libads/kerberos_verify.c
index 961b92ccc61..848bd61accf 100644
--- a/source/libads/kerberos_verify.c
+++ b/source/libads/kerberos_verify.c
@@ -41,14 +41,13 @@ static BOOL ads_keytab_verify_ticket(krb5_context context, krb5_auth_context aut
{
krb5_error_code ret = 0;
BOOL auth_ok = False;
-
krb5_keytab keytab = NULL;
- krb5_kt_cursor cursor;
- krb5_keytab_entry kt_entry;
- char *princ_name = NULL;
-
- ZERO_STRUCT(kt_entry);
- ZERO_STRUCT(cursor);
+ fstring my_fqdn, my_name;
+ fstring my_Fqdn, my_NAME;
+ char *p_fqdn;
+ char *host_princ_s[18];
+ krb5_principal host_princ;
+ int i;
ret = krb5_kt_default(context, &keytab);
if (ret) {
@@ -56,69 +55,78 @@ static BOOL ads_keytab_verify_ticket(krb5_context context, krb5_auth_context aut
goto out;
}
- ret = krb5_kt_start_seq_get(context, keytab, &cursor);
- if (ret) {
- DEBUG(1, ("ads_keytab_verify_ticket: krb5_kt_start_seq_get failed (%s)\n", error_message(ret)));
- goto out;
- }
-
- while (!krb5_kt_next_entry(context, keytab, &kt_entry, &cursor)) {
- ret = krb5_unparse_name(context, kt_entry.principal, &princ_name);
+ /* Generate the list of principal names which we expect clients might
+ * want to use for authenticating to the file service. */
+
+ fstrcpy(my_name, global_myname());
+ strlower_m(my_name);
+
+ fstrcpy(my_NAME, global_myname());
+ strupper_m(my_NAME);
+
+ my_fqdn[0] = '\0';
+ name_to_fqdn(my_fqdn, global_myname());
+ strlower_m(my_fqdn);
+
+ p_fqdn = strchr_m(my_fqdn, '.');
+ fstrcpy(my_Fqdn, my_NAME);
+ if (p_fqdn) {
+ fstrcat(my_Fqdn, p_fqdn);
+ }
+
+ asprintf(&host_princ_s[0], "%s$@%s", my_name, lp_realm());
+ asprintf(&host_princ_s[1], "%s$@%s", my_NAME, lp_realm());
+ asprintf(&host_princ_s[2], "host/%s@%s", my_name, lp_realm());
+ asprintf(&host_princ_s[3], "host/%s@%s", my_NAME, lp_realm());
+ asprintf(&host_princ_s[4], "host/%s@%s", my_fqdn, lp_realm());
+ asprintf(&host_princ_s[5], "host/%s@%s", my_Fqdn, lp_realm());
+ asprintf(&host_princ_s[6], "HOST/%s@%s", my_name, lp_realm());
+ asprintf(&host_princ_s[7], "HOST/%s@%s", my_NAME, lp_realm());
+ asprintf(&host_princ_s[8], "HOST/%s@%s", my_fqdn, lp_realm());
+ asprintf(&host_princ_s[9], "HOST/%s@%s", my_Fqdn, lp_realm());
+ asprintf(&host_princ_s[10], "cifs/%s@%s", my_name, lp_realm());
+ asprintf(&host_princ_s[11], "cifs/%s@%s", my_NAME, lp_realm());
+ asprintf(&host_princ_s[12], "cifs/%s@%s", my_fqdn, lp_realm());
+ asprintf(&host_princ_s[13], "cifs/%s@%s", my_Fqdn, lp_realm());
+ asprintf(&host_princ_s[14], "CIFS/%s@%s", my_name, lp_realm());
+ asprintf(&host_princ_s[15], "CIFS/%s@%s", my_NAME, lp_realm());
+ asprintf(&host_princ_s[16], "CIFS/%s@%s", my_fqdn, lp_realm());
+ asprintf(&host_princ_s[17], "CIFS/%s@%s", my_Fqdn, lp_realm());
+
+ /* Now try to verify the ticket using the key associated with each of
+ * the principals which we think clients will expect us to be
+ * participating as. */
+ for (i = 0; i < sizeof(host_princ_s) / sizeof(host_princ_s[0]); i++) {
+ host_princ = NULL;
+ ret = krb5_parse_name(context, host_princ_s[i], &host_princ);
if (ret) {
- DEBUG(1, ("ads_keytab_verify_ticket: krb5_unparse_name failed (%s)\n", error_message(ret)));
+ DEBUG(1, ("ads_keytab_verify_ticket: krb5_parse_name(%s) failed (%s)\n",
+ host_princ_s[i], error_message(ret)));
goto out;
}
- /* Look for a CIFS ticket */
- if (!StrnCaseCmp(princ_name, "cifs/", 5)) {
-#ifdef HAVE_KRB5_KEYTAB_ENTRY_KEYBLOCK
- krb5_auth_con_setuseruserkey(context, auth_context, &kt_entry.keyblock);
-#else
- krb5_auth_con_setuseruserkey(context, auth_context, &kt_entry.key);
-#endif
-
- p_packet->length = ticket->length;
- p_packet->data = (krb5_pointer)ticket->data;
-
- if (!(ret = krb5_rd_req(context, &auth_context, p_packet, NULL, NULL, NULL, pp_tkt))) {
- unsigned int keytype;
- krb5_free_unparsed_name(context, princ_name);
- princ_name = NULL;
-#ifdef HAVE_KRB5_KEYTAB_ENTRY_KEYBLOCK
- keytype = (unsigned int) kt_entry.keyblock.keytype;
-#else
- keytype = (unsigned int) kt_entry.key.enctype;
-#endif
- DEBUG(10,("ads_keytab_verify_ticket: enc type [%u] decrypted message !\n",
- keytype));
- auth_ok = True;
- break;
- }
- }
- krb5_free_unparsed_name(context, princ_name);
- princ_name = NULL;
+ p_packet->length = ticket->length;
+ p_packet->data = (krb5_pointer)ticket->data;
+ *pp_tkt = NULL;
+ ret = krb5_rd_req(context, &auth_context, p_packet, host_princ, keytab, NULL, pp_tkt);
+ krb5_free_principal(context, host_princ);
+ if (ret) {
+ DEBUG(0, ("krb5_rd_req(%s) failed: %s\n", host_princ_s[i], error_message(ret)));
+ } else {
+ DEBUG(10,("krb5_rd_req succeeded for principal %s\n", host_princ_s[i]));
+ auth_ok = True;
+ break;
+ }
}
- if (ret && ret != KRB5_KT_END) {
- /* This failed because something went wrong, not because the keytab file was empty. */
- DEBUG(1, ("ads_keytab_verify_ticket: krb5_kt_next_entry failed (%s)\n", error_message(ret)));
- goto out;
+
+ for (i = 0; i < sizeof(host_princ_s) / sizeof(host_princ_s[0]); i++) {
+ SAFE_FREE(host_princ_s[i]);
}
out:
- if (princ_name) {
- krb5_free_unparsed_name(context, princ_name);
- }
- {
- krb5_kt_cursor zero_csr;
- ZERO_STRUCT(zero_csr);
- if ((memcmp(&cursor, &zero_csr, sizeof(krb5_kt_cursor)) != 0) && keytab) {
- krb5_kt_end_seq_get(context, keytab, &cursor);
- }
- }
if (keytab) {
krb5_kt_close(context, keytab);
}
-
return auth_ok;
}
@@ -223,7 +231,6 @@ NTSTATUS ads_verify_ticket(const char *realm, const DATA_BLOB *ticket,
char *host_princ_s = NULL;
BOOL got_replay_mutex = False;
- fstring myname;
BOOL auth_ok = False;
ZERO_STRUCT(packet);
@@ -254,9 +261,8 @@ NTSTATUS ads_verify_ticket(const char *realm, const DATA_BLOB *ticket,
goto out;
}
- name_to_fqdn(myname, global_myname());
- strlower_m(myname);
- asprintf(&host_princ_s, "host/%s@%s", myname, lp_realm());
+ asprintf(&host_princ_s, "%s$", global_myname());
+ strlower_m(host_princ_s);
ret = krb5_parse_name(context, host_princ_s, &host_princ);
if (ret) {
DEBUG(1,("ads_verify_ticket: krb5_parse_name(%s) failed (%s)\n",
diff --git a/source/libads/krb5_setpw.c b/source/libads/krb5_setpw.c
index 84595212e6c..a45bf236107 100644
--- a/source/libads/krb5_setpw.c
+++ b/source/libads/krb5_setpw.c
@@ -25,7 +25,9 @@
#define DEFAULT_KPASSWD_PORT 464
#define KRB5_KPASSWD_VERS_CHANGEPW 1
+#ifndef KRB5_KPASSWD_VERS_SETPW
#define KRB5_KPASSWD_VERS_SETPW 2
+#endif
#define KRB5_KPASSWD_VERS_SETPW_MS 0xff80
#define KRB5_KPASSWD_ACCESSDENIED 5
#define KRB5_KPASSWD_BAD_VERSION 6
@@ -667,7 +669,7 @@ ADS_STATUS kerberos_set_password(const char *kpasswd_server,
{
int ret;
- if ((ret = kerberos_kinit_password(auth_principal, auth_password, time_offset, NULL))) {
+ if ((ret = kerberos_kinit_password(auth_principal, auth_password, time_offset, NULL, NULL))) {
DEBUG(1,("Failed kinit for principal %s (%s)\n", auth_principal, error_message(ret)));
return ADS_ERROR_KRB5(ret);
}
diff --git a/source/libads/ldap.c b/source/libads/ldap.c
index e5d2dfb8d3f..b2ae5aeb942 100644
--- a/source/libads/ldap.c
+++ b/source/libads/ldap.c
@@ -1228,11 +1228,11 @@ ADS_STATUS ads_add_service_principal_name(ADS_STRUCT *ads, const char *machine_n
ADS_STATUS ret;
TALLOC_CTX *ctx;
LDAPMessage *res = NULL;
- char *host_spn, *host_upn, *psp1, *psp2;
+ char *host_spn, *host_upn, *psp1, *psp2, *psp3;
ADS_MODLIST mods;
fstring my_fqdn;
char *dn_string = NULL;
- const char *servicePrincipalName[3] = {NULL, NULL, NULL};
+ const char *servicePrincipalName[4] = {NULL, NULL, NULL, NULL};
ret = ads_find_machine_acct(ads, (void **)&res, machine_name);
if (!ADS_ERR_OK(ret) || ads_count_replies(ads, res) != 1) {
@@ -1251,6 +1251,8 @@ ADS_STATUS ads_add_service_principal_name(ADS_STRUCT *ads, const char *machine_n
}
name_to_fqdn(my_fqdn, machine_name);
+ strlower_m(my_fqdn);
+
if (!(host_spn = talloc_asprintf(ctx, "HOST/%s", my_fqdn))) {
talloc_destroy(ctx);
ads_msgfree(ads, res);
@@ -1274,6 +1276,17 @@ ADS_STATUS ads_add_service_principal_name(ADS_STRUCT *ads, const char *machine_n
DEBUG(5,("ads_add_service_principal_name: INFO: Adding %s to host %s\n", psp2, machine_name));
servicePrincipalName[1] = psp2;
+ /* Add another principal in case the realm != the DNS domain, so that
+ * the KDC doesn't send "server principal unknown" errors to clients
+ * which use the DNS name in determining service principal names. */
+ psp3 = talloc_asprintf(ctx, "%s/%s", spn, my_fqdn);
+ strupper_m(psp3);
+ strlower_m(&psp3[strlen(spn)]);
+ if (strcmp(psp2, psp3) != 0) {
+ DEBUG(5,("ads_add_service_principal_name: INFO: Adding %s to host %s\n", psp3, machine_name));
+ servicePrincipalName[2] = psp3;
+ }
+
if (!(mods = ads_init_mods(ctx))) {
talloc_destroy(ctx);
ads_msgfree(ads, res);
@@ -1325,12 +1338,13 @@ static ADS_STATUS ads_add_machine_acct(ADS_STRUCT *ads, const char *machine_name
ADS_MODLIST mods;
const char *objectClass[] = {"top", "person", "organizationalPerson",
"user", "computer", NULL};
- const char *servicePrincipalName[5] = {NULL, NULL, NULL, NULL, NULL};
- char *psp, *psp2;
+ const char *servicePrincipalName[7] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL};
+ char *psp, *psp2, *psp3, *psp4;
unsigned acct_control;
unsigned exists=0;
fstring my_fqdn;
LDAPMessage *res = NULL;
+ int i, next_spn;
if (!(ctx = talloc_init("ads_add_machine_acct")))
return ADS_ERROR(LDAP_NO_MEMORY);
@@ -1384,6 +1398,30 @@ static ADS_STATUS ads_add_machine_acct(ADS_STRUCT *ads, const char *machine_name
strlower_m(&psp2[5]);
servicePrincipalName[3] = psp2;
+ /* Ensure servicePrincipalName[4] and [5] are unique. */
+ strlower_m(my_fqdn);
+ psp3 = talloc_asprintf(ctx, "CIFS/%s", my_fqdn);
+ strlower_m(&psp3[5]);
+
+ next_spn = 4;
+ for (i = 0; i < next_spn; i++) {
+ if (strequal(servicePrincipalName[i], psp3))
+ break;
+ }
+ if (i == next_spn) {
+ servicePrincipalName[next_spn++] = psp3;
+ }
+
+ psp4 = talloc_asprintf(ctx, "HOST/%s", my_fqdn);
+ strlower_m(&psp4[5]);
+ for (i = 0; i < next_spn; i++) {
+ if (strequal(servicePrincipalName[i], psp3))
+ break;
+ }
+ if (i == next_spn) {
+ servicePrincipalName[next_spn++] = psp4;
+ }
+
if (!(samAccountName = talloc_asprintf(ctx, "%s$", machine_name))) {
goto done;
}
@@ -1683,14 +1721,14 @@ ADS_STATUS ads_join_realm(ADS_STRUCT *ads, const char *machine_name,
status = ads_add_machine_acct(ads, machine, account_type, org_unit);
if (!ADS_ERR_OK(status)) {
- DEBUG(0, ("ads_add_machine_acct (%s): %s\n", machine, ads_errstr(status)));
+ DEBUG(0, ("ads_join_realm: ads_add_machine_acct failed (%s): %s\n", machine, ads_errstr(status)));
SAFE_FREE(machine);
return status;
}
status = ads_find_machine_acct(ads, (void **)&res, machine);
if (!ADS_ERR_OK(status)) {
- DEBUG(0, ("Host account test failed for machine %s\n", machine));
+ DEBUG(0, ("ads_join_realm: Host account test failed for machine %s\n", machine));
SAFE_FREE(machine);
return status;
}
@@ -2261,7 +2299,7 @@ char *ads_pull_username(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, void *msg)
breaks winbindd_getpwnam() */
ret = ads_pull_string(ads, mem_ctx, msg, "userPrincipalName");
- if (ret && (p = strchr(ret, '@'))) {
+ if (ret && (p = strchr_m(ret, '@'))) {
*p = 0;
return ret;
}
diff --git a/source/libads/util.c b/source/libads/util.c
index 9912a7ba831..f5b88735387 100644
--- a/source/libads/util.c
+++ b/source/libads/util.c
@@ -24,39 +24,45 @@
ADS_STATUS ads_change_trust_account_password(ADS_STRUCT *ads, char *host_principal)
{
- char *tmp_password;
- char *password;
- char *new_password;
- char *service_principal;
- ADS_STATUS ret;
- uint32 sec_channel_type;
+ char *password;
+ char *new_password;
+ char *service_principal;
+ ADS_STATUS ret;
+ uint32 sec_channel_type;
- if ((password = secrets_fetch_machine_password(lp_workgroup(), NULL, &sec_channel_type)) == NULL) {
- DEBUG(1,("Failed to retrieve password for principal %s\n", host_principal));
- return ADS_ERROR_SYSTEM(ENOENT);
- }
+ if ((password = secrets_fetch_machine_password(lp_workgroup(), NULL, &sec_channel_type)) == NULL) {
+ DEBUG(1,("Failed to retrieve password for principal %s\n", host_principal));
+ return ADS_ERROR_SYSTEM(ENOENT);
+ }
- tmp_password = generate_random_str(DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH);
- new_password = strdup(tmp_password);
+ new_password = generate_random_str(DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH);
- asprintf(&service_principal, "HOST/%s", host_principal);
+ asprintf(&service_principal, "HOST/%s", host_principal);
- ret = kerberos_set_password(ads->auth.kdc_server, service_principal, password, service_principal, new_password, ads->auth.time_offset);
+ ret = kerberos_set_password(ads->auth.kdc_server, service_principal, password, service_principal, new_password, ads->auth.time_offset);
- if (!ADS_ERR_OK(ret)) goto failed;
+ if (!ADS_ERR_OK(ret)) {
+ goto failed;
+ }
- if (!secrets_store_machine_password(new_password, lp_workgroup(), sec_channel_type)) {
- DEBUG(1,("Failed to save machine password\n"));
- return ADS_ERROR_SYSTEM(EACCES);
- }
+ if (!secrets_store_machine_password(new_password, lp_workgroup(), sec_channel_type)) {
+ DEBUG(1,("Failed to save machine password\n"));
+ ret = ADS_ERROR_SYSTEM(EACCES);
+ goto failed;
+ }
-failed:
- SAFE_FREE(service_principal);
- SAFE_FREE(new_password);
+ /* Determine if the KDC is salting keys for this principal in a
+ * non-obvious way. */
+ if (!kerberos_derive_salting_principal(service_principal)) {
+ DEBUG(1,("Failed to determine correct salting principal for %s\n", service_principal));
+ ret = ADS_ERROR_SYSTEM(EACCES);
+ goto failed;
+ }
- return ret;
+failed:
+ SAFE_FREE(service_principal);
+ SAFE_FREE(password);
+ SAFE_FREE(new_password);
+ return ret;
}
-
-
-
#endif
diff --git a/source/libsmb/cliconnect.c b/source/libsmb/cliconnect.c
index 4ff60c1b1ca..60691287e61 100644
--- a/source/libsmb/cliconnect.c
+++ b/source/libsmb/cliconnect.c
@@ -757,7 +757,7 @@ ADS_STATUS cli_session_setup_spnego(struct cli_state *cli, const char *user,
int ret;
use_in_memory_ccache();
- ret = kerberos_kinit_password(user, pass, 0 /* no time correction for now */, NULL);
+ ret = kerberos_kinit_password(user, pass, 0 /* no time correction for now */, NULL, NULL);
if (ret){
SAFE_FREE(principal);
diff --git a/source/libsmb/clikrb5.c b/source/libsmb/clikrb5.c
index f7f84f1e297..068e7822072 100644
--- a/source/libsmb/clikrb5.c
+++ b/source/libsmb/clikrb5.c
@@ -77,11 +77,11 @@
pkaddr->contents = (krb5_octet *)&(((struct sockaddr_in *)paddr)->sin_addr);
}
#else
- __ERROR__XX__UNKNOWN_ADDRTYPE
+#error UNKNOWN_ADDRTYPE
#endif
-#if defined(HAVE_KRB5_PRINCIPAL2SALT) && defined(HAVE_KRB5_USE_ENCTYPE) && defined(HAVE_KRB5_STRING_TO_KEY)
- int create_kerberos_key_from_string(krb5_context context,
+#if defined(HAVE_KRB5_PRINCIPAL2SALT) && defined(HAVE_KRB5_USE_ENCTYPE) && defined(HAVE_KRB5_STRING_TO_KEY) && defined(HAVE_KRB5_ENCRYPT_BLOCK)
+ int create_kerberos_key_from_string_direct(krb5_context context,
krb5_principal host_princ,
krb5_data *password,
krb5_keyblock *key,
@@ -102,7 +102,7 @@
return ret;
}
#elif defined(HAVE_KRB5_GET_PW_SALT) && defined(HAVE_KRB5_STRING_TO_KEY_SALT)
- int create_kerberos_key_from_string(krb5_context context,
+ int create_kerberos_key_from_string_direct(krb5_context context,
krb5_principal host_princ,
krb5_data *password,
krb5_keyblock *key,
@@ -120,9 +120,30 @@
salt, key);
}
#else
- __ERROR_XX_UNKNOWN_CREATE_KEY_FUNCTIONS
+#error UNKNOWN_CREATE_KEY_FUNCTIONS
#endif
+ int create_kerberos_key_from_string(krb5_context context,
+ krb5_principal host_princ,
+ krb5_data *password,
+ krb5_keyblock *key,
+ krb5_enctype enctype)
+{
+ krb5_principal salt_princ = NULL;
+ int ret;
+ /*
+ * Check if we've determined that the KDC is salting keys for this
+ * principal/enctype in a non-obvious way. If it is, try to match
+ * its behavior.
+ */
+ salt_princ = kerberos_fetch_salt_princ_for_host_princ(context, host_princ, enctype);
+ ret = create_kerberos_key_from_string_direct(context, salt_princ ? salt_princ : host_princ, password, key, enctype);
+ if (salt_princ) {
+ krb5_free_principal(context, salt_princ);
+ }
+ return ret;
+}
+
#if defined(HAVE_KRB5_GET_PERMITTED_ENCTYPES)
krb5_error_code get_kerberos_allowed_etypes(krb5_context context,
krb5_enctype **enctypes)
@@ -251,6 +272,42 @@
}
#endif
+ void kerberos_free_data_contents(krb5_context context, krb5_data *pdata)
+{
+#if defined(HAVE_KRB5_FREE_DATA_CONTENTS)
+ if (pdata->data) {
+ krb5_free_data_contents(context, pdata);
+ }
+#else
+ SAFE_FREE(pdata->data);
+#endif
+}
+
+ void kerberos_set_creds_enctype(krb5_creds *pcreds, int enctype)
+{
+#if defined(HAVE_KRB5_KEYBLOCK_IN_CREDS)
+ KRB5_KEY_TYPE((&pcreds->keyblock)) = enctype;
+#elif defined(HAVE_KRB5_SESSION_IN_CREDS)
+ KRB5_KEY_TYPE((&pcreds->session)) = enctype;
+#else
+#error UNKNOWN_KEYBLOCK_MEMBER_IN_KRB5_CREDS_STRUCT
+#endif
+}
+
+ BOOL kerberos_compatible_enctypes(krb5_context context,
+ krb5_enctype enctype1,
+ krb5_enctype enctype2)
+{
+#if defined(HAVE_KRB5_C_ENCTYPE_COMPARE)
+ krb5_boolean similar = 0;
+
+ krb5_c_enctype_compare(context, enctype1, enctype2, &similar);
+ return similar ? True : False;
+#elif defined(HAVE_KRB5_ENCTYPES_COMPATIBLE_KEYS)
+ return krb5_enctypes_compatible_keys(context, enctype1, enctype2) ? True : False;
+#endif
+}
+
static BOOL ads_cleanup_expired_creds(krb5_context context,
krb5_ccache ccache,
krb5_creds *credsp)
@@ -273,13 +330,13 @@ static BOOL ads_cleanup_expired_creds(krb5_context context,
we're using creds obtained outside of our exectuable
*/
if (StrCaseCmp(krb5_cc_get_type(context, ccache), "FILE") == 0) {
- DEBUG(5, ("We do not remove creds from a FILE ccache\n"));
+ DEBUG(5, ("ads_cleanup_expired_creds: We do not remove creds from a FILE ccache\n"));
return False;
}
retval = krb5_cc_remove_cred(context, ccache, 0, credsp);
if (retval) {
- DEBUG(1, ("krb5_cc_remove_cred failed, err %s\n",
+ DEBUG(1, ("ads_cleanup_expired_creds: krb5_cc_remove_cred failed, err %s\n",
error_message(retval)));
/* If we have an error in this, we want to display it,
but continue as though we deleted it */
@@ -306,7 +363,7 @@ static krb5_error_code ads_krb5_mk_req(krb5_context context,
retval = krb5_parse_name(context, principal, &server);
if (retval) {
- DEBUG(1,("Failed to parse principal %s\n", principal));
+ DEBUG(1,("ads_krb5_mk_req: Failed to parse principal %s\n", principal));
return retval;
}
@@ -319,7 +376,9 @@ static krb5_error_code ads_krb5_mk_req(krb5_context context,
}
if ((retval = krb5_cc_get_principal(context, ccache, &creds.client))) {
- DEBUG(1,("krb5_cc_get_principal failed (%s)\n",
+ /* This can commonly fail on smbd startup with no ticket in the cache.
+ * Report at higher level than 1. */
+ DEBUG(3,("ads_krb5_mk_req: krb5_cc_get_principal failed (%s)\n",
error_message(retval)));
goto cleanup_creds;
}
@@ -327,7 +386,7 @@ static krb5_error_code ads_krb5_mk_req(krb5_context context,
while(!creds_ready) {
if ((retval = krb5_get_credentials(context, 0, ccache,
&creds, &credsp))) {
- DEBUG(1,("krb5_get_credentials failed for %s (%s)\n",
+ DEBUG(1,("ads_krb5_mk_req: krb5_get_credentials failed for %s (%s)\n",
principal, error_message(retval)));
goto cleanup_creds;
}
@@ -336,7 +395,7 @@ static krb5_error_code ads_krb5_mk_req(krb5_context context,
if ((unsigned)credsp->times.starttime > time(NULL)) {
time_t t = time(NULL);
int time_offset =(unsigned)credsp->times.starttime-t;
- DEBUG(4,("Advancing clock by %d seconds to cope with clock skew\n", time_offset));
+ DEBUG(4,("ads_krb5_mk_req: Advancing clock by %d seconds to cope with clock skew\n", time_offset));
krb5_set_real_time(context, t + time_offset + 1, 0);
}
@@ -344,7 +403,7 @@ static krb5_error_code ads_krb5_mk_req(krb5_context context,
creds_ready = True;
}
- DEBUG(10,("Ticket (%s) in ccache (%s) is valid until: (%s - %d)\n",
+ DEBUG(10,("ads_krb5_mk_req: Ticket (%s) in ccache (%s) is valid until: (%s - %d)\n",
principal, krb5_cc_default_name(context),
http_timestring((unsigned)credsp->times.endtime),
(unsigned)credsp->times.endtime));
@@ -353,7 +412,7 @@ static krb5_error_code ads_krb5_mk_req(krb5_context context,
retval = krb5_mk_req_extended(context, auth_context, ap_req_options,
&in_data, credsp, outbuf);
if (retval) {
- DEBUG(1,("krb5_mk_req_extended failed (%s)\n",
+ DEBUG(1,("ads_krb5_mk_req: krb5_mk_req_extended failed (%s)\n",
error_message(retval)));
}
@@ -389,7 +448,7 @@ int cli_krb5_get_ticket(const char *principal, time_t time_offset,
retval = krb5_init_context(&context);
if (retval) {
- DEBUG(1,("krb5_init_context failed (%s)\n",
+ DEBUG(1,("cli_krb5_get_ticket: krb5_init_context failed (%s)\n",
error_message(retval)));
goto failed;
}
@@ -399,13 +458,13 @@ int cli_krb5_get_ticket(const char *principal, time_t time_offset,
}
if ((retval = krb5_cc_default(context, &ccdef))) {
- DEBUG(1,("krb5_cc_default failed (%s)\n",
+ DEBUG(1,("cli_krb5_get_ticket: krb5_cc_default failed (%s)\n",
error_message(retval)));
goto failed;
}
if ((retval = krb5_set_default_tgs_ktypes(context, enc_types))) {
- DEBUG(1,("krb5_set_default_tgs_ktypes failed (%s)\n",
+ DEBUG(1,("cli_krb5_get_ticket: krb5_set_default_tgs_ktypes failed (%s)\n",
error_message(retval)));
goto failed;
}
@@ -422,10 +481,7 @@ int cli_krb5_get_ticket(const char *principal, time_t time_offset,
*ticket = data_blob(packet.data, packet.length);
-/* Hmm, heimdal dooesn't have this - what's the correct call? */
-#ifdef HAVE_KRB5_FREE_DATA_CONTENTS
- krb5_free_data_contents(context, &packet);
-#endif
+ kerberos_free_data_contents(context, &packet);
failed:
diff --git a/source/libsmb/ntlm_check.c b/source/libsmb/ntlm_check.c
index a0ca08fb891..26e4c76fd34 100644
--- a/source/libsmb/ntlm_check.c
+++ b/source/libsmb/ntlm_check.c
@@ -93,6 +93,7 @@ static BOOL smb_pwd_check_ntlmv2(const DATA_BLOB *ntv2_response,
uchar value_from_encryption[16];
uchar client_response[16];
DATA_BLOB client_key_data;
+ BOOL res;
if (part_passwd == NULL) {
DEBUG(10,("No password set - DISALLOWING access\n"));
@@ -146,7 +147,10 @@ static BOOL smb_pwd_check_ntlmv2(const DATA_BLOB *ntv2_response,
dump_data(100, value_from_encryption, 16);
#endif
data_blob_clear_free(&client_key_data);
- return (memcmp(value_from_encryption, client_response, 16) == 0);
+ res = (memcmp(value_from_encryption, client_response, 16) == 0);
+ if ((!res) && (user_sess_key != NULL))
+ data_blob_clear_free(user_sess_key);
+ return res;
}
/**
diff --git a/source/libsmb/smb_signing.c b/source/libsmb/smb_signing.c
index 39131debf5e..b02a13c73e1 100644
--- a/source/libsmb/smb_signing.c
+++ b/source/libsmb/smb_signing.c
@@ -255,6 +255,7 @@ static void simple_packet_signature(struct smb_basic_signing_context *data,
const size_t offset_end_of_sig = (smb_ss_field + 8);
unsigned char sequence_buf[8];
struct MD5Context md5_ctx;
+ unsigned char key_buf[16];
/*
* Firstly put the sequence number into the first 4 bytes.
@@ -276,8 +277,14 @@ static void simple_packet_signature(struct smb_basic_signing_context *data,
MD5Init(&md5_ctx);
/* intialise with the key */
- MD5Update(&md5_ctx, data->mac_key.data,
- data->mac_key.length);
+ /* NB. When making and verifying SMB signatures, Windows apparently
+ zero-pads the key to 128 bits if it isn't long enough.
+ From Nalin Dahyabhai <nalin@redhat.com> */
+ MD5Update(&md5_ctx, data->mac_key.data, data->mac_key.length);
+ if (data->mac_key.length < sizeof(key_buf)) {
+ memset(key_buf, 0, sizeof(key_buf));
+ MD5Update(&md5_ctx, key_buf, sizeof(key_buf) - data->mac_key.length);
+ }
/* copy in the first bit of the SMB header */
MD5Update(&md5_ctx, buf + 4, smb_ss_field - 4);
diff --git a/source/param/loadparm.c b/source/param/loadparm.c
index 053626c730f..65e9e6b57f6 100644
--- a/source/param/loadparm.c
+++ b/source/param/loadparm.c
@@ -541,7 +541,7 @@ static service sDefault = {
False, /* bForcePrintername */
True, /* bNTAclSupport */
False, /* bForceUnknownAclUser */
- True, /* bUseSendfile */
+ False, /* bUseSendfile */
False, /* bProfileAcls */
False, /* bMap_acl_inherit */
False, /* bAfs_Share */
@@ -794,8 +794,8 @@ static struct parm_struct parm_table[] = {
{"server schannel", P_ENUM, P_GLOBAL, &Globals.serverSchannel, NULL, enum_bool_auto, FLAG_BASIC | FLAG_ADVANCED},
{"allow trusted domains", P_BOOL, P_GLOBAL, &Globals.bAllowTrustedDomains, NULL, NULL, FLAG_ADVANCED},
{"hosts equiv", P_STRING, P_GLOBAL, &Globals.szHostsEquiv, NULL, NULL, FLAG_ADVANCED},
- {"min passwd length", P_INTEGER, P_GLOBAL, &Globals.min_passwd_length, NULL, NULL, FLAG_ADVANCED},
{"min password length", P_INTEGER, P_GLOBAL, &Globals.min_passwd_length, NULL, NULL, FLAG_ADVANCED},
+ {"min passwd length", P_INTEGER, P_GLOBAL, &Globals.min_passwd_length, NULL, NULL, FLAG_ADVANCED},
{"map to guest", P_ENUM, P_GLOBAL, &Globals.map_to_guest, NULL, enum_map_to_guest, FLAG_ADVANCED},
{"null passwords", P_BOOL, P_GLOBAL, &Globals.bNullPasswords, NULL, NULL, FLAG_ADVANCED},
{"obey pam restrictions", P_BOOL, P_GLOBAL, &Globals.bObeyPamRestrictions, NULL, NULL, FLAG_ADVANCED},
@@ -881,8 +881,8 @@ static struct parm_struct parm_table[] = {
{"log file", P_STRING, P_GLOBAL, &Globals.szLogFile, NULL, NULL, FLAG_ADVANCED},
{"max log size", P_INTEGER, P_GLOBAL, &Globals.max_log_size, NULL, NULL, FLAG_ADVANCED},
- {"timestamp logs", P_BOOL, P_GLOBAL, &Globals.bTimestampLogs, NULL, NULL, FLAG_ADVANCED},
{"debug timestamp", P_BOOL, P_GLOBAL, &Globals.bTimestampLogs, NULL, NULL, FLAG_ADVANCED},
+ {"timestamp logs", P_BOOL, P_GLOBAL, &Globals.bTimestampLogs, NULL, NULL, FLAG_ADVANCED},
{"debug hires timestamp", P_BOOL, P_GLOBAL, &Globals.bDebugHiresTimestamp, NULL, NULL, FLAG_ADVANCED},
{"debug pid", P_BOOL, P_GLOBAL, &Globals.bDebugPid, NULL, NULL, FLAG_ADVANCED},
{"debug uid", P_BOOL, P_GLOBAL, &Globals.bDebugUid, NULL, NULL, FLAG_ADVANCED},
@@ -890,9 +890,9 @@ static struct parm_struct parm_table[] = {
{N_("Protocol Options"), P_SEP, P_SEPARATOR},
{"smb ports", P_STRING, P_GLOBAL, &Globals.smb_ports, NULL, NULL, FLAG_ADVANCED},
- {"protocol", P_ENUM, P_GLOBAL, &Globals.maxprotocol, NULL, enum_protocol, FLAG_ADVANCED},
{"large readwrite", P_BOOL, P_GLOBAL, &Globals.bLargeReadwrite, NULL, NULL, FLAG_ADVANCED},
{"max protocol", P_ENUM, P_GLOBAL, &Globals.maxprotocol, NULL, enum_protocol, FLAG_ADVANCED},
+ {"protocol", P_ENUM, P_GLOBAL, &Globals.maxprotocol, NULL, enum_protocol, FLAG_ADVANCED},
{"min protocol", P_ENUM, P_GLOBAL, &Globals.minprotocol, NULL, enum_protocol, FLAG_ADVANCED},
{"read bmpx", P_BOOL, P_GLOBAL, &Globals.bReadbmpx, NULL, NULL, FLAG_ADVANCED},
{"read raw", P_BOOL, P_GLOBAL, &Globals.bReadRaw, NULL, NULL, FLAG_ADVANCED},
@@ -1131,8 +1131,8 @@ static struct parm_struct parm_table[] = {
{"copy", P_STRING, P_LOCAL, &sDefault.szCopy, handle_copy, NULL, FLAG_HIDE},
{"include", P_STRING, P_LOCAL, &sDefault.szInclude, handle_include, NULL, FLAG_HIDE},
- {"exec", P_STRING, P_LOCAL, &sDefault.szPreExec, NULL, NULL, FLAG_ADVANCED | FLAG_SHARE | FLAG_PRINT},
- {"preexec", P_STRING, P_LOCAL, &sDefault.szPreExec, NULL, NULL, FLAG_ADVANCED},
+ {"preexec", P_STRING, P_LOCAL, &sDefault.szPreExec, NULL, NULL, FLAG_ADVANCED | FLAG_SHARE | FLAG_PRINT},
+ {"exec", P_STRING, P_LOCAL, &sDefault.szPreExec, NULL, NULL, FLAG_ADVANCED},
{"preexec close", P_BOOL, P_LOCAL, &sDefault.bPreexecClose, NULL, NULL, FLAG_ADVANCED | FLAG_SHARE},
{"postexec", P_STRING, P_LOCAL, &sDefault.szPostExec, NULL, NULL, FLAG_ADVANCED | FLAG_SHARE | FLAG_PRINT},
diff --git a/source/python/py_lsa.c b/source/python/py_lsa.c
index 07191be8682..aab526a4897 100644
--- a/source/python/py_lsa.c
+++ b/source/python/py_lsa.c
@@ -55,7 +55,7 @@ static PyObject *lsa_open_policy(PyObject *self, PyObject *args,
static char *kwlist[] = { "servername", "creds", "access", NULL };
char *server, *errstr;
PyObject *creds = NULL, *result = NULL;
- uint32 desired_access = MAXIMUM_ALLOWED_ACCESS;
+ uint32 desired_access = GENERIC_EXECUTE_ACCESS;
struct cli_state *cli = NULL;
NTSTATUS ntstatus;
TALLOC_CTX *mem_ctx = NULL;
@@ -90,7 +90,7 @@ static PyObject *lsa_open_policy(PyObject *self, PyObject *args,
}
ntstatus = cli_lsa_open_policy(cli, mem_ctx, True,
- SEC_RIGHTS_MAXIMUM_ALLOWED, &hnd);
+ desired_access, &hnd);
if (!NT_STATUS_IS_OK(ntstatus)) {
PyErr_SetObject(lsa_ntstatus, py_ntstatus_tuple(ntstatus));
diff --git a/source/python/samba/printerdata.py b/source/python/samba/printerdata.py
index 81575fecb2d..6c40cc4b26d 100644
--- a/source/python/samba/printerdata.py
+++ b/source/python/samba/printerdata.py
@@ -62,4 +62,5 @@ class printerdata_ex:
return self.hnd.getprinterdataex(self.key, key)['data']
def __getitem__(self, key):
- return self.printerdata_ex_subkey(self.host, key, self.creds, access)
+ return self.printerdata_ex_subkey(
+ self.host, key, self.creds, self.access)
diff --git a/source/sam/idmap_rid.c b/source/sam/idmap_rid.c
index 16784da12e5..48b38fb0d85 100644
--- a/source/sam/idmap_rid.c
+++ b/source/sam/idmap_rid.c
@@ -152,13 +152,32 @@ static NTSTATUS rid_idmap_get_domains(uint32 *num_domains, fstring **domain_name
char *domain = NULL;
uint32 info_class = 5;
char *domain_name = NULL;
- DOM_SID *domain_sid;
+ DOM_SID *domain_sid, sid;
fstring sid_str;
int i;
uint32 trusted_num_domains = 0;
char **trusted_domain_names;
DOM_SID *trusted_domain_sids;
-
+ uint32 enum_ctx = 0;
+
+ /* put the results together */
+ *num_domains = 1;
+ *domain_names = (fstring *) malloc(sizeof(fstring) * *num_domains);
+ *domain_sids = (DOM_SID *) malloc(sizeof(DOM_SID) * *num_domains);
+
+ /* avoid calling a DC when trusted domains are not allowed anyway */
+ if (!lp_allow_trusted_domains()) {
+
+ fstrcpy((*domain_names)[0], lp_workgroup());
+ if (!secrets_fetch_domain_sid(lp_workgroup(), &sid)) {
+ DEBUG(0,("rid_idmap_get_domains: failed to retrieve domain sid\n"));
+ return status;
+ }
+ sid_copy(&(*domain_sids)[0], &sid);
+
+ return NT_STATUS_OK;
+ }
+
/* create mem_ctx */
if (!(mem_ctx = talloc_init("rid_idmap_get_trusted_domains"))) {
DEBUG(0, ("rid_idmap_get_domains: talloc_init() failed\n"));
@@ -229,37 +248,32 @@ static NTSTATUS rid_idmap_get_domains(uint32 *num_domains, fstring **domain_name
sid_to_string(sid_str, domain_sid);
DEBUG(10,("rid_idmap_get_domains: my domain: [%s], sid: [%s]\n", domain_name, sid_str));
- if (lp_allow_trusted_domains()) {
-
- uint32 enum_ctx = 0;
-
- /* scan trusted domains */
- DEBUG(10, ("rid_idmap_get_domains: enumerating trusted domains\n"));
- status = cli_lsa_enum_trust_dom(cli, mem_ctx, &pol, &enum_ctx,
- &trusted_num_domains,
- &trusted_domain_names,
- &trusted_domain_sids);
-
- if (!NT_STATUS_IS_OK(status) &&
- !NT_STATUS_EQUAL(status, NT_STATUS_NO_MORE_ENTRIES) &&
- !NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
- DEBUG(1, ("rid_idmap_get_domains: could not enumerate trusted domains\n"));
- goto out;
- }
+ /* scan trusted domains */
+ DEBUG(10, ("rid_idmap_get_domains: enumerating trusted domains\n"));
+ status = cli_lsa_enum_trust_dom(cli, mem_ctx, &pol, &enum_ctx,
+ &trusted_num_domains,
+ &trusted_domain_names,
+ &trusted_domain_sids);
+
+ if (!NT_STATUS_IS_OK(status) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_NO_MORE_ENTRIES) &&
+ !NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
+ DEBUG(1, ("rid_idmap_get_domains: could not enumerate trusted domains\n"));
+ goto out;
+ }
- /* show trusted domains */
- DEBUG(10,("rid_idmap_get_domains: scan for trusted domains gave %d results:\n", trusted_num_domains));
- for (i=0; i<trusted_num_domains; i++) {
- sid_to_string(sid_str, &trusted_domain_sids[i]);
- DEBUGADD(10,("rid_idmap_get_domains:\t#%d\tDOMAIN: [%s], SID: [%s]\n",
- i, trusted_domain_names[i], sid_str));
- }
+ /* show trusted domains */
+ DEBUG(10,("rid_idmap_get_domains: scan for trusted domains gave %d results:\n", trusted_num_domains));
+ for (i=0; i<trusted_num_domains; i++) {
+ sid_to_string(sid_str, &trusted_domain_sids[i]);
+ DEBUGADD(10,("rid_idmap_get_domains:\t#%d\tDOMAIN: [%s], SID: [%s]\n",
+ i, trusted_domain_names[i], sid_str));
}
/* put the results together */
*num_domains = trusted_num_domains + 1;
- *domain_names = (fstring *) malloc(sizeof(fstring) * *num_domains);
- *domain_sids = (DOM_SID *) malloc(sizeof(DOM_SID) * *num_domains);
+ *domain_names = (fstring *) realloc(domain_names, sizeof(fstring) * *num_domains);
+ *domain_sids = (DOM_SID *) realloc(domain_sids, sizeof(DOM_SID) * *num_domains);
/* first add myself at the end*/
fstrcpy((*domain_names)[0], domain_name);
diff --git a/source/smbd/dosmode.c b/source/smbd/dosmode.c
index 7199b3ebbf3..3a3a6e6fdb0 100644
--- a/source/smbd/dosmode.c
+++ b/source/smbd/dosmode.c
@@ -344,7 +344,9 @@ int file_set_dosmode(connection_struct *conn, const char *fname, uint32 dosmode,
return(-1);
}
- get_acl_group_bits(conn, fname, &st->st_mode);
+ if (!get_acl_group_bits(conn, fname, &st->st_mode)) {
+ return(-1);
+ }
if (S_ISDIR(st->st_mode))
dosmode |= aDIR;
diff --git a/source/smbd/posix_acls.c b/source/smbd/posix_acls.c
index ab32d0591e9..be7f828b677 100644
--- a/source/smbd/posix_acls.c
+++ b/source/smbd/posix_acls.c
@@ -180,7 +180,7 @@ static char *create_pai_buf(canon_ace *file_ace_list, canon_ace *dir_ace_list, B
entry_offset = pai_buf + PAI_ENTRIES_BASE;
- for (ace_list = dir_ace_list; ace_list; ace_list = ace_list->next) {
+ for (ace_list = file_ace_list; ace_list; ace_list = ace_list->next) {
if (ace_list->inherited) {
uint8 type_val = (unsigned char)ace_list->owner_type;
uint32 entry_val = get_entry_val(ace_list);
@@ -191,7 +191,7 @@ static char *create_pai_buf(canon_ace *file_ace_list, canon_ace *dir_ace_list, B
}
}
- for (ace_list = file_ace_list; ace_list; ace_list = ace_list->next) {
+ for (ace_list = dir_ace_list; ace_list; ace_list = ace_list->next) {
if (ace_list->inherited) {
uint8 type_val = (unsigned char)ace_list->owner_type;
uint32 entry_val = get_entry_val(ace_list);
@@ -3226,7 +3226,7 @@ int get_acl_group_bits( connection_struct *conn, const char *fname, mode_t *mode
}
}
SMB_VFS_SYS_ACL_FREE_ACL(conn, posix_acl);
- return -1;
+ return result;
}
/****************************************************************************
diff --git a/source/smbd/server.c b/source/smbd/server.c
index 0fe633bb969..bf1da1a0c87 100644
--- a/source/smbd/server.c
+++ b/source/smbd/server.c
@@ -910,6 +910,15 @@ void build_options(BOOL screen);
smbd_process();
namecache_shutdown();
+
+ if (interactive) {
+ TALLOC_CTX *mem_ctx = talloc_init("end_description");
+ char *description = talloc_describe_all(mem_ctx);
+
+ DEBUG(3, ("tallocs left:\n%s\n", description));
+ talloc_destroy(mem_ctx);
+ }
+
exit_server("normal exit");
return(0);
}
diff --git a/source/smbd/trans2.c b/source/smbd/trans2.c
index 9b1f2aa2105..ac282ed95fc 100644
--- a/source/smbd/trans2.c
+++ b/source/smbd/trans2.c
@@ -1662,7 +1662,7 @@ resume_key = %d resume name = %s continue=%d level = %d\n",
* depend on the last file name instead.
*/
- if(requires_resume_key && *resume_name && !continue_bit) {
+ if(*resume_name && !continue_bit) {
/*
* Fix for NT redirector problem triggered by resume key indexes
@@ -1714,7 +1714,7 @@ resume_key = %d resume name = %s continue=%d level = %d\n",
if(current_pos < 0) {
DEBUG(7,("call_trans2findnext: notfound: seeking to pos %d\n", start_pos));
SeekDir(dirptr, start_pos);
- for(current_pos = start_pos; (dname = ReadDirName(dirptr)) != NULL; SeekDir(dirptr,++current_pos)) {
+ for(current_pos = start_pos; (dname = ReadDirName(dirptr)) != NULL; ++current_pos) {
/*
* Remember, mangle_map is called by
@@ -1737,7 +1737,11 @@ resume_key = %d resume name = %s continue=%d level = %d\n",
}
} /* end for */
} /* end if current_pos */
- } /* end if requires_resume_key && !continue_bit */
+ /* Can't find the name. Just resume from where we were... */
+ if (dname == 0) {
+ SeekDir(dirptr, start_pos);
+ }
+ } /* end if resume_name && !continue_bit */
for (i=0;(i<(int)maxentries) && !finished && !out_of_space ;i++) {
BOOL got_exact_match = False;
diff --git a/source/utils/net_ads.c b/source/utils/net_ads.c
index 19311cde654..9efa45e58f5 100644
--- a/source/utils/net_ads.c
+++ b/source/utils/net_ads.c
@@ -169,7 +169,7 @@ retry:
* extract the realm and convert to upper case.
* This is only used to establish the connection.
*/
- if ((cp = strchr(ads->auth.user_name, '@'))!=0) {
+ if ((cp = strchr_m(ads->auth.user_name, '@'))!=0) {
*cp++ = '\0';
ads->auth.realm = smb_xstrdup(cp);
strupper_m(ads->auth.realm);
@@ -823,6 +823,20 @@ int net_ads_join(int argc, const char **argv)
return -1;
}
+#ifdef HAVE_KRB5
+ if (!kerberos_derive_salting_principal(machine_account)) {
+ DEBUG(1,("Failed to determine salting principal\n"));
+ ads_destroy(&ads);
+ return -1;
+ }
+
+ if (!kerberos_derive_cifs_salting_principals()) {
+ DEBUG(1,("Failed to determine salting principals\n"));
+ ads_destroy(&ads);
+ return -1;
+ }
+#endif
+
if (!secrets_store_domain_sid(short_domain_name, &dom_sid)) {
DEBUG(1,("Failed to save domain sid\n"));
ads_destroy(&ads);
@@ -1126,7 +1140,7 @@ static int net_ads_password(int argc, const char **argv)
}
use_in_memory_ccache();
- c = strchr(auth_principal, '@');
+ c = strchr_m(auth_principal, '@');
if (c) {
realm = ++c;
} else {
diff --git a/source/utils/ntlm_auth.c b/source/utils/ntlm_auth.c
index b2c155dfb2a..3d515238316 100644
--- a/source/utils/ntlm_auth.c
+++ b/source/utils/ntlm_auth.c
@@ -920,7 +920,7 @@ static void manage_gss_spnego_request(enum stdio_helper_mode stdio_helper_mode,
if (NT_STATUS_IS_OK(status)) {
- domain = strchr(principal, '@');
+ domain = strchr_m(principal, '@');
if (domain == NULL) {
DEBUG(1, ("Did not get a valid principal "
@@ -1184,7 +1184,7 @@ static BOOL manage_client_krb5_init(SPNEGO_DATA spnego)
pstr_sprintf(user, "%s@%s", opt_username, opt_domain);
if ((retval = kerberos_kinit_password(user, opt_password,
- 0, NULL))) {
+ 0, NULL, NULL))) {
DEBUG(10, ("Requesting TGT failed: %s\n", error_message(retval)));
return False;
}