summaryrefslogtreecommitdiff
path: root/source3
diff options
context:
space:
mode:
authorAndrew Tridgell <tridge@samba.org>2008-01-23 13:08:14 +1100
committerAndrew Tridgell <tridge@samba.org>2008-01-23 13:08:14 +1100
commit39d172bf34d0cbb3bf3e3a04d534876097cdccb5 (patch)
tree3a32fd867e34c9a86c3a2f01308445b76bf2d50c /source3
parent2caa0e82f5ff2f45a5c912c624e54c4a43f0c3cc (diff)
parent9051199e40dec27d3532fbec7f5744033def1874 (diff)
downloadsamba-39d172bf34d0cbb3bf3e3a04d534876097cdccb5.tar.gz
samba-39d172bf34d0cbb3bf3e3a04d534876097cdccb5.tar.bz2
samba-39d172bf34d0cbb3bf3e3a04d534876097cdccb5.zip
Merge branch 'v3-2-test' of ssh://git.samba.org/data/git/samba into v3-2-test
(This used to be commit bc2973df8504850a40cb0a1172689dc0bdafa323)
Diffstat (limited to 'source3')
-rw-r--r--source3/Makefile.in92
-rw-r--r--source3/client/client.c88
-rw-r--r--source3/configure.in15
-rw-r--r--source3/include/includes.h9
-rw-r--r--source3/include/reg_objects.h10
-rw-r--r--source3/include/smb.h28
-rw-r--r--source3/include/vfs.h15
-rw-r--r--source3/include/vfs_macros.h6
-rw-r--r--source3/lib/afs.c23
-rw-r--r--source3/lib/dbwrap_tdb.c4
-rw-r--r--source3/lib/errmap_unix.c3
-rw-r--r--source3/lib/netapi/joindomain.c4
-rw-r--r--source3/lib/netapi/netapi.h11
-rw-r--r--source3/lib/replace/libreplace.m420
-rw-r--r--source3/lib/replace/libreplace_cc.m48
-rw-r--r--source3/lib/replace/libreplace_ld.m42
-rw-r--r--source3/lib/replace/libreplace_macros.m430
-rw-r--r--source3/lib/replace/system/config.m425
-rw-r--r--source3/lib/replace/system/network.h7
-rw-r--r--source3/lib/replace/system/printing.h50
-rw-r--r--source3/lib/replace/test/testsuite.c1
-rw-r--r--source3/lib/system.c5
-rw-r--r--source3/lib/util.c90
-rw-r--r--source3/lib/util_sock.c7
-rw-r--r--source3/lib/util_str.c6
-rw-r--r--source3/lib/version.c2
-rw-r--r--source3/libnet/libnet_conf.c22
-rw-r--r--source3/libsmb/clirap.c131
-rw-r--r--source3/libsmb/libsmbclient.c2
-rw-r--r--source3/locking/brlock.c5
-rw-r--r--source3/modules/vfs_default.c72
-rw-r--r--source3/modules/vfs_streams_depot.c641
-rw-r--r--source3/modules/vfs_streams_xattr.c685
-rw-r--r--source3/modules/vfs_xattr_tdb.c28
-rw-r--r--source3/nsswitch/libwbclient/wbclient.c4
-rw-r--r--source3/param/loadparm.c1
-rw-r--r--source3/registry/reg_api.c8
-rw-r--r--source3/registry/reg_backend_current_version.c81
-rw-r--r--source3/registry/reg_backend_db.c (renamed from source3/registry/reg_db.c)18
-rw-r--r--source3/registry/reg_backend_hkpt_params.c70
-rw-r--r--source3/registry/reg_backend_netlogon_params.c57
-rw-r--r--source3/registry/reg_backend_perflib.c106
-rw-r--r--source3/registry/reg_backend_printing.c (renamed from source3/registry/reg_printing.c)9
-rw-r--r--source3/registry/reg_backend_prod_options.c70
-rw-r--r--source3/registry/reg_backend_shares.c (renamed from source3/registry/reg_shares.c)9
-rw-r--r--source3/registry/reg_backend_smbconf.c (renamed from source3/registry/reg_smbconf.c)16
-rw-r--r--source3/registry/reg_backend_tcpip_params.c67
-rw-r--r--source3/registry/reg_cachehook.c13
-rw-r--r--source3/registry/reg_dispatcher.c (renamed from source3/registry/reg_frontend_hilvl.c)14
-rw-r--r--source3/registry/reg_dynamic.c264
-rw-r--r--source3/registry/reg_init_full.c (renamed from source3/registry/reg_frontend.c)34
-rw-r--r--source3/registry/reg_init_smbconf.c (renamed from source3/lib/util_reg_smbconf.c)0
-rw-r--r--source3/registry/reg_util_legacy.c47
-rw-r--r--source3/rpc_server/srv_samr_util.c12
-rwxr-xr-xsource3/script/tests/selftest.sh2
-rwxr-xr-xsource3/script/tests/test_posix_s3.sh2
-rw-r--r--source3/services/services_db.c4
-rw-r--r--source3/smbd/close.c115
-rw-r--r--source3/smbd/filename.c123
-rw-r--r--source3/smbd/nttrans.c3
-rw-r--r--source3/smbd/open.c222
-rw-r--r--source3/smbd/reply.c29
-rw-r--r--source3/smbd/service.c10
-rw-r--r--source3/smbd/trans2.c401
-rw-r--r--source3/smbd/utmp.c2
-rw-r--r--source3/torture/torture.c69
-rw-r--r--source3/utils/net_rpc_samsync.c6
-rw-r--r--source3/utils/ntlm_auth.c397
-rw-r--r--source3/winbindd/winbindd_cm.c13
-rw-r--r--source3/winbindd/winbindd_pam.c5
70 files changed, 3658 insertions, 792 deletions
diff --git a/source3/Makefile.in b/source3/Makefile.in
index 227650027a..c519ff8985 100644
--- a/source3/Makefile.in
+++ b/source3/Makefile.in
@@ -276,6 +276,7 @@ LIBNDR_GEN_OBJ = librpc/gen_ndr/ndr_wkssvc.o \
librpc/gen_ndr/ndr_netlogon.o \
librpc/gen_ndr/ndr_samr.o \
librpc/gen_ndr/ndr_notify.o \
+ librpc/gen_ndr/ndr_xattr.o \
librpc/gen_ndr/ndr_libnet_join.o
RPC_PARSE_OBJ0 = rpc_parse/parse_prs.o rpc_parse/parse_misc.o
@@ -410,14 +411,54 @@ LIBMSRPC_GEN_OBJ = librpc/gen_ndr/cli_lsa.o \
$(LIBNDR_GEN_OBJ) \
$(RPCCLIENT_NDR_OBJ)
+#
+# registry-related objects
+#
+UTIL_REG_OBJ = lib/util_reg.o
+UTIL_REG_API_OBJ = lib/util_reg_api.o
+REG_INIT_SMBCONF_OBJ = registry/reg_init_smbconf.o
+
+REGFIO_OBJ = registry/regfio.o
+
REGOBJS_OBJ = registry/reg_objects.o
-REGISTRY_OBJ = registry/reg_frontend.o registry/reg_cachehook.o registry/reg_printing.o \
- registry/reg_db.o registry/reg_eventlog.o registry/reg_shares.o \
- registry/reg_util.o registry/reg_dynamic.o registry/reg_perfcount.o \
- registry/reg_smbconf.o registry/reg_api.o \
- registry/reg_frontend_hilvl.o \
- $(UTIL_REG_API_OBJ) $(UTIL_REG_SMBCONF_OBJ)
+REGISTRY_BACKENDS = registry/reg_backend_printing.o \
+ registry/reg_backend_db.o \
+ registry/reg_backend_smbconf.o \
+ registry/reg_backend_shares.o \
+ registry/reg_backend_netlogon_params.o \
+ registry/reg_backend_prod_options.o \
+ registry/reg_backend_tcpip_params.o \
+ registry/reg_backend_hkpt_params.o \
+ registry/reg_backend_current_version.o \
+ registry/reg_backend_perflib.o
+
+
+REGISTRY_OBJ = registry/reg_init_full.o registry/reg_cachehook.o \
+ registry/reg_eventlog.o \
+ registry/reg_util.o registry/reg_perfcount.o \
+ registry/reg_util_legacy.o \
+ registry/reg_api.o \
+ registry/reg_dispatcher.o \
+ $(REGISTRY_BACKENDS) \
+ $(UTIL_REG_API_OBJ) \
+ $(REG_INIT_SMBCONF_OBJ)
+
+# objects to be used when not all of the registry code should be
+# loaded but only the portion needed by reg_api, typically for
+# using smbconf (registry) - full access
+REG_API_OBJ = registry/reg_api.o \
+ registry/reg_dispatcher.o \
+ registry/reg_backend_smbconf.o \
+ registry/reg_backend_db.o \
+ registry/reg_util.o \
+ \
+ registry/reg_cachehook.o \
+ \
+ lib/util_nttoken.o \
+ $(UTIL_REG_API_OBJ) \
+ $(REG_INIT_SMBCONF_OBJ)
+
RPC_LSA_OBJ = rpc_server/srv_lsa.o rpc_server/srv_lsa_nt.o librpc/gen_ndr/srv_lsa.o
@@ -426,8 +467,6 @@ RPC_NETLOG_OBJ = rpc_server/srv_netlog.o rpc_server/srv_netlog_nt.o
RPC_SAMR_OBJ = rpc_server/srv_samr.o rpc_server/srv_samr_nt.o \
rpc_server/srv_samr_util.o
-REGFIO_OBJ = registry/regfio.o
-
RPC_INITSHUTDOWN_OBJ = librpc/gen_ndr/srv_initshutdown.o rpc_server/srv_initshutdown_nt.o
RPC_REG_OBJ = rpc_server/srv_winreg_nt.o \
@@ -514,7 +553,7 @@ VFS_EXPAND_MSDFS_OBJ = modules/vfs_expand_msdfs.o
VFS_SHADOW_COPY_OBJ = modules/vfs_shadow_copy.o
VFS_SHADOW_COPY2_OBJ = modules/vfs_shadow_copy2.o
VFS_AFSACL_OBJ = modules/vfs_afsacl.o
-VFS_XATTR_TDB_OBJ = modules/vfs_xattr_tdb.o librpc/gen_ndr/ndr_xattr.o
+VFS_XATTR_TDB_OBJ = modules/vfs_xattr_tdb.o
VFS_POSIXACL_OBJ = modules/vfs_posixacl.o
VFS_AIXACL_OBJ = modules/vfs_aixacl.o modules/vfs_aixacl_util.o
VFS_AIXACL2_OBJ = modules/vfs_aixacl2.o modules/vfs_aixacl_util.o modules/nfs4_acls.o
@@ -524,6 +563,8 @@ VFS_HPUXACL_OBJ = modules/vfs_hpuxacl.o
VFS_IRIXACL_OBJ = modules/vfs_irixacl.o
VFS_TRU64ACL_OBJ = modules/vfs_tru64acl.o
VFS_CATIA_OBJ = modules/vfs_catia.o
+VFS_STREAMS_XATTR_OBJ = modules/vfs_streams_xattr.o
+VFS_STREAMS_DEPOT_OBJ = modules/vfs_streams_depot.o
VFS_CACHEPRIME_OBJ = modules/vfs_cacheprime.o
VFS_PREALLOC_OBJ = modules/vfs_prealloc.o
VFS_COMMIT_OBJ = modules/vfs_commit.o
@@ -716,29 +757,6 @@ CLIENT_OBJ = $(CLIENT_OBJ1) $(PARAM_OBJ) $(LIBSMB_OBJ) \
$(PASSDB_OBJ) @LIBWBCLIENT_STATIC@ $(SMBLDAP_OBJ) $(GROUPDB_OBJ) $(LDB_OBJ) \
$(DISPLAY_SEC_OBJ)
-UTIL_REG_OBJ = lib/util_reg.o
-UTIL_REG_API_OBJ = lib/util_reg_api.o
-UTIL_REG_SMBCONF_OBJ = lib/util_reg_smbconf.o
-
-# objects to be used when not all of the registry code should be
-# loaded but only the portion needed by reg_api, typically for
-# using smbconf (registry) - full access
-REG_API_OBJ = registry/reg_api.o \
- registry/reg_frontend_hilvl.o \
- registry/reg_smbconf.o \
- registry/reg_db.o \
- registry/reg_util.o \
- \
- registry/reg_cachehook.o \
- registry/reg_eventlog.o \
- registry/reg_perfcount.o \
- registry/reg_dynamic.o \
- \
- lib/util_nttoken.o \
- $(UTIL_REG_API_OBJ) \
- $(UTIL_REG_SMBCONF_OBJ)
-
-
LIBNETAPI_OBJ1 = lib/netapi/netapi.o \
lib/netapi/joindomain.o \
lib/netapi/serverinfo.o \
@@ -845,7 +863,7 @@ EVTLOGADM_OBJ = $(EVTLOGADM_OBJ0) $(PARAM_OBJ) $(LIB_NONSMBD_OBJ) $(REGOBJS_OBJ)
$(ERRORMAP_OBJ) $(RPC_PARSE_OBJ1) $(LIBSAMBA_OBJ) $(DOSERR_OBJ) \
$(SECRETS_OBJ) \
registry/reg_eventlog.o rpc_server/srv_eventlog_lib.o registry/reg_util.o \
- registry/reg_db.o
+ registry/reg_backend_db.o
SHARESEC_OBJ0 = utils/sharesec.o
SHARESEC_OBJ = $(SHARESEC_OBJ0) $(PARAM_OBJ) $(LIB_NONSMBD_OBJ) $(REGOBJS_OBJ) \
@@ -1745,6 +1763,14 @@ bin/catia.@SHLIBEXT@: $(BINARY_PREREQS) $(VFS_CATIA_OBJ)
@echo "Building plugin $@"
@$(SHLD_MODULE) $(VFS_CATIA_OBJ)
+bin/streams_xattr.@SHLIBEXT@: $(BINARY_PREREQS) $(VFS_STREAMS_XATTR_OBJ)
+ @echo "Building plugin $@"
+ @$(SHLD_MODULE) $(VFS_STREAMS_XATTR_OBJ)
+
+bin/streams_depot.@SHLIBEXT@: $(BINARY_PREREQS) $(VFS_STREAMS_DEPOT_OBJ)
+ @echo "Building plugin $@"
+ @$(SHLD_MODULE) $(VFS_STREAMS_DEPOT_OBJ)
+
bin/cacheprime.@SHLIBEXT@: $(BINARY_PREREQS) $(VFS_CACHEPRIME_OBJ)
@echo "Building plugin $@"
@$(SHLD_MODULE) $(VFS_CACHEPRIME_OBJ)
diff --git a/source3/client/client.c b/source3/client/client.c
index 267c13048e..28b4a2b24b 100644
--- a/source3/client/client.c
+++ b/source3/client/client.c
@@ -1528,6 +1528,92 @@ static int cmd_altname(void)
}
/****************************************************************************
+ Show all info we can get
+****************************************************************************/
+
+static int do_allinfo(const char *name)
+{
+ fstring altname;
+ struct timespec b_time, a_time, m_time, c_time;
+ SMB_OFF_T size;
+ uint16_t mode;
+ SMB_INO_T ino;
+ NTTIME tmp;
+ unsigned int num_streams;
+ struct stream_struct *streams;
+ unsigned int i;
+
+ if (!NT_STATUS_IS_OK(cli_qpathinfo_alt_name(cli, name, altname))) {
+ d_printf("%s getting alt name for %s\n",
+ cli_errstr(cli),name);
+ return false;
+ }
+ d_printf("altname: %s\n", altname);
+
+ if (!cli_qpathinfo2(cli, name, &b_time, &a_time, &m_time, &c_time,
+ &size, &mode, &ino)) {
+ d_printf("%s getting pathinfo for %s\n",
+ cli_errstr(cli),name);
+ return false;
+ }
+
+ unix_timespec_to_nt_time(&tmp, b_time);
+ d_printf("create_time: %s\n", nt_time_string(talloc_tos(), tmp));
+
+ unix_timespec_to_nt_time(&tmp, a_time);
+ d_printf("access_time: %s\n", nt_time_string(talloc_tos(), tmp));
+
+ unix_timespec_to_nt_time(&tmp, m_time);
+ d_printf("write_time: %s\n", nt_time_string(talloc_tos(), tmp));
+
+ unix_timespec_to_nt_time(&tmp, c_time);
+ d_printf("change_time: %s\n", nt_time_string(talloc_tos(), tmp));
+
+ if (!cli_qpathinfo_streams(cli, name, talloc_tos(), &num_streams,
+ &streams)) {
+ d_printf("%s getting streams for %s\n",
+ cli_errstr(cli),name);
+ return false;
+ }
+
+ for (i=0; i<num_streams; i++) {
+ d_printf("stream: [%s], %lld bytes\n", streams[i].name,
+ (unsigned long long)streams[i].size);
+ }
+
+ return 0;
+}
+
+/****************************************************************************
+ Show all info we can get
+****************************************************************************/
+
+static int cmd_allinfo(void)
+{
+ TALLOC_CTX *ctx = talloc_tos();
+ char *name;
+ char *buf;
+
+ name = talloc_strdup(ctx, client_get_cur_dir());
+ if (!name) {
+ return 1;
+ }
+
+ if (!next_token_talloc(ctx, &cmd_ptr, &buf, NULL)) {
+ d_printf("allinfo <file>\n");
+ return 1;
+ }
+ name = talloc_asprintf_append(name, buf);
+ if (!name) {
+ return 1;
+ }
+
+ do_allinfo(name);
+
+ return 0;
+}
+
+/****************************************************************************
Put a single file.
****************************************************************************/
@@ -3839,6 +3925,8 @@ static struct {
char compl_args[2]; /* Completion argument info */
} commands[] = {
{"?",cmd_help,"[command] give help on a command",{COMPL_NONE,COMPL_NONE}},
+ {"allinfo",cmd_allinfo,"<file> show all available info",
+ {COMPL_NONE,COMPL_NONE}},
{"altname",cmd_altname,"<file> show alt name",{COMPL_NONE,COMPL_NONE}},
{"archive",cmd_archive,"<level>\n0=ignore archive bit\n1=only get archive files\n2=only get archive files and reset archive bit\n3=get all files and reset archive bit",{COMPL_NONE,COMPL_NONE}},
{"blocksize",cmd_block,"blocksize <number> (default 20)",{COMPL_NONE,COMPL_NONE}},
diff --git a/source3/configure.in b/source3/configure.in
index f65eb3c204..fcbe56f268 100644
--- a/source3/configure.in
+++ b/source3/configure.in
@@ -707,7 +707,7 @@ dnl These have to be built static:
default_static_modules="pdb_smbpasswd pdb_tdbsam rpc_lsa rpc_samr rpc_winreg rpc_initshutdown rpc_lsa_ds rpc_wkssvc rpc_svcctl2 rpc_ntsvcs rpc_net rpc_netdfs rpc_srvsvc2 rpc_spoolss rpc_eventlog2 auth_sam auth_unix auth_winbind auth_server auth_domain auth_builtin vfs_default nss_info_template"
dnl These are preferably build shared, and static if dlopen() is not available
-default_shared_modules="vfs_recycle vfs_audit vfs_extd_audit vfs_full_audit vfs_netatalk vfs_fake_perms vfs_default_quota vfs_readonly vfs_cap vfs_expand_msdfs vfs_shadow_copy vfs_shadow_copy2 charset_CP850 charset_CP437 auth_script vfs_readahead vfs_syncops vfs_xattr_tdb"
+default_shared_modules="vfs_recycle vfs_audit vfs_extd_audit vfs_full_audit vfs_netatalk vfs_fake_perms vfs_default_quota vfs_readonly vfs_cap vfs_expand_msdfs vfs_shadow_copy vfs_shadow_copy2 charset_CP850 charset_CP437 auth_script vfs_readahead vfs_syncops vfs_xattr_tdb vfs_streams_xattr"
if test "x$developer" = xyes; then
default_static_modules="$default_static_modules rpc_rpcecho"
@@ -1864,7 +1864,7 @@ DSO_EXPORTS=""
*aix*) AC_DEFINE(AIX,1,[Whether the host os is aix])
BLDSHARED="true"
LDSHFLAGS="-Wl,-G,-bexpall,-bbigtoc"
- DYNEXP="-Wl,-brtl,-bexpall,-bbigtoc"
+ DYNEXP="-Wl,-brtl,-bexpfull,-bbigtoc"
PICFLAG="-O2"
# as AIX code is always position independent...
# .po will just create compile warnings, use po.o:
@@ -3051,15 +3051,6 @@ if test x"$samba_cv_HAVE_IFACE_IFREQ" = x"yes"; then
fi
fi
-dnl AIX 5.3.0.0
-AC_TRY_COMPILE([#include <sys/socket.h>],[
-struct sockaddr_storage s; s.__ss_family = 0],
-samba_cv_have_aix_sockaddr_storage=yes,samba_cv_have_aix_sockaddr_storage=no)
-
-if test x"$samba_cv_have_aix_sockaddr_storage" = x"yes"; then
- AC_DEFINE(HAVE_AIX_SOCKADDR_STORAGE, 1, [Whether struct sockaddr_storage has __sa_family])
-fi
-
if test $iface = no; then
AC_CACHE_CHECK([for iface AIX],samba_cv_HAVE_IFACE_AIX,[
SAVE_CPPFLAGS="$CPPFLAGS"
@@ -6506,6 +6497,8 @@ SMB_MODULE(vfs_irixacl, \$(VFS_IRIXACL_OBJ), "bin/irixacl.$SHLIBEXT", VFS)
SMB_MODULE(vfs_hpuxacl, \$(VFS_HPUXACL_OBJ), "bin/hpuxacl.$SHLIBEXT", VFS)
SMB_MODULE(vfs_tru64acl, \$(VFS_TRU64ACL_OBJ), "bin/tru64acl.$SHLIBEXT", VFS)
SMB_MODULE(vfs_catia, \$(VFS_CATIA_OBJ), "bin/catia.$SHLIBEXT", VFS)
+SMB_MODULE(vfs_streams_xattr, \$(VFS_STREAMS_XATTR_OBJ), "bin/streams_xattr.$SHLIBEXT", VFS)
+SMB_MODULE(vfs_streams_depot, \$(VFS_STREAMS_DEPOT_OBJ), "bin/streams_depot.$SHLIBEXT", VFS)
SMB_MODULE(vfs_cacheprime, \$(VFS_CACHEPRIME_OBJ), "bin/cacheprime.$SHLIBEXT", VFS)
SMB_MODULE(vfs_prealloc, \$(VFS_PREALLOC_OBJ), "bin/prealloc.$SHLIBEXT", VFS)
SMB_MODULE(vfs_commit, \$(VFS_COMMIT_OBJ), "bin/commit.$SHLIBEXT", VFS)
diff --git a/source3/include/includes.h b/source3/include/includes.h
index e9477d8ba1..c6d0885ad9 100644
--- a/source3/include/includes.h
+++ b/source3/include/includes.h
@@ -702,6 +702,7 @@ typedef char fstring[FSTRING_LEN];
#include "rpc_perfcount.h"
#include "rpc_perfcount_defs.h"
#include "librpc/gen_ndr/notify.h"
+#include "librpc/gen_ndr/xattr.h"
#include "nt_printing.h"
#include "idmap.h"
#include "client.h"
@@ -1107,6 +1108,14 @@ char *talloc_asprintf_strupper_m(TALLOC_CTX *t, const char *fmt, ...) PRINTF_ATT
#define VXFS_QUOTA
#endif
+#ifndef XATTR_CREATE
+#define XATTR_CREATE 0x1 /* set value, fail if attr already exists */
+#endif
+
+#ifndef XATTR_REPLACE
+#define XATTR_REPLACE 0x2 /* set value, fail if attr does not exist */
+#endif
+
#if defined(HAVE_KRB5)
krb5_error_code smb_krb5_parse_name(krb5_context context,
diff --git a/source3/include/reg_objects.h b/source3/include/reg_objects.h
index 23a14e6757..3df701f61c 100644
--- a/source3/include/reg_objects.h
+++ b/source3/include/reg_objects.h
@@ -94,11 +94,17 @@ typedef struct {
#define KEY_HKCU "HKCU"
#define KEY_HKDD "HKDD"
#define KEY_SERVICES "HKLM\\SYSTEM\\CurrentControlSet\\Services"
+#define KEY_EVENTLOG "HKLM\\SYSTEM\\CurrentControlSet\\Services\\Eventlog"
+#define KEY_SHARES "HKLM\\SYSTEM\\CurrentControlSet\\Services\\LanmanServer\\Shares"
+#define KEY_NETLOGON_PARAMS "HKLM\\SYSTEM\\CurrentControlSet\\Services\\Netlogon\\Parameters"
+#define KEY_TCPIP_PARAMS "HKLM\\SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters"
+#define KEY_PROD_OPTIONS "HKLM\\SYSTEM\\CurrentControlSet\\Control\\ProductOptions"
#define KEY_PRINTING "HKLM\\SYSTEM\\CurrentControlSet\\Control\\Print"
#define KEY_PRINTING_2K "HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Print\\Printers"
#define KEY_PRINTING_PORTS "HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Ports"
-#define KEY_EVENTLOG "HKLM\\SYSTEM\\CurrentControlSet\\Services\\Eventlog"
-#define KEY_SHARES "HKLM\\SYSTEM\\CurrentControlSet\\Services\\LanmanServer\\Shares"
+#define KEY_CURRENT_VERSION "HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"
+#define KEY_PERFLIB "HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Perflib"
+#define KEY_PERFLIB_009 "HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Perflib\\009"
#define KEY_SMBCONF "HKLM\\SOFTWARE\\Samba\\smbconf"
#define KEY_TREE_ROOT ""
diff --git a/source3/include/smb.h b/source3/include/smb.h
index d64b8ba80c..f3cf1db6f8 100644
--- a/source3/include/smb.h
+++ b/source3/include/smb.h
@@ -513,6 +513,8 @@ typedef struct files_struct {
FAKE_FILE_HANDLE *fake_file_handle;
struct notify_change_buf *notify;
+
+ struct files_struct *base_fsp; /* placeholder for delete on close */
} files_struct;
#include "ntquotas.h"
@@ -574,6 +576,16 @@ struct trans_state {
char *data;
};
+/*
+ * Info about an alternate data stream
+ */
+
+struct stream_struct {
+ SMB_OFF_T size;
+ SMB_OFF_T alloc_size;
+ char *name;
+};
+
/* Include VFS stuff */
#include "smb_acls.h"
@@ -1359,6 +1371,9 @@ struct bitmap {
#define NTCREATEX_OPTIONS_PRIVATE_DENY_DOS 0x01000000
#define NTCREATEX_OPTIONS_PRIVATE_DENY_FCB 0x02000000
+/* Private options for streams support */
+#define NTCREATEX_OPTIONS_PRIVATE_STREAM_DELETE 0x04000000
+
/* Responses when opening a file. */
#define FILE_WAS_SUPERSEDED 0
#define FILE_WAS_OPENED 1
@@ -1889,6 +1904,8 @@ struct ea_list {
#define SAMBA_POSIX_INHERITANCE_EA_NAME "user.SAMBA_PAI"
/* EA to use for DOS attributes */
#define SAMBA_XATTR_DOS_ATTRIB "user.DOSATTRIB"
+/* Prefix for DosStreams in the vfs_streams_xattr module */
+#define SAMBA_XATTR_DOSSTREAM_PREFIX "user.DosStream."
#define UUID_SIZE 16
@@ -1919,4 +1936,15 @@ enum usershare_err {
/* Different reasons for closing a file. */
enum file_close_type {NORMAL_CLOSE=0,SHUTDOWN_CLOSE,ERROR_CLOSE};
+/* Used in SMB_FS_OBJECTID_INFORMATION requests. Must be exactly 48 bytes. */
+#define SAMBA_EXTENDED_INFO_MAGIC 0x536d4261 /* "SmBa" */
+#define SAMBA_EXTENDED_INFO_VERSION_STRING_LENGTH 28
+struct smb_extended_info {
+ uint32 samba_magic; /* Always SAMBA_EXTRA_INFO_MAGIC */
+ uint32 samba_version; /* Major/Minor/Release/Revision */
+ uint32 samba_subversion; /* Prerelease/RC/Vendor patch */
+ NTTIME samba_gitcommitdate;
+ char samba_version_string[SAMBA_EXTENDED_INFO_VERSION_STRING_LENGTH];
+};
+
#endif /* _SMB_H */
diff --git a/source3/include/vfs.h b/source3/include/vfs.h
index d03cf3477d..ca176aabb2 100644
--- a/source3/include/vfs.h
+++ b/source3/include/vfs.h
@@ -103,7 +103,8 @@
/* Leave at 22 - not yet released. Remove parameter fd from write. - obnox */
/* Leave at 22 - not yet released. Remove parameter fromfd from sendfile. - obnox */
/* Leave at 22 - not yet released. Remove parameter fromfd from recvfile. - obnox */
-/* Leave at 22 - not yet released. Additional change: add operations for offline files and remote storage volume abstraction -- ab*/
+/* Leave at 22 - not yet released. Additional change: add operations for offline files -- ab */
+/* Leave at 22 - not yet released. Add the streaminfo call. -- jpeach, vl */
#define SMB_VFS_INTERFACE_VERSION 22
@@ -148,6 +149,7 @@ typedef enum _vfs_op_type {
SMB_VFS_OP_SET_QUOTA,
SMB_VFS_OP_GET_SHADOW_COPY_DATA,
SMB_VFS_OP_STATVFS,
+ SMB_VFS_OP_FS_CAPABILITIES,
/* Directory operations */
@@ -198,6 +200,7 @@ typedef enum _vfs_op_type {
SMB_VFS_OP_NOTIFY_WATCH,
SMB_VFS_OP_CHFLAGS,
SMB_VFS_OP_FILE_ID_CREATE,
+ SMB_VFS_OP_STREAMINFO,
/* NT ACL operations. */
@@ -282,6 +285,7 @@ struct vfs_ops {
int (*set_quota)(struct vfs_handle_struct *handle, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *qt);
int (*get_shadow_copy_data)(struct vfs_handle_struct *handle, struct files_struct *fsp, SHADOW_COPY_DATA *shadow_copy_data, bool labels);
int (*statvfs)(struct vfs_handle_struct *handle, const char *path, struct vfs_statvfs_struct *statbuf);
+ uint32_t (*fs_capabilities)(struct vfs_handle_struct *handle);
/* Directory operations */
@@ -339,6 +343,13 @@ struct vfs_ops {
int (*chflags)(struct vfs_handle_struct *handle, const char *path, unsigned int flags);
struct file_id (*file_id_create)(struct vfs_handle_struct *handle, SMB_DEV_T dev, SMB_INO_T inode);
+ NTSTATUS (*streaminfo)(struct vfs_handle_struct *handle,
+ struct files_struct *fsp,
+ const char *fname,
+ TALLOC_CTX *mem_ctx,
+ unsigned int *num_streams,
+ struct stream_struct **streams);
+
/* NT ACL operations. */
NTSTATUS (*fget_nt_acl)(struct vfs_handle_struct *handle,
@@ -426,6 +437,7 @@ struct vfs_ops {
struct vfs_handle_struct *set_quota;
struct vfs_handle_struct *get_shadow_copy_data;
struct vfs_handle_struct *statvfs;
+ struct vfs_handle_struct *fs_capabilities;
/* Directory operations */
@@ -476,6 +488,7 @@ struct vfs_ops {
struct vfs_handle_struct *notify_watch;
struct vfs_handle_struct *chflags;
struct vfs_handle_struct *file_id_create;
+ struct vfs_handle_struct *streaminfo;
/* NT ACL operations. */
diff --git a/source3/include/vfs_macros.h b/source3/include/vfs_macros.h
index dd30f977dc..1e64bd5ac3 100644
--- a/source3/include/vfs_macros.h
+++ b/source3/include/vfs_macros.h
@@ -34,6 +34,7 @@
#define SMB_VFS_SET_QUOTA(conn, qtype, id, qt) ((conn)->vfs.ops.set_quota((conn)->vfs.handles.set_quota, (qtype), (id), (qt)))
#define SMB_VFS_GET_SHADOW_COPY_DATA(fsp,shadow_copy_data,labels) ((fsp)->conn->vfs.ops.get_shadow_copy_data((fsp)->conn->vfs.handles.get_shadow_copy_data,(fsp),(shadow_copy_data),(labels)))
#define SMB_VFS_STATVFS(conn, path, statbuf) ((conn)->vfs.ops.statvfs((conn)->vfs.handles.statvfs, (path), (statbuf)))
+#define SMB_VFS_FS_CAPABILITIES(conn) ((conn)->vfs.ops.fs_capabilities((conn)->vfs.handles.fs_capabilities))
/* Directory operations */
#define SMB_VFS_OPENDIR(conn, fname, mask, attr) ((conn)->vfs.ops.opendir((conn)->vfs.handles.opendir, (fname), (mask), (attr)))
@@ -82,6 +83,7 @@
#define SMB_VFS_NOTIFY_WATCH(conn, ctx, e, callback, private_data, handle_p) ((conn)->vfs.ops.notify_watch((conn)->vfs.handles.notify_watch, (ctx), (e), (callback), (private_data), (handle_p)))
#define SMB_VFS_CHFLAGS(conn, path, flags) ((conn)->vfs.ops.chflags((conn)->vfs.handles.chflags, (path), (flags)))
#define SMB_VFS_FILE_ID_CREATE(conn, dev, inode) ((conn)->vfs.ops.file_id_create((conn)->vfs.handles.file_id_create, (dev), (inode)))
+#define SMB_VFS_STREAMINFO(conn, fsp, fname, mem_ctx, num_streams, streams) ((conn)->vfs.ops.streaminfo((conn)->vfs.handles.streaminfo, (fsp), (fname), (mem_ctx), (num_streams), (streams)))
/* NT ACL operations. */
#define SMB_VFS_FGET_NT_ACL(fsp, security_info, ppdesc) ((fsp)->conn->vfs.ops.fget_nt_acl((fsp)->conn->vfs.handles.fget_nt_acl, (fsp), (security_info), (ppdesc)))
@@ -158,6 +160,7 @@
#define SMB_VFS_OPAQUE_SET_QUOTA(conn, qtype, id, qt) ((conn)->vfs_opaque.ops.set_quota((conn)->vfs_opaque.handles.set_quota, (qtype), (id), (qt)))
#define SMB_VFS_OPAQUE_GET_SHADOW_COPY_DATA(fsp,shadow_copy_data,labels) ((fsp)->conn->vfs_opaque.ops.get_shadow_copy_data((fsp)->conn->vfs_opaque.handles.get_shadow_copy_data,(fsp),(shadow_copy_data),(labels)))
#define SMB_VFS_OPAQUE_STATVFS(conn, path, statbuf) ((conn)->vfs_opaque.ops.statvfs((conn)->vfs_opaque.handles.statvfs, (path), (statbuf)))
+#define SMB_VFS_OPAQUE_FS_CAPABILITIES(conn) ((conn)->vfs_opaque.ops.fs_capabilities((conn)->vfs_opaque.handles.fs_capabilities))
/* Directory operations */
#define SMB_VFS_OPAQUE_OPENDIR(conn, fname, mask, attr) ((conn)->vfs_opaque.ops.opendir((conn)->vfs_opaque.handles.opendir, (fname), (mask), (attr)))
@@ -206,6 +209,7 @@
#define SMB_VFS_OPAQUE_NOTIFY_WATCH(conn, ctx, e, callback, private_data, handle_p) ((conn)->vfs_opaque.ops.notify_watch((conn)->vfs_opaque.handles.notify_watch, (ctx), (e), (callback), (private_data), (handle_p)))
#define SMB_VFS_OPAQUE_CHFLAGS(conn, path, flags) ((conn)->vfs_opaque.ops.chflags((conn)->vfs_opaque.handles.chflags, (path), (flags)))
#define SMB_VFS_OPAQUE_FILE_ID_CREATE(conn, dev, inode) ((conn)->vfs.ops_opaque.file_id_create((conn)->vfs_opaque.handles.file_id_create, (dev), (inode)))
+#define SMB_VFS_OPAQUE_STREAMINFO(conn, fsp, fname, mem_ctx, num_streams, streams) ((conn)->vfs_opaque.ops.streaminfo((conn)->vfs_opaque.handles.streaminfo, (fsp), (fname), (mem_ctx), (num_streams), (streams)))
/* NT ACL operations. */
#define SMB_VFS_OPAQUE_FGET_NT_ACL(fsp, security_info, ppdesc) ((fsp)->conn->vfs_opaque.ops.fget_nt_acl((fsp)->conn->vfs_opaque.handles.fget_nt_acl, (fsp), (security_info), (ppdesc)))
@@ -282,6 +286,7 @@
#define SMB_VFS_NEXT_SET_QUOTA(handle, qtype, id, qt) ((handle)->vfs_next.ops.set_quota((handle)->vfs_next.handles.set_quota, (qtype), (id), (qt)))
#define SMB_VFS_NEXT_GET_SHADOW_COPY_DATA(handle, fsp, shadow_copy_data ,labels) ((handle)->vfs_next.ops.get_shadow_copy_data((handle)->vfs_next.handles.get_shadow_copy_data,(fsp),(shadow_copy_data),(labels)))
#define SMB_VFS_NEXT_STATVFS(handle, path, statbuf) ((handle)->vfs_next.ops.statvfs((handle)->vfs_next.handles.statvfs, (path), (statbuf)))
+#define SMB_VFS_NEXT_FS_CAPABILITIES(handle) ((handle)->vfs_next.ops.fs_capabilities((handle)->vfs_next.handles.fs_capabilities))
/* Directory operations */
#define SMB_VFS_NEXT_OPENDIR(handle, fname, mask, attr) ((handle)->vfs_next.ops.opendir((handle)->vfs_next.handles.opendir, (fname), (mask), (attr)))
@@ -331,6 +336,7 @@
#define SMB_VFS_NEXT_NOTIFY_WATCH(conn, ctx, e, callback, private_data, handle_p) ((conn)->vfs_next.ops.notify_watch((conn)->vfs_next.handles.notify_watch, (ctx), (e), (callback), (private_data), (handle_p)))
#define SMB_VFS_NEXT_CHFLAGS(handle, path, flags) ((handle)->vfs_next.ops.chflags((handle)->vfs_next.handles.chflags, (path), (flags)))
#define SMB_VFS_NEXT_FILE_ID_CREATE(handle, dev, inode) ((handle)->vfs_next.ops.file_id_create((handle)->vfs_next.handles.file_id_create, (dev), (inode)))
+#define SMB_VFS_NEXT_STREAMINFO(handle, fsp, fname, mem_ctx, num_streams, streams) ((handle)->vfs.ops.streaminfo((handle)->vfs.handles.streaminfo, (fsp), (fname), (mem_ctx), (num_streams), (streams)))
/* NT ACL operations. */
#define SMB_VFS_NEXT_FGET_NT_ACL(handle, fsp, security_info, ppdesc) ((handle)->vfs_next.ops.fget_nt_acl((handle)->vfs_next.handles.fget_nt_acl, (fsp), (security_info), (ppdesc)))
diff --git a/source3/lib/afs.c b/source3/lib/afs.c
index a7d6f6c9f7..9f5d81f442 100644
--- a/source3/lib/afs.c
+++ b/source3/lib/afs.c
@@ -42,20 +42,23 @@ static char *afs_encode_token(const char *cell, const DATA_BLOB ticket,
const struct ClearToken *ct)
{
char *base64_ticket;
- char *result;
+ char *result = NULL;
DATA_BLOB key = data_blob(ct->HandShakeKey, 8);
char *base64_key;
+ TALLOC_CTX *mem_ctx;
+
+ mem_ctx = talloc_stackframe();
+ if (mem_ctx == NULL)
+ goto done;
- base64_ticket = base64_encode_data_blob(ticket);
+ base64_ticket = base64_encode_data_blob(mem_ctx, ticket);
if (base64_ticket == NULL)
- return NULL;
+ goto done;
- base64_key = base64_encode_data_blob(key);
- if (base64_key == NULL) {
- TALLOC_FREE(base64_ticket);
- return NULL;
- }
+ base64_key = base64_encode_data_blob(mem_ctx, key);
+ if (base64_key == NULL)
+ goto done;
asprintf(&result, "%s\n%u\n%s\n%u\n%u\n%u\n%s\n", cell,
ct->AuthHandle, base64_key, ct->ViceId, ct->BeginTimestamp,
@@ -63,8 +66,8 @@ static char *afs_encode_token(const char *cell, const DATA_BLOB ticket,
DEBUG(10, ("Got ticket string:\n%s\n", result));
- TALLOC_FREE(base64_ticket);
- TALLOC_FREE(base64_key);
+done:
+ TALLOC_FREE(mem_ctx);
return result;
}
diff --git a/source3/lib/dbwrap_tdb.c b/source3/lib/dbwrap_tdb.c
index e87ceb428f..18f9495931 100644
--- a/source3/lib/dbwrap_tdb.c
+++ b/source3/lib/dbwrap_tdb.c
@@ -91,7 +91,6 @@ static struct db_record *db_tdb_fetch_locked(struct db_context *db,
struct db_tdb_ctx *ctx = talloc_get_type_abort(db->private_data,
struct db_tdb_ctx);
struct tdb_fetch_locked_state state;
- int res;
/* Do not accidently allocate/deallocate w/o need when debug level is lower than needed */
if(DEBUGLEVEL >= 10) {
@@ -110,8 +109,7 @@ static struct db_record *db_tdb_fetch_locked(struct db_context *db,
state.mem_ctx = mem_ctx;
state.result = NULL;
- res = tdb_parse_record(ctx->wtdb->tdb, key, db_tdb_fetchlock_parse,
- &state);
+ tdb_parse_record(ctx->wtdb->tdb, key, db_tdb_fetchlock_parse, &state);
if (state.result == NULL) {
db_tdb_fetchlock_parse(key, tdb_null, &state);
diff --git a/source3/lib/errmap_unix.c b/source3/lib/errmap_unix.c
index 885a1c55b2..8194cf80cc 100644
--- a/source3/lib/errmap_unix.c
+++ b/source3/lib/errmap_unix.c
@@ -92,6 +92,9 @@ const struct unix_error_map unix_dos_nt_errmap[] = {
#ifdef EWOULDBLOCK
{ EWOULDBLOCK, ERRDOS, 111, NT_STATUS_NETWORK_BUSY },
#endif
+#ifdef ENOATTR
+ { ENOATTR, ERRDOS, ERRbadfile, NT_STATUS_NOT_FOUND },
+#endif
{ 0, 0, 0, NT_STATUS_OK }
};
diff --git a/source3/lib/netapi/joindomain.c b/source3/lib/netapi/joindomain.c
index cbfc6c01e3..133aff3dd8 100644
--- a/source3/lib/netapi/joindomain.c
+++ b/source3/lib/netapi/joindomain.c
@@ -558,6 +558,7 @@ static WERROR NetGetJoinableOUsLocal(struct libnetapi_ctx *ctx,
uint32_t *ou_count,
const char ***ous)
{
+#ifdef WITH_ADS
NTSTATUS status;
ADS_STATUS ads_status;
ADS_STRUCT *ads = NULL;
@@ -608,6 +609,9 @@ static WERROR NetGetJoinableOUsLocal(struct libnetapi_ctx *ctx,
ads_destroy(&ads);
return WERR_OK;
+#else
+ return WERR_NOT_SUPPORTED;
+#endif
}
/****************************************************************
diff --git a/source3/lib/netapi/netapi.h b/source3/lib/netapi/netapi.h
index 67bb8a8fca..c2f1b488db 100644
--- a/source3/lib/netapi/netapi.h
+++ b/source3/lib/netapi/netapi.h
@@ -96,6 +96,17 @@ NET_API_STATUS NetGetJoinInformation(const char *server_name,
uint16_t *name_type);
/****************************************************************
+ NetGetJoinableOUs
+****************************************************************/
+
+NET_API_STATUS NetGetJoinableOUs(const char *server_name,
+ const char *domain,
+ const char *account,
+ const char *password,
+ uint32_t *ou_count,
+ const char ***ous);
+
+/****************************************************************
NetServerGetInfo
****************************************************************/
diff --git a/source3/lib/replace/libreplace.m4 b/source3/lib/replace/libreplace.m4
index 7a5283a4d6..f866b3648f 100644
--- a/source3/lib/replace/libreplace.m4
+++ b/source3/lib/replace/libreplace.m4
@@ -153,6 +153,26 @@ AC_HAVE_TYPE([struct sockaddr_in6], [
#include <netinet/in.h>
])
+if test x"$ac_cv_type_struct_sockaddr_storage" = x"yes"; then
+AC_CHECK_MEMBER(struct sockaddr_storage.ss_family,
+ AC_DEFINE(HAVE_SS_FAMILY, 1, [Defined if struct sockaddr_storage has ss_family field]),,
+ [
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+ ])
+
+if test x"$ac_cv_member_struct_sockaddr_storage_ss_family" != x"yes"; then
+AC_CHECK_MEMBER(struct sockaddr_storage.__ss_family,
+ AC_DEFINE(HAVE___SS_FAMILY, 1, [Defined if struct sockaddr_storage has __ss_family field]),,
+ [
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+ ])
+fi
+fi
+
AC_CHECK_FUNCS(seteuid setresuid setegid setresgid chroot bzero strerror)
AC_CHECK_FUNCS(vsyslog setlinebuf mktime ftruncate chsize rename)
AC_CHECK_FUNCS(waitpid strlcpy strlcat initgroups memmove strdup)
diff --git a/source3/lib/replace/libreplace_cc.m4 b/source3/lib/replace/libreplace_cc.m4
index a01bf1b290..bf5056838d 100644
--- a/source3/lib/replace/libreplace_cc.m4
+++ b/source3/lib/replace/libreplace_cc.m4
@@ -48,8 +48,7 @@ LIBREPLACE_C99_STRUCT_INIT([],[AC_MSG_WARN([c99 structure initializer are not su
AC_PROG_INSTALL
AC_ISC_POSIX
-AC_EXTENSION_FLAG(_XOPEN_SOURCE_EXTENDED)
-AC_EXTENSION_FLAG(_OSF_SOURCE)
+AC_N_DEFINE(_XOPEN_SOURCE_EXTENDED)
AC_SYS_LARGEFILE
@@ -77,6 +76,11 @@ case "$host_os" in
CFLAGS="$CFLAGS -D_LINUX_SOURCE_COMPAT -qmaxmem=32000"
fi
;;
+ *osf*)
+ # this brings in socklen_t
+ AC_N_DEFINE(_XOPEN_SOURCE,600)
+ AC_N_DEFINE(_OSF_SOURCE)
+ ;;
#
# VOS may need to have POSIX support and System V compatibility enabled.
#
diff --git a/source3/lib/replace/libreplace_ld.m4 b/source3/lib/replace/libreplace_ld.m4
index cb8e21434e..2aec698967 100644
--- a/source3/lib/replace/libreplace_ld.m4
+++ b/source3/lib/replace/libreplace_ld.m4
@@ -265,7 +265,7 @@ AC_DEFUN([AC_LIBREPLACE_LD_SHLIB_ALLOW_UNDEF_FLAG],
LD_SHLIB_ALLOW_UNDEF_FLAG="-Wl,--allow-shlib-undefined"
;;
*osf*)
- LD_SHLIB_ALLOW_UNDEF_FLAG="-expect_unresolved '*'"
+ LD_SHLIB_ALLOW_UNDEF_FLAG="-Wl,-expect_unresolved,\"*\""
;;
*darwin*)
LD_SHLIB_ALLOW_UNDEF_FLAG="-undefined dynamic_lookup"
diff --git a/source3/lib/replace/libreplace_macros.m4 b/source3/lib/replace/libreplace_macros.m4
index 92fecd3db8..1856eacf66 100644
--- a/source3/lib/replace/libreplace_macros.m4
+++ b/source3/lib/replace/libreplace_macros.m4
@@ -87,19 +87,6 @@ fi
rm -f conftest*
])])
-AC_DEFUN([AC_EXTENSION_FLAG],
-[
- cat >>confdefs.h <<\EOF
-#ifndef $1
-# define $1 1
-#endif
-EOF
-AH_VERBATIM([$1], [#ifndef $1
-# define $1 1
-#endif])
-])
-
-
dnl see if a declaration exists for a function or variable
dnl defines HAVE_function_DECL if it exists
dnl AC_HAVE_DECL(var, includes)
@@ -248,11 +235,18 @@ m4_define([AH_CHECK_FUNC_EXT],
dnl Define an AC_DEFINE with ifndef guard.
dnl AC_N_DEFINE(VARIABLE [, VALUE])
-define(AC_N_DEFINE,
-[cat >> confdefs.h <<\EOF
-[#ifndef] $1
-[#define] $1 ifelse($#, 2, [$2], $#, 3, [$2], 1)
-[#endif]
+AC_DEFUN([AC_N_DEFINE],
+[
+AH_VERBATIM([$1], [
+#ifndef $1
+# undef $1
+#endif
+])
+
+ cat >>confdefs.h <<\EOF
+#ifndef $1
+[#define] $1 m4_if($#, 1, 1, [$2])
+#endif
EOF
])
diff --git a/source3/lib/replace/system/config.m4 b/source3/lib/replace/system/config.m4
index 799187af7d..1c05733126 100644
--- a/source3/lib/replace/system/config.m4
+++ b/source3/lib/replace/system/config.m4
@@ -73,6 +73,18 @@ AC_VERIFY_C_PROTOTYPE([struct passwd *getpwent_r(struct passwd *src, char *buf,
#include <unistd.h>
#include <pwd.h>
])
+AC_VERIFY_C_PROTOTYPE([struct passwd *getpwent_r(struct passwd *src, char *buf, size_t buflen)],
+ [
+ #ifndef HAVE_GETPWENT_R_DECL
+ #error missing getpwent_r prototype
+ #endif
+ return NULL;
+ ],[
+ AC_DEFINE(SOLARIS_GETPWENT_R, 1, [getpwent_r irix (similar to solaris) function prototype])
+ ],[],[
+ #include <unistd.h>
+ #include <pwd.h>
+ ])
AC_CHECK_FUNCS(getgrnam_r getgrgid_r getgrent_r)
AC_HAVE_DECL(getgrent_r, [
#include <unistd.h>
@@ -91,6 +103,19 @@ AC_VERIFY_C_PROTOTYPE([struct group *getgrent_r(struct group *src, char *buf, in
#include <grp.h>
])
+AC_VERIFY_C_PROTOTYPE([struct group *getgrent_r(struct group *src, char *buf, size_t buflen)],
+ [
+ #ifndef HAVE_GETGRENT_R_DECL
+ #error missing getgrent_r prototype
+ #endif
+ return NULL;
+ ],[
+ AC_DEFINE(SOLARIS_GETGRENT_R, 1, [getgrent_r irix (similar to solaris) function prototype])
+ ],[],[
+ #include <unistd.h>
+ #include <grp.h>
+ ])
+
# locale
AC_CHECK_HEADERS(ctype.h locale.h)
diff --git a/source3/lib/replace/system/network.h b/source3/lib/replace/system/network.h
index b6ae3c7c6f..fe6e46817f 100644
--- a/source3/lib/replace/system/network.h
+++ b/source3/lib/replace/system/network.h
@@ -227,14 +227,19 @@ typedef unsigned short int sa_family_t;
#ifdef HAVE_STRUCT_SOCKADDR_IN6
#define sockaddr_storage sockaddr_in6
#define ss_family sin6_family
+#define HAVE_SS_FAMILY 1
#else
#define sockaddr_storage sockaddr_in
#define ss_family sin_family
+#define HAVE_SS_FAMILY 1
#endif
#endif
-#ifdef HAVE_AIX_SOCKADDR_STORAGE
+#ifndef HAVE_SS_FAMILY
+#ifdef HAVE___SS_FAMILY
#define ss_family __ss_family
+#define HAVE_SS_FAMILY 1
+#endif
#endif
#ifndef HAVE_STRUCT_ADDRINFO
diff --git a/source3/lib/replace/system/printing.h b/source3/lib/replace/system/printing.h
deleted file mode 100644
index 7eb02d004a..0000000000
--- a/source3/lib/replace/system/printing.h
+++ /dev/null
@@ -1,50 +0,0 @@
-#ifndef _system_printing_h
-#define _system_printing_h
-
-/*
- Unix SMB/CIFS implementation.
-
- printing system include wrappers
-
- Copyright (C) Andrew Tridgell 2004
-
- ** NOTE! The following LGPL license applies to the replace
- ** library. This does NOT imply that all of Samba is released
- ** under the LGPL
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 3 of the License, or (at your option) any later version.
-
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with this library; if not, see <http://www.gnu.org/licenses/>.
-
-*/
-
-#ifdef AIX
-#define DEFAULT_PRINTING PRINT_AIX
-#define PRINTCAP_NAME "/etc/qconfig"
-#endif
-
-#ifdef HPUX
-#define DEFAULT_PRINTING PRINT_HPUX
-#endif
-
-#ifdef QNX
-#define DEFAULT_PRINTING PRINT_QNX
-#endif
-
-#ifndef DEFAULT_PRINTING
-#define DEFAULT_PRINTING PRINT_BSD
-#endif
-#ifndef PRINTCAP_NAME
-#define PRINTCAP_NAME "/etc/printcap"
-#endif
-
-#endif
diff --git a/source3/lib/replace/test/testsuite.c b/source3/lib/replace/test/testsuite.c
index 269a2ff5d6..5b95ae395c 100644
--- a/source3/lib/replace/test/testsuite.c
+++ b/source3/lib/replace/test/testsuite.c
@@ -37,7 +37,6 @@
#include "system/locale.h"
#include "system/network.h"
#include "system/passwd.h"
-#include "system/printing.h"
#include "system/readline.h"
#include "system/select.h"
#include "system/shmem.h"
diff --git a/source3/lib/system.c b/source3/lib/system.c
index eb6dcae6fb..fa50955ef6 100644
--- a/source3/lib/system.c
+++ b/source3/lib/system.c
@@ -1917,11 +1917,6 @@ int sys_fremovexattr (int filedes, const char *name)
#endif
}
-#if !defined(HAVE_SETXATTR)
-#define XATTR_CREATE 0x1 /* set value, fail if attr already exists */
-#define XATTR_REPLACE 0x2 /* set value, fail if attr does not exist */
-#endif
-
int sys_setxattr (const char *path, const char *name, const void *value, size_t size, int flags)
{
#if defined(HAVE_SETXATTR)
diff --git a/source3/lib/util.c b/source3/lib/util.c
index bc3eaa8d5e..11f3660df8 100644
--- a/source3/lib/util.c
+++ b/source3/lib/util.c
@@ -3273,3 +3273,93 @@ void *talloc_zeronull(const void *context, size_t size, const char *name)
return talloc_named_const(context, size, name);
}
#endif
+
+/* Split a path name into filename and stream name components. Canonicalise
+ * such that an implicit $DATA token is always explicit.
+ *
+ * The "specification" of this function can be found in the
+ * run_local_stream_name() function in torture.c, I've tried those
+ * combinations against a W2k3 server.
+ */
+
+NTSTATUS split_ntfs_stream_name(TALLOC_CTX *mem_ctx, const char *fname,
+ char **pbase, char **pstream)
+{
+ char *base = NULL;
+ char *stream = NULL;
+ char *sname; /* stream name */
+ const char *stype; /* stream type */
+
+ DEBUG(10, ("split_ntfs_stream_name called for [%s]\n", fname));
+
+ sname = strchr_m(fname, ':');
+
+ if (lp_posix_pathnames() || (sname == NULL)) {
+ if (pbase != NULL) {
+ base = talloc_strdup(mem_ctx, fname);
+ NT_STATUS_HAVE_NO_MEMORY(base);
+ }
+ goto done;
+ }
+
+ if (pbase != NULL) {
+ base = talloc_strndup(mem_ctx, fname, PTR_DIFF(sname, fname));
+ NT_STATUS_HAVE_NO_MEMORY(base);
+ }
+
+ sname += 1;
+
+ stype = strchr_m(sname, ':');
+
+ if (stype == NULL) {
+ sname = talloc_strdup(mem_ctx, sname);
+ stype = "$DATA";
+ }
+ else {
+ if (StrCaseCmp(stype, ":$DATA") != 0) {
+ /*
+ * If there is an explicit stream type, so far we only
+ * allow $DATA. Is there anything else allowed? -- vl
+ */
+ DEBUG(10, ("[%s] is an invalid stream type\n", stype));
+ TALLOC_FREE(base);
+ return NT_STATUS_OBJECT_NAME_INVALID;
+ }
+ sname = talloc_strndup(mem_ctx, sname, PTR_DIFF(stype, sname));
+ stype += 1;
+ }
+
+ if (sname == NULL) {
+ TALLOC_FREE(base);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (sname[0] == '\0') {
+ /*
+ * no stream name, so no stream
+ */
+ goto done;
+ }
+
+ if (pstream != NULL) {
+ stream = talloc_asprintf(mem_ctx, "%s:%s", sname, stype);
+ if (stream == NULL) {
+ TALLOC_FREE(sname);
+ TALLOC_FREE(base);
+ return NT_STATUS_NO_MEMORY;
+ }
+ /*
+ * upper-case the type field
+ */
+ strupper_m(strchr_m(stream, ':')+1);
+ }
+
+ done:
+ if (pbase != NULL) {
+ *pbase = base;
+ }
+ if (pstream != NULL) {
+ *pstream = stream;
+ }
+ return NT_STATUS_OK;
+}
diff --git a/source3/lib/util_sock.c b/source3/lib/util_sock.c
index 10428113ae..a3975f6c1f 100644
--- a/source3/lib/util_sock.c
+++ b/source3/lib/util_sock.c
@@ -2080,14 +2080,15 @@ const char *get_mydnsfullname(void)
data_blob_string_const("get_mydnsfullname"),
data_blob_string_const(res->ai_canonname));
- freeaddrinfo(res);
-
if (!memcache_lookup(NULL, SINGLETON_CACHE,
data_blob_string_const("get_mydnsfullname"),
&tmp)) {
- return NULL;
+ tmp = data_blob_talloc(talloc_tos(), res->ai_canonname,
+ strlen(res->ai_canonname) + 1);
}
+ freeaddrinfo(res);
+
return (const char *)tmp.data;
}
diff --git a/source3/lib/util_str.c b/source3/lib/util_str.c
index 3e3268104c..bcb9197141 100644
--- a/source3/lib/util_str.c
+++ b/source3/lib/util_str.c
@@ -2415,13 +2415,13 @@ void base64_decode_inplace(char *s)
}
/**
- * Encode a base64 string into a malloc()ed string caller to free.
+ * Encode a base64 string into a talloc()ed string caller to free.
*
* From SQUID: adopted from http://ftp.sunet.se/pub2/gnu/vm/base64-encode.c
* with adjustments
**/
-char *base64_encode_data_blob(DATA_BLOB data)
+char *base64_encode_data_blob(TALLOC_CTX *mem_ctx, DATA_BLOB data)
{
int bits = 0;
int char_count = 0;
@@ -2434,7 +2434,7 @@ char *base64_encode_data_blob(DATA_BLOB data)
out_cnt = 0;
len = data.length;
output_len = data.length * 2;
- result = TALLOC_ARRAY(talloc_tos(), char, output_len); /* get us plenty of space */
+ result = TALLOC_ARRAY(mem_ctx, char, output_len); /* get us plenty of space */
SMB_ASSERT(result != NULL);
while (len-- && out_cnt < (data.length * 2) - 5) {
diff --git a/source3/lib/version.c b/source3/lib/version.c
index 204c2044a8..3cae02ad2e 100644
--- a/source3/lib/version.c
+++ b/source3/lib/version.c
@@ -51,6 +51,8 @@ const char *samba_version_string(void)
*/
assert(res != -1);
+ SAFE_FREE(samba_version);
+
samba_version = tmp_version;
#endif
diff --git a/source3/libnet/libnet_conf.c b/source3/libnet/libnet_conf.c
index d20e10b141..4d998acad8 100644
--- a/source3/libnet/libnet_conf.c
+++ b/source3/libnet/libnet_conf.c
@@ -48,6 +48,10 @@ static WERROR libnet_conf_add_string_to_array(TALLOC_CTX *mem_ctx,
}
new_array[count] = talloc_strdup(new_array, string);
+ if (new_array[count] == NULL) {
+ TALLOC_FREE(new_array);
+ return WERR_NOMEM;
+ }
*array = new_array;
@@ -134,6 +138,10 @@ static WERROR libnet_conf_reg_open_service_key(TALLOC_CTX *mem_ctx,
}
path = talloc_asprintf(mem_ctx, "%s\\%s", KEY_SMBCONF, servicename);
+ if (path == NULL) {
+ werr = WERR_NOMEM;
+ goto done;
+ }
werr = libnet_conf_reg_open_path(mem_ctx, ctx, path, desired_access,
key);
@@ -191,7 +199,7 @@ static WERROR libnet_conf_reg_create_service_key(TALLOC_CTX *mem_ctx,
/* create a new talloc ctx for creation. it will hold
* the intermediate parent key (SMBCONF) for creation
* and will be destroyed when leaving this function... */
- if (!(create_ctx = talloc_new(mem_ctx))) {
+ if (!(create_ctx = talloc_stackframe())) {
werr = WERR_NOMEM;
goto done;
}
@@ -316,8 +324,12 @@ static char *libnet_conf_format_registry_value(TALLOC_CTX *mem_ctx,
case REG_MULTI_SZ: {
uint32 j;
for (j = 0; j < value->v.multi_sz.num_strings; j++) {
- result = talloc_asprintf(mem_ctx, "\"%s\" ",
+ result = talloc_asprintf(mem_ctx, "%s \"%s\" ",
+ result,
value->v.multi_sz.strings[j]);
+ if (result == NULL) {
+ break;
+ }
}
break;
}
@@ -357,7 +369,7 @@ static WERROR libnet_conf_reg_get_values(TALLOC_CTX *mem_ctx,
goto done;
}
- tmp_ctx = talloc_new(mem_ctx);
+ tmp_ctx = talloc_stackframe();
if (tmp_ctx == NULL) {
werr = WERR_NOMEM;
goto done;
@@ -540,7 +552,7 @@ WERROR libnet_conf_get_config(TALLOC_CTX *mem_ctx,
goto done;
}
- tmp_ctx = talloc_new(mem_ctx);
+ tmp_ctx = talloc_stackframe();
if (tmp_ctx == NULL) {
werr = WERR_NOMEM;
goto done;
@@ -615,7 +627,7 @@ WERROR libnet_conf_get_share_names(TALLOC_CTX *mem_ctx,
goto done;
}
- tmp_ctx = talloc_new(mem_ctx);
+ tmp_ctx = talloc_stackframe();
if (tmp_ctx == NULL) {
werr = WERR_NOMEM;
goto done;
diff --git a/source3/libsmb/clirap.c b/source3/libsmb/clirap.c
index aab77a3d54..4c5e338606 100644
--- a/source3/libsmb/clirap.c
+++ b/source3/libsmb/clirap.c
@@ -806,6 +806,137 @@ bool cli_qpathinfo2(struct cli_state *cli, const char *fname,
}
/****************************************************************************
+ Get the stream info
+****************************************************************************/
+
+bool cli_qpathinfo_streams(struct cli_state *cli, const char *fname,
+ TALLOC_CTX *mem_ctx,
+ unsigned int *pnum_streams,
+ struct stream_struct **pstreams)
+{
+ unsigned int data_len = 0;
+ unsigned int param_len = 0;
+ uint16 setup = TRANSACT2_QPATHINFO;
+ char *param;
+ char *rparam=NULL, *rdata=NULL;
+ char *p;
+ unsigned int num_streams;
+ struct stream_struct *streams;
+ unsigned int ofs;
+ size_t namelen = 2*(strlen(fname)+1);
+
+ param = SMB_MALLOC_ARRAY(char, 6+namelen+2);
+ if (param == NULL) {
+ return false;
+ }
+ p = param;
+ memset(p, 0, 6);
+ SSVAL(p, 0, SMB_FILE_STREAM_INFORMATION);
+ p += 6;
+ p += clistr_push(cli, p, fname, namelen, STR_TERMINATE);
+
+ param_len = PTR_DIFF(p, param);
+
+ if (!cli_send_trans(cli, SMBtrans2,
+ NULL, /* name */
+ -1, 0, /* fid, flags */
+ &setup, 1, 0, /* setup, len, max */
+ param, param_len, 10, /* param, len, max */
+ NULL, data_len, cli->max_xmit /* data, len, max */
+ )) {
+ return false;
+ }
+
+ if (!cli_receive_trans(cli, SMBtrans2,
+ &rparam, &param_len,
+ &rdata, &data_len)) {
+ return false;
+ }
+
+ if (!rdata) {
+ SAFE_FREE(rparam);
+ return false;
+ }
+
+ num_streams = 0;
+ streams = NULL;
+ ofs = 0;
+
+ while ((data_len > ofs) && (data_len - ofs >= 24)) {
+ uint32_t nlen, len;
+ ssize_t size;
+ void *vstr;
+ struct stream_struct *tmp;
+ uint8_t *tmp_buf;
+
+ tmp = TALLOC_REALLOC_ARRAY(mem_ctx, streams,
+ struct stream_struct,
+ num_streams+1);
+
+ if (tmp == NULL) {
+ goto fail;
+ }
+ streams = tmp;
+
+ nlen = IVAL(rdata, ofs + 0x04);
+
+ streams[num_streams].size = IVAL_TO_SMB_OFF_T(
+ rdata, ofs + 0x08);
+ streams[num_streams].alloc_size = IVAL_TO_SMB_OFF_T(
+ rdata, ofs + 0x10);
+
+ if (nlen > data_len - (ofs + 24)) {
+ goto fail;
+ }
+
+ /*
+ * We need to null-terminate src, how do I do this with
+ * convert_string_talloc??
+ */
+
+ tmp_buf = TALLOC_ARRAY(streams, uint8_t, nlen+2);
+ if (tmp_buf == NULL) {
+ goto fail;
+ }
+
+ memcpy(tmp_buf, rdata+ofs+24, nlen);
+ tmp_buf[nlen] = 0;
+ tmp_buf[nlen+1] = 0;
+
+ size = convert_string_talloc(streams, CH_UTF16, CH_UNIX,
+ tmp_buf, nlen+2, &vstr,
+ false);
+ TALLOC_FREE(tmp_buf);
+
+ if (size == -1) {
+ goto fail;
+ }
+ streams[num_streams].name = (char *)vstr;
+ num_streams++;
+
+ len = IVAL(rdata, ofs);
+ if (len > data_len - ofs) {
+ goto fail;
+ }
+ if (len == 0) break;
+ ofs += len;
+ }
+
+ SAFE_FREE(rdata);
+ SAFE_FREE(rparam);
+
+ *pnum_streams = num_streams;
+ *pstreams = streams;
+ return true;
+
+ fail:
+ TALLOC_FREE(streams);
+ SAFE_FREE(rdata);
+ SAFE_FREE(rparam);
+ return false;
+}
+
+/****************************************************************************
Send a qfileinfo QUERY_FILE_NAME_INFO call.
****************************************************************************/
diff --git a/source3/libsmb/libsmbclient.c b/source3/libsmb/libsmbclient.c
index 2fd8294d04..fbcb7f64e2 100644
--- a/source3/libsmb/libsmbclient.c
+++ b/source3/libsmb/libsmbclient.c
@@ -5931,7 +5931,7 @@ smbc_setxattr_ctx(SMBCCTX *context,
} else {
ret = cacl_set(talloc_tos(), srv->cli,
ipc_srv->cli, &ipc_srv->pol, path,
- namevalue, SMBC_XATTR_MODE_CHOWN, 0);
+ namevalue, SMBC_XATTR_MODE_CHGRP, 0);
}
TALLOC_FREE(frame);
return ret;
diff --git a/source3/locking/brlock.c b/source3/locking/brlock.c
index 4191871bb1..341d00f3fe 100644
--- a/source3/locking/brlock.c
+++ b/source3/locking/brlock.c
@@ -1539,11 +1539,6 @@ int brl_forall(void (*fn)(struct file_id id, struct server_id pid,
static int byte_range_lock_destructor(struct byte_range_lock *br_lck)
{
- TDB_DATA key;
-
- key.dptr = (uint8 *)&br_lck->key;
- key.dsize = sizeof(struct file_id);
-
if (br_lck->read_only) {
SMB_ASSERT(!br_lck->modified);
}
diff --git a/source3/modules/vfs_default.c b/source3/modules/vfs_default.c
index 31234f23ec..9c5b644a50 100644
--- a/source3/modules/vfs_default.c
+++ b/source3/modules/vfs_default.c
@@ -90,6 +90,17 @@ static int vfswrap_statvfs(struct vfs_handle_struct *handle, const char *path,
return sys_statvfs(path, statbuf);
}
+static uint32_t vfswrap_fs_capabilities(struct vfs_handle_struct *handle)
+{
+#if defined(DARWINOS)
+ struct vfs_statvfs_struct statbuf;
+ ZERO_STRUCT(statbuf);
+ sys_statvfs(handle->conn->connectpath, &statbuf);
+ return statbuf.FsCapabilities;
+#endif
+ return FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES;
+}
+
/* Directory operations */
static SMB_STRUCT_DIR *vfswrap_opendir(vfs_handle_struct *handle, const char *fname, const char *mask, uint32 attr)
@@ -942,6 +953,63 @@ static struct file_id vfswrap_file_id_create(struct vfs_handle_struct *handle, S
return file_id_create_dev(dev, inode);
}
+static NTSTATUS vfswrap_streaminfo(vfs_handle_struct *handle,
+ struct files_struct *fsp,
+ const char *fname,
+ TALLOC_CTX *mem_ctx,
+ unsigned int *pnum_streams,
+ struct stream_struct **pstreams)
+{
+ SMB_STRUCT_STAT sbuf;
+ NTSTATUS status;
+ unsigned int num_streams = 0;
+ struct stream_struct *streams = NULL;
+ int ret;
+
+ if ((fsp != NULL) && (fsp->is_directory)) {
+ /*
+ * No default streams on directories
+ */
+ goto done;
+ }
+
+ if ((fsp != NULL) && (fsp->fh->fd != -1)) {
+ ret = SMB_VFS_FSTAT(fsp, &sbuf);
+ }
+ else {
+ ret = SMB_VFS_STAT(handle->conn, fname, &sbuf);
+ }
+
+ if (ret == -1) {
+ return map_nt_error_from_unix(errno);
+ }
+
+ if (S_ISDIR(sbuf.st_mode)) {
+ goto done;
+ }
+
+ streams = talloc(mem_ctx, struct stream_struct);
+
+ if (streams == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ streams->size = sbuf.st_size;
+ streams->alloc_size = get_allocation_size(handle->conn, fsp, &sbuf);
+
+ streams->name = talloc_strdup(streams, "::$DATA");
+ if (streams->name == NULL) {
+ TALLOC_FREE(streams);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ num_streams = 1;
+ done:
+ *pnum_streams = num_streams;
+ *pstreams = streams;
+ return NT_STATUS_OK;
+}
+
static NTSTATUS vfswrap_fget_nt_acl(vfs_handle_struct *handle,
files_struct *fsp,
uint32 security_info, SEC_DESC **ppdesc)
@@ -1273,6 +1341,8 @@ static vfs_op_tuple vfs_default_ops[] = {
SMB_VFS_LAYER_OPAQUE},
{SMB_VFS_OP(vfswrap_statvfs), SMB_VFS_OP_STATVFS,
SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_fs_capabilities), SMB_VFS_OP_FS_CAPABILITIES,
+ SMB_VFS_LAYER_OPAQUE},
/* Directory operations */
@@ -1367,6 +1437,8 @@ static vfs_op_tuple vfs_default_ops[] = {
SMB_VFS_LAYER_OPAQUE},
{SMB_VFS_OP(vfswrap_file_id_create), SMB_VFS_OP_FILE_ID_CREATE,
SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(vfswrap_streaminfo), SMB_VFS_OP_STREAMINFO,
+ SMB_VFS_LAYER_OPAQUE},
/* NT ACL operations. */
diff --git a/source3/modules/vfs_streams_depot.c b/source3/modules/vfs_streams_depot.c
new file mode 100644
index 0000000000..fa85ea4a57
--- /dev/null
+++ b/source3/modules/vfs_streams_depot.c
@@ -0,0 +1,641 @@
+/*
+ * Store streams in a separate subdirectory
+ *
+ * Copyright (C) Volker Lendecke, 2007
+ *
+ * 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_VFS
+
+/*
+ * Excerpt from a mail from tridge:
+ *
+ * Volker, what I'm thinking of is this:
+ * /mount-point/.streams/XX/YY/aaaa.bbbb/namedstream1
+ * /mount-point/.streams/XX/YY/aaaa.bbbb/namedstream2
+ *
+ * where XX/YY is a 2 level hash based on the fsid/inode. "aaaa.bbbb"
+ * is the fsid/inode. "namedstreamX" is a file named after the stream
+ * name.
+ */
+
+static uint32_t hash_fn(DATA_BLOB key)
+{
+ uint32_t value; /* Used to compute the hash value. */
+ uint32_t i; /* Used to cycle through random values. */
+
+ /* Set the initial value from the key size. */
+ for (value = 0x238F13AF * key.length, i=0; i < key.length; i++)
+ value = (value + (key.data[i] << (i*5 % 24)));
+
+ return (1103515243 * value + 12345);
+}
+
+/*
+ * With the hashing scheme based on the inode we need to protect against
+ * streams showing up on files with re-used inodes. This can happen if we
+ * create a stream directory from within Samba, and a local process or NFS
+ * client deletes the file without deleting the streams directory. When the
+ * inode is re-used and the stream directory is still around, the streams in
+ * there would be show up as belonging to the new file.
+ *
+ * There are several workarounds for this, probably the easiest one is on
+ * systems which have a true birthtime stat element: When the file has a later
+ * birthtime than the streams directory, then we have to recreate the
+ * directory.
+ *
+ * The other workaround is to somehow mark the file as generated by Samba with
+ * something that a NFS client would not do. The closest one is a special
+ * xattr value being set. On systems which do not support xattrs, it might be
+ * an option to put in a special ACL entry for a non-existing group.
+ */
+
+#define SAMBA_XATTR_MARKER "user.SAMBA_STREAMS"
+
+static bool file_is_valid(vfs_handle_struct *handle, const char *path)
+{
+ char buf;
+
+ DEBUG(10, ("file_is_valid (%s) called\n", path));
+
+ if (SMB_VFS_NEXT_GETXATTR(handle, path, SAMBA_XATTR_MARKER,
+ &buf, sizeof(buf)) != sizeof(buf)) {
+ DEBUG(10, ("GETXATTR failed: %s\n", strerror(errno)));
+ return false;
+ }
+
+ if (buf != '1') {
+ DEBUG(10, ("got wrong buffer content: '%c'\n", buf));
+ return false;
+ }
+
+ return true;
+}
+
+static bool mark_file_valid(vfs_handle_struct *handle, const char *path)
+{
+ char buf = '1';
+ int ret;
+
+ DEBUG(10, ("marking file %s as valid\n", path));
+
+ ret = SMB_VFS_NEXT_SETXATTR(handle, path, SAMBA_XATTR_MARKER,
+ &buf, sizeof(buf), 0);
+
+ if (ret == -1) {
+ DEBUG(10, ("SETXATTR failed: %s\n", strerror(errno)));
+ return false;
+ }
+
+ return true;
+}
+
+static char *stream_dir(vfs_handle_struct *handle, const char *base_path,
+ const SMB_STRUCT_STAT *base_sbuf, bool create_it)
+{
+ uint32_t hash;
+ char *result = NULL;
+ SMB_STRUCT_STAT sbuf;
+ uint8_t first, second;
+ char *tmp;
+ char *id_hex;
+ struct file_id id;
+ uint8 id_buf[16];
+
+ const char *rootdir = lp_parm_const_string(
+ SNUM(handle->conn), "streams", "directory",
+ handle->conn->connectpath);
+
+ if (base_sbuf == NULL) {
+ if (SMB_VFS_NEXT_STAT(handle, base_path, &sbuf) == -1) {
+ /*
+ * base file is not there
+ */
+ goto fail;
+ }
+ base_sbuf = &sbuf;
+ }
+
+ id = SMB_VFS_FILE_ID_CREATE(handle->conn, base_sbuf->st_dev,
+ base_sbuf->st_ino);
+
+ push_file_id_16((char *)id_buf, &id);
+
+ hash = hash_fn(data_blob_const(id_buf, sizeof(id_buf)));
+
+ first = hash & 0xff;
+ second = (hash >> 8) & 0xff;
+
+ id_hex = hex_encode(talloc_tos(), id_buf, sizeof(id_buf));
+
+ if (id_hex == NULL) {
+ errno = ENOMEM;
+ goto fail;
+ }
+
+ result = talloc_asprintf(talloc_tos(), "%s/%2.2X/%2.2X/%s", rootdir,
+ first, second, id_hex);
+
+ TALLOC_FREE(id_hex);
+
+ if (result == NULL) {
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ if (SMB_VFS_NEXT_STAT(handle, result, &sbuf) == 0) {
+ char *newname;
+
+ if (!S_ISDIR(sbuf.st_mode)) {
+ errno = EINVAL;
+ goto fail;
+ }
+
+ if (file_is_valid(handle, base_path)) {
+ return result;
+ }
+
+ /*
+ * Someone has recreated a file under an existing inode
+ * without deleting the streams directory. For now, just move
+ * it away.
+ */
+
+ again:
+ newname = talloc_asprintf(talloc_tos(), "lost-%lu", random());
+ if (newname == NULL) {
+ errno = ENOMEM;
+ goto fail;
+ }
+
+ if (SMB_VFS_NEXT_RENAME(handle, result, newname) == -1) {
+ if ((errno == EEXIST) || (errno == ENOTEMPTY)) {
+ TALLOC_FREE(newname);
+ goto again;
+ }
+ goto fail;
+ }
+
+ TALLOC_FREE(newname);
+ }
+
+ if (!create_it) {
+ errno = ENOENT;
+ goto fail;
+ }
+
+ if ((SMB_VFS_NEXT_MKDIR(handle, rootdir, 0755) != 0)
+ && (errno != EEXIST)) {
+ goto fail;
+ }
+
+ tmp = talloc_asprintf(result, "%s/%2.2X", rootdir, first);
+ if (tmp == NULL) {
+ errno = ENOMEM;
+ goto fail;
+ }
+
+ if ((SMB_VFS_NEXT_MKDIR(handle, tmp, 0755) != 0)
+ && (errno != EEXIST)) {
+ goto fail;
+ }
+
+ TALLOC_FREE(tmp);
+
+ tmp = talloc_asprintf(result, "%s/%2.2X/%2.2X", rootdir, first,
+ second);
+ if (tmp == NULL) {
+ errno = ENOMEM;
+ goto fail;
+ }
+
+ if ((SMB_VFS_NEXT_MKDIR(handle, tmp, 0755) != 0)
+ && (errno != EEXIST)) {
+ goto fail;
+ }
+
+ TALLOC_FREE(tmp);
+
+ if ((SMB_VFS_NEXT_MKDIR(handle, result, 0755) != 0)
+ && (errno != EEXIST)) {
+ goto fail;
+ }
+
+ if (!mark_file_valid(handle, base_path)) {
+ goto fail;
+ }
+
+ return result;
+
+ fail:
+ TALLOC_FREE(result);
+ return NULL;
+}
+
+static char *stream_name(vfs_handle_struct *handle, const char *fname,
+ bool create_dir)
+{
+ char *base = NULL;
+ char *sname = NULL;
+ char *id_hex = NULL;
+ char *dirname, *stream_fname;
+
+ if (!NT_STATUS_IS_OK(split_ntfs_stream_name(talloc_tos(), fname,
+ &base, &sname))) {
+ DEBUG(10, ("split_ntfs_stream_name failed\n"));
+ errno = ENOMEM;
+ goto fail;
+ }
+
+ dirname = stream_dir(handle, base, NULL, create_dir);
+
+ if (dirname == NULL) {
+ goto fail;
+ }
+
+ stream_fname = talloc_asprintf(talloc_tos(), "%s/:%s", dirname, sname);
+
+ if (stream_fname == NULL) {
+ errno = ENOMEM;
+ goto fail;
+ }
+
+ DEBUG(10, ("stream filename = %s\n", stream_fname));
+
+ TALLOC_FREE(base);
+ TALLOC_FREE(sname);
+ TALLOC_FREE(id_hex);
+
+ return stream_fname;
+
+ fail:
+ DEBUG(5, ("stream_name failed: %s\n", strerror(errno)));
+ TALLOC_FREE(base);
+ TALLOC_FREE(sname);
+ TALLOC_FREE(id_hex);
+ return NULL;
+}
+
+static NTSTATUS walk_streams(vfs_handle_struct *handle,
+ const char *fname,
+ const SMB_STRUCT_STAT *sbuf,
+ char **pdirname,
+ bool (*fn)(const char *dirname,
+ const char *dirent,
+ void *private_data),
+ void *private_data)
+{
+ char *dirname;
+ SMB_STRUCT_DIR *dirhandle = NULL;
+ char *dirent;
+
+ dirname = stream_dir(handle, fname, sbuf, false);
+
+ if (dirname == NULL) {
+ if (errno == ENOENT) {
+ /*
+ * no stream around
+ */
+ return NT_STATUS_OK;
+ }
+ return map_nt_error_from_unix(errno);
+ }
+
+ DEBUG(10, ("walk_streams: dirname=%s\n", dirname));
+
+ dirhandle = SMB_VFS_NEXT_OPENDIR(handle, dirname, NULL, 0);
+
+ if (dirhandle == NULL) {
+ TALLOC_FREE(dirname);
+ return map_nt_error_from_unix(errno);
+ }
+
+ while ((dirent = vfs_readdirname(handle->conn, dirhandle)) != NULL) {
+
+ if (ISDOT(dirent) || ISDOTDOT(dirent)) {
+ continue;
+ }
+
+ DEBUG(10, ("walk_streams: dirent=%s\n", dirent));
+
+ if (!fn(dirname, dirent, private_data)) {
+ break;
+ }
+ }
+
+ SMB_VFS_NEXT_CLOSEDIR(handle, dirhandle);
+
+ if (pdirname != NULL) {
+ *pdirname = dirname;
+ }
+ else {
+ TALLOC_FREE(dirname);
+ }
+
+ return NT_STATUS_OK;
+}
+
+static int streams_depot_stat(vfs_handle_struct *handle, const char *fname,
+ SMB_STRUCT_STAT *sbuf)
+{
+ char *stream_fname;
+ int ret = -1;
+
+ DEBUG(10, ("streams_depot_stat called for [%s]\n", fname));
+
+ if (!is_ntfs_stream_name(fname)) {
+ return SMB_VFS_NEXT_STAT(handle, fname, sbuf);
+ }
+
+ stream_fname = stream_name(handle, fname, false);
+ if (stream_fname == NULL) {
+ goto done;
+ }
+
+ ret = SMB_VFS_NEXT_STAT(handle, stream_fname, sbuf);
+
+ done:
+ TALLOC_FREE(stream_fname);
+ return ret;
+}
+
+static int streams_depot_lstat(vfs_handle_struct *handle, const char *fname,
+ SMB_STRUCT_STAT *sbuf)
+{
+ char *stream_fname;
+ int ret = -1;
+
+ if (!is_ntfs_stream_name(fname)) {
+ return SMB_VFS_NEXT_LSTAT(handle, fname, sbuf);
+ }
+
+ stream_fname = stream_name(handle, fname, false);
+ if (stream_fname == NULL) {
+ goto done;
+ }
+
+ ret = SMB_VFS_NEXT_LSTAT(handle, stream_fname, sbuf);
+
+ done:
+ TALLOC_FREE(stream_fname);
+ return ret;
+}
+
+static int streams_depot_open(vfs_handle_struct *handle, const char *fname,
+ files_struct *fsp, int flags, mode_t mode)
+{
+ TALLOC_CTX *frame;
+ char *base = NULL;
+ SMB_STRUCT_STAT base_sbuf;
+ char *stream_fname;
+ int ret = -1;
+
+ if (!is_ntfs_stream_name(fname)) {
+ return SMB_VFS_NEXT_OPEN(handle, fname, fsp, flags, mode);
+ }
+
+ frame = talloc_stackframe();
+
+ if (!NT_STATUS_IS_OK(split_ntfs_stream_name(talloc_tos(), fname,
+ &base, NULL))) {
+ errno = ENOMEM;
+ goto done;
+ }
+
+ ret = SMB_VFS_NEXT_STAT(handle, base, &base_sbuf);
+
+ if (ret == -1) {
+ goto done;
+ }
+
+ TALLOC_FREE(base);
+
+ stream_fname = stream_name(handle, fname, true);
+ if (stream_fname == NULL) {
+ goto done;
+ }
+
+ ret = SMB_VFS_NEXT_OPEN(handle, stream_fname, fsp, flags, mode);
+
+ done:
+ TALLOC_FREE(frame);
+ return ret;
+}
+
+static int streams_depot_unlink(vfs_handle_struct *handle, const char *fname)
+{
+ int ret = -1;
+ SMB_STRUCT_STAT sbuf;
+
+ DEBUG(10, ("streams_depot_unlink called for %s\n", fname));
+
+ if (is_ntfs_stream_name(fname)) {
+ char *stream_fname;
+
+ stream_fname = stream_name(handle, fname, false);
+ if (stream_fname == NULL) {
+ return -1;
+ }
+
+ ret = SMB_VFS_NEXT_UNLINK(handle, stream_fname);
+
+ TALLOC_FREE(stream_fname);
+ return ret;
+ }
+
+ /*
+ * We potentially need to delete the per-inode streams directory
+ */
+
+ if (SMB_VFS_NEXT_STAT(handle, fname, &sbuf) == -1) {
+ return -1;
+ }
+
+ if (sbuf.st_nlink == 1) {
+ char *dirname = stream_dir(handle, fname, &sbuf, false);
+
+ if (dirname != NULL) {
+ SMB_VFS_NEXT_RMDIR(handle, dirname);
+ }
+ TALLOC_FREE(dirname);
+ }
+
+ return SMB_VFS_NEXT_UNLINK(handle, fname);
+}
+
+static bool add_one_stream(TALLOC_CTX *mem_ctx, unsigned int *num_streams,
+ struct stream_struct **streams,
+ const char *name, SMB_OFF_T size,
+ SMB_OFF_T alloc_size)
+{
+ struct stream_struct *tmp;
+
+ tmp = TALLOC_REALLOC_ARRAY(mem_ctx, *streams, struct stream_struct,
+ (*num_streams)+1);
+ if (tmp == NULL) {
+ return false;
+ }
+
+ tmp[*num_streams].name = talloc_strdup(tmp, name);
+ if (tmp[*num_streams].name == NULL) {
+ return false;
+ }
+
+ tmp[*num_streams].size = size;
+ tmp[*num_streams].alloc_size = alloc_size;
+
+ *streams = tmp;
+ *num_streams += 1;
+ return true;
+}
+
+struct streaminfo_state {
+ TALLOC_CTX *mem_ctx;
+ vfs_handle_struct *handle;
+ unsigned int num_streams;
+ struct stream_struct *streams;
+ NTSTATUS status;
+};
+
+static bool collect_one_stream(const char *dirname,
+ const char *dirent,
+ void *private_data)
+{
+ struct streaminfo_state *state =
+ (struct streaminfo_state *)private_data;
+ char *full_sname;
+ SMB_STRUCT_STAT sbuf;
+
+ if (asprintf(&full_sname, "%s/%s", dirname, dirent) == -1) {
+ state->status = NT_STATUS_NO_MEMORY;
+ return false;
+ }
+ if (SMB_VFS_NEXT_STAT(state->handle, full_sname, &sbuf) == -1) {
+ DEBUG(10, ("Could not stat %s: %s\n", full_sname,
+ strerror(errno)));
+ SAFE_FREE(full_sname);
+ return true;
+ }
+
+ SAFE_FREE(full_sname);
+
+ if (!add_one_stream(state->mem_ctx,
+ &state->num_streams, &state->streams,
+ dirent, sbuf.st_size,
+ get_allocation_size(
+ state->handle->conn, NULL, &sbuf))) {
+ state->status = NT_STATUS_NO_MEMORY;
+ return false;
+ }
+
+ return true;
+}
+
+static NTSTATUS streams_depot_streaminfo(vfs_handle_struct *handle,
+ struct files_struct *fsp,
+ const char *fname,
+ TALLOC_CTX *mem_ctx,
+ unsigned int *pnum_streams,
+ struct stream_struct **pstreams)
+{
+ SMB_STRUCT_STAT sbuf;
+ int ret;
+ NTSTATUS status;
+ struct streaminfo_state state;
+
+ if ((fsp != NULL) && (fsp->fh->fd != -1)) {
+ if (is_ntfs_stream_name(fsp->fsp_name)) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ ret = SMB_VFS_NEXT_FSTAT(handle, fsp, &sbuf);
+ }
+ else {
+ if (is_ntfs_stream_name(fname)) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ ret = SMB_VFS_NEXT_STAT(handle, fname, &sbuf);
+ }
+
+ if (ret == -1) {
+ return map_nt_error_from_unix(errno);
+ }
+
+ state.streams = NULL;
+ state.num_streams = 0;
+
+ if (!S_ISDIR(sbuf.st_mode)) {
+ if (!add_one_stream(mem_ctx,
+ &state.num_streams, &state.streams,
+ "::$DATA", sbuf.st_size,
+ get_allocation_size(handle->conn, fsp,
+ &sbuf))) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ state.mem_ctx = mem_ctx;
+ state.handle = handle;
+ state.status = NT_STATUS_OK;
+
+ status = walk_streams(handle, fname, &sbuf, NULL, collect_one_stream,
+ &state);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(state.streams);
+ return status;
+ }
+
+ if (!NT_STATUS_IS_OK(state.status)) {
+ TALLOC_FREE(state.streams);
+ return state.status;
+ }
+
+ *pnum_streams = state.num_streams;
+ *pstreams = state.streams;
+ return NT_STATUS_OK;
+}
+
+static uint32_t streams_depot_fs_capabilities(struct vfs_handle_struct *handle)
+{
+ return SMB_VFS_NEXT_FS_CAPABILITIES(handle) | FILE_NAMED_STREAMS;
+}
+
+/* VFS operations structure */
+
+static vfs_op_tuple streams_depot_ops[] = {
+ {SMB_VFS_OP(streams_depot_fs_capabilities), SMB_VFS_OP_FS_CAPABILITIES,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(streams_depot_open), SMB_VFS_OP_OPEN,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(streams_depot_stat), SMB_VFS_OP_STAT,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(streams_depot_lstat), SMB_VFS_OP_LSTAT,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(streams_depot_unlink), SMB_VFS_OP_UNLINK,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(streams_depot_streaminfo), SMB_VFS_OP_STREAMINFO,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP, SMB_VFS_LAYER_NOOP}
+};
+
+NTSTATUS vfs_streams_depot_init(void);
+NTSTATUS vfs_streams_depot_init(void)
+{
+ return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "streams_depot",
+ streams_depot_ops);
+}
diff --git a/source3/modules/vfs_streams_xattr.c b/source3/modules/vfs_streams_xattr.c
new file mode 100644
index 0000000000..766e7d10ab
--- /dev/null
+++ b/source3/modules/vfs_streams_xattr.c
@@ -0,0 +1,685 @@
+/*
+ * Store streams in xattrs
+ *
+ * Copyright (C) Volker Lendecke, 2008
+ *
+ * Partly based on James Peach's Darwin module, which is
+ *
+ * Copyright (C) James Peach 2006-2007
+ *
+ * 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_VFS
+
+struct stream_io {
+ char *base;
+ char *xattr_name;
+};
+
+static SMB_INO_T stream_inode(const SMB_STRUCT_STAT *sbuf, const char *sname)
+{
+ struct MD5Context ctx;
+ unsigned char hash[16];
+ SMB_INO_T result;
+ char *upper_sname;
+
+ DEBUG(10, ("stream_inode called for %lu/%lu [%s]\n",
+ (unsigned long)sbuf->st_dev,
+ (unsigned long)sbuf->st_ino, sname));
+
+ upper_sname = talloc_strdup_upper(talloc_tos(), sname);
+ SMB_ASSERT(upper_sname != NULL);
+
+ MD5Init(&ctx);
+ MD5Update(&ctx, (unsigned char *)&(sbuf->st_dev),
+ sizeof(sbuf->st_dev));
+ MD5Update(&ctx, (unsigned char *)&(sbuf->st_ino),
+ sizeof(sbuf->st_ino));
+ MD5Update(&ctx, (unsigned char *)upper_sname,
+ talloc_get_size(upper_sname)-1);
+ MD5Final(hash, &ctx);
+
+ TALLOC_FREE(upper_sname);
+
+ /* Hopefully all the variation is in the lower 4 (or 8) bytes! */
+ memcpy(&result, hash, sizeof(result));
+
+ DEBUG(10, ("stream_inode returns %lu\n", (unsigned long)result));
+
+ return result;
+}
+
+static ssize_t get_xattr_size(connection_struct *conn, const char *fname,
+ const char *xattr_name)
+{
+ NTSTATUS status;
+ struct ea_struct ea;
+ ssize_t result;
+
+ status = get_ea_value(talloc_tos(), conn, NULL, fname,
+ xattr_name, &ea);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return -1;
+ }
+
+ result = ea.value.length-1;
+ TALLOC_FREE(ea.value.data);
+ return result;
+}
+
+
+static int streams_xattr_fstat(vfs_handle_struct *handle, files_struct *fsp,
+ SMB_STRUCT_STAT *sbuf)
+{
+ struct stream_io *io = (struct stream_io *)
+ VFS_FETCH_FSP_EXTENSION(handle, fsp);
+
+ DEBUG(10, ("streams_xattr_fstat called for %d\n", fsp->fh->fd));
+
+ if (io == NULL) {
+ return SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
+ }
+
+ if (SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf) == -1) {
+ return -1;
+ }
+
+ sbuf->st_size = get_xattr_size(handle->conn, io->base, io->xattr_name);
+ if (sbuf->st_size == -1) {
+ return -1;
+ }
+
+ DEBUG(10, ("sbuf->st_size = %d\n", (int)sbuf->st_size));
+
+ sbuf->st_ino = stream_inode(sbuf, io->xattr_name);
+ sbuf->st_mode &= ~S_IFMT;
+ sbuf->st_mode |= S_IFREG;
+ sbuf->st_blocks = sbuf->st_size % STAT_ST_BLOCKSIZE + 1;
+
+ return 0;
+}
+
+static int streams_xattr_stat(vfs_handle_struct *handle, const char *fname,
+ SMB_STRUCT_STAT *sbuf)
+{
+ NTSTATUS status;
+ char *base = NULL, *sname = NULL;
+ int result = -1;
+ char *xattr_name;
+
+ if (!is_ntfs_stream_name(fname)) {
+ return SMB_VFS_NEXT_STAT(handle, fname, sbuf);
+ }
+
+ status = split_ntfs_stream_name(talloc_tos(), fname, &base, &sname);
+ if (!NT_STATUS_IS_OK(status)) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (SMB_VFS_STAT(handle->conn, base, sbuf) == -1) {
+ goto fail;
+ }
+
+ xattr_name = talloc_asprintf(talloc_tos(), "%s%s",
+ SAMBA_XATTR_DOSSTREAM_PREFIX, sname);
+ if (xattr_name == NULL) {
+ errno = ENOMEM;
+ goto fail;
+ }
+
+ sbuf->st_size = get_xattr_size(handle->conn, base, xattr_name);
+ if (sbuf->st_size == -1) {
+ errno = ENOENT;
+ goto fail;
+ }
+
+ sbuf->st_ino = stream_inode(sbuf, xattr_name);
+ sbuf->st_mode &= ~S_IFMT;
+ sbuf->st_mode |= S_IFREG;
+ sbuf->st_blocks = sbuf->st_size % STAT_ST_BLOCKSIZE + 1;
+
+ result = 0;
+ fail:
+ TALLOC_FREE(base);
+ TALLOC_FREE(sname);
+ return result;
+}
+
+static int streams_xattr_lstat(vfs_handle_struct *handle, const char *fname,
+ SMB_STRUCT_STAT *sbuf)
+{
+ NTSTATUS status;
+ char *base, *sname;
+ int result = -1;
+ char *xattr_name;
+
+ if (!is_ntfs_stream_name(fname)) {
+ return SMB_VFS_NEXT_LSTAT(handle, fname, sbuf);
+ }
+
+ status = split_ntfs_stream_name(talloc_tos(), fname, &base, &sname);
+ if (!NT_STATUS_IS_OK(status)) {
+ errno = EINVAL;
+ goto fail;
+ }
+
+ if (SMB_VFS_LSTAT(handle->conn, base, sbuf) == -1) {
+ goto fail;
+ }
+
+ xattr_name = talloc_asprintf(talloc_tos(), "%s%s",
+ SAMBA_XATTR_DOSSTREAM_PREFIX, sname);
+ if (xattr_name == NULL) {
+ errno = ENOMEM;
+ goto fail;
+ }
+
+ sbuf->st_size = get_xattr_size(handle->conn, base, xattr_name);
+ if (sbuf->st_size == -1) {
+ errno = ENOENT;
+ goto fail;
+ }
+
+ sbuf->st_ino = stream_inode(sbuf, xattr_name);
+ sbuf->st_mode &= ~S_IFMT;
+ sbuf->st_mode |= S_IFREG;
+ sbuf->st_blocks = sbuf->st_size % STAT_ST_BLOCKSIZE + 1;
+
+ result = 0;
+ fail:
+ TALLOC_FREE(base);
+ TALLOC_FREE(sname);
+ return result;
+}
+
+static int streams_xattr_open(vfs_handle_struct *handle, const char *fname,
+ files_struct *fsp, int flags, mode_t mode)
+{
+ TALLOC_CTX *frame;
+ NTSTATUS status;
+ struct stream_io *sio;
+ char *base, *sname;
+ struct ea_struct ea;
+ char *xattr_name;
+ int baseflags;
+ int hostfd = -1;
+
+ DEBUG(10, ("streams_xattr_open called for %s\n", fname));
+
+ if (!is_ntfs_stream_name(fname)) {
+ return SMB_VFS_NEXT_OPEN(handle, fname, fsp, flags, mode);
+ }
+
+ frame = talloc_stackframe();
+
+ status = split_ntfs_stream_name(talloc_tos(), fname,
+ &base, &sname);
+ if (!NT_STATUS_IS_OK(status)) {
+ errno = EINVAL;
+ goto fail;
+ }
+
+ xattr_name = talloc_asprintf(talloc_tos(), "%s%s",
+ SAMBA_XATTR_DOSSTREAM_PREFIX, sname);
+ if (xattr_name == NULL) {
+ errno = ENOMEM;
+ goto fail;
+ }
+
+ /*
+ * We use baseflags to turn off nasty side-effects when opening the
+ * underlying file.
+ */
+ baseflags = flags;
+ baseflags &= ~O_TRUNC;
+ baseflags &= ~O_EXCL;
+ baseflags &= ~O_CREAT;
+
+ hostfd = SMB_VFS_OPEN(handle->conn, base, fsp, baseflags, mode);
+
+ /* It is legit to open a stream on a directory, but the base
+ * fd has to be read-only.
+ */
+ if ((hostfd == -1) && (errno == EISDIR)) {
+ baseflags &= ~O_ACCMODE;
+ baseflags |= O_RDONLY;
+ hostfd = SMB_VFS_OPEN(handle->conn, fname, fsp, baseflags,
+ mode);
+ }
+
+ if (hostfd == -1) {
+ goto fail;
+ }
+
+ status = get_ea_value(talloc_tos(), handle->conn, NULL, base,
+ xattr_name, &ea);
+
+ DEBUG(10, ("get_ea_value returned %s\n", nt_errstr(status)));
+
+ if (!NT_STATUS_IS_OK(status)
+ && !NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
+ /*
+ * The base file is not there. This is an error even if we got
+ * O_CREAT, the higher levels should have created the base
+ * file for us.
+ */
+ DEBUG(10, ("streams_xattr_open: base file %s not around, "
+ "returning ENOENT\n", base));
+ errno = ENOENT;
+ goto fail;
+ }
+
+ if (!NT_STATUS_IS_OK(status)) {
+ /*
+ * The attribute does not exist
+ */
+
+ if (flags & O_CREAT) {
+ /*
+ * Darn, xattrs need at least 1 byte
+ */
+ char null = '\0';
+
+ DEBUG(10, ("creating attribute %s on file %s\n",
+ xattr_name, base));
+
+ if (SMB_VFS_SETXATTR(
+ handle->conn, base, xattr_name,
+ &null, sizeof(null),
+ flags & O_EXCL ? XATTR_CREATE : 0) == -1) {
+ goto fail;
+ }
+ }
+ }
+
+ if (flags & O_TRUNC) {
+ char null = '\0';
+ if (SMB_VFS_SETXATTR(
+ handle->conn, base, xattr_name,
+ &null, sizeof(null),
+ flags & O_EXCL ? XATTR_CREATE : 0) == -1) {
+ goto fail;
+ }
+ }
+
+ sio = (struct stream_io *)VFS_ADD_FSP_EXTENSION(handle, fsp,
+ struct stream_io);
+ if (sio == NULL) {
+ errno = ENOMEM;
+ goto fail;
+ }
+
+ sio->xattr_name = talloc_strdup(VFS_MEMCTX_FSP_EXTENSION(handle, fsp),
+ xattr_name);
+ sio->base = talloc_strdup(VFS_MEMCTX_FSP_EXTENSION(handle, fsp),
+ base);
+
+ if ((sio->xattr_name == NULL) || (sio->base == NULL)) {
+ errno = ENOMEM;
+ goto fail;
+ }
+
+ TALLOC_FREE(frame);
+ return hostfd;
+
+ fail:
+ if (hostfd >= 0) {
+ /*
+ * BUGBUGBUG -- we would need to call fd_close_posix here, but
+ * we don't have a full fsp yet
+ */
+ SMB_VFS_CLOSE(fsp, hostfd);
+ }
+
+ TALLOC_FREE(frame);
+ return -1;
+}
+
+static int streams_xattr_unlink(vfs_handle_struct *handle, const char *fname)
+{
+ NTSTATUS status;
+ char *base = NULL;
+ char *sname = NULL;
+ int ret = -1;
+ char *xattr_name;
+
+ if (!is_ntfs_stream_name(fname)) {
+ return SMB_VFS_NEXT_UNLINK(handle, fname);
+ }
+
+ status = split_ntfs_stream_name(talloc_tos(), fname, &base, &sname);
+ if (!NT_STATUS_IS_OK(status)) {
+ errno = EINVAL;
+ goto fail;
+ }
+
+ xattr_name = talloc_asprintf(talloc_tos(), "%s%s",
+ SAMBA_XATTR_DOSSTREAM_PREFIX, sname);
+ if (xattr_name == NULL) {
+ errno = ENOMEM;
+ goto fail;
+ }
+
+ ret = SMB_VFS_REMOVEXATTR(handle->conn, base, xattr_name);
+
+ if ((ret == -1) && (errno == ENOATTR)) {
+ errno = ENOENT;
+ goto fail;
+ }
+
+ ret = 0;
+
+ fail:
+ TALLOC_FREE(base);
+ TALLOC_FREE(sname);
+ return ret;
+}
+
+static NTSTATUS walk_xattr_streams(connection_struct *conn, files_struct *fsp,
+ const char *fname,
+ bool (*fn)(struct ea_struct *ea,
+ void *private_data),
+ void *private_data)
+{
+ NTSTATUS status;
+ char **names;
+ size_t i, num_names;
+ size_t prefix_len = strlen(SAMBA_XATTR_DOSSTREAM_PREFIX);
+
+ status = get_ea_names_from_file(talloc_tos(), conn, fsp, fname,
+ &names, &num_names);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ for (i=0; i<num_names; i++) {
+ struct ea_struct ea;
+
+ if (strncmp(names[i], SAMBA_XATTR_DOSSTREAM_PREFIX,
+ prefix_len) != 0) {
+ continue;
+ }
+
+ status = get_ea_value(names, conn, fsp, fname, names[i], &ea);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("Could not get ea %s for file %s: %s\n",
+ names[i], fname, nt_errstr(status)));
+ continue;
+ }
+
+ ea.name = talloc_asprintf(ea.value.data, ":%s",
+ names[i] + prefix_len);
+ if (ea.name == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ continue;
+ }
+
+ if (!fn(&ea, private_data)) {
+ TALLOC_FREE(ea.value.data);
+ return NT_STATUS_OK;
+ }
+
+ TALLOC_FREE(ea.value.data);
+ }
+
+ TALLOC_FREE(names);
+ return NT_STATUS_OK;
+}
+
+static bool add_one_stream(TALLOC_CTX *mem_ctx, unsigned int *num_streams,
+ struct stream_struct **streams,
+ const char *name, SMB_OFF_T size,
+ SMB_OFF_T alloc_size)
+{
+ struct stream_struct *tmp;
+
+ tmp = TALLOC_REALLOC_ARRAY(mem_ctx, *streams, struct stream_struct,
+ (*num_streams)+1);
+ if (tmp == NULL) {
+ return false;
+ }
+
+ tmp[*num_streams].name = talloc_strdup(tmp, name);
+ if (tmp[*num_streams].name == NULL) {
+ return false;
+ }
+
+ tmp[*num_streams].size = size;
+ tmp[*num_streams].alloc_size = alloc_size;
+
+ *streams = tmp;
+ *num_streams += 1;
+ return true;
+}
+
+struct streaminfo_state {
+ TALLOC_CTX *mem_ctx;
+ vfs_handle_struct *handle;
+ unsigned int num_streams;
+ struct stream_struct *streams;
+ NTSTATUS status;
+};
+
+static bool collect_one_stream(struct ea_struct *ea, void *private_data)
+{
+ struct streaminfo_state *state =
+ (struct streaminfo_state *)private_data;
+
+ if (!add_one_stream(state->mem_ctx,
+ &state->num_streams, &state->streams,
+ ea->name, ea->value.length-1,
+ smb_roundup(state->handle->conn,
+ ea->value.length-1))) {
+ state->status = NT_STATUS_NO_MEMORY;
+ return false;
+ }
+
+ return true;
+}
+
+static NTSTATUS streams_xattr_streaminfo(vfs_handle_struct *handle,
+ struct files_struct *fsp,
+ const char *fname,
+ TALLOC_CTX *mem_ctx,
+ unsigned int *pnum_streams,
+ struct stream_struct **pstreams)
+{
+ SMB_STRUCT_STAT sbuf;
+ int ret;
+ NTSTATUS status;
+ struct streaminfo_state state;
+
+ if ((fsp != NULL) && (fsp->fh->fd != -1)) {
+ if (is_ntfs_stream_name(fsp->fsp_name)) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ ret = SMB_VFS_FSTAT(fsp, &sbuf);
+ }
+ else {
+ if (is_ntfs_stream_name(fname)) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ ret = SMB_VFS_STAT(handle->conn, fname, &sbuf);
+ }
+
+ if (ret == -1) {
+ return map_nt_error_from_unix(errno);
+ }
+
+ state.streams = NULL;
+ state.num_streams = 0;
+
+ if (!S_ISDIR(sbuf.st_mode)) {
+ if (!add_one_stream(mem_ctx,
+ &state.num_streams, &state.streams,
+ "::$DATA", sbuf.st_size,
+ get_allocation_size(handle->conn, fsp,
+ &sbuf))) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ }
+
+ state.mem_ctx = mem_ctx;
+ state.handle = handle;
+ state.status = NT_STATUS_OK;
+
+ status = walk_xattr_streams(handle->conn, fsp, fname,
+ collect_one_stream, &state);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(state.streams);
+ return status;
+ }
+
+ if (!NT_STATUS_IS_OK(state.status)) {
+ TALLOC_FREE(state.streams);
+ return state.status;
+ }
+
+ *pnum_streams = state.num_streams;
+ *pstreams = state.streams;
+ return NT_STATUS_OK;
+}
+
+static uint32_t streams_xattr_fs_capabilities(struct vfs_handle_struct *handle)
+{
+ return SMB_VFS_NEXT_FS_CAPABILITIES(handle) | FILE_NAMED_STREAMS;
+}
+
+static ssize_t streams_xattr_pwrite(vfs_handle_struct *handle,
+ files_struct *fsp, const void *data,
+ size_t n, SMB_OFF_T offset)
+{
+ struct stream_io *sio =
+ (struct stream_io *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
+ struct ea_struct ea;
+ NTSTATUS status;
+ int ret;
+
+ DEBUG(10, ("streams_xattr_pwrite called for %d bytes\n", (int)n));
+
+ if (sio == NULL) {
+ return SMB_VFS_NEXT_PWRITE(handle, fsp, data, n, offset);
+ }
+
+ status = get_ea_value(talloc_tos(), handle->conn, fsp->base_fsp,
+ sio->base, sio->xattr_name, &ea);
+ if (!NT_STATUS_IS_OK(status)) {
+ return -1;
+ }
+
+ if ((offset + n) > ea.value.length-1) {
+ uint8 *tmp;
+
+ tmp = TALLOC_REALLOC_ARRAY(talloc_tos(), ea.value.data, uint8,
+ offset + n + 1);
+
+ if (tmp == NULL) {
+ TALLOC_FREE(ea.value.data);
+ errno = ENOMEM;
+ return -1;
+ }
+ ea.value.data = tmp;
+ ea.value.length = offset + n + 1;
+ ea.value.data[offset+n] = 0;
+ }
+
+ memcpy(ea.value.data + offset, data, n);
+
+ ret = SMB_VFS_SETXATTR(fsp->conn, fsp->base_fsp->fsp_name,
+ sio->xattr_name,
+ ea.value.data, ea.value.length, 0);
+
+ TALLOC_FREE(ea.value.data);
+
+ if (ret == -1) {
+ return -1;
+ }
+
+ return n;
+}
+
+static ssize_t streams_xattr_pread(vfs_handle_struct *handle,
+ files_struct *fsp, void *data,
+ size_t n, SMB_OFF_T offset)
+{
+ struct stream_io *sio =
+ (struct stream_io *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
+ struct ea_struct ea;
+ NTSTATUS status;
+ size_t length, overlap;
+
+ if (sio == NULL) {
+ return SMB_VFS_NEXT_PREAD(handle, fsp, data, n, offset);
+ }
+
+ status = get_ea_value(talloc_tos(), handle->conn, fsp->base_fsp,
+ sio->base, sio->xattr_name, &ea);
+ if (!NT_STATUS_IS_OK(status)) {
+ return -1;
+ }
+
+ length = ea.value.length-1;
+
+ /* Attempt to read past EOF. */
+ if (length <= offset) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ overlap = (offset + n) > length ? (length - offset) : n;
+ memcpy(data, ea.value.data + offset, overlap);
+
+ TALLOC_FREE(ea.value.data);
+ return overlap;
+}
+
+/* VFS operations structure */
+
+static vfs_op_tuple streams_xattr_ops[] = {
+ {SMB_VFS_OP(streams_xattr_fs_capabilities), SMB_VFS_OP_FS_CAPABILITIES,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(streams_xattr_open), SMB_VFS_OP_OPEN,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(streams_xattr_stat), SMB_VFS_OP_STAT,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(streams_xattr_fstat), SMB_VFS_OP_FSTAT,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(streams_xattr_lstat), SMB_VFS_OP_LSTAT,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(streams_xattr_pread), SMB_VFS_OP_PREAD,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(streams_xattr_pwrite), SMB_VFS_OP_PWRITE,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(streams_xattr_lstat), SMB_VFS_OP_LSTAT,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(streams_xattr_unlink), SMB_VFS_OP_UNLINK,
+ SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(streams_xattr_streaminfo), SMB_VFS_OP_STREAMINFO,
+ SMB_VFS_LAYER_OPAQUE},
+ {SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP, SMB_VFS_LAYER_NOOP}
+};
+
+NTSTATUS vfs_streams_xattr_init(void);
+NTSTATUS vfs_streams_xattr_init(void)
+{
+ return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "streams_xattr",
+ streams_xattr_ops);
+}
diff --git a/source3/modules/vfs_xattr_tdb.c b/source3/modules/vfs_xattr_tdb.c
index 29864a8f94..208066bedc 100644
--- a/source3/modules/vfs_xattr_tdb.c
+++ b/source3/modules/vfs_xattr_tdb.c
@@ -110,7 +110,7 @@ static NTSTATUS xattr_tdb_load_attrs(TALLOC_CTX *mem_ctx,
status = xattr_tdb_pull_attrs(mem_ctx, &data, presult);
TALLOC_FREE(data.dptr);
- return NT_STATUS_OK;
+ return status;
}
/*
@@ -165,6 +165,9 @@ static ssize_t xattr_tdb_getattr(struct db_context *db_ctx,
ssize_t result = -1;
NTSTATUS status;
+ DEBUG(10, ("xattr_tdb_getattr called for file %s, name %s\n",
+ file_id_string_tos(id), name));
+
status = xattr_tdb_load_attrs(talloc_tos(), db_ctx, id, &attribs);
if (!NT_STATUS_IS_OK(status)) {
@@ -250,6 +253,9 @@ static int xattr_tdb_setattr(struct db_context *db_ctx,
struct tdb_xattrs *attribs;
uint32_t i;
+ DEBUG(10, ("xattr_tdb_setattr called for file %s, name %s\n",
+ file_id_string_tos(id), name));
+
rec = xattr_tdb_lock_attrs(talloc_tos(), db_ctx, id);
if (rec == NULL) {
@@ -269,6 +275,11 @@ static int xattr_tdb_setattr(struct db_context *db_ctx,
for (i=0; i<attribs->num_xattrs; i++) {
if (strcmp(attribs->xattrs[i].name, name) == 0) {
+ if (flags & XATTR_CREATE) {
+ TALLOC_FREE(rec);
+ errno = EEXIST;
+ return -1;
+ }
break;
}
}
@@ -276,6 +287,12 @@ static int xattr_tdb_setattr(struct db_context *db_ctx,
if (i == attribs->num_xattrs) {
struct tdb_xattr *tmp;
+ if (flags & XATTR_REPLACE) {
+ TALLOC_FREE(rec);
+ errno = ENOATTR;
+ return -1;
+ }
+
tmp = TALLOC_REALLOC_ARRAY(
attribs, attribs->xattrs, struct tdb_xattr,
attribs->num_xattrs + 1);
@@ -558,7 +575,8 @@ static bool xattr_tdb_init(int snum, struct db_context **p_db)
struct db_context *db;
const char *dbname;
- dbname = lp_parm_const_string(snum, "ea", "tdb", lock_path("eas.tdb"));
+ dbname = lp_parm_const_string(snum, "xattr", "tdb",
+ lock_path("xattr.tdb"));
if (dbname == NULL) {
errno = ENOTSUP;
@@ -660,7 +678,7 @@ static int xattr_tdb_rmdir(vfs_handle_struct *handle, const char *path)
* Destructor for the VFS private data
*/
-static void close_ea_db(void **data)
+static void close_xattr_db(void **data)
{
struct db_context **p_db = (struct db_context **)data;
TALLOC_FREE(*p_db);
@@ -688,14 +706,14 @@ static int xattr_tdb_connect(vfs_handle_struct *handle, const char *service,
}
if (!xattr_tdb_init(snum, &db)) {
- DEBUG(5, ("Could not init ea tdb\n"));
+ DEBUG(5, ("Could not init xattr tdb\n"));
lp_do_parameter(snum, "ea support", "False");
return 0;
}
lp_do_parameter(snum, "ea support", "True");
- SMB_VFS_HANDLE_SET_DATA(handle, db, close_ea_db,
+ SMB_VFS_HANDLE_SET_DATA(handle, db, close_xattr_db,
struct db_context, return -1);
return 0;
diff --git a/source3/nsswitch/libwbclient/wbclient.c b/source3/nsswitch/libwbclient/wbclient.c
index 321a7db669..42a9943523 100644
--- a/source3/nsswitch/libwbclient/wbclient.c
+++ b/source3/nsswitch/libwbclient/wbclient.c
@@ -72,10 +72,10 @@ wbcErr wbcRequestResponse(int cmd,
wbc_status = WBC_ERR_SUCCESS;
break;
case NSS_STATUS_UNAVAIL:
- return WBC_ERR_WINBIND_NOT_AVAILABLE;
+ wbc_status = WBC_ERR_WINBIND_NOT_AVAILABLE;
break;
case NSS_STATUS_NOTFOUND:
- return WBC_ERR_DOMAIN_NOT_FOUND;
+ wbc_status = WBC_ERR_DOMAIN_NOT_FOUND;
break;
default:
wbc_status = WBC_ERR_NSS_ERROR;
diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c
index 0d3fbbf77c..0796a78dd3 100644
--- a/source3/param/loadparm.c
+++ b/source3/param/loadparm.c
@@ -5725,6 +5725,7 @@ bool lp_load(const char *pszFname,
*/
config_backend = CONFIG_BACKEND_REGISTRY;
/* start over */
+ init_globals(false);
return lp_load(pszFname, global_only, save_defaults,
add_ipc, initialize_globals);
}
diff --git a/source3/registry/reg_api.c b/source3/registry/reg_api.c
index 18435ff033..9c4009368d 100644
--- a/source3/registry/reg_api.c
+++ b/source3/registry/reg_api.c
@@ -183,7 +183,7 @@ static WERROR regkey_open_onelevel(TALLOC_CTX *mem_ctx,
/* Look up the table of registry I/O operations */
if ( !(key->hook = reghook_cache_find( key->name )) ) {
- DEBUG(0,("reg_open_onelevel: Failed to assigned a "
+ DEBUG(0,("reg_open_onelevel: Failed to assign a "
"REGISTRY_HOOK to [%s]\n", key->name ));
result = WERR_BADFILE;
goto done;
@@ -453,7 +453,6 @@ WERROR reg_createkey(TALLOC_CTX *ctx, struct registry_key *parent,
TALLOC_CTX *mem_ctx;
char *path, *end;
WERROR err;
- REGSUBKEY_CTR *subkeys;
if (!(mem_ctx = talloc_new(ctx))) return WERR_NOMEM;
@@ -517,11 +516,6 @@ WERROR reg_createkey(TALLOC_CTX *ctx, struct registry_key *parent,
* Actually create the subkey
*/
- if (!(subkeys = TALLOC_ZERO_P(mem_ctx, REGSUBKEY_CTR))) {
- err = WERR_NOMEM;
- goto done;
- }
-
err = fill_subkey_cache(create_parent);
if (!W_ERROR_IS_OK(err)) goto done;
diff --git a/source3/registry/reg_backend_current_version.c b/source3/registry/reg_backend_current_version.c
new file mode 100644
index 0000000000..a9d281c522
--- /dev/null
+++ b/source3/registry/reg_backend_current_version.c
@@ -0,0 +1,81 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Virtual Windows Registry Layer
+ * Copyright (C) Gerald Carter 2002-2005
+ * Copyright (C) Michael Adam 2008
+ *
+ * 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * CurrentVersion registry backend.
+ *
+ * This is a virtual overlay, dynamically presenting version information.
+ */
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_REGISTRY
+
+extern REGISTRY_OPS regdb_ops;
+
+#define KEY_CURRENT_VERSION_NORM "HKLM/SOFTWARE/MICROSOFT/WINDOWS NT/CURRENTVERSION"
+
+static int current_version_fetch_values(const char *key, REGVAL_CTR *values)
+{
+ const char *sysroot_string = "c:\\Windows";
+ fstring sysversion;
+ fstring value;
+ uint32 value_length;
+ char *path = NULL;
+ TALLOC_CTX *ctx = talloc_tos();
+
+ path = talloc_strdup(ctx, key);
+ if (path == NULL) {
+ return -1;
+ }
+ path = normalize_reg_path(ctx, path);
+ if (path == NULL) {
+ return -1;
+ }
+
+ if (strncmp(path, KEY_CURRENT_VERSION_NORM, strlen(path)) != 0) {
+ return 0;
+ }
+
+ value_length = push_ucs2(value, value, sysroot_string, sizeof(value),
+ STR_TERMINATE|STR_NOALIGN );
+ regval_ctr_addvalue(values, "SystemRoot", REG_SZ, value, value_length);
+
+ fstr_sprintf(sysversion, "%d.%d", lp_major_announce_version(),
+ lp_minor_announce_version());
+ value_length = push_ucs2(value, value, sysversion, sizeof(value),
+ STR_TERMINATE|STR_NOALIGN);
+ regval_ctr_addvalue(values, "CurrentVersion", REG_SZ, value,
+ value_length);
+
+ return regval_ctr_numvals(values);
+}
+
+static int current_version_fetch_subkeys(const char *key,
+ REGSUBKEY_CTR *subkey_ctr)
+{
+ return regdb_ops.fetch_subkeys(key, subkey_ctr);
+}
+
+REGISTRY_OPS current_version_reg_ops = {
+ .fetch_values = current_version_fetch_values,
+ .fetch_subkeys = current_version_fetch_subkeys,
+};
diff --git a/source3/registry/reg_db.c b/source3/registry/reg_backend_db.c
index c4bfc2b6c9..e162fb587f 100644
--- a/source3/registry/reg_db.c
+++ b/source3/registry/reg_backend_db.c
@@ -44,17 +44,17 @@ static const char *builtin_registry_paths[] = {
KEY_SHARES,
KEY_EVENTLOG,
KEY_SMBCONF,
- "HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Perflib",
- "HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Perflib\\009",
+ KEY_PERFLIB,
+ KEY_PERFLIB_009,
"HKLM\\SYSTEM\\CurrentControlSet\\Control\\Print\\Monitors",
- "HKLM\\SYSTEM\\CurrentControlSet\\Control\\ProductOptions",
+ KEY_PROD_OPTIONS,
"HKLM\\SYSTEM\\CurrentControlSet\\Control\\Terminal Server\\DefaultUserConfiguration",
- "HKLM\\SYSTEM\\CurrentControlSet\\Services\\TcpIp\\Parameters",
- "HKLM\\SYSTEM\\CurrentControlSet\\Services\\Netlogon\\Parameters",
- "HKU",
- "HKCR",
- "HKPD",
- "HKPT",
+ KEY_TCPIP_PARAMS,
+ KEY_NETLOGON_PARAMS,
+ KEY_HKU,
+ KEY_HKCR,
+ KEY_HKPD,
+ KEY_HKPT,
NULL };
struct builtin_regkey_value {
diff --git a/source3/registry/reg_backend_hkpt_params.c b/source3/registry/reg_backend_hkpt_params.c
new file mode 100644
index 0000000000..2ed5e78e1c
--- /dev/null
+++ b/source3/registry/reg_backend_hkpt_params.c
@@ -0,0 +1,70 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Virtual Windows Registry Layer
+ * Copyright (C) Gerald Carter 2002-2005
+ * Copyright (C) Michael Adam 2008
+ *
+ * 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * HKPT parameters registry backend.
+ *
+ * This replaces the former dynamic hkpt parameters overlay.
+ */
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_REGISTRY
+
+extern REGISTRY_OPS regdb_ops;
+
+static int hkpt_params_fetch_values(const char *key, REGVAL_CTR *regvals)
+{
+ uint32 base_index;
+ uint32 buffer_size;
+ char *buffer = NULL;
+
+ /* This is ALMOST the same as perflib_009_params, but HKPT has
+ a "Counters" entry instead of a "Counter" key. <Grrrr> */
+
+ base_index = reg_perfcount_get_base_index();
+ buffer_size = reg_perfcount_get_counter_names(base_index, &buffer);
+ regval_ctr_addvalue(regvals, "Counters", REG_MULTI_SZ, buffer,
+ buffer_size);
+
+ if(buffer_size > 0) {
+ SAFE_FREE(buffer);
+ }
+
+ buffer_size = reg_perfcount_get_counter_help(base_index, &buffer);
+ regval_ctr_addvalue(regvals, "Help", REG_MULTI_SZ, buffer, buffer_size);
+ if(buffer_size > 0) {
+ SAFE_FREE(buffer);
+ }
+
+ return regval_ctr_numvals( regvals );
+}
+
+static int hkpt_params_fetch_subkeys(const char *key,
+ REGSUBKEY_CTR *subkey_ctr)
+{
+ return regdb_ops.fetch_subkeys(key, subkey_ctr);
+}
+
+REGISTRY_OPS hkpt_params_reg_ops = {
+ .fetch_values = hkpt_params_fetch_values,
+ .fetch_subkeys = hkpt_params_fetch_subkeys,
+};
diff --git a/source3/registry/reg_backend_netlogon_params.c b/source3/registry/reg_backend_netlogon_params.c
new file mode 100644
index 0000000000..71f88144c8
--- /dev/null
+++ b/source3/registry/reg_backend_netlogon_params.c
@@ -0,0 +1,57 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Virtual Windows Registry Layer
+ * Copyright (C) Gerald Carter 2002-2005
+ * Copyright (C) Michael Adam 2008
+ *
+ * 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Netlogon parameters registry backend.
+ *
+ * This replaces the former dynamic netlogon parameters overlay.
+ */
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_REGISTRY
+
+extern REGISTRY_OPS regdb_ops;
+
+static int netlogon_params_fetch_values(const char *key, REGVAL_CTR *regvals)
+{
+ uint32 dwValue;
+
+ if (!pdb_get_account_policy(AP_REFUSE_MACHINE_PW_CHANGE, &dwValue)) {
+ dwValue = 0;
+ }
+
+ regval_ctr_addvalue(regvals, "RefusePasswordChange", REG_DWORD,
+ (char*)&dwValue, sizeof(dwValue));
+
+ return regval_ctr_numvals(regvals);
+}
+
+static int netlogon_params_fetch_subkeys(const char *key,
+ REGSUBKEY_CTR *subkey_ctr)
+{
+ return regdb_ops.fetch_subkeys(key, subkey_ctr);
+}
+
+REGISTRY_OPS netlogon_params_reg_ops = {
+ .fetch_values = netlogon_params_fetch_values,
+ .fetch_subkeys = netlogon_params_fetch_subkeys,
+};
diff --git a/source3/registry/reg_backend_perflib.c b/source3/registry/reg_backend_perflib.c
new file mode 100644
index 0000000000..999bca2682
--- /dev/null
+++ b/source3/registry/reg_backend_perflib.c
@@ -0,0 +1,106 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Virtual Windows Registry Layer
+ * Copyright (C) Gerald Carter 2002-2005
+ * Copyright (C) Michael Adam 2008
+ *
+ * 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * perflib registry backend.
+ *
+ * This is a virtual overlay, dynamically presenting perflib values.
+ */
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_REGISTRY
+
+extern REGISTRY_OPS regdb_ops;
+
+#define KEY_PERFLIB_NORM "HKLM/SOFTWARE/MICROSOFT/WINDOWS NT/CURRENTVERSION/PERFLIB"
+#define KEY_PERFLIB_009_NORM "HKLM/SOFTWARE/MICROSOFT/WINDOWS NT/CURRENTVERSION/PERFLIB/009"
+
+static int perflib_params( REGVAL_CTR *regvals )
+{
+ int base_index = -1;
+ int last_counter = -1;
+ int last_help = -1;
+ int version = 0x00010001;
+
+ base_index = reg_perfcount_get_base_index();
+ regval_ctr_addvalue(regvals, "Base Index", REG_DWORD, (char *)&base_index, sizeof(base_index));
+ last_counter = reg_perfcount_get_last_counter(base_index);
+ regval_ctr_addvalue(regvals, "Last Counter", REG_DWORD, (char *)&last_counter, sizeof(last_counter));
+ last_help = reg_perfcount_get_last_help(last_counter);
+ regval_ctr_addvalue(regvals, "Last Help", REG_DWORD, (char *)&last_help, sizeof(last_help));
+ regval_ctr_addvalue(regvals, "Version", REG_DWORD, (char *)&version, sizeof(version));
+
+ return regval_ctr_numvals( regvals );
+}
+
+static int perflib_009_params( REGVAL_CTR *regvals )
+{
+ int base_index;
+ int buffer_size;
+ char *buffer = NULL;
+
+ base_index = reg_perfcount_get_base_index();
+ buffer_size = reg_perfcount_get_counter_names(base_index, &buffer);
+ regval_ctr_addvalue(regvals, "Counter", REG_MULTI_SZ, buffer, buffer_size);
+ if(buffer_size > 0)
+ SAFE_FREE(buffer);
+ buffer_size = reg_perfcount_get_counter_help(base_index, &buffer);
+ regval_ctr_addvalue(regvals, "Help", REG_MULTI_SZ, buffer, buffer_size);
+ if(buffer_size > 0)
+ SAFE_FREE(buffer);
+
+ return regval_ctr_numvals( regvals );
+}
+
+static int perflib_fetch_values(const char *key, REGVAL_CTR *regvals)
+{
+ char *path = NULL;
+ TALLOC_CTX *ctx = talloc_tos();
+
+ path = talloc_strdup(ctx, key);
+ if (path == NULL) {
+ return -1;
+ }
+ path = normalize_reg_path(ctx, path);
+ if (path == NULL) {
+ return -1;
+ }
+
+ if (strncmp(path, KEY_PERFLIB_NORM, strlen(path)) == 0) {
+ return perflib_params(regvals);
+ } else if (strncmp(path, KEY_PERFLIB_009_NORM, strlen(path)) == 0) {
+ return perflib_009_params(regvals);
+ } else {
+ return 0;
+ }
+}
+
+static int perflib_fetch_subkeys(const char *key,
+ REGSUBKEY_CTR *subkey_ctr)
+{
+ return regdb_ops.fetch_subkeys(key, subkey_ctr);
+}
+
+REGISTRY_OPS perflib_reg_ops = {
+ .fetch_values = perflib_fetch_values,
+ .fetch_subkeys = perflib_fetch_subkeys,
+};
diff --git a/source3/registry/reg_printing.c b/source3/registry/reg_backend_printing.c
index 5be0796002..a4da103d40 100644
--- a/source3/registry/reg_printing.c
+++ b/source3/registry/reg_backend_printing.c
@@ -1262,9 +1262,8 @@ static bool regprint_store_reg_values( const char *key, REGVAL_CTR *values )
*/
REGISTRY_OPS printing_ops = {
- regprint_fetch_reg_keys,
- regprint_fetch_reg_values,
- regprint_store_reg_keys,
- regprint_store_reg_values,
- NULL, NULL, NULL, NULL, NULL
+ .fetch_subkeys = regprint_fetch_reg_keys,
+ .fetch_values = regprint_fetch_reg_values,
+ .store_subkeys = regprint_store_reg_keys,
+ .store_values = regprint_store_reg_values,
};
diff --git a/source3/registry/reg_backend_prod_options.c b/source3/registry/reg_backend_prod_options.c
new file mode 100644
index 0000000000..7ac5c5b4b9
--- /dev/null
+++ b/source3/registry/reg_backend_prod_options.c
@@ -0,0 +1,70 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Virtual Windows Registry Layer
+ * Copyright (C) Gerald Carter 2002-2005
+ * Copyright (C) Michael Adam 2008
+ *
+ * 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * Product options registry backend.
+ *
+ * This replaces the former dynamic product options overlay.
+ */
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_REGISTRY
+
+extern REGISTRY_OPS regdb_ops;
+
+static int prod_options_fetch_values(const char *key, REGVAL_CTR *regvals)
+{
+ const char *value_ascii = "";
+ fstring value;
+ int value_length;
+
+ switch (lp_server_role()) {
+ case ROLE_DOMAIN_PDC:
+ case ROLE_DOMAIN_BDC:
+ value_ascii = "LanmanNT";
+ break;
+ case ROLE_STANDALONE:
+ value_ascii = "ServerNT";
+ break;
+ case ROLE_DOMAIN_MEMBER:
+ value_ascii = "WinNT";
+ break;
+ }
+
+ value_length = push_ucs2(value, value, value_ascii, sizeof(value),
+ STR_TERMINATE|STR_NOALIGN );
+ regval_ctr_addvalue(regvals, "ProductType", REG_SZ, value,
+ value_length);
+
+ return regval_ctr_numvals( regvals );
+}
+
+static int prod_options_fetch_subkeys(const char *key,
+ REGSUBKEY_CTR *subkey_ctr)
+{
+ return regdb_ops.fetch_subkeys(key, subkey_ctr);
+}
+
+REGISTRY_OPS prod_options_reg_ops = {
+ .fetch_values = prod_options_fetch_values,
+ .fetch_subkeys = prod_options_fetch_subkeys,
+};
diff --git a/source3/registry/reg_shares.c b/source3/registry/reg_backend_shares.c
index 4ac6e1d151..ee9e5dc5a1 100644
--- a/source3/registry/reg_shares.c
+++ b/source3/registry/reg_backend_shares.c
@@ -155,11 +155,10 @@ static bool shares_store_value( const char *key, REGVAL_CTR *val )
*/
REGISTRY_OPS shares_reg_ops = {
- shares_subkey_info,
- shares_value_info,
- shares_store_subkey,
- shares_store_value,
- NULL, NULL, NULL, NULL, NULL
+ .fetch_subkeys = shares_subkey_info,
+ .fetch_values = shares_value_info,
+ .store_subkeys = shares_store_subkey,
+ .store_values = shares_store_value,
};
diff --git a/source3/registry/reg_smbconf.c b/source3/registry/reg_backend_smbconf.c
index 8dfb745a7e..a6e478200f 100644
--- a/source3/registry/reg_smbconf.c
+++ b/source3/registry/reg_backend_smbconf.c
@@ -265,13 +265,11 @@ static WERROR smbconf_set_secdesc(const char *key,
*/
REGISTRY_OPS smbconf_reg_ops = {
- smbconf_fetch_keys,
- smbconf_fetch_values,
- smbconf_store_keys,
- smbconf_store_values,
- smbconf_reg_access_check,
- smbconf_get_secdesc,
- smbconf_set_secdesc,
- NULL,
- NULL
+ .fetch_subkeys = smbconf_fetch_keys,
+ .fetch_values = smbconf_fetch_values,
+ .store_subkeys = smbconf_store_keys,
+ .store_values = smbconf_store_values,
+ .reg_access_check = smbconf_reg_access_check,
+ .get_secdesc = smbconf_get_secdesc,
+ .set_secdesc = smbconf_set_secdesc,
};
diff --git a/source3/registry/reg_backend_tcpip_params.c b/source3/registry/reg_backend_tcpip_params.c
new file mode 100644
index 0000000000..db7df5dd8f
--- /dev/null
+++ b/source3/registry/reg_backend_tcpip_params.c
@@ -0,0 +1,67 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Virtual Windows Registry Layer
+ * Copyright (C) Gerald Carter 2002-2005
+ * Copyright (C) Michael Adam 2008
+ *
+ * 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * TCP/IP parameters registry backend.
+ *
+ * This replaces the former dynamic tcpip parameters overlay.
+ */
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_REGISTRY
+
+extern REGISTRY_OPS regdb_ops;
+
+static int tcpip_params_fetch_values(const char *key, REGVAL_CTR *regvals)
+{
+ fstring value;
+ int value_length;
+ char *hname;
+ char *mydomainname = NULL;
+
+ hname = myhostname();
+ value_length = push_ucs2(value, value, hname, sizeof(value),
+ STR_TERMINATE|STR_NOALIGN);
+ regval_ctr_addvalue(regvals, "Hostname",REG_SZ, value, value_length);
+
+ mydomainname = get_mydnsdomname(talloc_tos());
+ if (!mydomainname) {
+ return -1;
+ }
+
+ value_length = push_ucs2(value, value, mydomainname, sizeof(value),
+ STR_TERMINATE|STR_NOALIGN);
+ regval_ctr_addvalue(regvals, "Domain", REG_SZ, value, value_length);
+
+ return regval_ctr_numvals(regvals);
+}
+
+static int tcpip_params_fetch_subkeys(const char *key,
+ REGSUBKEY_CTR *subkey_ctr)
+{
+ return regdb_ops.fetch_subkeys(key, subkey_ctr);
+}
+
+REGISTRY_OPS tcpip_params_reg_ops = {
+ .fetch_values = tcpip_params_fetch_values,
+ .fetch_subkeys = tcpip_params_fetch_subkeys,
+};
diff --git a/source3/registry/reg_cachehook.c b/source3/registry/reg_cachehook.c
index 74670aac30..f9851c7810 100644
--- a/source3/registry/reg_cachehook.c
+++ b/source3/registry/reg_cachehook.c
@@ -37,6 +37,11 @@ bool reghook_cache_init( void )
{
if (cache_tree == NULL) {
cache_tree = pathtree_init(&default_hook, NULL);
+ if (cache_tree !=0) {
+ DEBUG(10, ("reghook_cache_init: new tree with default "
+ "ops %p for key [%s]\n", (void *)&regdb_ops,
+ KEY_TREE_ROOT));
+ }
}
return (cache_tree != NULL);
@@ -56,7 +61,7 @@ bool reghook_cache_add( REGISTRY_HOOK *hook )
return false;
}
- key = talloc_asprintf(ctx, "//%s", hook->keyname);
+ key = talloc_asprintf(ctx, "\\%s", hook->keyname);
if (!key) {
return false;
}
@@ -65,7 +70,8 @@ bool reghook_cache_add( REGISTRY_HOOK *hook )
return false;
}
- DEBUG(10,("reghook_cache_add: Adding key [%s]\n", key));
+ DEBUG(10, ("reghook_cache_add: Adding ops %p for key [%s]\n",
+ (void *)hook->ops, key));
return pathtree_add( cache_tree, key, hook );
}
@@ -102,6 +108,9 @@ REGISTRY_HOOK* reghook_cache_find( const char *keyname )
DEBUG(10,("reghook_cache_find: Searching for keyname [%s]\n", key));
hook = (REGISTRY_HOOK *)pathtree_find( cache_tree, key ) ;
+
+ DEBUG(10, ("reghook_cache_find: found ops %p for key [%s]\n",
+ hook ? (void *)hook->ops : 0, key));
SAFE_FREE( key );
diff --git a/source3/registry/reg_frontend_hilvl.c b/source3/registry/reg_dispatcher.c
index cd02eeef74..e6e7613457 100644
--- a/source3/registry/reg_frontend_hilvl.c
+++ b/source3/registry/reg_dispatcher.c
@@ -87,9 +87,6 @@ bool store_reg_keys( REGISTRY_KEY *key, REGSUBKEY_CTR *subkeys )
bool store_reg_values( REGISTRY_KEY *key, REGVAL_CTR *val )
{
- if ( check_dynamic_reg_values( key ) )
- return false;
-
if ( key->hook && key->hook->ops && key->hook->ops->store_values )
return key->hook->ops->store_values( key->name, val );
@@ -119,17 +116,12 @@ int fetch_reg_values( REGISTRY_KEY *key, REGVAL_CTR *val )
{
int result = -1;
+ DEBUG(10, ("fetch_reg_values called for key '%s' (ops %p)\n", key->name,
+ (key->hook && key->hook->ops) ? (void *)key->hook->ops : NULL));
+
if ( key->hook && key->hook->ops && key->hook->ops->fetch_values )
result = key->hook->ops->fetch_values( key->name, val );
- /* if the backend lookup returned no data, try the dynamic overlay */
-
- if ( result == 0 ) {
- result = fetch_dynamic_reg_values( key, val );
-
- return ( result != -1 ) ? result : 0;
- }
-
return result;
}
diff --git a/source3/registry/reg_dynamic.c b/source3/registry/reg_dynamic.c
deleted file mode 100644
index e70bd178f9..0000000000
--- a/source3/registry/reg_dynamic.c
+++ /dev/null
@@ -1,264 +0,0 @@
-/*
- * Unix SMB/CIFS implementation.
- * Virtual Windows Registry Layer
- * Copyright (C) Gerald Carter 2002-2005
- *
- * 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 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-/* Implementation of registry frontend view functions. */
-
-#include "includes.h"
-
-#undef DBGC_CLASS
-#define DBGC_CLASS DBGC_REGISTRY
-
-struct reg_dyn_values {
- const char *path;
- int (*fetch_values) ( REGVAL_CTR *val );
-};
-
-/***********************************************************************
-***********************************************************************/
-
-static int netlogon_params( REGVAL_CTR *regvals )
-{
- uint32 dwValue;
-
- if ( !pdb_get_account_policy(AP_REFUSE_MACHINE_PW_CHANGE, &dwValue) )
- dwValue = 0;
-
- regval_ctr_addvalue( regvals, "RefusePasswordChange", REG_DWORD,
- (char*)&dwValue, sizeof(dwValue) );
-
- return regval_ctr_numvals( regvals );
-}
-
-/***********************************************************************
-***********************************************************************/
-
-static int prod_options( REGVAL_CTR *regvals )
-{
- const char *value_ascii = "";
- fstring value;
- int value_length;
-
- switch (lp_server_role()) {
- case ROLE_DOMAIN_PDC:
- case ROLE_DOMAIN_BDC:
- value_ascii = "LanmanNT";
- break;
- case ROLE_STANDALONE:
- value_ascii = "ServerNT";
- break;
- case ROLE_DOMAIN_MEMBER:
- value_ascii = "WinNT";
- break;
- }
-
- value_length = push_ucs2( value, value, value_ascii, sizeof(value),
- STR_TERMINATE|STR_NOALIGN );
- regval_ctr_addvalue( regvals, "ProductType", REG_SZ, value,
- value_length );
-
- return regval_ctr_numvals( regvals );
-}
-
-/***********************************************************************
-***********************************************************************/
-
-static int tcpip_params( REGVAL_CTR *regvals )
-{
- fstring value;
- int value_length;
- char *hname;
- char *mydomainname = NULL;
-
- hname = myhostname();
- value_length = push_ucs2( value, value, hname, sizeof(value), STR_TERMINATE|STR_NOALIGN);
- regval_ctr_addvalue( regvals, "Hostname",REG_SZ, value, value_length );
-
- mydomainname = get_mydnsdomname(talloc_tos());
- if (!mydomainname) {
- return -1;
- }
-
- value_length = push_ucs2( value, value, mydomainname, sizeof(value), STR_TERMINATE|STR_NOALIGN);
- regval_ctr_addvalue( regvals, "Domain", REG_SZ, value, value_length );
-
- return regval_ctr_numvals( regvals );
-}
-
-/***********************************************************************
-***********************************************************************/
-
-static int perflib_params( REGVAL_CTR *regvals )
-{
- int base_index = -1;
- int last_counter = -1;
- int last_help = -1;
- int version = 0x00010001;
-
- base_index = reg_perfcount_get_base_index();
- regval_ctr_addvalue(regvals, "Base Index", REG_DWORD, (char *)&base_index, sizeof(base_index));
- last_counter = reg_perfcount_get_last_counter(base_index);
- regval_ctr_addvalue(regvals, "Last Counter", REG_DWORD, (char *)&last_counter, sizeof(last_counter));
- last_help = reg_perfcount_get_last_help(last_counter);
- regval_ctr_addvalue(regvals, "Last Help", REG_DWORD, (char *)&last_help, sizeof(last_help));
- regval_ctr_addvalue(regvals, "Version", REG_DWORD, (char *)&version, sizeof(version));
-
- return regval_ctr_numvals( regvals );
-}
-
-/***********************************************************************
-***********************************************************************/
-
-static int perflib_009_params( REGVAL_CTR *regvals )
-{
- int base_index;
- int buffer_size;
- char *buffer = NULL;
-
- base_index = reg_perfcount_get_base_index();
- buffer_size = reg_perfcount_get_counter_names(base_index, &buffer);
- regval_ctr_addvalue(regvals, "Counter", REG_MULTI_SZ, buffer, buffer_size);
- if(buffer_size > 0)
- SAFE_FREE(buffer);
- buffer_size = reg_perfcount_get_counter_help(base_index, &buffer);
- regval_ctr_addvalue(regvals, "Help", REG_MULTI_SZ, buffer, buffer_size);
- if(buffer_size > 0)
- SAFE_FREE(buffer);
-
- return regval_ctr_numvals( regvals );
-}
-
-/***********************************************************************
-***********************************************************************/
-
-static int hkpt_params( REGVAL_CTR *regvals )
-{
- uint32 base_index;
- uint32 buffer_size;
- char *buffer = NULL;
-
- /* This is ALMOST the same as perflib_009_params, but HKPT has
- a "Counters" entry instead of a "Counter" key. <Grrrr> */
-
- base_index = reg_perfcount_get_base_index();
- buffer_size = reg_perfcount_get_counter_names(base_index, &buffer);
- regval_ctr_addvalue(regvals, "Counters", REG_MULTI_SZ, buffer, buffer_size);
-
- if(buffer_size > 0)
- SAFE_FREE(buffer);
-
- buffer_size = reg_perfcount_get_counter_help(base_index, &buffer);
- regval_ctr_addvalue(regvals, "Help", REG_MULTI_SZ, buffer, buffer_size);
- if(buffer_size > 0)
- SAFE_FREE(buffer);
-
- return regval_ctr_numvals( regvals );
-}
-
-/***********************************************************************
-***********************************************************************/
-
-static int current_version( REGVAL_CTR *values )
-{
- const char *sysroot_string = "c:\\Windows";
- fstring sysversion;
- fstring value;
- uint32 value_length;
-
- value_length = push_ucs2( value, value, sysroot_string, sizeof(value),
- STR_TERMINATE|STR_NOALIGN );
- regval_ctr_addvalue( values, "SystemRoot", REG_SZ, value, value_length );
-
- fstr_sprintf( sysversion, "%d.%d", lp_major_announce_version(), lp_minor_announce_version() );
- value_length = push_ucs2( value, value, sysversion, sizeof(value),
- STR_TERMINATE|STR_NOALIGN );
- regval_ctr_addvalue( values, "CurrentVersion", REG_SZ, value, value_length );
-
-
- return regval_ctr_numvals( values );
-}
-
-
-/***********************************************************************
- Structure holding the registry paths and pointers to the value
- enumeration functions
-***********************************************************************/
-
-static struct reg_dyn_values dynamic_values[] = {
- { "HKLM/SYSTEM/CURRENTCONTROLSET/SERVICES/NETLOGON/PARAMETERS", &netlogon_params },
- { "HKLM/SYSTEM/CURRENTCONTROLSET/CONTROL/PRODUCTOPTIONS", &prod_options },
- { "HKLM/SYSTEM/CURRENTCONTROLSET/SERVICES/TCPIP/PARAMETERS", &tcpip_params },
- { "HKLM/SOFTWARE/MICROSOFT/WINDOWS NT/CURRENTVERSION/PERFLIB", &perflib_params },
- { "HKLM/SOFTWARE/MICROSOFT/WINDOWS NT/CURRENTVERSION/PERFLIB/009", &perflib_009_params },
- { "HKLM/SOFTWARE/MICROSOFT/WINDOWS NT/CURRENTVERSION", &current_version },
- { "HKPT", &hkpt_params },
- { NULL, NULL }
-};
-
-/***********************************************************************
-***********************************************************************/
-
-int fetch_dynamic_reg_values( REGISTRY_KEY *key, REGVAL_CTR *val )
-{
- int i;
- char *path = NULL;
- TALLOC_CTX *ctx = talloc_tos();
-
- path = talloc_strdup(ctx, key->name);
- if (!path) {
- return -1;
- }
- path = normalize_reg_path(ctx, path);
- if (!path) {
- return -1;
- }
-
- for ( i=0; dynamic_values[i].path; i++ ) {
- if ( strcmp( path, dynamic_values[i].path ) == 0 )
- return dynamic_values[i].fetch_values( val );
- }
-
- return -1;
-}
-
-/***********************************************************************
-***********************************************************************/
-
-bool check_dynamic_reg_values( REGISTRY_KEY *key )
-{
- int i;
- char *path = NULL;
- TALLOC_CTX *ctx = talloc_tos();
-
- path = talloc_strdup(ctx, key->name);
- if (!path) {
- return false;
- }
- path = normalize_reg_path(ctx, path);
- if (!path) {
- return false;
- }
-
- for ( i=0; dynamic_values[i].path; i++ ) {
- /* can't write to dynamic keys */
- if ( strcmp( path, dynamic_values[i].path ) == 0 )
- return true;
- }
-
- return false;
-}
diff --git a/source3/registry/reg_frontend.c b/source3/registry/reg_init_full.c
index 9e84d3a8c4..b6a644bb11 100644
--- a/source3/registry/reg_frontend.c
+++ b/source3/registry/reg_init_full.c
@@ -2,6 +2,7 @@
* Unix SMB/CIFS implementation.
* Virtual Windows Registry Layer
* Copyright (C) Gerald Carter 2002-2005
+ * Copyright (C) Michael Adam 2008
*
* 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
@@ -17,7 +18,7 @@
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
-/* Implementation of registry frontend view functions. */
+/* Initialize the registry with all available backends. */
#include "includes.h"
@@ -28,6 +29,12 @@ extern REGISTRY_OPS printing_ops;
extern REGISTRY_OPS eventlog_ops;
extern REGISTRY_OPS shares_reg_ops;
extern REGISTRY_OPS smbconf_reg_ops;
+extern REGISTRY_OPS netlogon_params_reg_ops;
+extern REGISTRY_OPS prod_options_reg_ops;
+extern REGISTRY_OPS tcpip_params_reg_ops;
+extern REGISTRY_OPS hkpt_params_reg_ops;
+extern REGISTRY_OPS current_version_reg_ops;
+extern REGISTRY_OPS perflib_reg_ops;
extern REGISTRY_OPS regdb_ops; /* these are the default */
/* array of REGISTRY_HOOK's which are read into a tree for easy access */
@@ -40,12 +47,19 @@ REGISTRY_HOOK reg_hooks[] = {
{ KEY_PRINTING_PORTS, &printing_ops },
{ KEY_SHARES, &shares_reg_ops },
{ KEY_SMBCONF, &smbconf_reg_ops },
+ { KEY_NETLOGON_PARAMS, &netlogon_params_reg_ops },
+ { KEY_PROD_OPTIONS, &prod_options_reg_ops },
+ { KEY_TCPIP_PARAMS, &tcpip_params_reg_ops },
+ { KEY_HKPT, &hkpt_params_reg_ops },
+ { KEY_CURRENT_VERSION, &current_version_reg_ops },
+ { KEY_PERFLIB, &perflib_reg_ops },
#endif
{ NULL, NULL }
};
/***********************************************************************
Open the registry database and initialize the REGISTRY_HOOK cache
+ with all available backens.
***********************************************************************/
bool init_registry( void )
@@ -87,21 +101,3 @@ bool init_registry( void )
TALLOC_FREE(frame);
return ret;
}
-
-WERROR regkey_open_internal( TALLOC_CTX *ctx, REGISTRY_KEY **regkey,
- const char *path,
- const struct nt_user_token *token,
- uint32 access_desired )
-{
- struct registry_key *key;
- WERROR err;
-
- err = reg_open_path(NULL, path, access_desired, token, &key);
- if (!W_ERROR_IS_OK(err)) {
- return err;
- }
-
- *regkey = talloc_move(ctx, &key->key);
- TALLOC_FREE(key);
- return WERR_OK;
-}
diff --git a/source3/lib/util_reg_smbconf.c b/source3/registry/reg_init_smbconf.c
index 6452b0b15b..6452b0b15b 100644
--- a/source3/lib/util_reg_smbconf.c
+++ b/source3/registry/reg_init_smbconf.c
diff --git a/source3/registry/reg_util_legacy.c b/source3/registry/reg_util_legacy.c
new file mode 100644
index 0000000000..3e68025ae9
--- /dev/null
+++ b/source3/registry/reg_util_legacy.c
@@ -0,0 +1,47 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * Virtual Windows Registry Layer
+ * Copyright (C) Gerald Carter 2002-2005
+ *
+ * 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Implementation of registry frontend view functions. */
+
+#include "includes.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_REGISTRY
+
+/**
+ * legacy open key function that should be replaced by uses of
+ * reg_open_path
+ */
+WERROR regkey_open_internal( TALLOC_CTX *ctx, REGISTRY_KEY **regkey,
+ const char *path,
+ const struct nt_user_token *token,
+ uint32 access_desired )
+{
+ struct registry_key *key;
+ WERROR err;
+
+ err = reg_open_path(NULL, path, access_desired, token, &key);
+ if (!W_ERROR_IS_OK(err)) {
+ return err;
+ }
+
+ *regkey = talloc_move(ctx, &key->key);
+ TALLOC_FREE(key);
+ return WERR_OK;
+}
diff --git a/source3/rpc_server/srv_samr_util.c b/source3/rpc_server/srv_samr_util.c
index bde7936343..c8f732153c 100644
--- a/source3/rpc_server/srv_samr_util.c
+++ b/source3/rpc_server/srv_samr_util.c
@@ -44,16 +44,16 @@ void copy_id20_to_sam_passwd(struct samu *to, SAM_USER_INFO_20 *from)
char *new_string;
DATA_BLOB mung;
- if (from == NULL || to == NULL)
+ if (from == NULL || to == NULL)
return;
-
+
if (from->hdr_munged_dial.buffer) {
old_string = pdb_get_munged_dial(to);
mung.length = from->hdr_munged_dial.uni_str_len;
mung.data = (uint8 *) from->uni_munged_dial.buffer;
mung.free = NULL;
new_string = (mung.length == 0) ?
- NULL : base64_encode_data_blob(mung);
+ NULL : base64_encode_data_blob(talloc_tos(), mung);
DEBUG(10,("INFO_20 UNI_MUNGED_DIAL: %s -> %s\n",old_string, new_string));
if (STRING_CHANGED_NC(old_string,new_string))
pdb_set_munged_dial(to , new_string, PDB_CHANGED);
@@ -196,7 +196,7 @@ void copy_id21_to_sam_passwd(struct samu *to, SAM_USER_INFO_21 *from)
mung.data = (uint8 *) from->uni_munged_dial.buffer;
mung.free = NULL;
newstr = (mung.length == 0) ?
- NULL : base64_encode_data_blob(mung);
+ NULL : base64_encode_data_blob(talloc_tos(), mung);
DEBUG(10,("INFO_21 UNI_MUNGED_DIAL: %s -> %s\n",old_string, newstr));
if (STRING_CHANGED_NC(old_string,newstr))
pdb_set_munged_dial(to , newstr, PDB_CHANGED);
@@ -421,7 +421,7 @@ void copy_id23_to_sam_passwd(struct samu *to, SAM_USER_INFO_23 *from)
mung.data = (uint8 *) from->uni_munged_dial.buffer;
mung.free = NULL;
newstr = (mung.length == 0) ?
- NULL : base64_encode_data_blob(mung);
+ NULL : base64_encode_data_blob(talloc_tos(), mung);
DEBUG(10,("INFO_23 UNI_MUNGED_DIAL: %s -> %s\n",old_string, newstr));
if (STRING_CHANGED_NC(old_string, newstr))
pdb_set_munged_dial(to , newstr, PDB_CHANGED);
@@ -633,7 +633,7 @@ void copy_id25_to_sam_passwd(struct samu *to, SAM_USER_INFO_25 *from)
mung.data = (uint8 *) from->uni_munged_dial.buffer;
mung.free = NULL;
newstr = (mung.length == 0) ?
- NULL : base64_encode_data_blob(mung);
+ NULL : base64_encode_data_blob(talloc_tos(), mung);
DEBUG(10,("INFO_25 UNI_MUNGED_DIAL: %s -> %s\n",old_string, newstr));
if (STRING_CHANGED_NC(old_string,newstr))
pdb_set_munged_dial(to , newstr, PDB_CHANGED);
diff --git a/source3/script/tests/selftest.sh b/source3/script/tests/selftest.sh
index 5a170b2117..c6232cf301 100755
--- a/source3/script/tests/selftest.sh
+++ b/source3/script/tests/selftest.sh
@@ -186,7 +186,7 @@ cat >$SERVERCONFFILE<<EOF
map hidden = yes
map system = yes
create mask = 755
- vfs objects = $BINDIR/xattr_tdb.so
+ vfs objects = $BINDIR/xattr_tdb.so $BINDIR/streams_xattr.so
[hideunread]
copy = tmp
hide unreadable = yes
diff --git a/source3/script/tests/test_posix_s3.sh b/source3/script/tests/test_posix_s3.sh
index 0b4a52d4b5..91863b7a6b 100755
--- a/source3/script/tests/test_posix_s3.sh
+++ b/source3/script/tests/test_posix_s3.sh
@@ -50,7 +50,7 @@ skipped="BASE-CHARSET BASE-DELAYWRITE BASE-TCONDEV"
skipped="$skipped RAW-ACLS RAW-COMPOSITE RAW-CONTEXT"
skipped="$skipped RAW-IOCTL"
skipped="$skipped RAW-QFILEINFO RAW-QFSINFO RAW-SEARCH"
-skipped="$skipped RAW-SFILEINFO RAW-STREAMS"
+skipped="$skipped RAW-SFILEINFO"
echo "WARNING: Skipping tests $skipped"
diff --git a/source3/services/services_db.c b/source3/services/services_db.c
index b1daae4df8..d4e144d5ff 100644
--- a/source3/services/services_db.c
+++ b/source3/services/services_db.c
@@ -526,7 +526,7 @@ SEC_DESC *svcctl_get_secdesc( TALLOC_CTX *ctx, const char *name, NT_USER_TOKEN *
SAFE_FREE(path);
if ( !(values = TALLOC_ZERO_P( key, REGVAL_CTR )) ) {
- DEBUG(0,("add_new_svc_name: talloc() failed!\n"));
+ DEBUG(0,("svcctl_get_secdesc: talloc() failed!\n"));
TALLOC_FREE( key );
return NULL;
}
@@ -582,7 +582,7 @@ bool svcctl_set_secdesc( TALLOC_CTX *ctx, const char *name, SEC_DESC *sec_desc,
SAFE_FREE(path);
if ( !(values = TALLOC_ZERO_P( key, REGVAL_CTR )) ) {
- DEBUG(0,("add_new_svc_name: talloc() failed!\n"));
+ DEBUG(0,("svcctl_set_secdesc: talloc() failed!\n"));
TALLOC_FREE( key );
return False;
}
diff --git a/source3/smbd/close.c b/source3/smbd/close.c
index 4c385d7611..4bd23a35fc 100644
--- a/source3/smbd/close.c
+++ b/source3/smbd/close.c
@@ -156,6 +156,75 @@ static void notify_deferred_opens(struct share_mode_lock *lck)
}
/****************************************************************************
+ Delete all streams
+****************************************************************************/
+
+static NTSTATUS delete_all_streams(connection_struct *conn, const char *fname)
+{
+ struct stream_struct *stream_info;
+ int i;
+ unsigned int num_streams;
+ TALLOC_CTX *frame = talloc_stackframe();
+ NTSTATUS status;
+
+ status = SMB_VFS_STREAMINFO(conn, NULL, fname, talloc_tos(),
+ &num_streams, &stream_info);
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)) {
+ DEBUG(10, ("no streams around\n"));
+ TALLOC_FREE(frame);
+ return NT_STATUS_OK;
+ }
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("SMB_VFS_STREAMINFO failed: %s\n",
+ nt_errstr(status)));
+ goto fail;
+ }
+
+ DEBUG(10, ("delete_all_streams found %d streams\n",
+ num_streams));
+
+ if (num_streams == 0) {
+ TALLOC_FREE(frame);
+ return NT_STATUS_OK;
+ }
+
+ for (i=0; i<num_streams; i++) {
+ int res;
+ char *streamname;
+
+ if (strequal(stream_info[i].name, "::$DATA")) {
+ continue;
+ }
+
+ streamname = talloc_asprintf(talloc_tos(), "%s%s", fname,
+ stream_info[i].name);
+
+ if (streamname == NULL) {
+ DEBUG(0, ("talloc_aprintf failed\n"));
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+
+ res = SMB_VFS_UNLINK(conn, streamname);
+
+ TALLOC_FREE(streamname);
+
+ if (res == -1) {
+ status = map_nt_error_from_unix(errno);
+ DEBUG(10, ("Could not delete stream %s: %s\n",
+ streamname, strerror(errno)));
+ break;
+ }
+ }
+
+ fail:
+ TALLOC_FREE(frame);
+ return status;
+}
+
+/****************************************************************************
Deal with removing a share mode on last close.
****************************************************************************/
@@ -305,6 +374,19 @@ static NTSTATUS close_remove_share_mode(files_struct *fsp,
goto done;
}
+ if ((conn->fs_capabilities & FILE_NAMED_STREAMS)
+ && !is_ntfs_stream_name(fsp->fsp_name)) {
+
+ status = delete_all_streams(conn, fsp->fsp_name);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(5, ("delete_all_streams failed: %s\n",
+ nt_errstr(status)));
+ goto done;
+ }
+ }
+
+
if (SMB_VFS_UNLINK(conn,fsp->fsp_name) != 0) {
/*
* This call can potentially fail as another smbd may
@@ -570,12 +652,37 @@ static NTSTATUS close_stat(files_struct *fsp)
NTSTATUS close_file(files_struct *fsp, enum file_close_type close_type)
{
+ NTSTATUS status;
+ struct files_struct *base_fsp = fsp->base_fsp;
+
if(fsp->is_directory) {
- return close_directory(fsp, close_type);
+ status = close_directory(fsp, close_type);
} else if (fsp->is_stat) {
- return close_stat(fsp);
+ status = close_stat(fsp);
} else if (fsp->fake_file_handle != NULL) {
- return close_fake_file(fsp);
+ status = close_fake_file(fsp);
+ } else {
+ status = close_normal_file(fsp, close_type);
+ }
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
}
- return close_normal_file(fsp, close_type);
+
+ if ((base_fsp != NULL) && (close_type != SHUTDOWN_CLOSE)) {
+
+ /*
+ * fsp was a stream, the base fsp can't be a stream as well
+ *
+ * For SHUTDOWN_CLOSE this is not possible here, because
+ * SHUTDOWN_CLOSE only happens from files.c which walks the
+ * complete list of files. If we mess with more than one fsp
+ * those loops will become confused.
+ */
+
+ SMB_ASSERT(base_fsp->base_fsp == NULL);
+ close_file(base_fsp, close_type);
+ }
+
+ return status;
}
diff --git a/source3/smbd/filename.c b/source3/smbd/filename.c
index be4960cab8..10e9583049 100644
--- a/source3/smbd/filename.c
+++ b/source3/smbd/filename.c
@@ -28,6 +28,13 @@
static bool scan_directory(connection_struct *conn, const char *path,
char *name, char **found_name);
+static NTSTATUS build_stream_path(TALLOC_CTX *mem_ctx,
+ connection_struct *conn,
+ const char *orig_path,
+ const char *basepath,
+ const char *streamname,
+ SMB_STRUCT_STAT *pst,
+ char **path);
/****************************************************************************
Mangle the 2nd name and check if it is then equal to the first name.
@@ -119,6 +126,7 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx,
char *start, *end;
char *dirpath = NULL;
char *name = NULL;
+ char *stream = NULL;
bool component_was_mangled = False;
bool name_has_wildcard = False;
NTSTATUS result;
@@ -206,6 +214,20 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx,
return NT_STATUS_NO_MEMORY;
}
+ if (!lp_posix_pathnames()) {
+ stream = strchr_m(name, ':');
+
+ if (stream != NULL) {
+ char *tmp = talloc_strdup(ctx, stream);
+ if (tmp == NULL) {
+ TALLOC_FREE(name);
+ return NT_STATUS_NO_MEMORY;
+ }
+ *stream = '\0';
+ stream = tmp;
+ }
+ }
+
/*
* Large directory fix normalization. If we're case sensitive, and
* the case preserving parameters are set to "no", normalize the case of
@@ -653,6 +675,20 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx,
DEBUG(5,("conversion finished %s -> %s\n",orig_path, name));
done:
+ if (stream != NULL) {
+ char *tmp = NULL;
+
+ result = build_stream_path(ctx, conn, orig_path, name, stream,
+ pst, &tmp);
+ if (!NT_STATUS_IS_OK(result)) {
+ goto fail;
+ }
+
+ DEBUG(10, ("build_stream_path returned %s\n", tmp));
+
+ TALLOC_FREE(name);
+ name = tmp;
+ }
*pp_conv_path = name;
TALLOC_FREE(dirpath);
return NT_STATUS_OK;
@@ -823,3 +859,90 @@ static bool scan_directory(connection_struct *conn, const char *path,
errno = ENOENT;
return False;
}
+
+static NTSTATUS build_stream_path(TALLOC_CTX *mem_ctx,
+ connection_struct *conn,
+ const char *orig_path,
+ const char *basepath,
+ const char *streamname,
+ SMB_STRUCT_STAT *pst,
+ char **path)
+{
+ SMB_STRUCT_STAT st;
+ char *result = NULL;
+ NTSTATUS status;
+ unsigned int i, num_streams;
+ struct stream_struct *streams = NULL;
+
+ result = talloc_asprintf(mem_ctx, "%s%s", basepath, streamname);
+ if (result == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ if (SMB_VFS_STAT(conn, result, &st) == 0) {
+ *pst = st;
+ *path = result;
+ return NT_STATUS_OK;
+ }
+
+ if (errno != ENOENT) {
+ status = map_nt_error_from_unix(errno);
+ DEBUG(10, ("vfs_stat failed: %s\n", nt_errstr(status)));
+ goto fail;
+ }
+
+ status = SMB_VFS_STREAMINFO(conn, NULL, basepath, mem_ctx,
+ &num_streams, &streams);
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
+ SET_STAT_INVALID(*pst);
+ *path = result;
+ return NT_STATUS_OK;
+ }
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("vfs_streaminfo failed: %s\n", nt_errstr(status)));
+ goto fail;
+ }
+
+ for (i=0; i<num_streams; i++) {
+ DEBUG(10, ("comparing [%s] and [%s]: ",
+ streamname, streams[i].name));
+ if (fname_equal(streamname, streams[i].name,
+ conn->case_sensitive)) {
+ DEBUGADD(10, ("equal\n"));
+ break;
+ }
+ DEBUGADD(10, ("not equal\n"));
+ }
+
+ if (i == num_streams) {
+ SET_STAT_INVALID(*pst);
+ *path = result;
+ TALLOC_FREE(streams);
+ return NT_STATUS_OK;
+ }
+
+ TALLOC_FREE(result);
+
+ result = talloc_asprintf(mem_ctx, "%s%s", basepath, streams[i].name);
+ if (result == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+
+ SET_STAT_INVALID(*pst);
+
+ if (SMB_VFS_STAT(conn, result, pst) == 0) {
+ stat_cache_add(orig_path, result, conn->case_sensitive);
+ }
+
+ *path = result;
+ TALLOC_FREE(streams);
+ return NT_STATUS_OK;
+
+ fail:
+ TALLOC_FREE(result);
+ TALLOC_FREE(streams);
+ return status;
+}
diff --git a/source3/smbd/nttrans.c b/source3/smbd/nttrans.c
index e8df732ea2..9381174af0 100644
--- a/source3/smbd/nttrans.c
+++ b/source3/smbd/nttrans.c
@@ -271,6 +271,9 @@ void send_nt_replies(connection_struct *conn,
/****************************************************************************
Is it an NTFS stream name ?
+ An NTFS file name is <path>.<extention>:<stream name>:<stream type>
+ $DATA can be used as both a stream name and a stream type. A missing stream
+ name or type implies $DATA.
****************************************************************************/
bool is_ntfs_stream_name(const char *fname)
diff --git a/source3/smbd/open.c b/source3/smbd/open.c
index 9d48bcc98b..aa4bc48f3d 100644
--- a/source3/smbd/open.c
+++ b/source3/smbd/open.c
@@ -1842,7 +1842,9 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
set_share_mode(lck, fsp, current_user.ut.uid, 0, fsp->oplock_type, new_file_created);
/* Handle strange delete on close create semantics. */
- if ((create_options & FILE_DELETE_ON_CLOSE) && can_set_initial_delete_on_close(lck)) {
+ if ((create_options & FILE_DELETE_ON_CLOSE)
+ && (is_ntfs_stream_name(fname)
+ || can_set_initial_delete_on_close(lck))) {
status = can_set_delete_on_close(fsp, True, new_dos_attributes);
if (!NT_STATUS_IS_OK(status)) {
@@ -2104,7 +2106,7 @@ NTSTATUS open_directory(connection_struct *conn,
(unsigned int)create_disposition,
(unsigned int)file_attributes));
- if (is_ntfs_stream_name(fname)) {
+ if (!(file_attributes & FILE_FLAG_POSIX_SEMANTICS) && is_ntfs_stream_name(fname)) {
DEBUG(2, ("open_directory: %s is a stream name!\n", fname));
return NT_STATUS_NOT_A_DIRECTORY;
}
@@ -2444,6 +2446,116 @@ static struct case_semantics_state *set_posix_case_semantics(TALLOC_CTX *mem_ctx
}
/*
+ * If a main file is opened for delete, all streams need to be checked for
+ * !FILE_SHARE_DELETE. Do this by opening with DELETE_ACCESS.
+ * If that works, delete them all by setting the delete on close and close.
+ */
+
+static NTSTATUS open_streams_for_delete(connection_struct *conn,
+ const char *fname)
+{
+ struct stream_struct *stream_info;
+ files_struct **streams;
+ int i;
+ unsigned int num_streams;
+ TALLOC_CTX *frame = talloc_stackframe();
+ NTSTATUS status;
+
+ status = SMB_VFS_STREAMINFO(conn, NULL, fname, talloc_tos(),
+ &num_streams, &stream_info);
+
+ if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)
+ || NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
+ DEBUG(10, ("no streams around\n"));
+ TALLOC_FREE(frame);
+ return NT_STATUS_OK;
+ }
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("SMB_VFS_STREAMINFO failed: %s\n",
+ nt_errstr(status)));
+ goto fail;
+ }
+
+ DEBUG(10, ("open_streams_for_delete found %d streams\n",
+ num_streams));
+
+ if (num_streams == 0) {
+ TALLOC_FREE(frame);
+ return NT_STATUS_OK;
+ }
+
+ streams = TALLOC_ARRAY(talloc_tos(), files_struct *, num_streams);
+ if (streams == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+
+ for (i=0; i<num_streams; i++) {
+ char *streamname;
+
+ if (strequal(stream_info[i].name, "::$DATA")) {
+ streams[i] = NULL;
+ continue;
+ }
+
+ streamname = talloc_asprintf(talloc_tos(), "%s%s", fname,
+ stream_info[i].name);
+
+ if (streamname == NULL) {
+ DEBUG(0, ("talloc_aprintf failed\n"));
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+
+ status = create_file_unixpath
+ (conn, /* conn */
+ NULL, /* req */
+ streamname, /* fname */
+ DELETE_ACCESS, /* access_mask */
+ FILE_SHARE_READ | FILE_SHARE_WRITE
+ | FILE_SHARE_DELETE, /* share_access */
+ FILE_OPEN, /* create_disposition*/
+ NTCREATEX_OPTIONS_PRIVATE_STREAM_DELETE, /* create_options */
+ FILE_ATTRIBUTE_NORMAL, /* file_attributes */
+ 0, /* oplock_request */
+ 0, /* allocation_size */
+ NULL, /* sd */
+ NULL, /* ea_list */
+ &streams[i], /* result */
+ NULL, /* pinfo */
+ NULL); /* psbuf */
+
+ TALLOC_FREE(streamname);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("Could not open stream %s: %s\n",
+ streamname, nt_errstr(status)));
+ break;
+ }
+ }
+
+ /*
+ * don't touch the variable "status" beyond this point :-)
+ */
+
+ for (i -= 1 ; i >= 0; i--) {
+ if (streams[i] == NULL) {
+ continue;
+ }
+
+ DEBUG(10, ("Closing stream # %d, %s\n", i,
+ streams[i]->fsp_name));
+ close_file(streams[i], NORMAL_CLOSE);
+ }
+
+ fail:
+ TALLOC_FREE(frame);
+ return status;
+}
+
+/*
* Wrapper around open_file_ntcreate and open_directory
*/
@@ -2466,6 +2578,7 @@ NTSTATUS create_file_unixpath(connection_struct *conn,
{
SMB_STRUCT_STAT sbuf;
int info = FILE_WAS_OPENED;
+ files_struct *base_fsp = NULL;
files_struct *fsp = NULL;
NTSTATUS status;
@@ -2495,7 +2608,23 @@ NTSTATUS create_file_unixpath(connection_struct *conn,
sbuf = *psbuf;
}
else {
- SET_STAT_INVALID(sbuf);
+ if (SMB_VFS_STAT(conn, fname, &sbuf) == -1) {
+ SET_STAT_INVALID(sbuf);
+ }
+ }
+
+ if ((conn->fs_capabilities & FILE_NAMED_STREAMS)
+ && (access_mask & DELETE_ACCESS)
+ && !is_ntfs_stream_name(fname)) {
+ /*
+ * We can't open a file with DELETE access if any of the
+ * streams is open without FILE_SHARE_DELETE
+ */
+ status = open_streams_for_delete(conn, fname);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ goto fail;
+ }
}
/* This is the correct thing to do (check every time) but can_delete
@@ -2528,12 +2657,61 @@ NTSTATUS create_file_unixpath(connection_struct *conn,
}
#endif
+ if ((conn->fs_capabilities & FILE_NAMED_STREAMS)
+ && is_ntfs_stream_name(fname)
+ && (!(create_options & NTCREATEX_OPTIONS_PRIVATE_STREAM_DELETE))) {
+ char *base;
+ uint32 base_create_disposition;
+
+ if (create_options & FILE_DIRECTORY_FILE) {
+ status = NT_STATUS_NOT_A_DIRECTORY;
+ goto fail;
+ }
+
+ status = split_ntfs_stream_name(talloc_tos(), fname,
+ &base, NULL);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("split_ntfs_stream_name failed: %s\n",
+ nt_errstr(status)));
+ goto fail;
+ }
+
+ SMB_ASSERT(!is_ntfs_stream_name(base)); /* paranoia.. */
+
+ switch (create_disposition) {
+ case FILE_OPEN:
+ base_create_disposition = FILE_OPEN;
+ break;
+ default:
+ base_create_disposition = FILE_OPEN_IF;
+ break;
+ }
+
+ status = create_file_unixpath(conn, NULL, base, 0,
+ FILE_SHARE_READ
+ | FILE_SHARE_WRITE
+ | FILE_SHARE_DELETE,
+ base_create_disposition,
+ 0, 0, 0, 0, NULL, NULL,
+ &base_fsp, NULL, NULL);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("create_file_unixpath for base %s failed: "
+ "%s\n", base, nt_errstr(status)));
+ goto fail;
+ }
+ }
+
/*
* If it's a request for a directory open, deal with it separately.
*/
if (create_options & FILE_DIRECTORY_FILE) {
+ if (create_options & FILE_NON_DIRECTORY_FILE) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto fail;
+ }
+
/* Can't open a temp directory. IFS kit test. */
if (file_attributes & FILE_ATTRIBUTE_TEMPORARY) {
status = NT_STATUS_INVALID_PARAMETER;
@@ -2664,6 +2842,16 @@ NTSTATUS create_file_unixpath(connection_struct *conn,
DEBUG(10, ("create_file: info=%d\n", info));
+ /*
+ * Set fsp->base_fsp late enough that we can't "goto fail" anymore. In
+ * the fail: branch we call close_file(fsp, ERROR_CLOSE) which would
+ * also close fsp->base_fsp which we have to also do explicitly in
+ * this routine here, as not in all "goto fail:" we have the fsp set
+ * up already to be initialized with the base_fsp.
+ */
+
+ fsp->base_fsp = base_fsp;
+
*result = fsp;
if (pinfo != NULL) {
*pinfo = info;
@@ -2685,6 +2873,10 @@ NTSTATUS create_file_unixpath(connection_struct *conn,
close_file(fsp, ERROR_CLOSE);
fsp = NULL;
}
+ if (base_fsp != NULL) {
+ close_file(base_fsp, ERROR_CLOSE);
+ base_fsp = NULL;
+ }
return status;
}
@@ -2812,19 +3004,18 @@ NTSTATUS create_file(connection_struct *conn,
status = NT_STATUS_NO_MEMORY;
goto fail;
}
- } else {
- /*
- * Check to see if this is a mac fork of some kind.
- */
+ }
- if (is_ntfs_stream_name(fname)) {
- enum FAKE_FILE_TYPE fake_file_type;
+ /*
+ * Check to see if this is a mac fork of some kind.
+ */
- fake_file_type = is_fake_file(fname);
+ if (is_ntfs_stream_name(fname)) {
+ enum FAKE_FILE_TYPE fake_file_type;
- if (fake_file_type == FAKE_FILE_TYPE_NONE) {
- return NT_STATUS_OBJECT_PATH_NOT_FOUND;
- }
+ fake_file_type = is_fake_file(fname);
+
+ if (fake_file_type != FAKE_FILE_TYPE_NONE) {
/*
* Here we go! support for changing the disk quotas
@@ -2843,8 +3034,7 @@ NTSTATUS create_file(connection_struct *conn,
goto fail;
}
- SET_STAT_INVALID(sbuf);
-
+ ZERO_STRUCT(sbuf);
goto done;
}
}
@@ -2889,6 +3079,8 @@ NTSTATUS create_file(connection_struct *conn,
fname = converted_fname;
}
+ TALLOC_FREE(case_state);
+
/* All file access must go through check_name() */
status = check_name(conn, fname);
diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c
index 381ddfe151..4ea81a3819 100644
--- a/source3/smbd/reply.c
+++ b/source3/smbd/reply.c
@@ -167,6 +167,7 @@ static NTSTATUS check_path_syntax_internal(char *path,
}
*d = '\0';
+
return ret;
}
@@ -2289,14 +2290,22 @@ static NTSTATUS do_unlink(connection_struct *conn,
/* On open checks the open itself will check the share mode, so
don't do it here as we'll get it wrong. */
- status = open_file_ntcreate(conn, req, fname, &sbuf,
- DELETE_ACCESS,
- FILE_SHARE_NONE,
- FILE_OPEN,
- 0,
- FILE_ATTRIBUTE_NORMAL,
- req != NULL ? 0 : INTERNAL_OPEN_ONLY,
- NULL, &fsp);
+ status = create_file_unixpath
+ (conn, /* conn */
+ req, /* req */
+ fname, /* fname */
+ DELETE_ACCESS, /* access_mask */
+ FILE_SHARE_NONE, /* share_access */
+ FILE_OPEN, /* create_disposition*/
+ FILE_NON_DIRECTORY_FILE, /* create_options */
+ FILE_ATTRIBUTE_NORMAL, /* file_attributes */
+ 0, /* oplock_request */
+ 0, /* allocation_size */
+ NULL, /* sd */
+ NULL, /* ea_list */
+ &fsp, /* result */
+ NULL, /* pinfo */
+ &sbuf); /* psbuf */
if (!NT_STATUS_IS_OK(status)) {
DEBUG(10, ("open_file_ntcreate failed: %s\n",
@@ -3366,7 +3375,6 @@ void error_to_writebrawerr(struct smb_request *req)
void reply_writebraw(struct smb_request *req)
{
connection_struct *conn = req->conn;
- int outsize = 0;
char *buf = NULL;
ssize_t nwritten=0;
ssize_t total_written=0;
@@ -3476,8 +3484,7 @@ void reply_writebraw(struct smb_request *req)
* it to send more bytes */
memcpy(buf, req->inbuf, smb_size);
- outsize = srv_set_message(buf,
- Protocol>PROTOCOL_COREPLUS?1:0,0,True);
+ srv_set_message(buf,Protocol>PROTOCOL_COREPLUS?1:0,0,True);
SCVAL(buf,smb_com,SMBwritebraw);
SSVALS(buf,smb_vwv0,0xFFFF);
show_msg(buf);
diff --git a/source3/smbd/service.c b/source3/smbd/service.c
index ed8061e2f7..a8aa25405a 100644
--- a/source3/smbd/service.c
+++ b/source3/smbd/service.c
@@ -1171,16 +1171,8 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser,
* assumes that all the filesystem mounted withing a share path have
* the same characteristics, which is likely but not guaranteed.
*/
- {
- vfs_statvfs_struct svfs;
-
- conn->fs_capabilities =
- FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES;
- if (SMB_VFS_STATVFS(conn, conn->connectpath, &svfs) == 0) {
- conn->fs_capabilities = svfs.FsCapabilities;
- }
- }
+ conn->fs_capabilities = SMB_VFS_FS_CAPABILITIES(conn);
/*
* Print out the 'connected as' stuff here as we need
diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c
index 23d6f12996..fb845220cd 100644
--- a/source3/smbd/trans2.c
+++ b/source3/smbd/trans2.c
@@ -5,7 +5,7 @@
Copyright (C) Stefan (metze) Metzmacher 2003
Copyright (C) Volker Lendecke 2005-2007
Copyright (C) Steve French 2005
- Copyright (C) James Peach 2007
+ Copyright (C) James Peach 2006-2007
Extensively modified by Andrew Tridgell, 1995
@@ -105,17 +105,22 @@ static bool samba_private_attr_name(const char *unix_ea_name)
for (i = 0; prohibited_ea_names[i]; i++) {
if (strequal( prohibited_ea_names[i], unix_ea_name))
- return True;
+ return true;
}
- return False;
+ if (StrnCaseCmp(unix_ea_name, SAMBA_XATTR_DOSSTREAM_PREFIX,
+ strlen(SAMBA_XATTR_DOSSTREAM_PREFIX)) == 0) {
+ return true;
+ }
+ return false;
}
/****************************************************************************
Get one EA value. Fill in a struct ea_struct.
****************************************************************************/
-static bool get_ea_value(TALLOC_CTX *mem_ctx, connection_struct *conn, files_struct *fsp,
- const char *fname, char *ea_name, struct ea_struct *pea)
+NTSTATUS get_ea_value(TALLOC_CTX *mem_ctx, connection_struct *conn,
+ files_struct *fsp, const char *fname,
+ const char *ea_name, struct ea_struct *pea)
{
/* Get the value of this xattr. Max size is 64k. */
size_t attr_size = 256;
@@ -126,7 +131,7 @@ static bool get_ea_value(TALLOC_CTX *mem_ctx, connection_struct *conn, files_str
val = TALLOC_REALLOC_ARRAY(mem_ctx, val, char, attr_size);
if (!val) {
- return False;
+ return NT_STATUS_NO_MEMORY;
}
if (fsp && fsp->fh->fd != -1) {
@@ -141,7 +146,7 @@ static bool get_ea_value(TALLOC_CTX *mem_ctx, connection_struct *conn, files_str
}
if (sizeret == -1) {
- return False;
+ return map_nt_error_from_unix(errno);
}
DEBUG(10,("get_ea_value: EA %s is of length %u\n", ea_name, (unsigned int)sizeret));
@@ -149,93 +154,192 @@ static bool get_ea_value(TALLOC_CTX *mem_ctx, connection_struct *conn, files_str
pea->flags = 0;
if (strnequal(ea_name, "user.", 5)) {
- pea->name = &ea_name[5];
+ pea->name = talloc_strdup(mem_ctx, &ea_name[5]);
} else {
- pea->name = ea_name;
+ pea->name = talloc_strdup(mem_ctx, ea_name);
+ }
+ if (pea->name == NULL) {
+ TALLOC_FREE(val);
+ return NT_STATUS_NO_MEMORY;
}
pea->value.data = (unsigned char *)val;
pea->value.length = (size_t)sizeret;
- return True;
+ return NT_STATUS_OK;
}
-/****************************************************************************
- Return a linked list of the total EA's. Plus the total size
-****************************************************************************/
-
-static struct ea_list *get_ea_list_from_file(TALLOC_CTX *mem_ctx, connection_struct *conn, files_struct *fsp,
- const char *fname, size_t *pea_total_len)
+NTSTATUS get_ea_names_from_file(TALLOC_CTX *mem_ctx, connection_struct *conn,
+ files_struct *fsp, const char *fname,
+ char ***pnames, size_t *pnum_names)
{
/* Get a list of all xattrs. Max namesize is 64k. */
size_t ea_namelist_size = 1024;
- char *ea_namelist;
+ char *ea_namelist = NULL;
+
char *p;
+ char **names, **tmp;
+ size_t num_names;
ssize_t sizeret;
- int i;
- struct ea_list *ea_list_head = NULL;
-
- *pea_total_len = 0;
if (!lp_ea_support(SNUM(conn))) {
- return NULL;
+ *pnames = NULL;
+ *pnum_names = 0;
+ return NT_STATUS_OK;
}
- for (i = 0, ea_namelist = TALLOC_ARRAY(mem_ctx, char, ea_namelist_size); i < 6;
- ea_namelist = TALLOC_REALLOC_ARRAY(mem_ctx, ea_namelist, char, ea_namelist_size), i++) {
+ /*
+ * TALLOC the result early to get the talloc hierarchy right.
+ */
- if (!ea_namelist) {
- return NULL;
+ names = TALLOC_ARRAY(mem_ctx, char *, 1);
+ if (names == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ while (ea_namelist_size <= 65536) {
+
+ ea_namelist = TALLOC_REALLOC_ARRAY(
+ names, ea_namelist, char, ea_namelist_size);
+ if (ea_namelist == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ TALLOC_FREE(names);
+ return NT_STATUS_NO_MEMORY;
}
if (fsp && fsp->fh->fd != -1) {
- sizeret = SMB_VFS_FLISTXATTR(fsp, ea_namelist, ea_namelist_size);
+ sizeret = SMB_VFS_FLISTXATTR(fsp, ea_namelist,
+ ea_namelist_size);
} else {
- sizeret = SMB_VFS_LISTXATTR(conn, fname, ea_namelist, ea_namelist_size);
+ sizeret = SMB_VFS_LISTXATTR(conn, fname, ea_namelist,
+ ea_namelist_size);
}
- if (sizeret == -1 && errno == ERANGE) {
+ if ((sizeret == -1) && (errno == ERANGE)) {
ea_namelist_size *= 2;
- } else {
+ }
+ else {
break;
}
}
- if (sizeret == -1)
- return NULL;
+ if (sizeret == -1) {
+ TALLOC_FREE(names);
+ return map_nt_error_from_unix(errno);
+ }
- DEBUG(10,("get_ea_list_from_file: ea_namelist size = %u\n", (unsigned int)sizeret ));
+ DEBUG(10, ("get_ea_list_from_file: ea_namelist size = %u\n",
+ (unsigned int)sizeret));
- if (sizeret) {
- for (p = ea_namelist; p - ea_namelist < sizeret; p += strlen(p) + 1) {
- struct ea_list *listp;
+ if (sizeret == 0) {
+ TALLOC_FREE(names);
+ *pnames = NULL;
+ *pnum_names = 0;
+ return NT_STATUS_OK;
+ }
- if (strnequal(p, "system.", 7) || samba_private_attr_name(p))
- continue;
+ /*
+ * Ensure the result is 0-terminated
+ */
- listp = TALLOC_P(mem_ctx, struct ea_list);
- if (!listp)
- return NULL;
+ if (ea_namelist[sizeret-1] != '\0') {
+ TALLOC_FREE(names);
+ return NT_STATUS_INTERNAL_ERROR;
+ }
- if (!get_ea_value(mem_ctx, conn, fsp, fname, p, &listp->ea)) {
- return NULL;
- }
+ /*
+ * count the names
+ */
+ num_names = 0;
- {
- fstring dos_ea_name;
- push_ascii_fstring(dos_ea_name, listp->ea.name);
- *pea_total_len += 4 + strlen(dos_ea_name) + 1 + listp->ea.value.length;
- DEBUG(10,("get_ea_list_from_file: total_len = %u, %s, val len = %u\n",
- (unsigned int)*pea_total_len, dos_ea_name,
- (unsigned int)listp->ea.value.length ));
- }
- DLIST_ADD_END(ea_list_head, listp, struct ea_list *);
+ for (p = ea_namelist; p - ea_namelist < sizeret; p += strlen(p)+1) {
+ num_names += 1;
+ }
+
+ tmp = TALLOC_REALLOC_ARRAY(mem_ctx, names, char *, num_names);
+ if (tmp == NULL) {
+ DEBUG(0, ("talloc failed\n"));
+ TALLOC_FREE(names);
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ names = tmp;
+ num_names = 0;
+
+ for (p = ea_namelist; p - ea_namelist < sizeret; p += strlen(p)+1) {
+ names[num_names++] = p;
+ }
+
+ *pnames = names;
+ *pnum_names = num_names;
+ return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ Return a linked list of the total EA's. Plus the total size
+****************************************************************************/
+
+static struct ea_list *get_ea_list_from_file(TALLOC_CTX *mem_ctx, connection_struct *conn, files_struct *fsp,
+ const char *fname, size_t *pea_total_len)
+{
+ /* Get a list of all xattrs. Max namesize is 64k. */
+ size_t i, num_names;
+ char **names;
+ struct ea_list *ea_list_head = NULL;
+ NTSTATUS status;
+
+ *pea_total_len = 0;
+
+ if (!lp_ea_support(SNUM(conn))) {
+ return NULL;
+ }
+
+ status = get_ea_names_from_file(talloc_tos(), conn, fsp, fname,
+ &names, &num_names);
+
+ if (!NT_STATUS_IS_OK(status) || (num_names == 0)) {
+ return NULL;
+ }
+
+ for (i=0; i<num_names; i++) {
+ struct ea_list *listp;
+ fstring dos_ea_name;
+
+ if (strnequal(names[i], "system.", 7)
+ || samba_private_attr_name(names[i]))
+ continue;
+
+ listp = TALLOC_P(mem_ctx, struct ea_list);
+ if (listp == NULL) {
+ return NULL;
}
- /* Add on 4 for total length. */
- if (*pea_total_len) {
- *pea_total_len += 4;
+
+ if (!NT_STATUS_IS_OK(get_ea_value(mem_ctx, conn, fsp,
+ fname, names[i],
+ &listp->ea))) {
+ return NULL;
}
+
+ push_ascii_fstring(dos_ea_name, listp->ea.name);
+
+ *pea_total_len +=
+ 4 + strlen(dos_ea_name) + 1 + listp->ea.value.length;
+
+ DEBUG(10,("get_ea_list_from_file: total_len = %u, %s, val len "
+ "= %u\n", (unsigned int)*pea_total_len, dos_ea_name,
+ (unsigned int)listp->ea.value.length));
+
+ DLIST_ADD_END(ea_list_head, listp, struct ea_list *);
+
+ }
+
+ /* Add on 4 for total length. */
+ if (*pea_total_len) {
+ *pea_total_len += 4;
}
- DEBUG(10,("get_ea_list_from_file: total_len = %u\n", (unsigned int)*pea_total_len));
+ DEBUG(10, ("get_ea_list_from_file: total_len = %u\n",
+ (unsigned int)*pea_total_len));
+
return ea_list_head;
}
@@ -2355,6 +2459,40 @@ unsigned char *create_volume_objectid(connection_struct *conn, unsigned char obj
return objid;
}
+static void samba_extended_info_version(struct smb_extended_info *extended_info)
+{
+ SMB_ASSERT(extended_info != NULL);
+
+ extended_info->samba_magic = SAMBA_EXTENDED_INFO_MAGIC;
+ extended_info->samba_version = ((SAMBA_VERSION_MAJOR & 0xff) << 24)
+ | ((SAMBA_VERSION_MINOR & 0xff) << 16)
+ | ((SAMBA_VERSION_RELEASE & 0xff) << 8);
+#ifdef SAMBA_VERSION_REVISION
+ extended_info->samba_version |= (tolower(*SAMBA_VERSION_REVISION) - 'a' + 1) & 0xff;
+#endif
+#ifdef SAMBA_VERSION_RC_RELEASE
+ extended_info->samba_subversion |= (SAMBA_VERSION_RC_RELEASE & 0xff) << 24;
+#else
+#ifdef SAMBA_VERSION_PRE_RELEASE
+ extended_info->samba_subversion |= (SAMBA_VERSION_PRE_RELEASE & 0xff) << 16;
+#endif
+#endif
+#ifdef SAMBA_VERSION_VENDOR_PATCH
+ extended_info->samba_subversion |= (SAMBA_VERSION_VENDOR_PATCH & 0xffff);
+#endif
+ /* FIXME: samba_gitcommitdate should contain the git commit date. */
+#ifdef SAMBA_VERSION_GIT_COMMIT_TIME
+ unix_to_nt_time(&extended_info->samba_gitcommitdate, SAMBA_VERSION_GIT_COMMIT_TIME);
+#endif
+
+ memset(extended_info->samba_version_string, 0,
+ sizeof(extended_info->samba_version_string));
+
+ snprintf (extended_info->samba_version_string,
+ sizeof(extended_info->samba_version_string),
+ "%s", samba_version_string());
+}
+
/****************************************************************************
Reply to a TRANS2_QFSINFO (query filesystem info).
****************************************************************************/
@@ -2693,7 +2831,14 @@ cBytesSector=%u, cUnitTotal=%u, cUnitAvail=%d\n", (unsigned int)bsize, (unsigned
case SMB_FS_OBJECTID_INFORMATION:
{
unsigned char objid[16];
+ struct smb_extended_info extended_info;
memcpy(pdata,create_volume_objectid(conn, objid),16);
+ samba_extended_info_version (&extended_info);
+ SIVAL(pdata,16,extended_info.samba_magic);
+ SIVAL(pdata,20,extended_info.samba_version);
+ SIVAL(pdata,24,extended_info.samba_subversion);
+ SBIG_UINT(pdata,28,extended_info.samba_gitcommitdate);
+ memcpy(pdata+36,extended_info.samba_version_string,28);
data_len = 64;
break;
}
@@ -3468,6 +3613,72 @@ static char *store_file_unix_basic_info2(connection_struct *conn,
return pdata;
}
+static NTSTATUS marshall_stream_info(unsigned int num_streams,
+ const struct stream_struct *streams,
+ char *data,
+ unsigned int max_data_bytes,
+ unsigned int *data_size)
+{
+ unsigned int i;
+ unsigned int ofs = 0;
+
+ for (i=0; i<num_streams; i++) {
+ unsigned int next_offset;
+ size_t namelen;
+ smb_ucs2_t *namebuf;
+
+ namelen = push_ucs2_talloc(talloc_tos(), &namebuf,
+ streams[i].name);
+
+ if ((namelen == (size_t)-1) || (namelen <= 2)) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ /*
+ * name_buf is now null-terminated, we need to marshall as not
+ * terminated
+ */
+
+ namelen -= 2;
+
+ if (ofs + 24 + namelen > max_data_bytes) {
+ TALLOC_FREE(namebuf);
+ return NT_STATUS_BUFFER_TOO_SMALL;
+ }
+
+ SIVAL(data, ofs+4, namelen);
+ SOFF_T(data, ofs+8, streams[i].size);
+ SOFF_T(data, ofs+16, streams[i].alloc_size);
+ memcpy(data+ofs+24, namebuf, namelen);
+ TALLOC_FREE(namebuf);
+
+ next_offset = ofs + 24 + namelen;
+
+ if (i == num_streams-1) {
+ SIVAL(data, ofs, 0);
+ }
+ else {
+ unsigned int align = ndr_align_size(next_offset, 8);
+
+ if (next_offset + align > max_data_bytes) {
+ return NT_STATUS_BUFFER_TOO_SMALL;
+ }
+
+ memset(data+next_offset, 0, align);
+ next_offset += align;
+
+ SIVAL(data, ofs, next_offset - ofs);
+ ofs = next_offset;
+ }
+
+ ofs = next_offset;
+ }
+
+ *data_size = ofs;
+
+ return NT_STATUS_OK;
+}
+
/****************************************************************************
Reply to a TRANSACT2_QFILEINFO on a PIPE !
****************************************************************************/
@@ -3743,17 +3954,6 @@ static void call_trans2qfilepathinfo(connection_struct *conn,
}
}
- nlink = sbuf.st_nlink;
-
- if ((nlink > 0) && S_ISDIR(sbuf.st_mode)) {
- /* NTFS does not seem to count ".." */
- nlink -= 1;
- }
-
- if ((nlink > 0) && delete_pending) {
- nlink -= 1;
- }
-
if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions()) {
reply_nterror(req, NT_STATUS_INVALID_LEVEL);
return;
@@ -3772,6 +3972,16 @@ static void call_trans2qfilepathinfo(connection_struct *conn,
if (!mode)
mode = FILE_ATTRIBUTE_NORMAL;
+ nlink = sbuf.st_nlink;
+
+ if (nlink && (mode&aDIR)) {
+ nlink = 1;
+ }
+
+ if ((nlink > 0) && delete_pending) {
+ nlink -= 1;
+ }
+
fullpathname = fname;
if (!(mode & aDIR))
file_size = get_file_size(sbuf);
@@ -4166,28 +4376,49 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd
data_size = 4;
break;
-#if 0
/*
- * NT4 server just returns "invalid query" to this - if we try to answer
- * it then NTws gets a BSOD! (tridge).
- * W2K seems to want this. JRA.
+ * NT4 server just returns "invalid query" to this - if we try
+ * to answer it then NTws gets a BSOD! (tridge). W2K seems to
+ * want this. JRA.
+ */
+ /* The first statement above is false - verified using Thursby
+ * client against NT4 -- gcolley.
*/
case SMB_QUERY_FILE_STREAM_INFO:
-#endif
- case SMB_FILE_STREAM_INFORMATION:
- DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_STREAM_INFORMATION\n"));
- if (mode & aDIR) {
- data_size = 0;
- } else {
- size_t byte_len = dos_PutUniCode(pdata+24,"::$DATA", (size_t)0xE, False);
- SIVAL(pdata,0,0); /* ??? */
- SIVAL(pdata,4,byte_len); /* Byte length of unicode string ::$DATA */
- SOFF_T(pdata,8,file_size);
- SOFF_T(pdata,16,allocation_size);
- data_size = 24 + byte_len;
+ case SMB_FILE_STREAM_INFORMATION: {
+ unsigned int num_streams;
+ struct stream_struct *streams;
+ NTSTATUS status;
+
+ DEBUG(10,("call_trans2qfilepathinfo: "
+ "SMB_FILE_STREAM_INFORMATION\n"));
+
+ status = SMB_VFS_STREAMINFO(
+ conn, fsp, fname, talloc_tos(),
+ &num_streams, &streams);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("could not get stream info: %s\n",
+ nt_errstr(status)));
+ reply_nterror(req, status);
+ return;
}
- break;
+ status = marshall_stream_info(num_streams, streams,
+ pdata, max_data_bytes,
+ &data_size);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10, ("marshall_stream_info failed: %s\n",
+ nt_errstr(status)));
+ reply_nterror(req, status);
+ return;
+ }
+
+ TALLOC_FREE(streams);
+
+ break;
+ }
case SMB_QUERY_COMPRESSION_INFO:
case SMB_FILE_COMPRESSION_INFORMATION:
DEBUG(10,("call_trans2qfilepathinfo: SMB_FILE_COMPRESSION_INFORMATION\n"));
diff --git a/source3/smbd/utmp.c b/source3/smbd/utmp.c
index e82bbea3b3..5931b2b1d0 100644
--- a/source3/smbd/utmp.c
+++ b/source3/smbd/utmp.c
@@ -223,7 +223,7 @@ static char *uw_pathname(TALLOC_CTX *ctx,
}
/* For u-files and non-explicit w-dir, look for "utmp dir" */
- if (!dirname == 0 || strlen(dirname) == 0) {
+ if ((dirname == NULL) || (strlen(dirname) == 0)) {
dirname = talloc_strdup(ctx, lp_utmpdir());
if (!dirname) {
return NULL;
diff --git a/source3/torture/torture.c b/source3/torture/torture.c
index 05b41413b4..070474cf6f 100644
--- a/source3/torture/torture.c
+++ b/source3/torture/torture.c
@@ -5098,6 +5098,74 @@ static bool run_local_rbtree(int dummy)
return ret;
}
+static bool test_stream_name(const char *fname, const char *expected_base,
+ const char *expected_stream,
+ NTSTATUS expected_status)
+{
+ NTSTATUS status;
+ char *base = NULL;
+ char *stream = NULL;
+
+ status = split_ntfs_stream_name(talloc_tos(), fname, &base, &stream);
+ if (!NT_STATUS_EQUAL(status, expected_status)) {
+ goto error;
+ }
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return true;
+ }
+
+ if (base == NULL) goto error;
+
+ if (strcmp(expected_base, base) != 0) goto error;
+
+ if ((expected_stream != NULL) && (stream == NULL)) goto error;
+ if ((expected_stream == NULL) && (stream != NULL)) goto error;
+
+ if ((stream != NULL) && (strcmp(expected_stream, stream) != 0))
+ goto error;
+
+ TALLOC_FREE(base);
+ TALLOC_FREE(stream);
+ return true;
+
+ error:
+ d_fprintf(stderr, "test_stream(%s, %s, %s, %s)\n",
+ fname, expected_base ? expected_base : "<NULL>",
+ expected_stream ? expected_stream : "<NULL>",
+ nt_errstr(expected_status));
+ d_fprintf(stderr, "-> base=%s, stream=%s, status=%s\n",
+ base ? base : "<NULL>", stream ? stream : "<NULL>",
+ nt_errstr(status));
+ TALLOC_FREE(base);
+ TALLOC_FREE(stream);
+ return false;
+}
+
+static bool run_local_stream_name(int dummy)
+{
+ bool ret = true;
+
+ ret &= test_stream_name(
+ "bla", "bla", NULL, NT_STATUS_OK);
+ ret &= test_stream_name(
+ "bla::$DATA", "bla", NULL, NT_STATUS_OK);
+ ret &= test_stream_name(
+ "bla:blub:", "bla", NULL, NT_STATUS_OBJECT_NAME_INVALID);
+ ret &= test_stream_name(
+ "bla::", NULL, NULL, NT_STATUS_OBJECT_NAME_INVALID);
+ ret &= test_stream_name(
+ "bla::123", "bla", NULL, NT_STATUS_OBJECT_NAME_INVALID);
+ ret &= test_stream_name(
+ "bla:$DATA", "bla", "$DATA:$DATA", NT_STATUS_OK);
+ ret &= test_stream_name(
+ "bla:x:$DATA", "bla", "x:$DATA", NT_STATUS_OK);
+ ret &= test_stream_name(
+ "bla:x", "bla", "x:$DATA", NT_STATUS_OK);
+
+ return ret;
+}
+
static bool data_blob_equal(DATA_BLOB a, DATA_BLOB b)
{
if (a.length != b.length) {
@@ -5328,6 +5396,7 @@ static struct {
{ "LOCAL-GENCACHE", run_local_gencache, 0},
{ "LOCAL-RBTREE", run_local_rbtree, 0},
{ "LOCAL-MEMCACHE", run_local_memcache, 0},
+ { "LOCAL-STREAM-NAME", run_local_stream_name, 0},
{NULL, NULL, 0}};
diff --git a/source3/utils/net_rpc_samsync.c b/source3/utils/net_rpc_samsync.c
index 779006884d..d0fcfe3aeb 100644
--- a/source3/utils/net_rpc_samsync.c
+++ b/source3/utils/net_rpc_samsync.c
@@ -365,7 +365,8 @@ static NTSTATUS sam_account_from_delta(struct samu *account, SAM_ACCOUNT_INFO *d
old_string = pdb_get_munged_dial(account);
mung.length = delta->hdr_parameters.uni_str_len;
mung.data = (uint8 *) delta->uni_parameters.buffer;
- newstr = (mung.length == 0) ? NULL : base64_encode_data_blob(mung);
+ newstr = (mung.length == 0) ? NULL :
+ base64_encode_data_blob(talloc_tos(), mung);
if (STRING_CHANGED_NC(old_string, newstr))
pdb_set_munged_dial(account, newstr, PDB_CHANGED);
@@ -1422,12 +1423,11 @@ static int fprintf_attr(FILE *add_fd, const char *attr_name,
base64_blob.data = (unsigned char *)value;
base64_blob.length = strlen(value);
- base64 = base64_encode_data_blob(base64_blob);
+ base64 = base64_encode_data_blob(value, base64_blob);
SMB_ASSERT(base64 != NULL);
res = fprintf(add_fd, "%s:: %s\n", attr_name, base64);
TALLOC_FREE(value);
- TALLOC_FREE(base64);
return res;
}
diff --git a/source3/utils/ntlm_auth.c b/source3/utils/ntlm_auth.c
index 6a702fc0cf..3e2093a194 100644
--- a/source3/utils/ntlm_auth.c
+++ b/source3/utils/ntlm_auth.c
@@ -1,23 +1,24 @@
-/*
+/*
Unix SMB/CIFS implementation.
Winbind status program.
Copyright (C) Tim Potter 2000-2003
Copyright (C) Andrew Bartlett <abartlet@samba.org> 2003-2004
- Copyright (C) Francesco Chemolli <kinkie@kame.usr.dsi.unimi.it> 2000
+ Copyright (C) Francesco Chemolli <kinkie@kame.usr.dsi.unimi.it> 2000
Copyright (C) Robert O'Callahan 2006 (added cached credential code).
+ Copyright (C) Kai Blin <kai@samba.org> 2008
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 3 of the License, or
(at your option) any later version.
-
+
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
-
+
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
@@ -28,7 +29,8 @@
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_WINBIND
-#define SQUID_BUFFER_SIZE 2010
+#define INITIAL_BUFFER_SIZE 300
+#define MAX_BUFFER_SIZE 630000
enum stdio_helper_mode {
SQUID_2_4_BASIC,
@@ -42,28 +44,56 @@ enum stdio_helper_mode {
NUM_HELPER_MODES
};
-typedef void (*stdio_helper_function)(enum stdio_helper_mode stdio_helper_mode,
- char *buf, int length);
+enum ntlm_auth_cli_state {
+ CLIENT_INITIAL = 0,
+ CLIENT_RESPONSE,
+ CLIENT_FINISHED,
+ CLIENT_ERROR
+};
+
+enum ntlm_auth_svr_state {
+ SERVER_INITIAL = 0,
+ SERVER_CHALLENGE,
+ SERVER_FINISHED,
+ SERVER_ERROR
+};
+
+struct ntlm_auth_state {
+ TALLOC_CTX *mem_ctx;
+ enum stdio_helper_mode helper_mode;
+ enum ntlm_auth_cli_state cli_state;
+ enum ntlm_auth_svr_state svr_state;
+ struct ntlmssp_state *ntlmssp_state;
+ uint32_t neg_flags;
+ char *want_feature_list;
+ bool have_session_key;
+ DATA_BLOB session_key;
+ DATA_BLOB initial_message;
+};
+
+typedef void (*stdio_helper_function)(struct ntlm_auth_state *state, char *buf,
+ int length);
-static void manage_squid_basic_request (enum stdio_helper_mode stdio_helper_mode,
+static void manage_squid_basic_request (struct ntlm_auth_state *state,
char *buf, int length);
-static void manage_squid_ntlmssp_request (enum stdio_helper_mode stdio_helper_mode,
- char *buf, int length);
+static void manage_squid_ntlmssp_request (struct ntlm_auth_state *state,
+ char *buf, int length);
-static void manage_client_ntlmssp_request (enum stdio_helper_mode stdio_helper_mode,
- char *buf, int length);
+static void manage_client_ntlmssp_request (struct ntlm_auth_state *state,
+ char *buf, int length);
-static void manage_gss_spnego_request (enum stdio_helper_mode stdio_helper_mode,
- char *buf, int length);
+static void manage_gss_spnego_request (struct ntlm_auth_state *state,
+ char *buf, int length);
-static void manage_gss_spnego_client_request (enum stdio_helper_mode stdio_helper_mode,
- char *buf, int length);
+static void manage_gss_spnego_client_request (struct ntlm_auth_state *state,
+ char *buf, int length);
-static void manage_ntlm_server_1_request (enum stdio_helper_mode stdio_helper_mode,
- char *buf, int length);
+static void manage_ntlm_server_1_request (struct ntlm_auth_state *state,
+ char *buf, int length);
-static void manage_ntlm_change_password_1_request(enum stdio_helper_mode helper_mode, char *buf, int length);
+static void manage_ntlm_change_password_1_request(struct ntlm_auth_state *state,
+ char *buf, int length);
static const struct {
enum stdio_helper_mode mode;
@@ -123,7 +153,7 @@ static char winbind_separator(void)
d_printf("winbind separator was NULL!\n");
return *lp_winbind_separator();
}
-
+
return sep;
}
@@ -679,14 +709,9 @@ static NTSTATUS do_ccache_ntlm_auth(DATA_BLOB initial_msg, DATA_BLOB challenge_m
return NT_STATUS_MORE_PROCESSING_REQUIRED;
}
-static void manage_squid_ntlmssp_request(enum stdio_helper_mode stdio_helper_mode,
- char *buf, int length)
+static void manage_squid_ntlmssp_request(struct ntlm_auth_state *state,
+ char *buf, int length)
{
- static NTLMSSP_STATE *ntlmssp_state = NULL;
- static char* want_feature_list = NULL;
- static uint32 neg_flags = 0;
- static bool have_session_key = False;
- static DATA_BLOB session_key;
DATA_BLOB request, reply;
NTSTATUS nt_status;
@@ -699,8 +724,9 @@ static void manage_squid_ntlmssp_request(enum stdio_helper_mode stdio_helper_mod
if (strlen(buf) > 3) {
if(strncmp(buf, "SF ", 3) == 0){
DEBUG(10, ("Setting flags to negotioate\n"));
- SAFE_FREE(want_feature_list);
- want_feature_list = SMB_STRNDUP(buf+3, strlen(buf)-3);
+ TALLOC_FREE(state->want_feature_list);
+ state->want_feature_list = talloc_strdup(state->mem_ctx,
+ buf+3);
x_fprintf(x_stdout, "OK\n");
return;
}
@@ -710,9 +736,11 @@ static void manage_squid_ntlmssp_request(enum stdio_helper_mode stdio_helper_mod
}
if ((strncmp(buf, "PW ", 3) == 0)) {
- /* The calling application wants us to use a local password (rather than winbindd) */
+ /* The calling application wants us to use a local password
+ * (rather than winbindd) */
- opt_password = SMB_STRNDUP((const char *)request.data, request.length);
+ opt_password = SMB_STRNDUP((const char *)request.data,
+ request.length);
if (opt_password == NULL) {
DEBUG(1, ("Out of memory\n"));
@@ -727,25 +755,33 @@ static void manage_squid_ntlmssp_request(enum stdio_helper_mode stdio_helper_mod
}
if (strncmp(buf, "YR", 2) == 0) {
- if (ntlmssp_state)
- ntlmssp_end(&ntlmssp_state);
+ if (state->ntlmssp_state)
+ ntlmssp_end(&state->ntlmssp_state);
+ state->svr_state = SERVER_INITIAL;
} else if (strncmp(buf, "KK", 2) == 0) {
-
+ /* No special preprocessing required */
} else if (strncmp(buf, "GF", 2) == 0) {
DEBUG(10, ("Requested negotiated NTLMSSP flags\n"));
- x_fprintf(x_stdout, "GF 0x%08lx\n", have_session_key?neg_flags:0l);
+
+ if (state->svr_state == SERVER_FINISHED) {
+ x_fprintf(x_stdout, "GF 0x%08x\n", state->neg_flags);
+ }
+ else {
+ x_fprintf(x_stdout, "BH\n");
+ }
data_blob_free(&request);
return;
} else if (strncmp(buf, "GK", 2) == 0) {
DEBUG(10, ("Requested NTLMSSP session key\n"));
- if(have_session_key) {
- char *key64 = base64_encode_data_blob(session_key);
+ if(state->have_session_key) {
+ char *key64 = base64_encode_data_blob(state->mem_ctx,
+ state->session_key);
x_fprintf(x_stdout, "GK %s\n", key64?key64:"<NULL>");
TALLOC_FREE(key64);
} else {
x_fprintf(x_stdout, "BH\n");
}
-
+
data_blob_free(&request);
return;
} else {
@@ -754,65 +790,62 @@ static void manage_squid_ntlmssp_request(enum stdio_helper_mode stdio_helper_mod
return;
}
- if (!ntlmssp_state) {
- if (!NT_STATUS_IS_OK(nt_status = ntlm_auth_start_ntlmssp_server(&ntlmssp_state))) {
+ if (!state->ntlmssp_state) {
+ nt_status = ntlm_auth_start_ntlmssp_server(
+ &state->ntlmssp_state);
+ if (!NT_STATUS_IS_OK(nt_status)) {
x_fprintf(x_stdout, "BH %s\n", nt_errstr(nt_status));
return;
}
- ntlmssp_want_feature_list(ntlmssp_state, want_feature_list);
+ ntlmssp_want_feature_list(state->ntlmssp_state,
+ state->want_feature_list);
}
DEBUG(10, ("got NTLMSSP packet:\n"));
dump_data(10, request.data, request.length);
- nt_status = ntlmssp_update(ntlmssp_state, request, &reply);
-
+ nt_status = ntlmssp_update(state->ntlmssp_state, request, &reply);
+
if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
- char *reply_base64 = base64_encode_data_blob(reply);
+ char *reply_base64 = base64_encode_data_blob(state->mem_ctx,
+ reply);
x_fprintf(x_stdout, "TT %s\n", reply_base64);
TALLOC_FREE(reply_base64);
data_blob_free(&reply);
+ state->svr_state = SERVER_CHALLENGE;
DEBUG(10, ("NTLMSSP challenge\n"));
} else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_ACCESS_DENIED)) {
x_fprintf(x_stdout, "BH %s\n", nt_errstr(nt_status));
DEBUG(0, ("NTLMSSP BH: %s\n", nt_errstr(nt_status)));
- ntlmssp_end(&ntlmssp_state);
+ ntlmssp_end(&state->ntlmssp_state);
} else if (!NT_STATUS_IS_OK(nt_status)) {
x_fprintf(x_stdout, "NA %s\n", nt_errstr(nt_status));
DEBUG(10, ("NTLMSSP %s\n", nt_errstr(nt_status)));
} else {
- x_fprintf(x_stdout, "AF %s\n", (char *)ntlmssp_state->auth_context);
+ x_fprintf(x_stdout, "AF %s\n",
+ (char *)state->ntlmssp_state->auth_context);
DEBUG(10, ("NTLMSSP OK!\n"));
-
- if(have_session_key)
- data_blob_free(&session_key);
- session_key = data_blob(ntlmssp_state->session_key.data,
- ntlmssp_state->session_key.length);
- neg_flags = ntlmssp_state->neg_flags;
- have_session_key = True;
+
+ if(state->have_session_key)
+ data_blob_free(&state->session_key);
+ state->session_key = data_blob(
+ state->ntlmssp_state->session_key.data,
+ state->ntlmssp_state->session_key.length);
+ state->neg_flags = state->ntlmssp_state->neg_flags;
+ state->have_session_key = true;
+ state->svr_state = SERVER_FINISHED;
}
data_blob_free(&request);
}
-static void manage_client_ntlmssp_request(enum stdio_helper_mode stdio_helper_mode,
- char *buf, int length)
+static void manage_client_ntlmssp_request(struct ntlm_auth_state *state,
+ char *buf, int length)
{
- /* The statics here are *HORRIBLE* and this entire concept
- needs to be rewritten. Essentially it's using these statics
- as the state in a state machine. BLEEEGH ! JRA. */
-
- static NTLMSSP_STATE *ntlmssp_state = NULL;
- static DATA_BLOB initial_message;
- static char* want_feature_list = NULL;
- static uint32 neg_flags = 0;
- static bool have_session_key = False;
- static DATA_BLOB session_key;
DATA_BLOB request, reply;
NTSTATUS nt_status;
- bool first = False;
-
+
if (!opt_username || !*opt_username) {
x_fprintf(x_stderr, "username must be specified!\n\n");
exit(1);
@@ -827,8 +860,9 @@ static void manage_client_ntlmssp_request(enum stdio_helper_mode stdio_helper_mo
if (strlen(buf) > 3) {
if(strncmp(buf, "SF ", 3) == 0) {
DEBUG(10, ("Looking for flags to negotiate\n"));
- SAFE_FREE(want_feature_list);
- want_feature_list = SMB_STRNDUP(buf+3, strlen(buf)-3);
+ talloc_free(state->want_feature_list);
+ state->want_feature_list = talloc_strdup(state->mem_ctx,
+ buf+3);
x_fprintf(x_stdout, "OK\n");
return;
}
@@ -840,7 +874,8 @@ static void manage_client_ntlmssp_request(enum stdio_helper_mode stdio_helper_mo
if (strncmp(buf, "PW ", 3) == 0) {
/* We asked for a password and obviously got it :-) */
- opt_password = SMB_STRNDUP((const char *)request.data, request.length);
+ opt_password = SMB_STRNDUP((const char *)request.data,
+ request.length);
if (opt_password == NULL) {
DEBUG(1, ("Out of memory\n"));
@@ -854,8 +889,8 @@ static void manage_client_ntlmssp_request(enum stdio_helper_mode stdio_helper_mo
return;
}
- if (!ntlmssp_state && use_cached_creds) {
- /* check whether credentials are usable. */
+ if (!state->ntlmssp_state && use_cached_creds) {
+ /* check whether cached credentials are usable. */
DATA_BLOB empty_blob = data_blob_null;
nt_status = do_ccache_ntlm_auth(empty_blob, empty_blob, NULL);
@@ -866,30 +901,39 @@ static void manage_client_ntlmssp_request(enum stdio_helper_mode stdio_helper_mo
}
if (opt_password == NULL && !use_cached_creds) {
-
/* Request a password from the calling process. After
- sending it, the calling process should retry asking for the negotiate. */
-
+ sending it, the calling process should retry asking for the
+ negotiate. */
+
DEBUG(10, ("Requesting password\n"));
x_fprintf(x_stdout, "PW\n");
return;
}
if (strncmp(buf, "YR", 2) == 0) {
- if (ntlmssp_state)
- ntlmssp_end(&ntlmssp_state);
+ if (state->ntlmssp_state)
+ ntlmssp_end(&state->ntlmssp_state);
+ state->cli_state = CLIENT_INITIAL;
} else if (strncmp(buf, "TT", 2) == 0) {
-
+ /* No special preprocessing required */
} else if (strncmp(buf, "GF", 2) == 0) {
DEBUG(10, ("Requested negotiated NTLMSSP flags\n"));
- x_fprintf(x_stdout, "GF 0x%08lx\n", have_session_key?neg_flags:0l);
+
+ if(state->cli_state == CLIENT_FINISHED) {
+ x_fprintf(x_stdout, "GF 0x%08x\n", state->neg_flags);
+ }
+ else {
+ x_fprintf(x_stdout, "BH\n");
+ }
+
data_blob_free(&request);
return;
} else if (strncmp(buf, "GK", 2) == 0 ) {
DEBUG(10, ("Requested session key\n"));
- if(have_session_key) {
- char *key64 = base64_encode_data_blob(session_key);
+ if(state->cli_state == CLIENT_FINISHED) {
+ char *key64 = base64_encode_data_blob(state->mem_ctx,
+ state->session_key);
x_fprintf(x_stdout, "GK %s\n", key64?key64:"<NULL>");
TALLOC_FREE(key64);
}
@@ -905,67 +949,75 @@ static void manage_client_ntlmssp_request(enum stdio_helper_mode stdio_helper_mo
return;
}
- if (!ntlmssp_state) {
- if (!NT_STATUS_IS_OK(nt_status = ntlm_auth_start_ntlmssp_client(&ntlmssp_state))) {
+ if (!state->ntlmssp_state) {
+ nt_status = ntlm_auth_start_ntlmssp_client(
+ &state->ntlmssp_state);
+ if (!NT_STATUS_IS_OK(nt_status)) {
x_fprintf(x_stdout, "BH %s\n", nt_errstr(nt_status));
return;
}
- ntlmssp_want_feature_list(ntlmssp_state, want_feature_list);
- first = True;
- initial_message = data_blob_null;
+ ntlmssp_want_feature_list(state->ntlmssp_state,
+ state->want_feature_list);
+ state->initial_message = data_blob_null;
}
DEBUG(10, ("got NTLMSSP packet:\n"));
dump_data(10, request.data, request.length);
- if (use_cached_creds && !opt_password && !first) {
- nt_status = do_ccache_ntlm_auth(initial_message, request, &reply);
+ if (use_cached_creds && !opt_password &&
+ (state->cli_state == CLIENT_RESPONSE)) {
+ nt_status = do_ccache_ntlm_auth(state->initial_message, request,
+ &reply);
} else {
- nt_status = ntlmssp_update(ntlmssp_state, request, &reply);
+ nt_status = ntlmssp_update(state->ntlmssp_state, request,
+ &reply);
}
-
+
if (NT_STATUS_EQUAL(nt_status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
- char *reply_base64 = base64_encode_data_blob(reply);
- if (first) {
+ char *reply_base64 = base64_encode_data_blob(state->mem_ctx,
+ reply);
+ if (state->cli_state == CLIENT_INITIAL) {
x_fprintf(x_stdout, "YR %s\n", reply_base64);
- } else {
- x_fprintf(x_stdout, "KK %s\n", reply_base64);
- }
- TALLOC_FREE(reply_base64);
- if (first) {
- initial_message = reply;
+ state->initial_message = reply;
+ state->cli_state = CLIENT_RESPONSE;
} else {
+ x_fprintf(x_stdout, "KK %s\n", reply_base64);
data_blob_free(&reply);
}
+ TALLOC_FREE(reply_base64);
DEBUG(10, ("NTLMSSP challenge\n"));
} else if (NT_STATUS_IS_OK(nt_status)) {
- char *reply_base64 = base64_encode_data_blob(reply);
+ char *reply_base64 = base64_encode_data_blob(talloc_tos(),
+ reply);
x_fprintf(x_stdout, "AF %s\n", reply_base64);
TALLOC_FREE(reply_base64);
- if(have_session_key)
- data_blob_free(&session_key);
+ if(state->have_session_key)
+ data_blob_free(&state->session_key);
- session_key = data_blob(ntlmssp_state->session_key.data,
- ntlmssp_state->session_key.length);
- neg_flags = ntlmssp_state->neg_flags;
- have_session_key = True;
+ state->session_key = data_blob(
+ state->ntlmssp_state->session_key.data,
+ state->ntlmssp_state->session_key.length);
+ state->neg_flags = state->ntlmssp_state->neg_flags;
+ state->have_session_key = true;
DEBUG(10, ("NTLMSSP OK!\n"));
- if (ntlmssp_state)
- ntlmssp_end(&ntlmssp_state);
+ state->cli_state = CLIENT_FINISHED;
+ if (state->ntlmssp_state)
+ ntlmssp_end(&state->ntlmssp_state);
} else {
x_fprintf(x_stdout, "BH %s\n", nt_errstr(nt_status));
DEBUG(0, ("NTLMSSP BH: %s\n", nt_errstr(nt_status)));
- if (ntlmssp_state)
- ntlmssp_end(&ntlmssp_state);
+ state->cli_state = CLIENT_ERROR;
+ if (state->ntlmssp_state)
+ ntlmssp_end(&state->ntlmssp_state);
}
data_blob_free(&request);
}
-static void manage_squid_basic_request(enum stdio_helper_mode stdio_helper_mode,
- char *buf, int length)
+static void manage_squid_basic_request(struct ntlm_auth_state *state,
+ char *buf, int length)
{
char *user, *pass;
user=buf;
@@ -979,7 +1031,7 @@ static void manage_squid_basic_request(enum stdio_helper_mode stdio_helper_mode,
*pass='\0';
pass++;
- if (stdio_helper_mode == SQUID_2_5_BASIC) {
+ if (state->helper_mode == SQUID_2_5_BASIC) {
rfc1738_unescape(user);
rfc1738_unescape(pass);
}
@@ -1039,7 +1091,7 @@ static void offer_gss_spnego_mechs(void) {
return;
}
- reply_base64 = base64_encode_data_blob(token);
+ reply_base64 = base64_encode_data_blob(talloc_tos(), token);
x_fprintf(x_stdout, "TT %s *\n", reply_base64);
TALLOC_FREE(reply_base64);
@@ -1048,8 +1100,8 @@ static void offer_gss_spnego_mechs(void) {
return;
}
-static void manage_gss_spnego_request(enum stdio_helper_mode stdio_helper_mode,
- char *buf, int length)
+static void manage_gss_spnego_request(struct ntlm_auth_state *state,
+ char *buf, int length)
{
static NTLMSSP_STATE *ntlmssp_state = NULL;
SPNEGO_DATA request, response;
@@ -1276,7 +1328,7 @@ static void manage_gss_spnego_request(enum stdio_helper_mode stdio_helper_mode,
return;
}
- reply_base64 = base64_encode_data_blob(token);
+ reply_base64 = base64_encode_data_blob(talloc_tos(), token);
x_fprintf(x_stdout, "%s %s %s\n",
reply_code, reply_base64, reply_argument);
@@ -1343,7 +1395,7 @@ static bool manage_client_ntlmssp_init(SPNEGO_DATA spnego)
write_spnego_data(&to_server, &spnego);
data_blob_free(&spnego.negTokenInit.mechToken);
- to_server_base64 = base64_encode_data_blob(to_server);
+ to_server_base64 = base64_encode_data_blob(talloc_tos(), to_server);
data_blob_free(&to_server);
x_fprintf(x_stdout, "KK %s\n", to_server_base64);
TALLOC_FREE(to_server_base64);
@@ -1401,7 +1453,7 @@ static void manage_client_ntlmssp_targ(SPNEGO_DATA spnego)
write_spnego_data(&to_server, &spnego);
data_blob_free(&request);
- to_server_base64 = base64_encode_data_blob(to_server);
+ to_server_base64 = base64_encode_data_blob(talloc_tos(), to_server);
data_blob_free(&to_server);
x_fprintf(x_stdout, "KK %s\n", to_server_base64);
TALLOC_FREE(to_server_base64);
@@ -1490,7 +1542,7 @@ static bool manage_client_krb5_init(SPNEGO_DATA spnego)
return False;
}
- reply_base64 = base64_encode_data_blob(to_server);
+ reply_base64 = base64_encode_data_blob(talloc_tos(), to_server);
x_fprintf(x_stdout, "KK %s *\n", reply_base64);
TALLOC_FREE(reply_base64);
@@ -1522,8 +1574,8 @@ static void manage_client_krb5_targ(SPNEGO_DATA spnego)
#endif
-static void manage_gss_spnego_client_request(enum stdio_helper_mode stdio_helper_mode,
- char *buf, int length)
+static void manage_gss_spnego_client_request(struct ntlm_auth_state *state,
+ char *buf, int length)
{
DATA_BLOB request;
SPNEGO_DATA spnego;
@@ -1660,8 +1712,8 @@ static void manage_gss_spnego_client_request(enum stdio_helper_mode stdio_helper
return;
}
-static void manage_ntlm_server_1_request(enum stdio_helper_mode stdio_helper_mode,
- char *buf, int length)
+static void manage_ntlm_server_1_request(struct ntlm_auth_state *state,
+ char *buf, int length)
{
char *request, *parameter;
static DATA_BLOB challenge;
@@ -1853,7 +1905,8 @@ static void manage_ntlm_server_1_request(enum stdio_helper_mode stdio_helper_mod
}
}
-static void manage_ntlm_change_password_1_request(enum stdio_helper_mode helper_mode, char *buf, int length)
+static void manage_ntlm_change_password_1_request(struct ntlm_auth_state *state,
+ char *buf, int length)
{
char *request, *parameter;
static DATA_BLOB new_nt_pswd;
@@ -2063,57 +2116,93 @@ static void manage_ntlm_change_password_1_request(enum stdio_helper_mode helper_
}
}
-static void manage_squid_request(enum stdio_helper_mode helper_mode, stdio_helper_function fn)
+static void manage_squid_request(struct ntlm_auth_state *state,
+ stdio_helper_function fn)
{
- char buf[SQUID_BUFFER_SIZE+1];
- int length;
+ char *buf;
+ char tmp[INITIAL_BUFFER_SIZE+1];
+ int length, buf_size = 0;
char *c;
- static bool err;
- /* this is not a typo - x_fgets doesn't work too well under squid */
- if (fgets(buf, sizeof(buf)-1, stdin) == NULL) {
- if (ferror(stdin)) {
- DEBUG(1, ("fgets() failed! dying..... errno=%d (%s)\n", ferror(stdin),
- strerror(ferror(stdin))));
-
- exit(1); /* BIIG buffer */
- }
- exit(0);
- }
-
- c=(char *)memchr(buf,'\n',sizeof(buf)-1);
- if (c) {
- *c = '\0';
- length = c-buf;
- } else {
- err = 1;
- return;
- }
- if (err) {
- DEBUG(2, ("Oversized message\n"));
+ buf = talloc_strdup(state->mem_ctx, "");
+ if (!buf) {
+ DEBUG(0, ("Failed to allocate input buffer.\n"));
x_fprintf(x_stderr, "ERR\n");
- err = 0;
- return;
+ exit(1);
}
+ do {
+
+ /* this is not a typo - x_fgets doesn't work too well under
+ * squid */
+ if (fgets(tmp, sizeof(tmp)-1, stdin) == NULL) {
+ if (ferror(stdin)) {
+ DEBUG(1, ("fgets() failed! dying..... errno=%d "
+ "(%s)\n", ferror(stdin),
+ strerror(ferror(stdin))));
+
+ exit(1);
+ }
+ exit(0);
+ }
+
+ buf = talloc_strdup_append_buffer(buf, tmp);
+ buf_size += INITIAL_BUFFER_SIZE;
+
+ if (buf_size > MAX_BUFFER_SIZE) {
+ DEBUG(2, ("Oversized message\n"));
+ x_fprintf(x_stderr, "ERR\n");
+ talloc_free(buf);
+ return;
+ }
+
+ c = strchr(buf, '\n');
+ } while (c == NULL);
+
+ *c = '\0';
+ length = c-buf;
+
DEBUG(10, ("Got '%s' from squid (length: %d).\n",buf,length));
if (buf[0] == '\0') {
DEBUG(2, ("Invalid Request\n"));
x_fprintf(x_stderr, "ERR\n");
+ talloc_free(buf);
return;
}
-
- fn(helper_mode, buf, length);
+
+ fn(state, buf, length);
+ talloc_free(buf);
}
static void squid_stream(enum stdio_helper_mode stdio_mode, stdio_helper_function fn) {
+ TALLOC_CTX *mem_ctx;
+ struct ntlm_auth_state *state;
+
/* initialize FDescs */
x_setbuf(x_stdout, NULL);
x_setbuf(x_stderr, NULL);
+
+ mem_ctx = talloc_init("ntlm_auth");
+ if (!mem_ctx) {
+ DEBUG(0, ("squid_stream: Failed to create talloc context\n"));
+ x_fprintf(x_stderr, "ERR\n");
+ exit(1);
+ }
+
+ state = talloc_zero(mem_ctx, struct ntlm_auth_state);
+ if (!state) {
+ DEBUG(0, ("squid_stream: Failed to talloc ntlm_auth_state\n"));
+ x_fprintf(x_stderr, "ERR\n");
+ exit(1);
+ }
+
+ state->mem_ctx = mem_ctx;
+ state->helper_mode = stdio_mode;
+
while(1) {
- manage_squid_request(stdio_mode, fn);
+ manage_squid_request(state, fn);
}
}
diff --git a/source3/winbindd/winbindd_cm.c b/source3/winbindd/winbindd_cm.c
index 908228717e..ef159f0670 100644
--- a/source3/winbindd/winbindd_cm.c
+++ b/source3/winbindd/winbindd_cm.c
@@ -613,7 +613,13 @@ static bool get_dc_name_via_netlogon(struct winbindd_domain *domain,
DS_RETURN_DNS_NAME,
&domain_info);
if (W_ERROR_IS_OK(werr)) {
- fstrcpy(tmp, domain_info->domain_controller_name);
+ tmp = talloc_strdup(
+ mem_ctx, domain_info->domain_controller_name);
+ if (tmp == NULL) {
+ DEBUG(0, ("talloc_strdup failed\n"));
+ talloc_destroy(mem_ctx);
+ return false;
+ }
if (strlen(domain->alt_name) == 0) {
fstrcpy(domain->alt_name,
domain_info->domain_name);
@@ -635,11 +641,10 @@ static bool get_dc_name_via_netlogon(struct winbindd_domain *domain,
/* And restore our original timeout. */
cli_set_timeout(netlogon_pipe->cli, orig_timeout);
- talloc_destroy(mem_ctx);
-
if (!W_ERROR_IS_OK(werr)) {
DEBUG(10, ("rpccli_netlogon_getanydcname failed: %s\n",
dos_errstr(werr)));
+ talloc_destroy(mem_ctx);
return False;
}
@@ -654,6 +659,8 @@ static bool get_dc_name_via_netlogon(struct winbindd_domain *domain,
fstrcpy(dcname, p);
+ talloc_destroy(mem_ctx);
+
DEBUG(10, ("rpccli_netlogon_getanydcname returned %s\n", dcname));
if (!resolve_name(dcname, dc_ss, 0x20)) {
diff --git a/source3/winbindd/winbindd_pam.c b/source3/winbindd/winbindd_pam.c
index 0c75cb17a9..98c9ae2ffe 100644
--- a/source3/winbindd/winbindd_pam.c
+++ b/source3/winbindd/winbindd_pam.c
@@ -31,8 +31,6 @@ static NTSTATUS append_info3_as_txt(TALLOC_CTX *mem_ctx,
struct winbindd_cli_state *state,
NET_USER_INFO_3 *info3)
{
- fstring str_sid;
-
state->response.data.auth.info3.logon_time =
nt_time_to_unix(info3->logon_time);
state->response.data.auth.info3.logoff_time =
@@ -51,8 +49,7 @@ static NTSTATUS append_info3_as_txt(TALLOC_CTX *mem_ctx,
state->response.data.auth.info3.user_rid = info3->user_rid;
state->response.data.auth.info3.group_rid = info3->group_rid;
- sid_to_fstring(str_sid, &(info3->dom_sid.sid));
- fstrcpy(state->response.data.auth.info3.dom_sid, str_sid);
+ sid_to_fstring(state->response.data.auth.info3.dom_sid, &(info3->dom_sid.sid));
state->response.data.auth.info3.num_groups = info3->num_groups;
state->response.data.auth.info3.user_flgs = info3->user_flgs;