diff options
author | Andrew Tridgell <tridge@samba.org> | 2008-01-23 13:08:14 +1100 |
---|---|---|
committer | Andrew Tridgell <tridge@samba.org> | 2008-01-23 13:08:14 +1100 |
commit | 39d172bf34d0cbb3bf3e3a04d534876097cdccb5 (patch) | |
tree | 3a32fd867e34c9a86c3a2f01308445b76bf2d50c /source3 | |
parent | 2caa0e82f5ff2f45a5c912c624e54c4a43f0c3cc (diff) | |
parent | 9051199e40dec27d3532fbec7f5744033def1874 (diff) | |
download | samba-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')
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, ¶m_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 *)®db_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", ¤t_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, ¤t_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; |