From f0ae41fc1025aa840218545add3fbe2c207cc5bc Mon Sep 17 00:00:00 2001 From: Gerald Carter Date: Sun, 7 Nov 2004 20:42:45 +0000 Subject: r3605: * sync up with 3.0 with the exception of volker's recent changes to the getaliases call --- packaging/Solaris/makepkg.sh | 4 - source/Makefile.in | 21 +- source/VERSION | 2 +- source/client/client.c | 4 +- source/client/smbspool.c | 8 +- source/configure.in | 104 +++++-- source/groupdb/mapping.c | 5 +- source/include/includes.h | 13 +- source/include/secrets.h | 3 + source/lib/account_pol.c | 5 +- source/libads/kerberos.c | 600 ++++++++++++++++++++++++++++++++++++- source/libads/kerberos_keytab.c | 176 ++++++++--- source/libads/kerberos_verify.c | 132 ++++---- source/libads/krb5_setpw.c | 4 +- source/libads/ldap.c | 52 +++- source/libads/util.c | 58 ++-- source/libsmb/cliconnect.c | 2 +- source/libsmb/clikrb5.c | 96 ++++-- source/libsmb/ntlm_check.c | 6 +- source/libsmb/smb_signing.c | 11 +- source/param/loadparm.c | 12 +- source/python/py_lsa.c | 4 +- source/python/samba/printerdata.py | 3 +- source/sam/idmap_rid.c | 70 +++-- source/smbd/dosmode.c | 4 +- source/smbd/posix_acls.c | 6 +- source/smbd/server.c | 9 + source/smbd/trans2.c | 10 +- source/utils/net_ads.c | 18 +- source/utils/ntlm_auth.c | 4 +- 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_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 ], @@ -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_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_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 ], 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 -#endif - -#if HAVE_GSSAPI_GSSAPI_H +#elif HAVE_GSSAPI_GSSAPI_H #include -#endif - -#if HAVE_GSSAPI_GSSAPI_GENERIC_H +#elif HAVE_GSSAPI_GSSAPI_GENERIC_H #include #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 */ + 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; ist_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; } -- cgit