summaryrefslogtreecommitdiff
path: root/source3
diff options
context:
space:
mode:
authorJelmer Vernooij <jelmer@samba.org>2009-01-25 05:35:21 +0100
committerJelmer Vernooij <jelmer@samba.org>2009-01-25 05:35:21 +0100
commit5baac15781779a3ebfa3807299e5329809835370 (patch)
tree0ea19612d064f02a8bd9fc62df1bef63da276e67 /source3
parentc9d193eb08b036c5196d63c22790f3cd3583ba82 (diff)
parent8b804077128cd981bf238b2506c589dff3bf8ff4 (diff)
downloadsamba-5baac15781779a3ebfa3807299e5329809835370.tar.gz
samba-5baac15781779a3ebfa3807299e5329809835370.tar.bz2
samba-5baac15781779a3ebfa3807299e5329809835370.zip
Merge branch 'master' of ssh://git.samba.org/data/git/samba
Diffstat (limited to 'source3')
-rw-r--r--source3/Makefile.in9
-rw-r--r--source3/configure.in41
-rw-r--r--source3/include/async_req.h160
-rw-r--r--source3/include/client.h63
-rw-r--r--source3/include/proto.h17
-rw-r--r--source3/include/smb.h7
-rw-r--r--source3/include/smb_macros.h2
-rw-r--r--source3/include/vfs.h4
-rw-r--r--source3/lib/async_req.c340
-rw-r--r--source3/lib/ldb/common/ldb.c13
-rw-r--r--source3/lib/time.c12
-rw-r--r--source3/libaddns/dns.h2
-rw-r--r--source3/modules/nfs4_acls.c84
-rw-r--r--source3/modules/onefs.h13
-rw-r--r--source3/modules/onefs_acl.c238
-rw-r--r--source3/modules/onefs_streams.c128
-rw-r--r--source3/modules/onefs_system.c2
-rw-r--r--source3/modules/vfs_aixacl2.c2
-rw-r--r--source3/modules/vfs_cap.c5
-rw-r--r--source3/modules/vfs_catia.c4
-rw-r--r--source3/modules/vfs_default.c15
-rw-r--r--source3/modules/vfs_full_audit.c6
-rw-r--r--source3/modules/vfs_onefs.c35
-rw-r--r--source3/modules/vfs_recycle.c10
-rw-r--r--source3/modules/vfs_shadow_copy2.c4
-rw-r--r--source3/rpc_client/cli_pipe.c477
-rw-r--r--source3/rpc_client/rpc_transport_np.c329
-rw-r--r--source3/rpc_client/rpc_transport_sock.c116
-rw-r--r--source3/rpc_parse/parse_eventlog.c4
-rw-r--r--source3/rpc_server/srv_eventlog_lib.c2
-rw-r--r--source3/rpc_server/srv_eventlog_nt.c32
-rw-r--r--source3/rpcclient/cmd_eventlog.c264
-rw-r--r--source3/smbd/close.c8
-rw-r--r--source3/smbd/dosmode.c13
-rw-r--r--source3/smbd/posix_acls.c290
-rw-r--r--source3/smbd/reply.c46
-rw-r--r--source3/smbd/trans2.c99
-rw-r--r--source3/torture/cmd_vfs.c11
38 files changed, 1667 insertions, 1240 deletions
diff --git a/source3/Makefile.in b/source3/Makefile.in
index 1924ade8fb..cbbf821b22 100644
--- a/source3/Makefile.in
+++ b/source3/Makefile.in
@@ -340,7 +340,7 @@ LIB_OBJ = $(LIBSAMBAUTIL_OBJ) $(UTIL_OBJ) $(CRYPTO_OBJ) \
lib/messages.o librpc/gen_ndr/ndr_messaging.o lib/messages_local.o \
lib/messages_ctdbd.o lib/packet.o lib/ctdbd_conn.o \
lib/interfaces.o lib/memcache.o \
- lib/util_transfer_file.o lib/async_req.o \
+ lib/util_transfer_file.o ../lib/async_req/async_req.o \
lib/async_sock.o \
$(TDB_LIB_OBJ) \
$(VERSION_OBJ) lib/charcnv.o lib/debug.o lib/fault.o \
@@ -576,7 +576,8 @@ RPC_PARSE_OBJ = $(RPC_PARSE_OBJ2) \
rpc_parse/parse_spoolss.o \
rpc_parse/parse_eventlog.o rpc_parse/parse_buffer.o
-RPC_CLIENT_OBJ = rpc_client/cli_pipe.o
+RPC_CLIENT_OBJ = rpc_client/cli_pipe.o rpc_client/rpc_transport_np.o \
+ rpc_client/rpc_transport_sock.o
LOCKING_OBJ = locking/locking.o locking/brlock.o locking/posix.o
@@ -761,7 +762,7 @@ SMBCONTROL_OBJ = utils/smbcontrol.o $(LOCKING_OBJ) $(PARAM_OBJ) \
SMBTREE_OBJ = utils/smbtree.o $(PARAM_OBJ) \
$(PROFILE_OBJ) $(LIB_NONSMBD_OBJ) $(LIBSMB_OBJ) \
$(KRBCLIENT_OBJ) $(POPT_LIB_OBJ) \
- rpc_client/cli_pipe.o ../librpc/rpc/binding.o $(RPC_PARSE_OBJ2) \
+ $(RPC_CLIENT_OBJ) ../librpc/rpc/binding.o $(RPC_PARSE_OBJ2) \
$(RPC_CLIENT_OBJ1) \
$(PASSDB_OBJ) @LIBWBCLIENT_STATIC@ $(SMBLDAP_OBJ) $(LDB_OBJ) $(GROUPDB_OBJ) \
$(LIBMSRPC_GEN_OBJ)
@@ -844,7 +845,7 @@ LIBBIGBALLOFMUD_OBJ = $(PARAM_OBJ) $(LIB_NONSMBD_OBJ) \
$(LIBSMB_OBJ) $(LIBMSRPC_OBJ) $(LIBMSRPC_GEN_OBJ) $(RPC_PARSE_OBJ) $(PASSDB_OBJ) @LIBWBCLIENT_STATIC@ \
$(GROUPDB_OBJ) $(KRBCLIENT_OBJ) $(SMBLDAP_OBJ) $(LDB_OBJ)
-CLIENT_OBJ1 = client/client.o client/clitar.o rpc_client/cli_pipe.o \
+CLIENT_OBJ1 = client/client.o client/clitar.o $(RPC_CLIENT_OBJ) \
../librpc/rpc/binding.o \
client/dnsbrowse.o \
$(RPC_CLIENT_OBJ1) \
diff --git a/source3/configure.in b/source3/configure.in
index 44a932c6f5..321924889a 100644
--- a/source3/configure.in
+++ b/source3/configure.in
@@ -63,6 +63,7 @@ SAMBA_CPPFLAGS="${SAMBA_CPPFLAGS} ${TEVENT_CFLAGS}"
SAMBA_CPPFLAGS="${SAMBA_CPPFLAGS} ${TDB_CFLAGS}"
SAMBA_CPPFLAGS="${SAMBA_CPPFLAGS} -I${srcdir-.}/libaddns"
SAMBA_CPPFLAGS="${SAMBA_CPPFLAGS} -I${srcdir-.}/librpc"
+SAMBA_CPPFLAGS="${SAMBA_CPPFLAGS} -I${srcdir-.}/../lib/async_req"
SAMBA_CONFIGURE_CPPFLAGS="${SAMBA_CPPFLAGS} -I${srcdir-.}/../lib/popt"
@@ -1307,7 +1308,8 @@ fi
#################################################
# Check whether struct stat has timestamps with sub-second resolution.
-# At least IRIX and Solaris have these.
+# At least IRIX and Solaris have these. FREEBSD does as well,
+# but with different members
#
# We check that
# all of st_mtim, st_atim and st_ctim exist
@@ -1316,6 +1318,43 @@ fi
# There is some conflicting standards weirdness about whether we should use
# "struct timespec" or "timespec_t". Linux doesn't have timespec_t, so we
# prefer struct timespec.
+AC_CACHE_CHECK([whether struct stat has timespec timestamps],
+ samba_cv_stat_timespec_hires,
+ [
+ AC_TRY_COMPILE(
+ [
+#if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+#else
+# if HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else
+# include <time.h>
+# endif
+#endif
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+ ],
+ [
+ struct timespec t;
+ struct stat s = {0};
+ t = s.st_mtimespec;
+ t = s.st_ctimespec;
+ t = s.st_atimespec;
+ ],
+ samba_cv_stat_timespec_hires=yes, samba_cv_stat_timespec_hires=no)
+ ])
+
+if test x"$samba_cv_stat_timespec_hires" = x"yes" ; then
+ AC_DEFINE(HAVE_STAT_ST_MTIMESPEC, 1, [whether struct stat contains st_mtimepec])
+ AC_DEFINE(HAVE_STAT_ST_ATIMESPEC, 1, [whether struct stat contains st_atimespec])
+ AC_DEFINE(HAVE_STAT_ST_CTIMESPEC, 1, [whether struct stat contains st_ctimespec])
+ AC_DEFINE(HAVE_STAT_HIRES_TIMESTAMPS, 1, [whether struct stat has sub-second timestamps])
+fi
+
+
AC_CACHE_CHECK([whether struct stat has sub-second timestamps], samba_cv_stat_hires,
[
diff --git a/source3/include/async_req.h b/source3/include/async_req.h
deleted file mode 100644
index 3907a08f67..0000000000
--- a/source3/include/async_req.h
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- Unix SMB/CIFS implementation.
- Infrastructure for async requests
- Copyright (C) Volker Lendecke 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/>.
-*/
-
-#ifndef __ASYNC_REQ_H__
-#define __ASYNC_REQ_H__
-
-#include "includes.h"
-
-/**
- * An async request moves between the following 4 states:
- */
-
-enum async_req_state {
- /**
- * we are creating the request
- */
- ASYNC_REQ_INIT,
- /**
- * we are waiting the request to complete
- */
- ASYNC_REQ_IN_PROGRESS,
- /**
- * the request is finished
- */
- ASYNC_REQ_DONE,
- /**
- * an error has occured
- */
- ASYNC_REQ_ERROR
-};
-
-/**
- * @brief An async request
- *
- * This represents an async request being processed by callbacks via an event
- * context. A user can issue for example a write request to a socket, giving
- * an implementation function the fd, the buffer and the number of bytes to
- * transfer. The function issuing the request will immediately return without
- * blocking most likely without having sent anything. The API user then fills
- * in req->async.fn and req->async.priv, functions that are called when the
- * request is finished.
- *
- * It is up to the user of the async request to talloc_free it after it has
- * finished. This can happen while the completion function is called.
- */
-
-struct async_req {
- /**
- * @brief The external state - will be queried by the caller
- *
- * While the async request is being processed, state will remain in
- * ASYNC_REQ_IN_PROGRESS. A request is finished if
- * req->state>=ASYNC_REQ_DONE.
- */
- enum async_req_state state;
-
- /**
- * @brief Private pointer for the actual implementation
- *
- * The implementation doing the work for the async request needs a
- * current state like for example a fd event. The user of an async
- * request should not touch this.
- */
- void *private_data;
-
- /**
- * @brief Print yourself, for debugging purposes
- *
- * Async requests are opaque data structures. The implementation of an
- * async request can define a custom function to print more debug
- * info.
- */
- char *(*print)(TALLOC_CTX *mem_ctx, struct async_req *);
-
- /**
- * @brief status code when finished
- *
- * This status can be queried in the async completion function. It
- * will be set to NT_STATUS_OK when everything went fine.
- **/
- NTSTATUS status;
-
- /**
- * @brief What to do on completion
- *
- * This is used for the user of an async request, fn is called when
- * the request completes, either successfully or with an error.
- */
- struct {
- /**
- * @brief Completion function
- * Completion function, to be filled by the API user
- */
- void (*fn)(struct async_req *);
- /**
- * @brief Private data for the completion function
- */
- void *priv;
- } async;
-};
-
-struct async_req *async_req_new(TALLOC_CTX *mem_ctx);
-
-char *async_req_print(TALLOC_CTX *mem_ctx, struct async_req *req);
-
-void async_req_done(struct async_req *req);
-
-void async_req_error(struct async_req *req, NTSTATUS status);
-
-bool async_post_status(struct async_req *req, struct event_context *ev,
- NTSTATUS status);
-
-bool async_req_nomem(const void *p, struct async_req *req);
-
-bool async_req_is_error(struct async_req *req, NTSTATUS *status);
-
-NTSTATUS async_req_simple_recv(struct async_req *req);
-
-bool async_req_set_timeout(struct async_req *req, struct event_context *ev,
- struct timeval to);
-
-struct async_req *async_wait_send(TALLOC_CTX *mem_ctx,
- struct event_context *ev,
- struct timeval to);
-
-NTSTATUS async_wait_recv(struct async_req *req);
-
-struct async_req_queue;
-
-struct async_req_queue *async_req_queue_init(TALLOC_CTX *mem_ctx);
-
-bool async_req_enqueue(struct async_req_queue *queue,
- struct event_context *ev,
- struct async_req *req,
- void (*trigger)(struct async_req *req));
-
-bool _async_req_setup(TALLOC_CTX *mem_ctx, struct async_req **preq,
- void *pstate, size_t state_size, const char *typename);
-
-#define async_req_setup(_mem_ctx, _preq, _pstate, type) \
- _async_req_setup((_mem_ctx), (_preq), (_pstate), sizeof(type), #type)
-
-
-#endif
diff --git a/source3/include/client.h b/source3/include/client.h
index 09fdb81462..d62d1c05d2 100644
--- a/source3/include/client.h
+++ b/source3/include/client.h
@@ -61,21 +61,60 @@ struct cli_pipe_auth_data {
} a_u;
};
+/**
+ * rpc_cli_transport defines a transport mechanism to ship rpc requests
+ * asynchronously to a server and receive replies
+ */
+
+struct rpc_cli_transport {
+
+ /**
+ * Trigger an async read from the server. May return a short read.
+ */
+ struct async_req *(*read_send)(TALLOC_CTX *mem_ctx,
+ struct event_context *ev,
+ uint8_t *data, size_t size,
+ void *priv);
+ /**
+ * Get the result from the read_send operation.
+ */
+ NTSTATUS (*read_recv)(struct async_req *req, ssize_t *preceived);
+
+ /**
+ * Trigger an async write to the server. May return a short write.
+ */
+ struct async_req *(*write_send)(TALLOC_CTX *mem_ctx,
+ struct event_context *ev,
+ const uint8_t *data, size_t size,
+ void *priv);
+ /**
+ * Get the result from the read_send operation.
+ */
+ NTSTATUS (*write_recv)(struct async_req *req, ssize_t *psent);
+
+ /**
+ * This is an optimization for the SMB transport. It models the
+ * TransactNamedPipe API call: Send and receive data in one round
+ * trip. The transport implementation is free to set this to NULL,
+ * cli_pipe.c will fall back to the explicit write/read routines.
+ */
+ struct async_req *(*trans_send)(TALLOC_CTX *mem_ctx,
+ struct event_context *ev,
+ uint8_t *data, size_t data_len,
+ uint32_t max_rdata_len,
+ void *priv);
+ /**
+ * Get the result from the read_send operation.
+ */
+ NTSTATUS (*trans_recv)(struct async_req *req, TALLOC_CTX *mem_ctx,
+ uint8_t **prdata, uint32_t *prdata_len);
+ void *priv;
+};
+
struct rpc_pipe_client {
struct rpc_pipe_client *prev, *next;
- enum dcerpc_transport_t transport_type;
-
- union {
- struct {
- struct cli_state *cli;
- const char *pipe_name;
- uint16 fnum;
- } np;
- struct {
- int fd;
- } sock;
- } trans ;
+ struct rpc_cli_transport *transport;
struct ndr_syntax_id abstract_syntax;
struct ndr_syntax_id transfer_syntax;
diff --git a/source3/include/proto.h b/source3/include/proto.h
index d55546f94c..1414ba89ec 100644
--- a/source3/include/proto.h
+++ b/source3/include/proto.h
@@ -5216,7 +5216,6 @@ NTSTATUS rpc_pipe_bind(struct rpc_pipe_client *cli,
unsigned int rpccli_set_timeout(struct rpc_pipe_client *cli,
unsigned int timeout);
bool rpccli_get_pwd_hash(struct rpc_pipe_client *cli, uint8_t nt_hash[16]);
-struct cli_state *rpc_pipe_np_smb_conn(struct rpc_pipe_client *p);
NTSTATUS rpccli_anon_bind_data(TALLOC_CTX *mem_ctx,
struct cli_pipe_auth_data **presult);
NTSTATUS rpccli_ntlmssp_bind_data(TALLOC_CTX *mem_ctx,
@@ -5296,6 +5295,17 @@ NTSTATUS cli_get_session_key(TALLOC_CTX *mem_ctx,
struct rpc_pipe_client *cli,
DATA_BLOB *session_key);
+/* The following definitions come from rpc_client/rpc_transport_np.c */
+
+NTSTATUS rpc_transport_np_init(TALLOC_CTX *mem_ctx, struct cli_state *cli,
+ const struct ndr_syntax_id *abstract_syntax,
+ struct rpc_cli_transport **presult);
+struct cli_state *rpc_pipe_np_smb_conn(struct rpc_pipe_client *p);
+
+/* The following definitions come from rpc_client/rpc_transport_sock.c */
+
+NTSTATUS rpc_transport_sock_init(TALLOC_CTX *mem_ctx, int fd,
+ struct rpc_cli_transport **presult);
/* The following definitions come from rpc_client/cli_reg.c */
@@ -6678,7 +6688,8 @@ int file_set_dosmode(connection_struct *conn, const char *fname,
uint32 dosmode, SMB_STRUCT_STAT *st,
const char *parent_dir,
bool newfile);
-int file_ntimes(connection_struct *conn, const char *fname, const struct timespec ts[2]);
+int file_ntimes(connection_struct *conn, const char *fname,
+ struct smb_file_time *ft);
bool set_sticky_write_time_path(connection_struct *conn, const char *fname,
struct file_id fileid, const struct timespec mtime);
bool set_sticky_write_time_fsp(struct files_struct *fsp, const struct timespec mtime);
@@ -7414,7 +7425,7 @@ NTSTATUS smb_set_file_time(connection_struct *conn,
files_struct *fsp,
const char *fname,
const SMB_STRUCT_STAT *psbuf,
- struct timespec ts[2],
+ struct smb_file_time *ft,
bool setting_write_time);
void reply_findclose(struct smb_request *req);
void reply_findnclose(struct smb_request *req);
diff --git a/source3/include/smb.h b/source3/include/smb.h
index 19d2208ada..aa2db693a3 100644
--- a/source3/include/smb.h
+++ b/source3/include/smb.h
@@ -1901,4 +1901,11 @@ struct smb_extended_info {
*/
#define CFF_DOS_PATH 0x00000001
+/* time info */
+struct smb_file_time {
+ struct timespec mtime;
+ struct timespec atime;
+ struct timespec create_time;
+};
+
#endif /* _SMB_H */
diff --git a/source3/include/smb_macros.h b/source3/include/smb_macros.h
index 5149da0cb3..92c60a7530 100644
--- a/source3/include/smb_macros.h
+++ b/source3/include/smb_macros.h
@@ -256,7 +256,7 @@ NULL returns on zero request. JRA.
#define TALLOC_REALLOC(ctx, ptr, count) _talloc_realloc(ctx, ptr, count, __location__)
#define TALLOC_REALLOC_ARRAY(ctx, ptr, type, count) (type *)_talloc_realloc_array(ctx, ptr, sizeof(type), count, #type)
#define talloc_destroy(ctx) talloc_free(ctx)
-#define TALLOC_FREE(ctx) do { if ((ctx) != NULL) {talloc_free(ctx); ctx=NULL;} } while(0)
+#define TALLOC_FREE(ctx) do { talloc_free(ctx); ctx=NULL; } while(0)
/* only define PARANOID_MALLOC_CHECKER with --enable-developer */
diff --git a/source3/include/vfs.h b/source3/include/vfs.h
index d02d14b854..5df71da905 100644
--- a/source3/include/vfs.h
+++ b/source3/include/vfs.h
@@ -111,6 +111,7 @@
/* Changed to version 24 - make security descriptor const in fset_nt_acl. JRA. */
/* Changed to version 25 - Jelmer's change from SMB_BIG_UINT to uint64_t. */
/* Leave at 25 - not yet released. Add create_file call. -- tprouty. */
+/* Leave at 25 - not yet released. Add create time to ntimes. -- tstecher. */
#define SMB_VFS_INTERFACE_VERSION 25
@@ -137,6 +138,7 @@ struct security_descriptor;
struct vfs_statvfs_struct;
struct smb_request;
struct ea_list;
+struct smb_file_time;
/*
Available VFS operations. These values must be in sync with vfs_ops struct
@@ -348,7 +350,7 @@ struct vfs_ops {
int (*lchown)(struct vfs_handle_struct *handle, const char *path, uid_t uid, gid_t gid);
int (*chdir)(struct vfs_handle_struct *handle, const char *path);
char *(*getwd)(struct vfs_handle_struct *handle, char *buf);
- int (*ntimes)(struct vfs_handle_struct *handle, const char *path, const struct timespec ts[2]);
+ int (*ntimes)(struct vfs_handle_struct *handle, const char *path, struct smb_file_time *ft);
int (*ftruncate)(struct vfs_handle_struct *handle, struct files_struct *fsp, SMB_OFF_T offset);
bool (*lock)(struct vfs_handle_struct *handle, struct files_struct *fsp, int op, SMB_OFF_T offset, SMB_OFF_T count, int type);
int (*kernel_flock)(struct vfs_handle_struct *handle, struct files_struct *fsp, uint32 share_mode);
diff --git a/source3/lib/async_req.c b/source3/lib/async_req.c
deleted file mode 100644
index 011948a158..0000000000
--- a/source3/lib/async_req.c
+++ /dev/null
@@ -1,340 +0,0 @@
-/*
- Unix SMB/CIFS implementation.
- Infrastructure for async requests
- Copyright (C) Volker Lendecke 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/>.
-*/
-
-#include "includes.h"
-
-/**
- * @brief Print an async_req structure
- * @param[in] mem_ctx The memory context for the result
- * @param[in] req The request to be printed
- * @retval Text representation of req
- *
- * This is a default print function for async requests. Implementations should
- * override this with more specific information.
- *
- * This function should not be used by async API users, this is non-static
- * only to allow implementations to easily provide default information in
- * their specific functions.
- */
-
-char *async_req_print(TALLOC_CTX *mem_ctx, struct async_req *req)
-{
- return talloc_asprintf(mem_ctx, "async_req: state=%d, status=%s, "
- "priv=%s", req->state, nt_errstr(req->status),
- talloc_get_name(req->private_data));
-}
-
-/**
- * @brief Create an async request
- * @param[in] mem_ctx The memory context for the result
- * @param[in] ev The event context this async request will be driven by
- * @retval A new async request
- *
- * The new async request will be initialized in state ASYNC_REQ_IN_PROGRESS
- */
-
-struct async_req *async_req_new(TALLOC_CTX *mem_ctx)
-{
- struct async_req *result;
-
- result = TALLOC_ZERO_P(mem_ctx, struct async_req);
- if (result == NULL) {
- return NULL;
- }
- result->state = ASYNC_REQ_IN_PROGRESS;
- result->print = async_req_print;
- return result;
-}
-
-/**
- * @brief An async request has successfully finished
- * @param[in] req The finished request
- *
- * async_req_done is to be used by implementors of async requests. When a
- * request is successfully finished, this function calls the user's completion
- * function.
- */
-
-void async_req_done(struct async_req *req)
-{
- req->status = NT_STATUS_OK;
- req->state = ASYNC_REQ_DONE;
- if (req->async.fn != NULL) {
- req->async.fn(req);
- }
-}
-
-/**
- * @brief An async request has seen an error
- * @param[in] req The request with an error
- * @param[in] status The error code
- *
- * async_req_done is to be used by implementors of async requests. When a
- * request can not successfully completed, the implementation should call this
- * function with the appropriate status code.
- */
-
-void async_req_error(struct async_req *req, NTSTATUS status)
-{
- req->status = status;
- req->state = ASYNC_REQ_ERROR;
- if (req->async.fn != NULL) {
- req->async.fn(req);
- }
-}
-
-/**
- * @brief Timed event callback
- * @param[in] ev Event context
- * @param[in] te The timed event
- * @param[in] now zero time
- * @param[in] priv The async request to be finished
- */
-
-static void async_trigger(struct event_context *ev, struct timed_event *te,
- struct timeval now, void *priv)
-{
- struct async_req *req = talloc_get_type_abort(priv, struct async_req);
-
- TALLOC_FREE(te);
- if (NT_STATUS_IS_OK(req->status)) {
- async_req_done(req);
- }
- else {
- async_req_error(req, req->status);
- }
-}
-
-/**
- * @brief Finish a request before it started processing
- * @param[in] req The finished request
- * @param[in] status The success code
- *
- * An implementation of an async request might find that it can either finish
- * the request without waiting for an external event, or it can't even start
- * the engine. To present the illusion of a callback to the user of the API,
- * the implementation can call this helper function which triggers an
- * immediate timed event. This way the caller can use the same calling
- * conventions, independent of whether the request was actually deferred.
- */
-
-bool async_post_status(struct async_req *req, struct event_context *ev,
- NTSTATUS status)
-{
- req->status = status;
-
- if (event_add_timed(ev, req, timeval_zero(),
- async_trigger, req) == NULL) {
- return false;
- }
- return true;
-}
-
-/**
- * @brief Helper function for nomem check
- * @param[in] p The pointer to be checked
- * @param[in] req The request being processed
- *
- * Convenience helper to easily check alloc failure within a callback
- * implementing the next step of an async request.
- *
- * Call pattern would be
- * \code
- * p = talloc(mem_ctx, bla);
- * if (async_req_nomem(p, req)) {
- * return;
- * }
- * \endcode
- */
-
-bool async_req_nomem(const void *p, struct async_req *req)
-{
- if (p != NULL) {
- return false;
- }
- async_req_error(req, NT_STATUS_NO_MEMORY);
- return true;
-}
-
-bool async_req_is_error(struct async_req *req, NTSTATUS *status)
-{
- if (req->state < ASYNC_REQ_DONE) {
- *status = NT_STATUS_INTERNAL_ERROR;
- return true;
- }
- if (req->state == ASYNC_REQ_ERROR) {
- *status = req->status;
- return true;
- }
- return false;
-}
-
-NTSTATUS async_req_simple_recv(struct async_req *req)
-{
- NTSTATUS status;
-
- if (async_req_is_error(req, &status)) {
- return status;
- }
- return NT_STATUS_OK;
-}
-
-static void async_req_timedout(struct event_context *ev,
- struct timed_event *te,
- struct timeval now,
- void *priv)
-{
- struct async_req *req = talloc_get_type_abort(
- priv, struct async_req);
- TALLOC_FREE(te);
- async_req_error(req, NT_STATUS_IO_TIMEOUT);
-}
-
-bool async_req_set_timeout(struct async_req *req, struct event_context *ev,
- struct timeval to)
-{
- return (event_add_timed(ev, req,
- timeval_current_ofs(to.tv_sec, to.tv_usec),
- async_req_timedout, req)
- != NULL);
-}
-
-struct async_req *async_wait_send(TALLOC_CTX *mem_ctx,
- struct event_context *ev,
- struct timeval to)
-{
- struct async_req *result;
-
- result = async_req_new(mem_ctx);
- if (result == NULL) {
- return result;
- }
- if (!async_req_set_timeout(result, ev, to)) {
- TALLOC_FREE(result);
- return NULL;
- }
- return result;
-}
-
-NTSTATUS async_wait_recv(struct async_req *req)
-{
- return NT_STATUS_OK;
-}
-
-struct async_queue_entry {
- struct async_queue_entry *prev, *next;
- struct async_req_queue *queue;
- struct async_req *req;
- void (*trigger)(struct async_req *req);
-};
-
-struct async_req_queue {
- struct async_queue_entry *queue;
-};
-
-struct async_req_queue *async_req_queue_init(TALLOC_CTX *mem_ctx)
-{
- return TALLOC_ZERO_P(mem_ctx, struct async_req_queue);
-}
-
-static int async_queue_entry_destructor(struct async_queue_entry *e)
-{
- struct async_req_queue *queue = e->queue;
-
- DLIST_REMOVE(queue->queue, e);
-
- if (queue->queue != NULL) {
- queue->queue->trigger(queue->queue->req);
- }
-
- return 0;
-}
-
-static void async_req_immediate_trigger(struct event_context *ev,
- struct timed_event *te,
- struct timeval now,
- void *priv)
-{
- struct async_queue_entry *e = talloc_get_type_abort(
- priv, struct async_queue_entry);
-
- TALLOC_FREE(te);
- e->trigger(e->req);
-}
-
-bool async_req_enqueue(struct async_req_queue *queue, struct event_context *ev,
- struct async_req *req,
- void (*trigger)(struct async_req *req))
-{
- struct async_queue_entry *e;
- bool busy;
-
- busy = (queue->queue != NULL);
-
- e = talloc(req, struct async_queue_entry);
- if (e == NULL) {
- return false;
- }
-
- e->req = req;
- e->trigger = trigger;
- e->queue = queue;
-
- DLIST_ADD_END(queue->queue, e, struct async_queue_entry *);
- talloc_set_destructor(e, async_queue_entry_destructor);
-
- if (!busy) {
- struct timed_event *te;
-
- te = event_add_timed(ev, e, timeval_zero(),
- async_req_immediate_trigger,
- e);
- if (te == NULL) {
- TALLOC_FREE(e);
- return false;
- }
- }
-
- return true;
-}
-
-bool _async_req_setup(TALLOC_CTX *mem_ctx, struct async_req **preq,
- void *pstate, size_t state_size, const char *typename)
-{
- struct async_req *req;
- void **ppstate = (void **)pstate;
- void *state;
-
- req = async_req_new(mem_ctx);
- if (req == NULL) {
- return false;
- }
- state = talloc_size(req, state_size);
- if (state == NULL) {
- TALLOC_FREE(req);
- return false;
- }
- talloc_set_name(state, typename);
- req->private_data = state;
-
- *preq = req;
- *ppstate = state;
-
- return true;
-}
diff --git a/source3/lib/ldb/common/ldb.c b/source3/lib/ldb/common/ldb.c
index 6e28528dbf..cef7373c26 100644
--- a/source3/lib/ldb/common/ldb.c
+++ b/source3/lib/ldb/common/ldb.c
@@ -808,15 +808,18 @@ int ldb_search(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_result *
va_list ap;
int ret;
+ expression = NULL;
res = NULL;
*result = NULL;
- va_start(ap, exp_fmt);
- expression = talloc_vasprintf(mem_ctx, exp_fmt, ap);
- va_end(ap);
+ if (exp_fmt) {
+ va_start(ap, exp_fmt);
+ expression = talloc_vasprintf(mem_ctx, exp_fmt, ap);
+ va_end(ap);
- if ( ! expression) {
- return LDB_ERR_OPERATIONS_ERROR;
+ if ( ! expression) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
}
ret = _ldb_search(ldb, ldb, &res, base, scope, attrs, expression);
diff --git a/source3/lib/time.c b/source3/lib/time.c
index cae6b479b0..7dd0da8fa8 100644
--- a/source3/lib/time.c
+++ b/source3/lib/time.c
@@ -404,6 +404,8 @@ struct timespec get_atimespec(const SMB_STRUCT_STAT *pst)
ret.tv_sec = pst->st_atime;
ret.tv_nsec = pst->st_atimensec;
return ret;
+#elif defined(HAVE_STAT_ST_ATIMESPEC)
+ return pst->st_atimespec;
#else
#error CONFIGURE_ERROR_IN_DETECTING_TIMESPEC_IN_STAT
#endif
@@ -421,6 +423,8 @@ void set_atimespec(SMB_STRUCT_STAT *pst, struct timespec ts)
#elif defined(HAVE_STAT_ST_ATIMENSEC)
pst->st_atime = ts.tv_sec;
pst->st_atimensec = ts.tv_nsec
+#elif defined(HAVE_STAT_ST_ATIMESPEC)
+ pst->st_atimespec = ts;
#else
#error CONFIGURE_ERROR_IN_DETECTING_TIMESPEC_IN_STAT
#endif
@@ -444,6 +448,8 @@ struct timespec get_mtimespec(const SMB_STRUCT_STAT *pst)
ret.tv_sec = pst->st_mtime;
ret.tv_nsec = pst->st_mtimensec;
return ret;
+#elif defined(HAVE_STAT_ST_MTIMESPEC)
+ return pst->st_mtimespec;
#else
#error CONFIGURE_ERROR_IN_DETECTING_TIMESPEC_IN_STAT
#endif
@@ -461,6 +467,8 @@ void set_mtimespec(SMB_STRUCT_STAT *pst, struct timespec ts)
#elif defined(HAVE_STAT_ST_MTIMENSEC)
pst->st_mtime = ts.tv_sec;
pst->st_mtimensec = ts.tv_nsec
+#elif defined(HAVE_STAT_ST_ATIMESPEC)
+ pst->st_atimespec = ts;
#else
#error CONFIGURE_ERROR_IN_DETECTING_TIMESPEC_IN_STAT
#endif
@@ -484,6 +492,8 @@ struct timespec get_ctimespec(const SMB_STRUCT_STAT *pst)
ret.tv_sec = pst->st_ctime;
ret.tv_nsec = pst->st_ctimensec;
return ret;
+#elif defined(HAVE_STAT_ST_CTIMESPEC)
+ return pst->st_ctimespec;
#else
#error CONFIGURE_ERROR_IN_DETECTING_TIMESPEC_IN_STAT
#endif
@@ -501,6 +511,8 @@ void set_ctimespec(SMB_STRUCT_STAT *pst, struct timespec ts)
#elif defined(HAVE_STAT_ST_CTIMENSEC)
pst->st_ctime = ts.tv_sec;
pst->st_ctimensec = ts.tv_nsec
+#elif defined(HAVE_STAT_ST_CTIMESPEC)
+ pst->st_ctimespec = ts;
#else
#error CONFIGURE_ERROR_IN_DETECTING_TIMESPEC_IN_STAT
#endif
diff --git a/source3/libaddns/dns.h b/source3/libaddns/dns.h
index 3f95c739d5..42662a224b 100644
--- a/source3/libaddns/dns.h
+++ b/source3/libaddns/dns.h
@@ -133,7 +133,7 @@ void *talloc_zeronull(const void *context, size_t size, const char *name);
#define TALLOC_REALLOC(ctx, ptr, count) _talloc_realloc(ctx, ptr, count, __location__)
#define TALLOC_REALLOC_ARRAY(ctx, ptr, type, count) (type *)_talloc_realloc_array(ctx, ptr, sizeof(type), count, #type)
#define talloc_destroy(ctx) talloc_free(ctx)
-#define TALLOC_FREE(ctx) do { if ((ctx) != NULL) {talloc_free(ctx); ctx=NULL;} } while(0)
+#define TALLOC_FREE(ctx) do { talloc_free(ctx); ctx=NULL; } while(0)
/*******************************************************************
Type definitions for int16, int32, uint16 and uint32. Needed
diff --git a/source3/modules/nfs4_acls.c b/source3/modules/nfs4_acls.c
index f411176590..556dad6b5e 100644
--- a/source3/modules/nfs4_acls.c
+++ b/source3/modules/nfs4_acls.c
@@ -698,9 +698,10 @@ NTSTATUS smb_set_nt_acl_nfs4(files_struct *fsp,
bool result;
SMB_STRUCT_STAT sbuf;
- bool need_chown = False;
+ bool set_acl_as_root = false;
uid_t newUID = (uid_t)-1;
gid_t newGID = (gid_t)-1;
+ int saved_errno;
DEBUG(10, ("smb_set_nt_acl_nfs4 invoked for %s\n", fsp->fsp_name));
@@ -728,59 +729,48 @@ NTSTATUS smb_set_nt_acl_nfs4(files_struct *fsp,
}
if (((newUID != (uid_t)-1) && (sbuf.st_uid != newUID)) ||
((newGID != (gid_t)-1) && (sbuf.st_gid != newGID))) {
- need_chown = True;
- }
- if (need_chown) {
- if ((newUID == (uid_t)-1
- || newUID == fsp->conn->server_info->utok.uid)) {
- if(try_chown(fsp->conn, fsp->fsp_name, newUID, newGID)) {
- DEBUG(3,("chown %s, %u, %u failed. Error = %s.\n",
- fsp->fsp_name, (unsigned int)newUID, (unsigned int)newGID,
- strerror(errno)));
- return map_nt_error_from_unix(errno);
- }
-
- DEBUG(10,("chown %s, %u, %u succeeded.\n",
- fsp->fsp_name, (unsigned int)newUID, (unsigned int)newGID));
- if (smbacl4_GetFileOwner(fsp->conn, fsp->fsp_name, &sbuf))
- return map_nt_error_from_unix(errno);
- need_chown = False;
- } else { /* chown is needed, but _after_ changing acl */
- sbuf.st_uid = newUID; /* OWNER@ in case of e_special */
- sbuf.st_gid = newGID; /* GROUP@ in case of e_special */
+ if(try_chown(fsp->conn, fsp->fsp_name, newUID, newGID)) {
+ DEBUG(3,("chown %s, %u, %u failed. Error = %s.\n",
+ fsp->fsp_name, (unsigned int)newUID, (unsigned int)newGID,
+ strerror(errno)));
+ return map_nt_error_from_unix(errno);
}
+
+ DEBUG(10,("chown %s, %u, %u succeeded.\n",
+ fsp->fsp_name, (unsigned int)newUID, (unsigned int)newGID));
+ if (smbacl4_GetFileOwner(fsp->conn, fsp->fsp_name, &sbuf))
+ return map_nt_error_from_unix(errno);
+
+ /* If we successfully chowned, we know we must
+ * be able to set the acl, so do it as root.
+ */
+ set_acl_as_root = true;
}
}
- if ((security_info_sent & DACL_SECURITY_INFORMATION)!=0 && psd->dacl!=NULL)
- {
- acl = smbacl4_win2nfs4(fsp->fsp_name, psd->dacl, &params, sbuf.st_uid, sbuf.st_gid);
- if (!acl)
- return map_nt_error_from_unix(errno);
+ if (!(security_info_sent & DACL_SECURITY_INFORMATION) || psd->dacl ==NULL) {
+ DEBUG(10, ("no dacl found; security_info_sent = 0x%x\n", security_info_sent));
+ return NT_STATUS_OK;
+ }
- smbacl4_dump_nfs4acl(10, acl);
+ acl = smbacl4_win2nfs4(fsp->fsp_name, psd->dacl, &params, sbuf.st_uid, sbuf.st_gid);
+ if (!acl)
+ return map_nt_error_from_unix(errno);
- result = set_nfs4_native(fsp, acl);
- if (result!=True)
- {
- DEBUG(10, ("set_nfs4_native failed with %s\n", strerror(errno)));
- return map_nt_error_from_unix(errno);
- }
- } else
- DEBUG(10, ("no dacl found; security_info_sent = 0x%x\n", security_info_sent));
+ smbacl4_dump_nfs4acl(10, acl);
- /* Any chown pending? */
- if (need_chown) {
- DEBUG(3,("chown#2 %s. uid = %u, gid = %u.\n",
- fsp->fsp_name, (unsigned int)newUID, (unsigned int)newGID));
- if (try_chown(fsp->conn, fsp->fsp_name, newUID, newGID)) {
- DEBUG(2,("chown#2 %s, %u, %u failed. Error = %s.\n",
- fsp->fsp_name, (unsigned int)newUID, (unsigned int)newGID,
- strerror(errno)));
- return map_nt_error_from_unix(errno);
- }
- DEBUG(10,("chown#2 %s, %u, %u succeeded.\n",
- fsp->fsp_name, (unsigned int)newUID, (unsigned int)newGID));
+ if (set_acl_as_root) {
+ become_root();
+ }
+ result = set_nfs4_native(fsp, acl);
+ saved_errno = errno;
+ if (set_acl_as_root) {
+ unbecome_root();
+ }
+ if (result!=True) {
+ errno = saved_errno;
+ DEBUG(10, ("set_nfs4_native failed with %s\n", strerror(errno)));
+ return map_nt_error_from_unix(errno);
}
DEBUG(10, ("smb_set_nt_acl_nfs4 succeeded\n"));
diff --git a/source3/modules/onefs.h b/source3/modules/onefs.h
index 6e5eae3085..9c1c1647ba 100644
--- a/source3/modules/onefs.h
+++ b/source3/modules/onefs.h
@@ -45,6 +45,14 @@ enum onefs_acl_wire_format
#define PARM_SIMPLE_FILE_SHARING_COMPATIBILITY_MODE_DEFAULT false
#define PARM_CREATOR_OWNER_GETS_FULL_CONTROL "creator owner gets full control"
#define PARM_CREATOR_OWNER_GETS_FULL_CONTROL_DEFAULT true
+#define PARM_UNMAPPABLE_SIDS_DENY_EVERYONE "unmappable sids deny everyone"
+#define PARM_UNMAPPABLE_SIDS_DENY_EVERYONE_DEFAULT false
+#define PARM_UNMAPPABLE_SIDS_IGNORE "ignore unmappable sids"
+#define PARM_UNMAPPABLE_SIDS_IGNORE_DEFAULT false
+#define PARM_UNMAPPABLE_SIDS_IGNORE_LIST "unmappable sids ignore list"
+#define PARM_UNMAPPABLE_SIDS_IGNORE_LIST_DEFAULT NULL
+#define PARM_IGNORE_SACL "ignore sacl"
+#define PARM_IGNORE_SACL_DEFAULT false
/*
* vfs interface handlers
@@ -93,6 +101,9 @@ NTSTATUS onefs_streaminfo(vfs_handle_struct *handle,
unsigned int *num_streams,
struct stream_struct **streams);
+int onefs_vtimes_streams(vfs_handle_struct *handle, const char *fname,
+ int flags, struct timespec times[3]);
+
NTSTATUS onefs_fget_nt_acl(vfs_handle_struct *handle, files_struct *fsp,
uint32 security_info, SEC_DESC **ppdesc);
@@ -105,7 +116,7 @@ NTSTATUS onefs_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp,
* Utility functions
*/
NTSTATUS onefs_samba_sd_to_sd(uint32 security_info_sent, SEC_DESC *psd,
- struct ifs_security_descriptor *sd);
+ struct ifs_security_descriptor *sd, int snum);
NTSTATUS onefs_split_ntfs_stream_name(TALLOC_CTX *mem_ctx, const char *fname,
char **pbase, char **pstream);
diff --git a/source3/modules/onefs_acl.c b/source3/modules/onefs_acl.c
index 9258e0cddc..b9ec2d68e0 100644
--- a/source3/modules/onefs_acl.c
+++ b/source3/modules/onefs_acl.c
@@ -35,7 +35,8 @@ const struct enum_list enum_onefs_acl_wire_format[] = {
* Turn SID into UID/GID and setup a struct ifs_identity
*/
static bool
-onefs_sid_to_identity(const DOM_SID *sid, struct ifs_identity *id, bool is_group)
+onefs_sid_to_identity(const DOM_SID *sid, struct ifs_identity *id,
+ bool is_group)
{
enum ifs_identity_type type = IFS_ID_TYPE_LAST+1;
uid_t uid = 0;
@@ -111,18 +112,137 @@ onefs_identity_to_sid(struct ifs_identity *id, DOM_SID *sid)
return true;
}
+static bool
+onefs_og_to_identity(DOM_SID *sid, struct ifs_identity * ident,
+ bool is_group, int snum)
+{
+ const DOM_SID *b_admin_sid = &global_sid_Builtin_Administrators;
+
+ if (!onefs_sid_to_identity(sid, ident, is_group)) {
+ if (!lp_parm_bool(snum, PARM_ONEFS_TYPE,
+ PARM_UNMAPPABLE_SIDS_IGNORE,
+ PARM_UNMAPPABLE_SIDS_IGNORE_DEFAULT)) {
+ DEBUG(3, ("Unresolvable SID (%s) found.\n",
+ sid_string_dbg(sid)));
+ return false;
+ }
+ if (!onefs_sid_to_identity(b_admin_sid, ident, is_group)) {
+ return false;
+ }
+ DEBUG(3, ("Mapping unresolvable owner SID (%s) to Builtin "
+ "Administrators group.\n",
+ sid_string_dbg(sid)));
+ }
+ return true;
+}
+
+static bool
+sid_in_ignore_list(DOM_SID * sid, int snum)
+{
+ const char ** sid_list = NULL;
+ DOM_SID match;
+
+ sid_list = lp_parm_string_list(snum, PARM_ONEFS_TYPE,
+ PARM_UNMAPPABLE_SIDS_IGNORE_LIST,
+ PARM_UNMAPPABLE_SIDS_IGNORE_LIST_DEFAULT);
+
+ /* Fast path a NULL list */
+ if (!sid_list || *sid_list == NULL)
+ return false;
+
+ while (*sid_list) {
+ if (string_to_sid(&match, *sid_list))
+ if (sid_equal(sid, &match))
+ return true;
+ sid_list++;
+ }
+
+ return false;
+}
+
+/**
+ * Convert a trustee to a struct identity
+ */
+static bool
+onefs_samba_ace_to_ace(SEC_ACE * samba_ace, struct ifs_ace * ace,
+ bool *mapped, int snum)
+{
+ struct ifs_identity ident = {.type=IFS_ID_TYPE_LAST, .id.uid=0};
+
+ SMB_ASSERT(ace);
+ SMB_ASSERT(mapped);
+ SMB_ASSERT(samba_ace);
+
+ if (onefs_sid_to_identity(&samba_ace->trustee, &ident, false)) {
+ *mapped = true;
+ } else {
+
+ SMB_ASSERT(ident.id.uid >= 0);
+
+ /* Ignore the sid if it's in the list */
+ if (sid_in_ignore_list(&samba_ace->trustee, snum)) {
+ DEBUG(3, ("Silently failing to set ACE for SID (%s) "
+ "because it is in the ignore sids list\n",
+ sid_string_dbg(&samba_ace->trustee)));
+ *mapped = false;
+ } else if ((samba_ace->type == SEC_ACE_TYPE_ACCESS_DENIED) &&
+ lp_parm_bool(snum, PARM_ONEFS_TYPE,
+ PARM_UNMAPPABLE_SIDS_DENY_EVERYONE,
+ PARM_UNMAPPABLE_SIDS_DENY_EVERYONE_DEFAULT)) {
+ /* If the ace is deny translated to Everyone */
+ DEBUG(3, ("Mapping unresolvable deny ACE SID (%s) "
+ "to Everyone.\n",
+ sid_string_dbg(&samba_ace->trustee)));
+ if (aclu_initialize_identity(&ident,
+ IFS_ID_TYPE_EVERYONE, 0, 0, False) != 0) {
+ DEBUG(2, ("aclu_initialize_identity() "
+ "failed making Everyone\n"));
+ return false;
+ }
+ *mapped = true;
+ } else if (lp_parm_bool(snum, PARM_ONEFS_TYPE,
+ PARM_UNMAPPABLE_SIDS_IGNORE,
+ PARM_UNMAPPABLE_SIDS_IGNORE_DEFAULT)) {
+ DEBUG(3, ("Silently failing to set ACE for SID (%s) "
+ "because it is unresolvable\n",
+ sid_string_dbg(&samba_ace->trustee)));
+ *mapped = false;
+ } else {
+ /* Fail for lack of a better option */
+ return false;
+ }
+ }
+
+ if (*mapped) {
+ if (aclu_initialize_ace(ace, samba_ace->type,
+ samba_ace->access_mask, samba_ace->flags, 0,
+ &ident))
+ return false;
+
+ if ((ace->trustee.type == IFS_ID_TYPE_CREATOR_OWNER ||
+ ace->trustee.type == IFS_ID_TYPE_CREATOR_GROUP) &&
+ nt4_compatible_acls())
+ ace->flags |= SEC_ACE_FLAG_INHERIT_ONLY;
+ }
+
+ return true;
+}
+
/**
* Convert a SEC_ACL to a struct ifs_security_acl
*/
static bool
-onefs_samba_acl_to_acl(SEC_ACL *samba_acl, struct ifs_security_acl **acl)
+onefs_samba_acl_to_acl(SEC_ACL *samba_acl, struct ifs_security_acl **acl,
+ bool * ignore_aces, int snum)
{
int num_aces = 0;
struct ifs_ace *aces = NULL;
- struct ifs_identity temp;
SEC_ACE *samba_aces;
+ bool mapped;
int i, j;
+ SMB_ASSERT(ignore_aces);
+
if ((!acl) || (!samba_acl))
return false;
@@ -134,39 +254,30 @@ onefs_samba_acl_to_acl(SEC_ACL *samba_acl, struct ifs_security_acl **acl)
aces = SMB_MALLOC_ARRAY(struct ifs_ace, num_aces);
for (i = 0, j = 0; j < num_aces; i++, j++) {
- if (!onefs_sid_to_identity(&samba_aces[j].trustee,
- &temp, false))
+ if (!onefs_samba_ace_to_ace(&samba_aces[j],
+ &aces[i], &mapped, snum))
goto err_free;
- /*
- * XXX Act like we did pre-Thai: Silently fail setting
- * ACEs for BUILTIN accounts.
- */
- if (temp.id.uid == -1) {
- DEBUG(3, ("Silently failing to set ACE "
- "because our id was == -1.\n"));
+ if (!mapped)
i--;
- continue;
- }
-
- if (aclu_initialize_ace(&aces[i], samba_aces[i].type,
- samba_aces[i].access_mask, samba_aces[i].flags,
- 0, &temp))
- goto err_free;
-
- if ((aces[i].trustee.type == IFS_ID_TYPE_CREATOR_OWNER ||
- aces[i].trustee.type == IFS_ID_TYPE_CREATOR_GROUP) &&
- nt4_compatible_acls())
- aces[i].flags |= IFS_ACE_FLAG_INHERIT_ONLY;
}
num_aces = i;
}
+ /* If aces are given but we cannot apply them due to the reasons
+ * above we do not change the SD. However, if we are told to
+ * explicitly set an SD with 0 aces we honor this operation */
+ *ignore_aces = samba_acl->num_aces > 0 && num_aces < 1;
+
+ if (*ignore_aces == false)
+ if (aclu_initialize_acl(acl, aces, num_aces))
+ goto err_free;
+
if (aclu_initialize_acl(acl, aces, num_aces))
goto err_free;
- /* Currently aclu_initialize_acl should copy the aces over, allowing us
- * to immediately free */
+ /* Currently aclu_initialize_acl should copy the aces over, allowing
+ * us to immediately free */
free(aces);
return true;
@@ -697,10 +808,11 @@ onefs_get_nt_acl(vfs_handle_struct *handle, const char* name,
* @return NTSTATUS_OK if successful
*/
NTSTATUS onefs_samba_sd_to_sd(uint32 security_info_sent, SEC_DESC *psd,
- struct ifs_security_descriptor *sd)
+ struct ifs_security_descriptor *sd, int snum)
{
- struct ifs_security_acl dacl, sacl, *daclp, *saclp;
+ struct ifs_security_acl *daclp, *saclp;
struct ifs_identity owner, group, *ownerp, *groupp;
+ bool ignore_aces;
ownerp = NULL;
groupp = NULL;
@@ -709,58 +821,53 @@ NTSTATUS onefs_samba_sd_to_sd(uint32 security_info_sent, SEC_DESC *psd,
/* Setup owner */
if (security_info_sent & OWNER_SECURITY_INFORMATION) {
- if (!onefs_sid_to_identity(psd->owner_sid, &owner, false))
+ if (!onefs_og_to_identity(psd->owner_sid, &owner, false, snum))
return NT_STATUS_UNSUCCESSFUL;
- /*
- * XXX Act like we did pre-Thai: Silently fail setting the
- * owner to a BUILTIN account.
- */
- if (owner.id.uid == -1) {
- DEBUG(3, ("Silently failing to set owner because our "
- "id was == -1.\n"));
- security_info_sent &= ~OWNER_SECURITY_INFORMATION;
- if (!security_info_sent)
- return NT_STATUS_OK;
- }
- else
- ownerp = &owner;
+ SMB_ASSERT(owner.id.uid >= 0);
+
+ ownerp = &owner;
}
/* Setup group */
if (security_info_sent & GROUP_SECURITY_INFORMATION) {
- if (!onefs_sid_to_identity(psd->group_sid, &group, true))
+ if (!onefs_og_to_identity(psd->group_sid, &group, true, snum))
return NT_STATUS_UNSUCCESSFUL;
- /*
- * XXX Act like we did pre-Thai: Silently fail setting the
- * group to a BUILTIN account.
- */
- if (group.id.gid == -1) {
- DEBUG(3, ("Silently failing to set group because our "
- "id was == -1.\n"));
- security_info_sent &= ~GROUP_SECURITY_INFORMATION;
- if (!security_info_sent)
- return NT_STATUS_OK;
- }
- else
- groupp = &group;
+ SMB_ASSERT(group.id.gid >= 0);
+
+ groupp = &group;
}
/* Setup DACL */
if ((security_info_sent & DACL_SECURITY_INFORMATION) && (psd->dacl)) {
- daclp = &dacl;
-
- if (!onefs_samba_acl_to_acl(psd->dacl, &daclp))
+ if (!onefs_samba_acl_to_acl(psd->dacl, &daclp, &ignore_aces,
+ snum))
return NT_STATUS_UNSUCCESSFUL;
+
+ if (ignore_aces == true)
+ security_info_sent &= ~DACL_SECURITY_INFORMATION;
}
/* Setup SACL */
- if ((security_info_sent & SACL_SECURITY_INFORMATION) && (psd->sacl)) {
- saclp = &sacl;
-
- if (!onefs_samba_acl_to_acl(psd->sacl, &saclp))
- return NT_STATUS_UNSUCCESSFUL;
+ if (security_info_sent & SACL_SECURITY_INFORMATION) {
+
+ if (lp_parm_bool(snum, PARM_ONEFS_TYPE,
+ PARM_IGNORE_SACL, PARM_IGNORE_SACL_DEFAULT)) {
+ DEBUG(5, ("Ignoring SACLs.\n"));
+ security_info_sent &= ~SACL_SECURITY_INFORMATION;
+ } else {
+ if (psd->sacl) {
+ if (!onefs_samba_acl_to_acl(psd->sacl,
+ &saclp, &ignore_aces, snum))
+ return NT_STATUS_UNSUCCESSFUL;
+
+ if (ignore_aces == true) {
+ security_info_sent &=
+ ~SACL_SECURITY_INFORMATION;
+ }
+ }
+ }
}
/* Setup ifs_security_descriptor */
@@ -789,7 +896,8 @@ onefs_fset_nt_acl(vfs_handle_struct *handle, files_struct *fsp,
DEBUG(5,("Setting SD on file %s.\n", fsp->fsp_name ));
- status = onefs_samba_sd_to_sd(security_info_sent, psd, &sd);
+ status = onefs_samba_sd_to_sd(security_info_sent, psd, &sd,
+ SNUM(handle->conn));
if (!NT_STATUS_IS_OK(status)) {
DEBUG(3, ("SD initialization failure: %s", nt_errstr(status)));
diff --git a/source3/modules/onefs_streams.c b/source3/modules/onefs_streams.c
index 184fe4f0c9..e9543e237f 100644
--- a/source3/modules/onefs_streams.c
+++ b/source3/modules/onefs_streams.c
@@ -51,6 +51,25 @@ NTSTATUS onefs_split_ntfs_stream_name(TALLOC_CTX *mem_ctx, const char *fname,
return NT_STATUS_OK;
}
+int onefs_is_stream(const char *path, char **pbase, char **pstream,
+ bool *is_stream)
+{
+ (*is_stream) = is_ntfs_stream_name(path);
+
+ if (!(*is_stream)) {
+ return 0;
+ }
+
+ if (!NT_STATUS_IS_OK(onefs_split_ntfs_stream_name(talloc_tos(), path,
+ pbase, pstream))) {
+ DEBUG(10, ("onefs_split_ntfs_stream_name failed\n"));
+ errno = ENOMEM;
+ return -1;
+ }
+
+ return 0;
+}
+
int onefs_close(vfs_handle_struct *handle, struct files_struct *fsp)
{
int ret2, ret = 0;
@@ -141,27 +160,18 @@ int onefs_rename(vfs_handle_struct *handle, const char *oldname,
char *nbase = NULL;
char *nsname = NULL;
- old_is_stream = is_ntfs_stream_name(oldname);
- new_is_stream = is_ntfs_stream_name(newname);
-
- if (!old_is_stream && !new_is_stream) {
- return SMB_VFS_NEXT_RENAME(handle, oldname, newname);
- }
-
frame = talloc_stackframe();
- if (!NT_STATUS_IS_OK(onefs_split_ntfs_stream_name(talloc_tos(),
- oldname, &obase,
- &osname))) {
- errno = ENOMEM;
- goto done;
- }
+ ret = onefs_is_stream(oldname, &obase, &osname, &old_is_stream);
+ if (ret)
+ return ret;
- if (!NT_STATUS_IS_OK(onefs_split_ntfs_stream_name(talloc_tos(),
- newname, &nbase,
- &nsname))) {
- errno = ENOMEM;
- goto done;
+ ret = onefs_is_stream(newname, &nbase, &nsname, &new_is_stream);
+ if (ret)
+ return ret;
+
+ if (!old_is_stream && !new_is_stream) {
+ return SMB_VFS_NEXT_RENAME(handle, oldname, newname);
}
dir_fd = get_stream_dir_fd(handle->conn, obase, NULL);
@@ -237,18 +247,17 @@ static int stat_stream(vfs_handle_struct *handle, const char *base,
int onefs_stat(vfs_handle_struct *handle, const char *path,
SMB_STRUCT_STAT *sbuf)
{
+ int ret;
+ bool is_stream;
char *base = NULL;
char *stream = NULL;
- if (!is_ntfs_stream_name(path)) {
- return SMB_VFS_NEXT_STAT(handle, path, sbuf);
- }
+ ret = onefs_is_stream(path, &base, &stream, &is_stream);
+ if (ret)
+ return ret;
- if (!NT_STATUS_IS_OK(onefs_split_ntfs_stream_name(talloc_tos(), path,
- &base, &stream))) {
- DEBUG(10, ("onefs_split_ntfs_stream_name failed\n"));
- errno = ENOMEM;
- return -1;
+ if (!is_stream) {
+ return SMB_VFS_NEXT_STAT(handle, path, sbuf);
}
/* If it's the ::$DATA stream just stat the base file name. */
@@ -285,18 +294,17 @@ int onefs_fstat(vfs_handle_struct *handle, struct files_struct *fsp,
int onefs_lstat(vfs_handle_struct *handle, const char *path,
SMB_STRUCT_STAT *sbuf)
{
+ int ret;
+ bool is_stream;
char *base = NULL;
char *stream = NULL;
- if (!is_ntfs_stream_name(path)) {
- return SMB_VFS_NEXT_LSTAT(handle, path, sbuf);
- }
+ ret = onefs_is_stream(path, &base, &stream, &is_stream);
+ if (ret)
+ return ret;
- if (!NT_STATUS_IS_OK(onefs_split_ntfs_stream_name(talloc_tos(), path,
- &base, &stream))) {
- DEBUG(10, ("onefs_split_ntfs_stream_name failed\n"));
- errno = ENOMEM;
- return -1;
+ if (!is_stream) {
+ return SMB_VFS_NEXT_LSTAT(handle, path, sbuf);
}
/* If it's the ::$DATA stream just stat the base file name. */
@@ -309,19 +317,19 @@ int onefs_lstat(vfs_handle_struct *handle, const char *path,
int onefs_unlink(vfs_handle_struct *handle, const char *path)
{
+ int ret;
+ bool is_stream;
char *base = NULL;
char *stream = NULL;
- int dir_fd, ret, saved_errno;
+ int dir_fd, saved_errno;
- if (!is_ntfs_stream_name(path)) {
- return SMB_VFS_NEXT_UNLINK(handle, path);
+ ret = onefs_is_stream(path, &base, &stream, &is_stream);
+ if (ret) {
+ return ret;
}
- if (!NT_STATUS_IS_OK(onefs_split_ntfs_stream_name(talloc_tos(), path,
- &base, &stream))) {
- DEBUG(10, ("onefs_split_ntfs_stream_name failed\n"));
- errno = ENOMEM;
- return -1;
+ if (!is_stream) {
+ return SMB_VFS_NEXT_UNLINK(handle, path);
}
/* If it's the ::$DATA stream just unlink the base file name. */
@@ -342,6 +350,42 @@ int onefs_unlink(vfs_handle_struct *handle, const char *path)
return ret;
}
+int onefs_vtimes_streams(vfs_handle_struct *handle, const char *fname,
+ int flags, struct timespec times[3])
+{
+ int ret;
+ bool is_stream;
+ char *base;
+ char *stream;
+ int dirfd;
+ int saved_errno;
+
+ START_PROFILE(syscall_ntimes);
+
+ ret = onefs_is_stream(fname, &base, &stream, &is_stream);
+ if (ret)
+ return ret;
+
+ if (!is_stream) {
+ ret = vtimes(fname, times, flags);
+ return ret;
+ }
+
+ dirfd = get_stream_dir_fd(handle->conn, base, NULL);
+ if (dirfd < -1) {
+ return -1;
+ }
+
+ ret = enc_vtimesat(dirfd, stream, ENC_DEFAULT, times, flags);
+
+ END_PROFILE(syscall_ntimes);
+
+ saved_errno = errno;
+ close(dirfd);
+ errno = saved_errno;
+ return ret;
+}
+
int onefs_chflags(vfs_handle_struct *handle, const char *path,
unsigned int flags)
{
diff --git a/source3/modules/onefs_system.c b/source3/modules/onefs_system.c
index ee257d8f90..4ebdf12a50 100644
--- a/source3/modules/onefs_system.c
+++ b/source3/modules/onefs_system.c
@@ -152,7 +152,7 @@ int onefs_sys_create_file(connection_struct *conn,
secinfo = (get_sec_info(sd) & IFS_SEC_INFO_KNOWN_MASK);
- status = onefs_samba_sd_to_sd(secinfo, sd, &ifs_sd);
+ status = onefs_samba_sd_to_sd(secinfo, sd, &ifs_sd, SNUM(conn));
if (!NT_STATUS_IS_OK(status)) {
DEBUG(1, ("SD initialization failure: %s",
diff --git a/source3/modules/vfs_aixacl2.c b/source3/modules/vfs_aixacl2.c
index a078b9f9f6..5ebc3a12f8 100644
--- a/source3/modules/vfs_aixacl2.c
+++ b/source3/modules/vfs_aixacl2.c
@@ -25,8 +25,6 @@
#define AIXACL2_MODULE_NAME "aixacl2"
-extern int try_chown(connection_struct *conn, const char *fname, uid_t uid, gid_t gid);
-
extern SMB_ACL_T aixacl_to_smbacl( struct acl *file_acl);
extern struct acl *aixacl_smb_to_aixacl(SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl);
diff --git a/source3/modules/vfs_cap.c b/source3/modules/vfs_cap.c
index 6950ab2168..ac85d3a804 100644
--- a/source3/modules/vfs_cap.c
+++ b/source3/modules/vfs_cap.c
@@ -208,7 +208,8 @@ static int cap_chdir(vfs_handle_struct *handle, const char *path)
return SMB_VFS_NEXT_CHDIR(handle, cappath);
}
-static int cap_ntimes(vfs_handle_struct *handle, const char *path, const struct timespec ts[2])
+static int cap_ntimes(vfs_handle_struct *handle, const char *path,
+ struct smb_file_time *ft)
{
char *cappath = capencode(talloc_tos(), path);
@@ -216,7 +217,7 @@ static int cap_ntimes(vfs_handle_struct *handle, const char *path, const struct
errno = ENOMEM;
return -1;
}
- return SMB_VFS_NEXT_NTIMES(handle, cappath, ts);
+ return SMB_VFS_NEXT_NTIMES(handle, cappath, ft);
}
diff --git a/source3/modules/vfs_catia.c b/source3/modules/vfs_catia.c
index 47d178a33f..d0c341fdd3 100644
--- a/source3/modules/vfs_catia.c
+++ b/source3/modules/vfs_catia.c
@@ -252,9 +252,9 @@ static char *catia_getwd(vfs_handle_struct *handle, char *buf)
}
static int catia_ntimes(vfs_handle_struct *handle,
- const char *path, const struct timespec ts[2])
+ const char *path, struct smb_file_time *ft)
{
- return SMB_VFS_NEXT_NTIMES(handle, path, ts);
+ return SMB_VFS_NEXT_NTIMES(handle, path, ft);
}
static bool catia_symlink(vfs_handle_struct *handle,
diff --git a/source3/modules/vfs_default.c b/source3/modules/vfs_default.c
index 61e1deb81e..a9aabab768 100644
--- a/source3/modules/vfs_default.c
+++ b/source3/modules/vfs_default.c
@@ -682,25 +682,26 @@ static char *vfswrap_getwd(vfs_handle_struct *handle, char *path)
system will support.
**********************************************************************/
-static int vfswrap_ntimes(vfs_handle_struct *handle, const char *path, const struct timespec ts[2])
+static int vfswrap_ntimes(vfs_handle_struct *handle, const char *path,
+ struct smb_file_time *ft)
{
int result;
START_PROFILE(syscall_ntimes);
#if defined(HAVE_UTIMES)
- if (ts != NULL) {
+ if (ft != NULL) {
struct timeval tv[2];
- tv[0] = convert_timespec_to_timeval(ts[0]);
- tv[1] = convert_timespec_to_timeval(ts[1]);
+ tv[0] = convert_timespec_to_timeval(ft->atime);
+ tv[1] = convert_timespec_to_timeval(ft->mtime);
result = utimes(path, tv);
} else {
result = utimes(path, NULL);
}
#elif defined(HAVE_UTIME)
- if (ts != NULL) {
+ if (ft != NULL) {
struct utimbuf times;
- times.actime = convert_timespec_to_time_t(ts[0]);
- times.modtime = convert_timespec_to_time_t(ts[1]);
+ times.actime = convert_timespec_to_time_t(ft->atime);
+ times.modtime = convert_timespec_to_time_t(ft->mtime);
result = utime(path, times);
} else {
result = utime(path, NULL);
diff --git a/source3/modules/vfs_full_audit.c b/source3/modules/vfs_full_audit.c
index 1d9983a753..73758a2d9d 100644
--- a/source3/modules/vfs_full_audit.c
+++ b/source3/modules/vfs_full_audit.c
@@ -172,7 +172,7 @@ static int smb_full_audit_chdir(vfs_handle_struct *handle,
static char *smb_full_audit_getwd(vfs_handle_struct *handle,
char *path);
static int smb_full_audit_ntimes(vfs_handle_struct *handle,
- const char *path, const struct timespec ts[2]);
+ const char *path, struct smb_file_time *ft);
static int smb_full_audit_ftruncate(vfs_handle_struct *handle, files_struct *fsp,
SMB_OFF_T len);
static bool smb_full_audit_lock(vfs_handle_struct *handle, files_struct *fsp,
@@ -1426,11 +1426,11 @@ static char *smb_full_audit_getwd(vfs_handle_struct *handle,
}
static int smb_full_audit_ntimes(vfs_handle_struct *handle,
- const char *path, const struct timespec ts[2])
+ const char *path, struct smb_file_time *ft)
{
int result;
- result = SMB_VFS_NEXT_NTIMES(handle, path, ts);
+ result = SMB_VFS_NEXT_NTIMES(handle, path, ft);
do_log(SMB_VFS_OP_NTIMES, (result >= 0), handle, "%s", path);
diff --git a/source3/modules/vfs_onefs.c b/source3/modules/vfs_onefs.c
index 6b42c0f373..e048e89589 100644
--- a/source3/modules/vfs_onefs.c
+++ b/source3/modules/vfs_onefs.c
@@ -66,6 +66,39 @@ static int onefs_statvfs(vfs_handle_struct *handle, const char *path,
return result;
}
+static int onefs_ntimes(vfs_handle_struct *handle, const char *fname,
+ struct smb_file_time *ft)
+{
+ int flags = 0;
+ struct timespec times[3];
+
+ if (!null_timespec(ft->atime)) {
+ flags |= VT_ATIME;
+ times[0] = ft->atime;
+ DEBUG(6,("**** onefs_ntimes: actime: %s.%d\n",
+ time_to_asc(convert_timespec_to_time_t(ft->atime)),
+ ft->atime.tv_nsec));
+ }
+
+ if (!null_timespec(ft->mtime)) {
+ flags |= VT_MTIME;
+ times[1] = ft->mtime;
+ DEBUG(6,("**** onefs_ntimes: modtime: %s.%d\n",
+ time_to_asc(convert_timespec_to_time_t(ft->mtime)),
+ ft->mtime.tv_nsec));
+ }
+
+ if (!null_timespec(ft->create_time)) {
+ flags |= VT_BTIME;
+ times[2] = ft->create_time;
+ DEBUG(6,("**** onefs_ntimes: createtime: %s.%d\n",
+ time_to_asc(convert_timespec_to_time_t(ft->create_time)),
+ ft->create_time.tv_nsec));
+ }
+
+ return onefs_vtimes_streams(handle, fname, flags, times);
+}
+
static uint32_t onefs_fs_capabilities(struct vfs_handle_struct *handle)
{
return SMB_VFS_NEXT_FS_CAPABILITIES(handle) | FILE_NAMED_STREAMS;
@@ -92,6 +125,8 @@ static vfs_op_tuple onefs_ops[] = {
SMB_VFS_LAYER_TRANSPARENT},
{SMB_VFS_OP(onefs_unlink), SMB_VFS_OP_UNLINK,
SMB_VFS_LAYER_TRANSPARENT},
+ {SMB_VFS_OP(onefs_ntimes), SMB_VFS_OP_NTIMES,
+ SMB_VFS_LAYER_OPAQUE},
{SMB_VFS_OP(onefs_chflags), SMB_VFS_OP_CHFLAGS,
SMB_VFS_LAYER_TRANSPARENT},
{SMB_VFS_OP(onefs_streaminfo), SMB_VFS_OP_STREAMINFO,
diff --git a/source3/modules/vfs_recycle.c b/source3/modules/vfs_recycle.c
index cb985e1be2..2b0edcdb4a 100644
--- a/source3/modules/vfs_recycle.c
+++ b/source3/modules/vfs_recycle.c
@@ -391,19 +391,21 @@ static void recycle_do_touch(vfs_handle_struct *handle, const char *fname,
bool touch_mtime)
{
SMB_STRUCT_STAT st;
- struct timespec ts[2];
+ struct smb_file_time ft;
int ret, err;
+ ZERO_STRUCT(ft);
+
if (SMB_VFS_NEXT_STAT(handle, fname, &st) != 0) {
DEBUG(0,("recycle: stat for %s returned %s\n",
fname, strerror(errno)));
return;
}
- ts[0] = timespec_current(); /* atime */
- ts[1] = touch_mtime ? ts[0] : get_mtimespec(&st); /* mtime */
+ ft.atime = timespec_current(); /* atime */
+ ft.mtime = touch_mtime ? ft.atime : get_mtimespec(&st); /* mtime */
become_root();
- ret = SMB_VFS_NEXT_NTIMES(handle, fname, ts);
+ ret = SMB_VFS_NEXT_NTIMES(handle, fname, &ft);
err = errno;
unbecome_root();
if (ret == -1 ) {
diff --git a/source3/modules/vfs_shadow_copy2.c b/source3/modules/vfs_shadow_copy2.c
index c95600b642..56dd6ea8d8 100644
--- a/source3/modules/vfs_shadow_copy2.c
+++ b/source3/modules/vfs_shadow_copy2.c
@@ -393,9 +393,9 @@ static int shadow_copy2_chdir(vfs_handle_struct *handle,
}
static int shadow_copy2_ntimes(vfs_handle_struct *handle,
- const char *fname, const struct timespec ts[2])
+ const char *fname, struct smb_file_time *ft)
{
- SHADOW2_NEXT(NTIMES, (handle, name, ts), int, -1);
+ SHADOW2_NEXT(NTIMES, (handle, name, ft), int, -1);
}
static int shadow_copy2_readlink(vfs_handle_struct *handle,
diff --git a/source3/rpc_client/cli_pipe.c b/source3/rpc_client/cli_pipe.c
index cf2c833c28..5a53c0d940 100644
--- a/source3/rpc_client/cli_pipe.c
+++ b/source3/rpc_client/cli_pipe.c
@@ -136,28 +136,13 @@ static int map_pipe_auth_type_to_rpc_auth_type(enum pipe_auth_type auth_type)
/********************************************************************
Pipe description for a DEBUG
********************************************************************/
-static char *rpccli_pipe_txt(TALLOC_CTX *mem_ctx, struct rpc_pipe_client *cli)
+static const char *rpccli_pipe_txt(TALLOC_CTX *mem_ctx,
+ struct rpc_pipe_client *cli)
{
- char *result;
-
- switch (cli->transport_type) {
- case NCACN_NP:
- result = talloc_asprintf(mem_ctx, "host %s, pipe %s, "
- "fnum 0x%x",
- cli->desthost,
- cli->trans.np.pipe_name,
- (unsigned int)(cli->trans.np.fnum));
- break;
- case NCACN_IP_TCP:
- case NCACN_UNIX_STREAM:
- result = talloc_asprintf(mem_ctx, "host %s, fd %d",
- cli->desthost, cli->trans.sock.fd);
- break;
- default:
- result = talloc_asprintf(mem_ctx, "host %s", cli->desthost);
- break;
+ char *result = talloc_asprintf(mem_ctx, "host %s", cli->desthost);
+ if (result == NULL) {
+ return "pipe";
}
- SMB_ASSERT(result != NULL);
return result;
}
@@ -204,19 +189,18 @@ static bool rpc_grow_buffer(prs_struct *pdu, size_t size)
struct rpc_read_state {
struct event_context *ev;
- struct rpc_pipe_client *cli;
- char *data;
+ struct rpc_cli_transport *transport;
+ uint8_t *data;
size_t size;
size_t num_read;
};
-static void rpc_read_np_done(struct async_req *subreq);
-static void rpc_read_sock_done(struct async_req *subreq);
+static void rpc_read_done(struct async_req *subreq);
static struct async_req *rpc_read_send(TALLOC_CTX *mem_ctx,
struct event_context *ev,
- struct rpc_pipe_client *cli,
- char *data, size_t size)
+ struct rpc_cli_transport *transport,
+ uint8_t *data, size_t size)
{
struct async_req *result, *subreq;
struct rpc_read_state *state;
@@ -226,48 +210,28 @@ static struct async_req *rpc_read_send(TALLOC_CTX *mem_ctx,
return NULL;
}
state->ev = ev;
- state->cli = cli;
+ state->transport = transport;
state->data = data;
state->size = size;
state->num_read = 0;
DEBUG(5, ("rpc_read_send: data_to_read: %u\n", (unsigned int)size));
- if (cli->transport_type == NCACN_NP) {
- subreq = cli_read_andx_send(
- state, ev, cli->trans.np.cli,
- cli->trans.np.fnum, 0, size);
- if (subreq == NULL) {
- DEBUG(10, ("cli_read_andx_send failed\n"));
- goto fail;
- }
- subreq->async.fn = rpc_read_np_done;
- subreq->async.priv = result;
- return result;
- }
-
- if ((cli->transport_type == NCACN_IP_TCP)
- || (cli->transport_type == NCACN_UNIX_STREAM)) {
- subreq = recvall_send(state, ev, cli->trans.sock.fd,
- data, size, 0);
- if (subreq == NULL) {
- DEBUG(10, ("recvall_send failed\n"));
- goto fail;
- }
- subreq->async.fn = rpc_read_sock_done;
- subreq->async.priv = result;
- return result;
+ subreq = transport->read_send(state, ev, (uint8_t *)data, size,
+ transport->priv);
+ if (subreq == NULL) {
+ goto fail;
}
+ subreq->async.fn = rpc_read_done;
+ subreq->async.priv = result;
+ return result;
- if (async_post_status(result, ev, NT_STATUS_INVALID_PARAMETER)) {
- return result;
- }
fail:
TALLOC_FREE(result);
return NULL;
}
-static void rpc_read_np_done(struct async_req *subreq)
+static void rpc_read_done(struct async_req *subreq)
{
struct async_req *req = talloc_get_type_abort(
subreq->async.priv, struct async_req);
@@ -275,61 +239,31 @@ static void rpc_read_np_done(struct async_req *subreq)
req->private_data, struct rpc_read_state);
NTSTATUS status;
ssize_t received;
- uint8_t *rcvbuf;
- status = cli_read_andx_recv(subreq, &received, &rcvbuf);
- /*
- * We can't TALLOC_FREE(subreq) as usual here, as rcvbuf still is a
- * child of that.
- */
- if (NT_STATUS_EQUAL(status, NT_STATUS_BUFFER_TOO_SMALL)) {
- status = NT_STATUS_OK;
- }
+ status = state->transport->read_recv(subreq, &received);
+ TALLOC_FREE(subreq);
if (!NT_STATUS_IS_OK(status)) {
- TALLOC_FREE(subreq);
async_req_error(req, status);
return;
}
- memcpy(state->data + state->num_read, rcvbuf, received);
- TALLOC_FREE(subreq);
-
state->num_read += received;
-
if (state->num_read == state->size) {
async_req_done(req);
return;
}
- subreq = cli_read_andx_send(
- state, state->ev, state->cli->trans.np.cli,
- state->cli->trans.np.fnum, 0,
- state->size - state->num_read);
-
+ subreq = state->transport->read_send(state, state->ev,
+ state->data + state->num_read,
+ state->size - state->num_read,
+ state->transport->priv);
if (async_req_nomem(subreq, req)) {
return;
}
-
- subreq->async.fn = rpc_read_np_done;
+ subreq->async.fn = rpc_read_done;
subreq->async.priv = req;
}
-static void rpc_read_sock_done(struct async_req *subreq)
-{
- struct async_req *req = talloc_get_type_abort(
- subreq->async.priv, struct async_req);
- NTSTATUS status;
-
- status = recvall_recv(subreq);
- TALLOC_FREE(subreq);
- if (!NT_STATUS_IS_OK(status)) {
- async_req_error(req, status);
- return;
- }
-
- async_req_done(req);
-}
-
static NTSTATUS rpc_read_recv(struct async_req *req)
{
return async_req_simple_recv(req);
@@ -337,19 +271,18 @@ static NTSTATUS rpc_read_recv(struct async_req *req)
struct rpc_write_state {
struct event_context *ev;
- struct rpc_pipe_client *cli;
- const char *data;
+ struct rpc_cli_transport *transport;
+ const uint8_t *data;
size_t size;
size_t num_written;
};
-static void rpc_write_np_done(struct async_req *subreq);
-static void rpc_write_sock_done(struct async_req *subreq);
+static void rpc_write_done(struct async_req *subreq);
static struct async_req *rpc_write_send(TALLOC_CTX *mem_ctx,
struct event_context *ev,
- struct rpc_pipe_client *cli,
- const char *data, size_t size)
+ struct rpc_cli_transport *transport,
+ const uint8_t *data, size_t size)
{
struct async_req *result, *subreq;
struct rpc_write_state *state;
@@ -359,58 +292,35 @@ static struct async_req *rpc_write_send(TALLOC_CTX *mem_ctx,
return NULL;
}
state->ev = ev;
- state->cli = cli;
+ state->transport = transport;
state->data = data;
state->size = size;
state->num_written = 0;
DEBUG(5, ("rpc_write_send: data_to_write: %u\n", (unsigned int)size));
- if (cli->transport_type == NCACN_NP) {
- subreq = cli_write_andx_send(
- state, ev, cli->trans.np.cli,
- cli->trans.np.fnum, 8, /* 8 means message mode. */
- (uint8_t *)data, 0, size);
- if (subreq == NULL) {
- DEBUG(10, ("cli_write_andx_send failed\n"));
- goto fail;
- }
- subreq->async.fn = rpc_write_np_done;
- subreq->async.priv = result;
- return result;
- }
-
- if ((cli->transport_type == NCACN_IP_TCP)
- || (cli->transport_type == NCACN_UNIX_STREAM)) {
- subreq = sendall_send(state, ev, cli->trans.sock.fd,
- data, size, 0);
- if (subreq == NULL) {
- DEBUG(10, ("sendall_send failed\n"));
- goto fail;
- }
- subreq->async.fn = rpc_write_sock_done;
- subreq->async.priv = result;
- return result;
- }
-
- if (async_post_status(result, ev, NT_STATUS_INVALID_PARAMETER)) {
- return result;
+ subreq = transport->write_send(state, ev, data, size, transport->priv);
+ if (subreq == NULL) {
+ goto fail;
}
+ subreq->async.fn = rpc_write_done;
+ subreq->async.priv = result;
+ return result;
fail:
TALLOC_FREE(result);
return NULL;
}
-static void rpc_write_np_done(struct async_req *subreq)
+static void rpc_write_done(struct async_req *subreq)
{
struct async_req *req = talloc_get_type_abort(
subreq->async.priv, struct async_req);
struct rpc_write_state *state = talloc_get_type_abort(
req->private_data, struct rpc_write_state);
NTSTATUS status;
- size_t written;
+ ssize_t written;
- status = cli_write_andx_recv(subreq, &written);
+ status = state->transport->write_recv(subreq, &written);
TALLOC_FREE(subreq);
if (!NT_STATUS_IS_OK(status)) {
async_req_error(req, status);
@@ -424,36 +334,17 @@ static void rpc_write_np_done(struct async_req *subreq)
return;
}
- subreq = cli_write_andx_send(
- state, state->ev, state->cli->trans.np.cli,
- state->cli->trans.np.fnum, 8,
- (uint8_t *)(state->data + state->num_written),
- 0, state->size - state->num_written);
-
+ subreq = state->transport->write_send(state, state->ev,
+ state->data + state->num_written,
+ state->size - state->num_written,
+ state->transport->priv);
if (async_req_nomem(subreq, req)) {
return;
}
-
- subreq->async.fn = rpc_write_np_done;
+ subreq->async.fn = rpc_write_done;
subreq->async.priv = req;
}
-static void rpc_write_sock_done(struct async_req *subreq)
-{
- struct async_req *req = talloc_get_type_abort(
- subreq->async.priv, struct async_req);
- NTSTATUS status;
-
- status = sendall_recv(subreq);
- TALLOC_FREE(subreq);
- if (!NT_STATUS_IS_OK(status)) {
- async_req_error(req, status);
- return;
- }
-
- async_req_done(req);
-}
-
static NTSTATUS rpc_write_recv(struct async_req *req)
{
return async_req_simple_recv(req);
@@ -525,9 +416,11 @@ static struct async_req *get_complete_frag_send(TALLOC_CTX *mem_ctx,
status = NT_STATUS_NO_MEMORY;
goto post_status;
}
- subreq = rpc_read_send(state, state->ev, state->cli,
- prs_data_p(state->pdu) + pdu_len,
- RPC_HEADER_LEN - pdu_len);
+ subreq = rpc_read_send(
+ state, state->ev,
+ state->cli->transport,
+ (uint8_t *)(prs_data_p(state->pdu) + pdu_len),
+ RPC_HEADER_LEN - pdu_len);
if (subreq == NULL) {
status = NT_STATUS_NO_MEMORY;
goto post_status;
@@ -550,8 +443,9 @@ static struct async_req *get_complete_frag_send(TALLOC_CTX *mem_ctx,
status = NT_STATUS_NO_MEMORY;
goto post_status;
}
- subreq = rpc_read_send(state, state->ev, state->cli,
- prs_data_p(pdu) + pdu_len,
+ subreq = rpc_read_send(state, state->ev,
+ state->cli->transport,
+ (uint8_t *)(prs_data_p(pdu) + pdu_len),
prhdr->frag_len - pdu_len);
if (subreq == NULL) {
status = NT_STATUS_NO_MEMORY;
@@ -602,9 +496,10 @@ static void get_complete_frag_got_header(struct async_req *subreq)
* RPC_HEADER_LEN bytes into state->pdu.
*/
- subreq = rpc_read_send(state, state->ev, state->cli,
- prs_data_p(state->pdu) + RPC_HEADER_LEN,
- state->prhdr->frag_len - RPC_HEADER_LEN);
+ subreq = rpc_read_send(
+ state, state->ev, state->cli->transport,
+ (uint8_t *)(prs_data_p(state->pdu) + RPC_HEADER_LEN),
+ state->prhdr->frag_len - RPC_HEADER_LEN);
if (async_req_nomem(subreq, req)) {
return;
}
@@ -1125,19 +1020,18 @@ static NTSTATUS cli_pipe_reset_current_pdu(struct rpc_pipe_client *cli, RPC_HDR
struct cli_api_pipe_state {
struct event_context *ev;
- struct rpc_pipe_client *cli;
- uint32_t max_rdata_len;
+ struct rpc_cli_transport *transport;
uint8_t *rdata;
uint32_t rdata_len;
};
-static void cli_api_pipe_np_trans_done(struct async_req *subreq);
-static void cli_api_pipe_sock_send_done(struct async_req *subreq);
-static void cli_api_pipe_sock_read_done(struct async_req *subreq);
+static void cli_api_pipe_trans_done(struct async_req *subreq);
+static void cli_api_pipe_write_done(struct async_req *subreq);
+static void cli_api_pipe_read_done(struct async_req *subreq);
static struct async_req *cli_api_pipe_send(TALLOC_CTX *mem_ctx,
struct event_context *ev,
- struct rpc_pipe_client *cli,
+ struct rpc_cli_transport *transport,
uint8_t *data, size_t data_len,
uint32_t max_rdata_len)
{
@@ -1150,10 +1044,9 @@ static struct async_req *cli_api_pipe_send(TALLOC_CTX *mem_ctx,
return NULL;
}
state->ev = ev;
- state->cli = cli;
- state->max_rdata_len = max_rdata_len;
+ state->transport = transport;
- if (state->max_rdata_len < RPC_HEADER_LEN) {
+ if (max_rdata_len < RPC_HEADER_LEN) {
/*
* For a RPC reply we always need at least RPC_HEADER_LEN
* bytes. We check this here because we will receive
@@ -1163,37 +1056,30 @@ static struct async_req *cli_api_pipe_send(TALLOC_CTX *mem_ctx,
goto post_status;
}
- if (cli->transport_type == NCACN_NP) {
-
- uint16_t setup[2];
- SSVAL(setup+0, 0, TRANSACT_DCERPCCMD);
- SSVAL(setup+1, 0, cli->trans.np.fnum);
-
- subreq = cli_trans_send(
- state, ev, cli->trans.np.cli, SMBtrans,
- "\\PIPE\\", 0, 0, 0, setup, 2, 0,
- NULL, 0, 0, data, data_len, max_rdata_len);
+ if (transport->trans_send != NULL) {
+ subreq = transport->trans_send(state, ev, data, data_len,
+ max_rdata_len, transport->priv);
if (subreq == NULL) {
status = NT_STATUS_NO_MEMORY;
goto post_status;
}
- subreq->async.fn = cli_api_pipe_np_trans_done;
+ subreq->async.fn = cli_api_pipe_trans_done;
subreq->async.priv = result;
return result;
}
- if ((cli->transport_type == NCACN_IP_TCP)
- || (cli->transport_type == NCACN_UNIX_STREAM)) {
- subreq = sendall_send(state, ev, cli->trans.sock.fd,
- data, data_len, 0);
- if (subreq == NULL) {
- status = NT_STATUS_NO_MEMORY;
- goto post_status;
- }
- subreq->async.fn = cli_api_pipe_sock_send_done;
- subreq->async.priv = result;
- return result;
+ /*
+ * If the transport does not provide a "trans" routine, i.e. for
+ * example the ncacn_ip_tcp transport, do the write/read step here.
+ */
+
+ subreq = rpc_write_send(state, ev, transport, data, data_len);
+ if (subreq == NULL) {
+ goto fail;
}
+ subreq->async.fn = cli_api_pipe_write_done;
+ subreq->async.priv = result;
+ return result;
status = NT_STATUS_INVALID_PARAMETER;
@@ -1201,11 +1087,12 @@ static struct async_req *cli_api_pipe_send(TALLOC_CTX *mem_ctx,
if (async_post_status(result, ev, status)) {
return result;
}
+ fail:
TALLOC_FREE(result);
return NULL;
}
-static void cli_api_pipe_np_trans_done(struct async_req *subreq)
+static void cli_api_pipe_trans_done(struct async_req *subreq)
{
struct async_req *req = talloc_get_type_abort(
subreq->async.priv, struct async_req);
@@ -1213,8 +1100,8 @@ static void cli_api_pipe_np_trans_done(struct async_req *subreq)
req->private_data, struct cli_api_pipe_state);
NTSTATUS status;
- status = cli_trans_recv(subreq, state, NULL, NULL, NULL, NULL,
- &state->rdata, &state->rdata_len);
+ status = state->transport->trans_recv(subreq, state, &state->rdata,
+ &state->rdata_len);
TALLOC_FREE(subreq);
if (!NT_STATUS_IS_OK(status)) {
async_req_error(req, status);
@@ -1223,7 +1110,7 @@ static void cli_api_pipe_np_trans_done(struct async_req *subreq)
async_req_done(req);
}
-static void cli_api_pipe_sock_send_done(struct async_req *subreq)
+static void cli_api_pipe_write_done(struct async_req *subreq)
{
struct async_req *req = talloc_get_type_abort(
subreq->async.priv, struct async_req);
@@ -1231,7 +1118,7 @@ static void cli_api_pipe_sock_send_done(struct async_req *subreq)
req->private_data, struct cli_api_pipe_state);
NTSTATUS status;
- status = sendall_recv(subreq);
+ status = rpc_write_recv(subreq);
TALLOC_FREE(subreq);
if (!NT_STATUS_IS_OK(status)) {
async_req_error(req, status);
@@ -1242,29 +1129,38 @@ static void cli_api_pipe_sock_send_done(struct async_req *subreq)
if (async_req_nomem(state->rdata, req)) {
return;
}
- state->rdata_len = RPC_HEADER_LEN;
- subreq = recvall_send(state, state->ev, state->cli->trans.sock.fd,
- state->rdata, RPC_HEADER_LEN, 0);
+ /*
+ * We don't need to use rpc_read_send here, the upper layer will cope
+ * with a short read, transport->trans_send could also return less
+ * than state->max_rdata_len.
+ */
+ subreq = state->transport->read_send(state, state->ev, state->rdata,
+ RPC_HEADER_LEN,
+ state->transport->priv);
if (async_req_nomem(subreq, req)) {
return;
}
- subreq->async.fn = cli_api_pipe_sock_read_done;
+ subreq->async.fn = cli_api_pipe_read_done;
subreq->async.priv = req;
}
-static void cli_api_pipe_sock_read_done(struct async_req *subreq)
+static void cli_api_pipe_read_done(struct async_req *subreq)
{
struct async_req *req = talloc_get_type_abort(
subreq->async.priv, struct async_req);
+ struct cli_api_pipe_state *state = talloc_get_type_abort(
+ req->private_data, struct cli_api_pipe_state);
NTSTATUS status;
+ ssize_t received;
- status = recvall_recv(subreq);
+ status = state->transport->read_recv(subreq, &received);
TALLOC_FREE(subreq);
if (!NT_STATUS_IS_OK(status)) {
async_req_error(req, status);
return;
}
+ state->rdata_len = received;
async_req_done(req);
}
@@ -1376,7 +1272,8 @@ static struct async_req *rpc_api_pipe_send(TALLOC_CTX *mem_ctx,
max_recv_frag = RPC_HEADER_LEN + 10 + (sys_random() % 32);
#endif
- subreq = cli_api_pipe_send(state, ev, cli, (uint8_t *)prs_data_p(data),
+ subreq = cli_api_pipe_send(state, ev, cli->transport,
+ (uint8_t *)prs_data_p(data),
prs_offset(data), max_recv_frag);
if (subreq == NULL) {
status = NT_STATUS_NO_MEMORY;
@@ -2194,9 +2091,10 @@ struct async_req *rpc_api_pipe_req_send(TALLOC_CTX *mem_ctx,
subreq->async.fn = rpc_api_pipe_req_done;
subreq->async.priv = result;
} else {
- subreq = rpc_write_send(state, ev, cli,
- prs_data_p(&state->outgoing_frag),
- prs_offset(&state->outgoing_frag));
+ subreq = rpc_write_send(
+ state, ev, cli->transport,
+ (uint8_t *)prs_data_p(&state->outgoing_frag),
+ prs_offset(&state->outgoing_frag));
if (subreq == NULL) {
status = NT_STATUS_NO_MEMORY;
goto post_status;
@@ -2331,9 +2229,11 @@ static void rpc_api_pipe_req_write_done(struct async_req *subreq)
subreq->async.fn = rpc_api_pipe_req_done;
subreq->async.priv = req;
} else {
- subreq = rpc_write_send(state, state->ev, state->cli,
- prs_data_p(&state->outgoing_frag),
- prs_offset(&state->outgoing_frag));
+ subreq = rpc_write_send(
+ state, state->ev,
+ state->cli->transport,
+ (uint8_t *)prs_data_p(&state->outgoing_frag),
+ prs_offset(&state->outgoing_frag));
if (async_req_nomem(subreq, req)) {
return;
}
@@ -2817,8 +2717,8 @@ static NTSTATUS rpc_finish_auth3_bind_send(struct async_req *req,
return status;
}
- subreq = rpc_write_send(state, state->ev, state->cli,
- prs_data_p(&state->rpc_out),
+ subreq = rpc_write_send(state, state->ev, state->cli->transport,
+ (uint8_t *)prs_data_p(&state->rpc_out),
prs_offset(&state->rpc_out));
if (subreq == NULL) {
return NT_STATUS_NO_MEMORY;
@@ -3030,56 +2930,33 @@ NTSTATUS rpc_pipe_bind(struct rpc_pipe_client *cli,
return status;
}
-unsigned int rpccli_set_timeout(struct rpc_pipe_client *cli,
+unsigned int rpccli_set_timeout(struct rpc_pipe_client *rpc_cli,
unsigned int timeout)
{
- return cli_set_timeout(cli->trans.np.cli, timeout);
-}
-
-bool rpccli_get_pwd_hash(struct rpc_pipe_client *cli, uint8_t nt_hash[16])
-{
- if ((cli->auth->auth_type == PIPE_AUTH_TYPE_NTLMSSP)
- || (cli->auth->auth_type == PIPE_AUTH_TYPE_SPNEGO_NTLMSSP)) {
- memcpy(nt_hash, cli->auth->a_u.ntlmssp_state->nt_hash, 16);
- return true;
- }
-
- if (cli->transport_type == NCACN_NP) {
- E_md4hash(cli->trans.np.cli->pwd.password, nt_hash);
- return true;
- }
-
- return false;
-}
+ struct cli_state *cli = rpc_pipe_np_smb_conn(rpc_cli);
-struct cli_state *rpc_pipe_np_smb_conn(struct rpc_pipe_client *p)
-{
- if (p->transport_type == NCACN_NP) {
- return p->trans.np.cli;
+ if (cli == NULL) {
+ return 0;
}
- return NULL;
+ return cli_set_timeout(cli, timeout);
}
-static int rpc_pipe_destructor(struct rpc_pipe_client *p)
+bool rpccli_get_pwd_hash(struct rpc_pipe_client *rpc_cli, uint8_t nt_hash[16])
{
- if (p->transport_type == NCACN_NP) {
- bool ret;
- ret = cli_close(p->trans.np.cli, p->trans.np.fnum);
- if (!ret) {
- DEBUG(1, ("rpc_pipe_destructor: cli_close failed on "
- "pipe %s. Error was %s\n",
- rpccli_pipe_txt(debug_ctx(), p),
- cli_errstr(p->trans.np.cli)));
- }
-
- DEBUG(10, ("rpc_pipe_destructor: closed %s\n",
- rpccli_pipe_txt(debug_ctx(), p)));
+ struct cli_state *cli;
- DLIST_REMOVE(p->trans.np.cli->pipe_list, p);
- return ret ? -1 : 0;
+ if ((rpc_cli->auth->auth_type == PIPE_AUTH_TYPE_NTLMSSP)
+ || (rpc_cli->auth->auth_type == PIPE_AUTH_TYPE_SPNEGO_NTLMSSP)) {
+ memcpy(nt_hash, rpc_cli->auth->a_u.ntlmssp_state->nt_hash, 16);
+ return true;
}
- return -1;
+ cli = rpc_pipe_np_smb_conn(rpc_cli);
+ if (cli == NULL) {
+ return false;
+ }
+ E_md4hash(cli->pwd.password, nt_hash);
+ return true;
}
NTSTATUS rpccli_anon_bind_data(TALLOC_CTX *mem_ctx,
@@ -3287,12 +3164,6 @@ NTSTATUS rpccli_kerberos_bind_data(TALLOC_CTX *mem_ctx,
#endif
}
-static int rpc_pipe_sock_destructor(struct rpc_pipe_client *p)
-{
- close(p->trans.sock.fd);
- return 0;
-}
-
/**
* Create an rpc pipe client struct, connecting to a tcp port.
*/
@@ -3304,14 +3175,13 @@ static NTSTATUS rpc_pipe_open_tcp_port(TALLOC_CTX *mem_ctx, const char *host,
struct rpc_pipe_client *result;
struct sockaddr_storage addr;
NTSTATUS status;
+ int fd;
result = TALLOC_ZERO_P(mem_ctx, struct rpc_pipe_client);
if (result == NULL) {
return NT_STATUS_NO_MEMORY;
}
- result->transport_type = NCACN_IP_TCP;
-
result->abstract_syntax = *abstract_syntax;
result->transfer_syntax = ndr_transfer_syntax;
result->dispatch = cli_do_rpc_ndr;
@@ -3332,12 +3202,17 @@ static NTSTATUS rpc_pipe_open_tcp_port(TALLOC_CTX *mem_ctx, const char *host,
goto fail;
}
- status = open_socket_out(&addr, port, 60, &result->trans.sock.fd);
+ status = open_socket_out(&addr, port, 60, &fd);
if (!NT_STATUS_IS_OK(status)) {
goto fail;
}
+ set_socket_options(fd, lp_socket_options());
- talloc_set_destructor(result, rpc_pipe_sock_destructor);
+ status = rpc_transport_sock_init(result, fd, &result->transport);
+ if (!NT_STATUS_IS_OK(status)) {
+ close(fd);
+ goto fail;
+ }
*presult = result;
return NT_STATUS_OK;
@@ -3512,14 +3387,13 @@ NTSTATUS rpc_pipe_open_ncalrpc(TALLOC_CTX *mem_ctx, const char *socket_path,
struct rpc_pipe_client *result;
struct sockaddr_un addr;
NTSTATUS status;
+ int fd;
result = talloc_zero(mem_ctx, struct rpc_pipe_client);
if (result == NULL) {
return NT_STATUS_NO_MEMORY;
}
- result->transport_type = NCACN_UNIX_STREAM;
-
result->abstract_syntax = *abstract_syntax;
result->transfer_syntax = ndr_transfer_syntax;
result->dispatch = cli_do_rpc_ndr;
@@ -3535,26 +3409,29 @@ NTSTATUS rpc_pipe_open_ncalrpc(TALLOC_CTX *mem_ctx, const char *socket_path,
result->max_xmit_frag = RPC_MAX_PDU_FRAG_LEN;
result->max_recv_frag = RPC_MAX_PDU_FRAG_LEN;
- result->trans.sock.fd = socket(AF_UNIX, SOCK_STREAM, 0);
- if (result->trans.sock.fd == -1) {
+ fd = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (fd == -1) {
status = map_nt_error_from_unix(errno);
goto fail;
}
- talloc_set_destructor(result, rpc_pipe_sock_destructor);
-
ZERO_STRUCT(addr);
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, socket_path, sizeof(addr.sun_path));
- if (sys_connect(result->trans.sock.fd,
- (struct sockaddr *)&addr) == -1) {
+ if (sys_connect(fd, (struct sockaddr *)&addr) == -1) {
DEBUG(0, ("connect(%s) failed: %s\n", socket_path,
strerror(errno)));
- close(result->trans.sock.fd);
+ close(fd);
return map_nt_error_from_unix(errno);
}
+ status = rpc_transport_sock_init(result, fd, &result->transport);
+ if (!NT_STATUS_IS_OK(status)) {
+ close(fd);
+ goto fail;
+ }
+
*presult = result;
return NT_STATUS_OK;
@@ -3563,6 +3440,16 @@ NTSTATUS rpc_pipe_open_ncalrpc(TALLOC_CTX *mem_ctx, const char *socket_path,
return status;
}
+static int rpc_pipe_client_np_destructor(struct rpc_pipe_client *p)
+{
+ struct cli_state *cli;
+
+ cli = rpc_pipe_np_smb_conn(p);
+ if (cli != NULL) {
+ DLIST_REMOVE(cli->pipe_list, p);
+ }
+ return 0;
+}
/****************************************************************************
Open a named pipe over SMB to a remote server.
@@ -3582,7 +3469,7 @@ static NTSTATUS rpc_pipe_open_np(struct cli_state *cli,
struct rpc_pipe_client **presult)
{
struct rpc_pipe_client *result;
- int fnum;
+ NTSTATUS status;
/* sanity check to protect against crashes */
@@ -3595,17 +3482,6 @@ static NTSTATUS rpc_pipe_open_np(struct cli_state *cli,
return NT_STATUS_NO_MEMORY;
}
- result->transport_type = NCACN_NP;
-
- result->trans.np.pipe_name = cli_get_pipe_name_from_iface(
- result, abstract_syntax);
- if (result->trans.np.pipe_name == NULL) {
- DEBUG(1, ("Could not find pipe for interface\n"));
- TALLOC_FREE(result);
- return NT_STATUS_INVALID_PARAMETER;
- }
-
- result->trans.np.cli = cli;
result->abstract_syntax = *abstract_syntax;
result->transfer_syntax = ndr_transfer_syntax;
result->dispatch = cli_do_rpc_ndr;
@@ -3621,21 +3497,15 @@ static NTSTATUS rpc_pipe_open_np(struct cli_state *cli,
return NT_STATUS_NO_MEMORY;
}
- fnum = cli_nt_create(cli, result->trans.np.pipe_name,
- DESIRED_ACCESS_PIPE);
- if (fnum == -1) {
- DEBUG(3,("rpc_pipe_open_np: cli_nt_create failed on pipe %s "
- "to machine %s. Error was %s\n",
- result->trans.np.pipe_name, cli->desthost,
- cli_errstr(cli)));
+ status = rpc_transport_np_init(result, cli, abstract_syntax,
+ &result->transport);
+ if (!NT_STATUS_IS_OK(status)) {
TALLOC_FREE(result);
- return cli_get_nt_error(cli);
+ return status;
}
- result->trans.np.fnum = fnum;
-
DLIST_ADD(cli->pipe_list, result);
- talloc_set_destructor(result, rpc_pipe_destructor);
+ talloc_set_destructor(result, rpc_pipe_client_np_destructor);
*presult = result;
return NT_STATUS_OK;
@@ -3725,7 +3595,8 @@ NTSTATUS cli_rpc_pipe_open_noauth(struct cli_state *cli,
}
DEBUG(10,("cli_rpc_pipe_open_noauth: opened pipe %s to machine "
- "%s and bound anonymously.\n", result->trans.np.pipe_name,
+ "%s and bound anonymously.\n",
+ cli_get_pipe_name_from_iface(debug_ctx(), interface),
cli->desthost ));
*presult = result;
@@ -3772,8 +3643,8 @@ static NTSTATUS cli_rpc_pipe_open_ntlmssp_internal(struct cli_state *cli,
DEBUG(10,("cli_rpc_pipe_open_ntlmssp_internal: opened pipe %s to "
"machine %s and bound NTLMSSP as user %s\\%s.\n",
- result->trans.np.pipe_name, cli->desthost,
- domain, username ));
+ cli_get_pipe_name_from_iface(debug_ctx(), interface),
+ cli->desthost, domain, username ));
*presult = result;
return NT_STATUS_OK;
@@ -3963,9 +3834,9 @@ NTSTATUS cli_rpc_pipe_open_schannel_with_key(struct cli_state *cli,
}
DEBUG(10,("cli_rpc_pipe_open_schannel_with_key: opened pipe %s to machine %s "
- "for domain %s "
- "and bound using schannel.\n",
- result->trans.np.pipe_name, cli->desthost, domain ));
+ "for domain %s and bound using schannel.\n",
+ cli_get_pipe_name_from_iface(debug_ctx(), interface),
+ cli->desthost, domain ));
*presult = result;
return NT_STATUS_OK;
@@ -4190,8 +4061,6 @@ NTSTATUS rpc_pipe_open_internal(TALLOC_CTX *mem_ctx, const struct ndr_syntax_id
return NT_STATUS_NO_MEMORY;
}
- result->transport_type = NCACN_INTERNAL;
-
result->abstract_syntax = *abstract_syntax;
result->transfer_syntax = ndr_transfer_syntax;
result->dispatch = dispatch;
diff --git a/source3/rpc_client/rpc_transport_np.c b/source3/rpc_client/rpc_transport_np.c
new file mode 100644
index 0000000000..e8a333e509
--- /dev/null
+++ b/source3/rpc_client/rpc_transport_np.c
@@ -0,0 +1,329 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * RPC client transport over named pipes
+ * Copyright (C) Volker Lendecke 2009
+ *
+ * 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_RPC_CLI
+
+struct rpc_transport_np_state {
+ struct cli_state *cli;
+ const char *pipe_name;
+ uint16_t fnum;
+};
+
+static int rpc_transport_np_state_destructor(struct rpc_transport_np_state *s)
+{
+ bool ret;
+ ret = cli_close(s->cli, s->fnum);
+ if (!ret) {
+ DEBUG(1, ("rpc_transport_np_state_destructor: cli_close "
+ "failed on pipe %s. Error was %s\n", s->pipe_name,
+ cli_errstr(s->cli)));
+ }
+ DEBUG(10, ("rpc_pipe_destructor: closed %s\n", s->pipe_name));
+ /*
+ * We can't do much on failure
+ */
+ return 0;
+}
+
+struct rpc_np_write_state {
+ size_t size;
+ size_t written;
+};
+
+static void rpc_np_write_done(struct async_req *subreq);
+
+static struct async_req *rpc_np_write_send(TALLOC_CTX *mem_ctx,
+ struct event_context *ev,
+ const uint8_t *data, size_t size,
+ void *priv)
+{
+ struct rpc_transport_np_state *np_transport = talloc_get_type_abort(
+ priv, struct rpc_transport_np_state);
+ struct async_req *result, *subreq;
+ struct rpc_np_write_state *state;
+
+ if (!async_req_setup(mem_ctx, &result, &state,
+ struct rpc_np_write_state)) {
+ return NULL;
+ }
+ state->size = size;
+
+ subreq = cli_write_andx_send(mem_ctx, ev, np_transport->cli,
+ np_transport->fnum,
+ 8, /* 8 means message mode. */
+ data, 0, size);
+ if (subreq == NULL) {
+ goto fail;
+ }
+ subreq->async.fn = rpc_np_write_done;
+ subreq->async.priv = result;
+ return result;
+ fail:
+ TALLOC_FREE(result);
+ return NULL;
+}
+
+static void rpc_np_write_done(struct async_req *subreq)
+{
+ struct async_req *req = talloc_get_type_abort(
+ subreq->async.priv, struct async_req);
+ struct rpc_np_write_state *state = talloc_get_type_abort(
+ req->private_data, struct rpc_np_write_state);
+ NTSTATUS status;
+
+ status = cli_write_andx_recv(subreq, &state->written);
+ TALLOC_FREE(subreq);
+ if (!NT_STATUS_IS_OK(status)) {
+ async_req_error(req, status);
+ return;
+ }
+ async_req_done(req);
+}
+
+static NTSTATUS rpc_np_write_recv(struct async_req *req, ssize_t *pwritten)
+{
+ struct rpc_np_write_state *state = talloc_get_type_abort(
+ req->private_data, struct rpc_np_write_state);
+ NTSTATUS status;
+
+ if (async_req_is_error(req, &status)) {
+ return status;
+ }
+ *pwritten = state->written;
+ return NT_STATUS_OK;
+}
+
+struct rpc_np_read_state {
+ uint8_t *data;
+ size_t size;
+ ssize_t received;
+};
+
+static void rpc_np_read_done(struct async_req *subreq);
+
+static struct async_req *rpc_np_read_send(TALLOC_CTX *mem_ctx,
+ struct event_context *ev,
+ uint8_t *data, size_t size,
+ void *priv)
+{
+ struct rpc_transport_np_state *np_transport = talloc_get_type_abort(
+ priv, struct rpc_transport_np_state);
+ struct async_req *result, *subreq;
+ struct rpc_np_read_state *state;
+
+ if (!async_req_setup(mem_ctx, &result, &state,
+ struct rpc_np_read_state)) {
+ return NULL;
+ }
+ state->data = data;
+ state->size = size;
+
+ subreq = cli_read_andx_send(mem_ctx, ev, np_transport->cli,
+ np_transport->fnum, 0, size);
+ if (subreq == NULL) {
+ goto fail;
+ }
+ subreq->async.fn = rpc_np_read_done;
+ subreq->async.priv = result;
+ return result;
+ fail:
+ TALLOC_FREE(result);
+ return NULL;
+}
+
+static void rpc_np_read_done(struct async_req *subreq)
+{
+ struct async_req *req = talloc_get_type_abort(
+ subreq->async.priv, struct async_req);
+ struct rpc_np_read_state *state = talloc_get_type_abort(
+ req->private_data, struct rpc_np_read_state);
+ NTSTATUS status;
+ uint8_t *rcvbuf;
+
+ status = cli_read_andx_recv(subreq, &state->received, &rcvbuf);
+ /*
+ * We can't TALLOC_FREE(subreq) as usual here, as rcvbuf still is a
+ * child of that.
+ */
+ if (NT_STATUS_EQUAL(status, NT_STATUS_BUFFER_TOO_SMALL)) {
+ status = NT_STATUS_OK;
+ }
+ if (!NT_STATUS_IS_OK(status)) {
+ TALLOC_FREE(subreq);
+ async_req_error(req, status);
+ return;
+ }
+
+ if (state->received > state->size) {
+ TALLOC_FREE(subreq);
+ async_req_error(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
+ return;
+ }
+
+ memcpy(state->data, rcvbuf, state->received);
+ async_req_done(req);
+}
+
+static NTSTATUS rpc_np_read_recv(struct async_req *req, ssize_t *preceived)
+{
+ struct rpc_np_read_state *state = talloc_get_type_abort(
+ req->private_data, struct rpc_np_read_state);
+ NTSTATUS status;
+
+ if (async_req_is_error(req, &status)) {
+ return status;
+ }
+ *preceived = state->received;
+ return NT_STATUS_OK;
+}
+
+struct rpc_np_trans_state {
+ uint16_t setup[2];
+ uint8_t *rdata;
+ uint32_t rdata_len;
+};
+
+static void rpc_np_trans_done(struct async_req *subreq);
+
+static struct async_req *rpc_np_trans_send(TALLOC_CTX *mem_ctx,
+ struct event_context *ev,
+ uint8_t *data, size_t data_len,
+ uint32_t max_rdata_len,
+ void *priv)
+{
+ struct rpc_transport_np_state *np_transport = talloc_get_type_abort(
+ priv, struct rpc_transport_np_state);
+ struct async_req *result, *subreq;
+ struct rpc_np_trans_state *state;
+
+ if (!async_req_setup(mem_ctx, &result, &state,
+ struct rpc_np_trans_state)) {
+ return NULL;
+ }
+
+ SSVAL(state->setup+0, 0, TRANSACT_DCERPCCMD);
+ SSVAL(state->setup+1, 0, np_transport->fnum);
+
+ subreq = cli_trans_send(
+ state, ev, np_transport->cli, SMBtrans,
+ "\\PIPE\\", 0, 0, 0, state->setup, 2, 0,
+ NULL, 0, 0, data, data_len, max_rdata_len);
+ if (subreq == NULL) {
+ goto fail;
+ }
+ subreq->async.fn = rpc_np_trans_done;
+ subreq->async.priv = result;
+ return result;
+
+ fail:
+ TALLOC_FREE(result);
+ return NULL;
+}
+
+static void rpc_np_trans_done(struct async_req *subreq)
+{
+ struct async_req *req = talloc_get_type_abort(
+ subreq->async.priv, struct async_req);
+ struct rpc_np_trans_state *state = talloc_get_type_abort(
+ req->private_data, struct rpc_np_trans_state);
+ NTSTATUS status;
+
+ status = cli_trans_recv(subreq, state, NULL, NULL, NULL, NULL,
+ &state->rdata, &state->rdata_len);
+ TALLOC_FREE(subreq);
+ if (!NT_STATUS_IS_OK(status)) {
+ async_req_error(req, status);
+ return;
+ }
+ async_req_done(req);
+}
+
+static NTSTATUS rpc_np_trans_recv(struct async_req *req, TALLOC_CTX *mem_ctx,
+ uint8_t **prdata, uint32_t *prdata_len)
+{
+ struct rpc_np_trans_state *state = talloc_get_type_abort(
+ req->private_data, struct rpc_np_trans_state);
+ NTSTATUS status;
+
+ if (async_req_is_error(req, &status)) {
+ return status;
+ }
+ *prdata = talloc_move(mem_ctx, &state->rdata);
+ *prdata_len = state->rdata_len;
+ return NT_STATUS_OK;
+}
+
+NTSTATUS rpc_transport_np_init(TALLOC_CTX *mem_ctx, struct cli_state *cli,
+ const struct ndr_syntax_id *abstract_syntax,
+ struct rpc_cli_transport **presult)
+{
+ struct rpc_cli_transport *result;
+ struct rpc_transport_np_state *state;
+ int fnum;
+
+ result = talloc(mem_ctx, struct rpc_cli_transport);
+ if (result == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ state = talloc(result, struct rpc_transport_np_state);
+ if (state == NULL) {
+ TALLOC_FREE(result);
+ return NT_STATUS_NO_MEMORY;
+ }
+ result->priv = state;
+
+ state->cli = cli;
+ state->pipe_name = cli_get_pipe_name_from_iface(
+ state, abstract_syntax);
+
+ fnum = cli_nt_create(cli, state->pipe_name, DESIRED_ACCESS_PIPE);
+ if (fnum == -1) {
+ DEBUG(3,("rpc_pipe_open_np: cli_nt_create failed on pipe %s "
+ "to machine %s. Error was %s\n", state->pipe_name,
+ cli->desthost, cli_errstr(cli)));
+ TALLOC_FREE(result);
+ return cli_get_nt_error(cli);
+ }
+ state->fnum = fnum;
+ talloc_set_destructor(state, rpc_transport_np_state_destructor);
+
+ result->write_send = rpc_np_write_send;
+ result->write_recv = rpc_np_write_recv;
+ result->read_send = rpc_np_read_send;
+ result->read_recv = rpc_np_read_recv;
+ result->trans_send = rpc_np_trans_send;
+ result->trans_recv = rpc_np_trans_recv;
+
+ *presult = result;
+ return NT_STATUS_OK;
+}
+
+struct cli_state *rpc_pipe_np_smb_conn(struct rpc_pipe_client *p)
+{
+ struct rpc_transport_np_state *state = talloc_get_type(
+ p->transport->priv, struct rpc_transport_np_state);
+
+ if (state == NULL) {
+ return NULL;
+ }
+ return state->cli;
+}
diff --git a/source3/rpc_client/rpc_transport_sock.c b/source3/rpc_client/rpc_transport_sock.c
new file mode 100644
index 0000000000..c0fa41b0de
--- /dev/null
+++ b/source3/rpc_client/rpc_transport_sock.c
@@ -0,0 +1,116 @@
+/*
+ * Unix SMB/CIFS implementation.
+ * RPC client transport over a socket
+ * Copyright (C) Volker Lendecke 2009
+ *
+ * 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_RPC_CLI
+
+struct rpc_transport_sock_state {
+ int fd;
+};
+
+static int rpc_transport_sock_state_destructor(struct rpc_transport_sock_state *s)
+{
+ if (s->fd != -1) {
+ close(s->fd);
+ s->fd = -1;
+ }
+ return 0;
+}
+
+static struct async_req *rpc_sock_read_send(TALLOC_CTX *mem_ctx,
+ struct event_context *ev,
+ uint8_t *data, size_t size,
+ void *priv)
+{
+ struct rpc_transport_sock_state *sock_transp = talloc_get_type_abort(
+ priv, struct rpc_transport_sock_state);
+ return async_recv(mem_ctx, ev, sock_transp->fd, data, size, 0);
+}
+
+static NTSTATUS rpc_sock_read_recv(struct async_req *req, ssize_t *preceived)
+{
+ ssize_t received;
+ int sys_errno;
+
+ received = async_syscall_result_ssize_t(req, &sys_errno);
+ if (received == -1) {
+ return map_nt_error_from_unix(sys_errno);
+ }
+ if (received == 0) {
+ return NT_STATUS_END_OF_FILE;
+ }
+ *preceived = received;
+ return NT_STATUS_OK;
+}
+
+static struct async_req *rpc_sock_write_send(TALLOC_CTX *mem_ctx,
+ struct event_context *ev,
+ const uint8_t *data, size_t size,
+ void *priv)
+{
+ struct rpc_transport_sock_state *sock_transp = talloc_get_type_abort(
+ priv, struct rpc_transport_sock_state);
+ return async_send(mem_ctx, ev, sock_transp->fd, data, size, 0);
+}
+
+static NTSTATUS rpc_sock_write_recv(struct async_req *req, ssize_t *psent)
+{
+ ssize_t sent;
+ int sys_errno;
+
+ sent = async_syscall_result_ssize_t(req, &sys_errno);
+ if (sent == -1) {
+ return map_nt_error_from_unix(sys_errno);
+ }
+ *psent = sent;
+ return NT_STATUS_OK;
+}
+
+NTSTATUS rpc_transport_sock_init(TALLOC_CTX *mem_ctx, int fd,
+ struct rpc_cli_transport **presult)
+{
+ struct rpc_cli_transport *result;
+ struct rpc_transport_sock_state *state;
+
+ result = talloc(mem_ctx, struct rpc_cli_transport);
+ if (result == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ state = talloc(result, struct rpc_transport_sock_state);
+ if (state == NULL) {
+ TALLOC_FREE(result);
+ return NT_STATUS_NO_MEMORY;
+ }
+ result->priv = state;
+
+ state->fd = fd;
+ talloc_set_destructor(state, rpc_transport_sock_state_destructor);
+
+ result->trans_send = NULL;
+ result->trans_recv = NULL;
+ result->write_send = rpc_sock_write_send;
+ result->write_recv = rpc_sock_write_recv;
+ result->read_send = rpc_sock_read_send;
+ result->read_recv = rpc_sock_read_recv;
+
+ *presult = result;
+ return NT_STATUS_OK;
+}
diff --git a/source3/rpc_parse/parse_eventlog.c b/source3/rpc_parse/parse_eventlog.c
index a55993cc2e..40930a2500 100644
--- a/source3/rpc_parse/parse_eventlog.c
+++ b/source3/rpc_parse/parse_eventlog.c
@@ -185,6 +185,7 @@ bool eventlog_io_r_read_eventlog(const char *desc,
/* Now pad with whitespace until the end of the response buffer */
if (q_u->max_read_size - r_u->num_bytes_in_resp) {
+ r_u->end_of_entries_padding = PRS_ALLOC_MEM(ps, uint8_t, q_u->max_read_size - r_u->num_bytes_in_resp);
if (!r_u->end_of_entries_padding) {
return False;
}
@@ -192,11 +193,8 @@ bool eventlog_io_r_read_eventlog(const char *desc,
if(!(prs_uint8s(False, "end of entries padding", ps,
depth, r_u->end_of_entries_padding,
(q_u->max_read_size - r_u->num_bytes_in_resp)))) {
- free(r_u->end_of_entries_padding);
return False;
}
-
- free(r_u->end_of_entries_padding);
}
/* We had better be DWORD aligned here */
diff --git a/source3/rpc_server/srv_eventlog_lib.c b/source3/rpc_server/srv_eventlog_lib.c
index aa75fb1b46..8cbb319e9b 100644
--- a/source3/rpc_server/srv_eventlog_lib.c
+++ b/source3/rpc_server/srv_eventlog_lib.c
@@ -715,7 +715,7 @@ bool parse_logentry( char *line, Eventlog_entry * entry, bool * eor )
if (!entry->data_record.strings) {
return false;
}
- memcpy(entry->data_record.strings + old_len,
+ memcpy(((char *)entry->data_record.strings) + old_len,
temp,
tmp_len);
entry->data_record.strings_len += tmp_len;
diff --git a/source3/rpc_server/srv_eventlog_nt.c b/source3/rpc_server/srv_eventlog_nt.c
index 0bf0730d39..a687025ba6 100644
--- a/source3/rpc_server/srv_eventlog_nt.c
+++ b/source3/rpc_server/srv_eventlog_nt.c
@@ -539,30 +539,30 @@ static Eventlog_entry *read_package_entry( TALLOC_CTX *mem_ctx,
return NULL;
}
offset = entry->data;
- memcpy( offset, &( entry->data_record.source_name ),
+ memcpy( offset, entry->data_record.source_name,
entry->data_record.source_name_len );
offset += entry->data_record.source_name_len;
- memcpy( offset, &( entry->data_record.computer_name ),
+ memcpy( offset, entry->data_record.computer_name,
entry->data_record.computer_name_len );
offset += entry->data_record.computer_name_len;
/* SID needs to be DWORD-aligned */
offset += entry->data_record.sid_padding;
entry->record.user_sid_offset =
sizeof( Eventlog_record ) + ( offset - entry->data );
- memcpy( offset, &( entry->data_record.sid ),
+ memcpy( offset, entry->data_record.sid,
entry->record.user_sid_length );
offset += entry->record.user_sid_length;
/* Now do the strings */
entry->record.string_offset =
sizeof( Eventlog_record ) + ( offset - entry->data );
- memcpy( offset, &( entry->data_record.strings ),
+ memcpy( offset, entry->data_record.strings,
entry->data_record.strings_len );
offset += entry->data_record.strings_len;
/* Now do the data */
entry->record.data_length = entry->data_record.user_data_len;
entry->record.data_offset =
sizeof( Eventlog_record ) + ( offset - entry->data );
- memcpy( offset, &( entry->data_record.user_data ),
+ memcpy( offset, entry->data_record.user_data,
entry->data_record.user_data_len );
offset += entry->data_record.user_data_len;
@@ -578,17 +578,15 @@ static Eventlog_entry *read_package_entry( TALLOC_CTX *mem_ctx,
/********************************************************************
********************************************************************/
-static bool add_record_to_resp( Eventlog_entry *entry,
- uint32_t *num_records,
- uint32_t *num_bytes_in_resp,
+static bool add_record_to_resp( EVENTLOG_R_READ_EVENTLOG * r_u,
Eventlog_entry * ee_new )
{
Eventlog_entry *insert_point;
- insert_point = entry;
+ insert_point = r_u->entry;
if ( NULL == insert_point ) {
- entry = ee_new;
+ r_u->entry = ee_new;
ee_new->next = NULL;
} else {
while ( ( NULL != insert_point->next ) ) {
@@ -597,8 +595,8 @@ static bool add_record_to_resp( Eventlog_entry *entry,
ee_new->next = NULL;
insert_point->next = ee_new;
}
- (*num_records)++;
- *num_bytes_in_resp += ee_new->record.length;
+ r_u->num_records++;
+ r_u->num_bytes_in_resp += ee_new->record.length;
return True;
}
@@ -775,10 +773,7 @@ NTSTATUS _eventlog_read_eventlog( pipes_struct * p,
break;
}
- add_record_to_resp( r_u->entry,
- &r_u->num_records, &r_u->num_bytes_in_resp,
- ee_new );
-
+ add_record_to_resp( r_u, ee_new );
bytes_left -= ee_new->record.length;
TALLOC_FREE(entry);
num_records_read = r_u->num_records - num_records_read;
@@ -961,3 +956,8 @@ NTSTATUS _eventlog_FlushEventLog(pipes_struct *p, struct eventlog_FlushEventLog
return NT_STATUS_NOT_IMPLEMENTED;
}
+NTSTATUS _eventlog_ReportEventAndSourceW(pipes_struct *p, struct eventlog_ReportEventAndSourceW *r)
+{
+ p->rng_fault_state = True;
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
diff --git a/source3/rpcclient/cmd_eventlog.c b/source3/rpcclient/cmd_eventlog.c
index a8373f466d..905b147ce6 100644
--- a/source3/rpcclient/cmd_eventlog.c
+++ b/source3/rpcclient/cmd_eventlog.c
@@ -197,10 +197,274 @@ static NTSTATUS cmd_eventlog_oldestrecord(struct rpc_pipe_client *cli,
return status;
}
+static NTSTATUS cmd_eventlog_reportevent(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv)
+{
+ NTSTATUS status;
+ struct policy_handle handle;
+
+ uint16_t num_of_strings = 1;
+ uint32_t data_size = 0;
+ struct lsa_String servername;
+ struct lsa_String *strings;
+ uint8_t *data = NULL;
+ uint32_t record_number = 0;
+ time_t time_written = 0;
+
+ if (argc != 2) {
+ printf("Usage: %s logname\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ status = get_eventlog_handle(cli, mem_ctx, argv[1], &handle);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ strings = talloc_array(mem_ctx, struct lsa_String, num_of_strings);
+ if (!strings) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ init_lsa_String(&strings[0], "test event written by rpcclient\n");
+ init_lsa_String(&servername, NULL);
+
+ status = rpccli_eventlog_ReportEventW(cli, mem_ctx,
+ &handle,
+ time(NULL),
+ EVENTLOG_INFORMATION_TYPE,
+ 0, /* event_category */
+ 0, /* event_id */
+ num_of_strings,
+ data_size,
+ &servername,
+ NULL, /* user_sid */
+ &strings,
+ data,
+ 0, /* flags */
+ &record_number,
+ &time_written);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+
+ printf("entry: %d written at %s\n", record_number,
+ http_timestring(talloc_tos(), time_written));
+
+ done:
+ rpccli_eventlog_CloseEventLog(cli, mem_ctx, &handle);
+
+ return status;
+}
+
+static NTSTATUS cmd_eventlog_reporteventsource(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv)
+{
+ NTSTATUS status;
+ struct policy_handle handle;
+
+ uint16_t num_of_strings = 1;
+ uint32_t data_size = 0;
+ struct lsa_String servername, sourcename;
+ struct lsa_String *strings;
+ uint8_t *data = NULL;
+ uint32_t record_number = 0;
+ time_t time_written = 0;
+
+ if (argc != 2) {
+ printf("Usage: %s logname\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ status = get_eventlog_handle(cli, mem_ctx, argv[1], &handle);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ strings = talloc_array(mem_ctx, struct lsa_String, num_of_strings);
+ if (!strings) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ init_lsa_String(&strings[0], "test event written by rpcclient\n");
+ init_lsa_String(&servername, NULL);
+ init_lsa_String(&sourcename, "rpcclient");
+
+ status = rpccli_eventlog_ReportEventAndSourceW(cli, mem_ctx,
+ &handle,
+ time(NULL),
+ EVENTLOG_INFORMATION_TYPE,
+ 0, /* event_category */
+ 0, /* event_id */
+ &sourcename,
+ num_of_strings,
+ data_size,
+ &servername,
+ NULL, /* user_sid */
+ &strings,
+ data,
+ 0, /* flags */
+ &record_number,
+ &time_written);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+
+ printf("entry: %d written at %s\n", record_number,
+ http_timestring(talloc_tos(), time_written));
+
+ done:
+ rpccli_eventlog_CloseEventLog(cli, mem_ctx, &handle);
+
+ return status;
+}
+
+static NTSTATUS cmd_eventlog_registerevsource(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv)
+{
+ NTSTATUS status;
+ struct policy_handle log_handle;
+ struct lsa_String module_name, reg_module_name;
+ struct eventlog_OpenUnknown0 unknown0;
+
+ unknown0.unknown0 = 0x005c;
+ unknown0.unknown1 = 0x0001;
+
+ if (argc != 2) {
+ printf("Usage: %s logname\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ init_lsa_String(&module_name, "rpcclient");
+ init_lsa_String(&reg_module_name, NULL);
+
+ status = rpccli_eventlog_RegisterEventSourceW(cli, mem_ctx,
+ &unknown0,
+ &module_name,
+ &reg_module_name,
+ 1, /* major_version */
+ 1, /* minor_version */
+ &log_handle);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+
+ done:
+ rpccli_eventlog_DeregisterEventSource(cli, mem_ctx, &log_handle);
+
+ return status;
+}
+
+static NTSTATUS cmd_eventlog_backuplog(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv)
+{
+ NTSTATUS status;
+ struct policy_handle handle;
+ struct lsa_String backup_filename;
+ const char *tmp;
+
+ if (argc != 3) {
+ printf("Usage: %s logname backupname\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ status = get_eventlog_handle(cli, mem_ctx, argv[1], &handle);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ tmp = talloc_asprintf(mem_ctx, "\\??\\%s", argv[2]);
+ if (!tmp) {
+ status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ init_lsa_String(&backup_filename, tmp);
+
+ status = rpccli_eventlog_BackupEventLogW(cli, mem_ctx,
+ &handle,
+ &backup_filename);
+
+ done:
+ rpccli_eventlog_CloseEventLog(cli, mem_ctx, &handle);
+
+ return status;
+}
+
+static NTSTATUS cmd_eventlog_loginfo(struct rpc_pipe_client *cli,
+ TALLOC_CTX *mem_ctx,
+ int argc,
+ const char **argv)
+{
+ NTSTATUS status;
+ struct policy_handle handle;
+ uint8_t *buffer = NULL;
+ uint32_t buf_size = 0;
+ uint32_t bytes_needed = 0;
+
+ if (argc != 2) {
+ printf("Usage: %s logname\n", argv[0]);
+ return NT_STATUS_OK;
+ }
+
+ status = get_eventlog_handle(cli, mem_ctx, argv[1], &handle);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ status = rpccli_eventlog_GetLogIntormation(cli, mem_ctx,
+ &handle,
+ 0, /* level */
+ buffer,
+ buf_size,
+ &bytes_needed);
+ if (!NT_STATUS_IS_OK(status) &&
+ !NT_STATUS_EQUAL(status, NT_STATUS_BUFFER_TOO_SMALL)) {
+ goto done;
+ }
+
+ buf_size = bytes_needed;
+ buffer = talloc_array(mem_ctx, uint8_t, bytes_needed);
+ if (!buffer) {
+ status = NT_STATUS_NO_MEMORY;
+ goto done;
+ }
+
+ status = rpccli_eventlog_GetLogIntormation(cli, mem_ctx,
+ &handle,
+ 0, /* level */
+ buffer,
+ buf_size,
+ &bytes_needed);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+
+ done:
+ rpccli_eventlog_CloseEventLog(cli, mem_ctx, &handle);
+
+ return status;
+}
+
+
struct cmd_set eventlog_commands[] = {
{ "EVENTLOG" },
{ "eventlog_readlog", RPC_RTYPE_NTSTATUS, cmd_eventlog_readlog, NULL, &ndr_table_eventlog.syntax_id, NULL, "Read Eventlog", "" },
{ "eventlog_numrecord", RPC_RTYPE_NTSTATUS, cmd_eventlog_numrecords, NULL, &ndr_table_eventlog.syntax_id, NULL, "Get number of records", "" },
{ "eventlog_oldestrecord", RPC_RTYPE_NTSTATUS, cmd_eventlog_oldestrecord, NULL, &ndr_table_eventlog.syntax_id, NULL, "Get oldest record", "" },
+ { "eventlog_reportevent", RPC_RTYPE_NTSTATUS, cmd_eventlog_reportevent, NULL, &ndr_table_eventlog.syntax_id, NULL, "Report event", "" },
+ { "eventlog_reporteventsource", RPC_RTYPE_NTSTATUS, cmd_eventlog_reporteventsource, NULL, &ndr_table_eventlog.syntax_id, NULL, "Report event and source", "" },
+ { "eventlog_registerevsource", RPC_RTYPE_NTSTATUS, cmd_eventlog_registerevsource, NULL, &ndr_table_eventlog.syntax_id, NULL, "Register event source", "" },
+ { "eventlog_backuplog", RPC_RTYPE_NTSTATUS, cmd_eventlog_backuplog, NULL, &ndr_table_eventlog.syntax_id, NULL, "Backup Eventlog File", "" },
+ { "eventlog_loginfo", RPC_RTYPE_NTSTATUS, cmd_eventlog_loginfo, NULL, &ndr_table_eventlog.syntax_id, NULL, "Get Eventlog Information", "" },
{ NULL }
};
diff --git a/source3/smbd/close.c b/source3/smbd/close.c
index abcd651d93..2fb8ec2bb5 100644
--- a/source3/smbd/close.c
+++ b/source3/smbd/close.c
@@ -465,11 +465,11 @@ void set_close_write_time(struct files_struct *fsp, struct timespec ts)
static NTSTATUS update_write_time_on_close(struct files_struct *fsp)
{
SMB_STRUCT_STAT sbuf;
- struct timespec ts[2];
+ struct smb_file_time ft;
NTSTATUS status;
ZERO_STRUCT(sbuf);
- ZERO_STRUCT(ts);
+ ZERO_STRUCT(ft);
if (!fsp->update_write_time_on_close) {
return NT_STATUS_OK;
@@ -495,9 +495,9 @@ static NTSTATUS update_write_time_on_close(struct files_struct *fsp)
return NT_STATUS_OK;
}
- ts[1] = fsp->close_write_time;
+ ft.mtime = fsp->close_write_time;
status = smb_set_file_time(fsp->conn, fsp, fsp->fsp_name,
- &sbuf, ts, true);
+ &sbuf, &ft, true);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
diff --git a/source3/smbd/dosmode.c b/source3/smbd/dosmode.c
index ade5e66e86..555718bd83 100644
--- a/source3/smbd/dosmode.c
+++ b/source3/smbd/dosmode.c
@@ -704,7 +704,8 @@ int file_set_dosmode(connection_struct *conn, const char *fname,
than POSIX.
*******************************************************************/
-int file_ntimes(connection_struct *conn, const char *fname, const struct timespec ts[2])
+int file_ntimes(connection_struct *conn, const char *fname,
+ struct smb_file_time *ft)
{
SMB_STRUCT_STAT sbuf;
int ret = -1;
@@ -713,9 +714,11 @@ int file_ntimes(connection_struct *conn, const char *fname, const struct timespe
ZERO_STRUCT(sbuf);
DEBUG(6, ("file_ntime: actime: %s",
- time_to_asc(convert_timespec_to_time_t(ts[0]))));
+ time_to_asc(convert_timespec_to_time_t(ft->atime))));
DEBUG(6, ("file_ntime: modtime: %s",
- time_to_asc(convert_timespec_to_time_t(ts[1]))));
+ time_to_asc(convert_timespec_to_time_t(ft->mtime))));
+ DEBUG(6, ("file_ntime: createtime: %s",
+ time_to_asc(convert_timespec_to_time_t(ft->create_time))));
/* Don't update the time on read-only shares */
/* We need this as set_filetime (which can be called on
@@ -728,7 +731,7 @@ int file_ntimes(connection_struct *conn, const char *fname, const struct timespe
return 0;
}
- if(SMB_VFS_NTIMES(conn, fname, ts) == 0) {
+ if(SMB_VFS_NTIMES(conn, fname, ft) == 0) {
return 0;
}
@@ -750,7 +753,7 @@ int file_ntimes(connection_struct *conn, const char *fname, const struct timespe
if (can_write_to_file(conn, fname, &sbuf)) {
/* We are allowed to become root and change the filetime. */
become_root();
- ret = SMB_VFS_NTIMES(conn, fname, ts);
+ ret = SMB_VFS_NTIMES(conn, fname, ft);
unbecome_root();
}
diff --git a/source3/smbd/posix_acls.c b/source3/smbd/posix_acls.c
index 951046c562..72f5c94bc5 100644
--- a/source3/smbd/posix_acls.c
+++ b/source3/smbd/posix_acls.c
@@ -3187,6 +3187,15 @@ int try_chown(connection_struct *conn, const char *fname, uid_t uid, gid_t gid)
return -1;
}
+ /* only allow chown to the current user. This is more secure,
+ and also copes with the case where the SID in a take ownership ACL is
+ a local SID on the users workstation
+ */
+ if (uid != current_user.ut.uid) {
+ errno = EPERM;
+ return -1;
+ }
+
if (SMB_VFS_STAT(conn,fname,&st)) {
return -1;
}
@@ -3195,12 +3204,6 @@ int try_chown(connection_struct *conn, const char *fname, uid_t uid, gid_t gid)
return -1;
}
- /* only allow chown to the current user. This is more secure,
- and also copes with the case where the SID in a take ownership ACL is
- a local SID on the users workstation
- */
- uid = current_user.ut.uid;
-
become_root();
/* Keep the current file gid the same. */
ret = SMB_VFS_FCHOWN(fsp, uid, (gid_t)-1);
@@ -3426,8 +3429,9 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, const SEC_DESC
bool acl_perms = False;
mode_t orig_mode = (mode_t)0;
NTSTATUS status;
- uid_t orig_uid;
- gid_t orig_gid;
+ bool set_acl_as_root = false;
+ bool acl_set_support = false;
+ bool ret = false;
DEBUG(10,("set_nt_acl: called for file %s\n", fsp->fsp_name ));
@@ -3448,10 +3452,8 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, const SEC_DESC
return map_nt_error_from_unix(errno);
}
- /* Save the original elements we check against. */
+ /* Save the original element we check against. */
orig_mode = sbuf.st_mode;
- orig_uid = sbuf.st_uid;
- orig_gid = sbuf.st_gid;
/*
* Unpack the user/group/world id's.
@@ -3468,7 +3470,7 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, const SEC_DESC
* Noticed by Simo.
*/
- if (((user != (uid_t)-1) && (orig_uid != user)) || (( grp != (gid_t)-1) && (orig_gid != grp))) {
+ if (((user != (uid_t)-1) && (sbuf.st_uid != user)) || (( grp != (gid_t)-1) && (sbuf.st_gid != grp))) {
DEBUG(3,("set_nt_acl: chown %s. uid = %u, gid = %u.\n",
fsp->fsp_name, (unsigned int)user, (unsigned int)grp ));
@@ -3493,174 +3495,188 @@ NTSTATUS set_nt_acl(files_struct *fsp, uint32 security_info_sent, const SEC_DESC
}
} else {
- int ret;
+ int sret;
if(fsp->fh->fd == -1)
- ret = SMB_VFS_STAT(fsp->conn, fsp->fsp_name, &sbuf);
+ sret = SMB_VFS_STAT(fsp->conn, fsp->fsp_name, &sbuf);
else
- ret = SMB_VFS_FSTAT(fsp, &sbuf);
+ sret = SMB_VFS_FSTAT(fsp, &sbuf);
- if(ret != 0)
+ if(sret != 0)
return map_nt_error_from_unix(errno);
}
- /* Save the original elements we check against. */
+ /* Save the original element we check against. */
orig_mode = sbuf.st_mode;
- orig_uid = sbuf.st_uid;
- orig_gid = sbuf.st_gid;
+
+ /* If we successfully chowned, we know we must
+ * be able to set the acl, so do it as root.
+ */
+ set_acl_as_root = true;
}
create_file_sids(&sbuf, &file_owner_sid, &file_grp_sid);
-#if 0
- /* Disable this - prevents ACL inheritance from the ACL editor. JRA. */
-
- /* See here: http://www.codeproject.com/KB/winsdk/accessctrl2.aspx
- * for details and also the log trace in bug #4308. JRA.
- */
-
- if ((security_info_sent & DACL_SECURITY_INFORMATION) &&
- psd->dacl != NULL &&
- (psd->type & (SE_DESC_DACL_AUTO_INHERITED|
- SE_DESC_DACL_AUTO_INHERIT_REQ))==
- (SE_DESC_DACL_AUTO_INHERITED|
- SE_DESC_DACL_AUTO_INHERIT_REQ) ) {
- SEC_DESC *new_sd = NULL;
- status = append_parent_acl(fsp, psd, &new_sd);
- if (!NT_STATUS_IS_OK(status)) {
- return status;
- }
- psd = new_sd;
- }
-#endif
-
acl_perms = unpack_canon_ace( fsp, &sbuf, &file_owner_sid, &file_grp_sid,
&file_ace_list, &dir_ace_list, security_info_sent, psd);
/* Ignore W2K traverse DACL set. */
- if (file_ace_list || dir_ace_list) {
+ if (!file_ace_list && !dir_ace_list) {
+ return NT_STATUS_OK;
+ }
- if (!acl_perms) {
- DEBUG(3,("set_nt_acl: cannot set permissions\n"));
- free_canon_ace_list(file_ace_list);
- free_canon_ace_list(dir_ace_list);
- return NT_STATUS_ACCESS_DENIED;
- }
+ if (!acl_perms) {
+ DEBUG(3,("set_nt_acl: cannot set permissions\n"));
+ free_canon_ace_list(file_ace_list);
+ free_canon_ace_list(dir_ace_list);
+ return NT_STATUS_ACCESS_DENIED;
+ }
- /*
- * Only change security if we got a DACL.
- */
+ /*
+ * Only change security if we got a DACL.
+ */
- if((security_info_sent & DACL_SECURITY_INFORMATION) && (psd->dacl != NULL)) {
+ if(!(security_info_sent & DACL_SECURITY_INFORMATION) || (psd->dacl == NULL)) {
+ free_canon_ace_list(file_ace_list);
+ free_canon_ace_list(dir_ace_list);
+ return NT_STATUS_OK;
+ }
+
+ /*
+ * Try using the POSIX ACL set first. Fall back to chmod if
+ * we have no ACL support on this filesystem.
+ */
- bool acl_set_support = False;
- bool ret = False;
+ if (acl_perms && file_ace_list) {
+ if (set_acl_as_root) {
+ become_root();
+ }
+ ret = set_canon_ace_list(fsp, file_ace_list, False, sbuf.st_gid, &acl_set_support);
+ if (set_acl_as_root) {
+ unbecome_root();
+ }
+ if (acl_set_support && ret == false) {
+ DEBUG(3,("set_nt_acl: failed to set file acl on file %s (%s).\n", fsp->fsp_name, strerror(errno) ));
+ free_canon_ace_list(file_ace_list);
+ free_canon_ace_list(dir_ace_list);
+ return map_nt_error_from_unix(errno);
+ }
+ }
+
+ if (acl_perms && acl_set_support && fsp->is_directory) {
+ if (dir_ace_list) {
+ if (set_acl_as_root) {
+ become_root();
+ }
+ ret = set_canon_ace_list(fsp, dir_ace_list, True, sbuf.st_gid, &acl_set_support);
+ if (set_acl_as_root) {
+ unbecome_root();
+ }
+ if (ret == false) {
+ DEBUG(3,("set_nt_acl: failed to set default acl on directory %s (%s).\n", fsp->fsp_name, strerror(errno) ));
+ free_canon_ace_list(file_ace_list);
+ free_canon_ace_list(dir_ace_list);
+ return map_nt_error_from_unix(errno);
+ }
+ } else {
+ int sret = -1;
/*
- * Try using the POSIX ACL set first. Fall back to chmod if
- * we have no ACL support on this filesystem.
+ * No default ACL - delete one if it exists.
*/
- if (acl_perms && file_ace_list) {
- ret = set_canon_ace_list(fsp, file_ace_list, False, sbuf.st_gid, &acl_set_support);
- if (acl_set_support && ret == False) {
- DEBUG(3,("set_nt_acl: failed to set file acl on file %s (%s).\n", fsp->fsp_name, strerror(errno) ));
+ if (set_acl_as_root) {
+ become_root();
+ }
+ sret = SMB_VFS_SYS_ACL_DELETE_DEF_FILE(conn, fsp->fsp_name);
+ if (set_acl_as_root) {
+ unbecome_root();
+ }
+ if (sret == -1) {
+ if (acl_group_override(conn, sbuf.st_gid, fsp->fsp_name)) {
+ DEBUG(5,("set_nt_acl: acl group control on and "
+ "current user in file %s primary group. Override delete_def_acl\n",
+ fsp->fsp_name ));
+
+ become_root();
+ sret = SMB_VFS_SYS_ACL_DELETE_DEF_FILE(conn, fsp->fsp_name);
+ unbecome_root();
+ }
+
+ if (sret == -1) {
+ DEBUG(3,("set_nt_acl: sys_acl_delete_def_file failed (%s)\n", strerror(errno)));
free_canon_ace_list(file_ace_list);
- free_canon_ace_list(dir_ace_list);
+ free_canon_ace_list(dir_ace_list);
return map_nt_error_from_unix(errno);
}
}
+ }
+ }
- if (acl_perms && acl_set_support && fsp->is_directory) {
- if (dir_ace_list) {
- if (!set_canon_ace_list(fsp, dir_ace_list, True, sbuf.st_gid, &acl_set_support)) {
- DEBUG(3,("set_nt_acl: failed to set default acl on directory %s (%s).\n", fsp->fsp_name, strerror(errno) ));
- free_canon_ace_list(file_ace_list);
- free_canon_ace_list(dir_ace_list);
- return map_nt_error_from_unix(errno);
- }
- } else {
+ if (acl_set_support) {
+ if (set_acl_as_root) {
+ become_root();
+ }
+ store_inheritance_attributes(fsp, file_ace_list, dir_ace_list,
+ (psd->type & SE_DESC_DACL_PROTECTED) ? True : False);
+ if (set_acl_as_root) {
+ unbecome_root();
+ }
+ }
- /*
- * No default ACL - delete one if it exists.
- */
+ /*
+ * If we cannot set using POSIX ACLs we fall back to checking if we need to chmod.
+ */
- if (SMB_VFS_SYS_ACL_DELETE_DEF_FILE(conn, fsp->fsp_name) == -1) {
- int sret = -1;
-
- if (acl_group_override(conn, sbuf.st_gid, fsp->fsp_name)) {
- DEBUG(5,("set_nt_acl: acl group control on and "
- "current user in file %s primary group. Override delete_def_acl\n",
- fsp->fsp_name ));
-
- become_root();
- sret = SMB_VFS_SYS_ACL_DELETE_DEF_FILE(conn, fsp->fsp_name);
- unbecome_root();
- }
-
- if (sret == -1) {
- DEBUG(3,("set_nt_acl: sys_acl_delete_def_file failed (%s)\n", strerror(errno)));
- free_canon_ace_list(file_ace_list);
- free_canon_ace_list(dir_ace_list);
- return map_nt_error_from_unix(errno);
- }
- }
- }
- }
+ if(!acl_set_support && acl_perms) {
+ mode_t posix_perms;
- if (acl_set_support) {
- store_inheritance_attributes(fsp, file_ace_list, dir_ace_list,
- (psd->type & SE_DESC_DACL_PROTECTED) ? True : False);
- }
+ if (!convert_canon_ace_to_posix_perms( fsp, file_ace_list, &posix_perms)) {
+ free_canon_ace_list(file_ace_list);
+ free_canon_ace_list(dir_ace_list);
+ DEBUG(3,("set_nt_acl: failed to convert file acl to posix permissions for file %s.\n",
+ fsp->fsp_name ));
+ return NT_STATUS_ACCESS_DENIED;
+ }
- /*
- * If we cannot set using POSIX ACLs we fall back to checking if we need to chmod.
- */
+ if (orig_mode != posix_perms) {
+ int sret = -1;
- if(!acl_set_support && acl_perms) {
- mode_t posix_perms;
+ DEBUG(3,("set_nt_acl: chmod %s. perms = 0%o.\n",
+ fsp->fsp_name, (unsigned int)posix_perms ));
- if (!convert_canon_ace_to_posix_perms( fsp, file_ace_list, &posix_perms)) {
- free_canon_ace_list(file_ace_list);
- free_canon_ace_list(dir_ace_list);
- DEBUG(3,("set_nt_acl: failed to convert file acl to posix permissions for file %s.\n",
+ if (set_acl_as_root) {
+ become_root();
+ }
+ sret = SMB_VFS_CHMOD(conn,fsp->fsp_name, posix_perms);
+ if (set_acl_as_root) {
+ unbecome_root();
+ }
+ if(sret == -1) {
+ if (acl_group_override(conn, sbuf.st_gid, fsp->fsp_name)) {
+ DEBUG(5,("set_nt_acl: acl group control on and "
+ "current user in file %s primary group. Override chmod\n",
fsp->fsp_name ));
- return NT_STATUS_ACCESS_DENIED;
+
+ become_root();
+ sret = SMB_VFS_CHMOD(conn,fsp->fsp_name, posix_perms);
+ unbecome_root();
}
- if (orig_mode != posix_perms) {
-
- DEBUG(3,("set_nt_acl: chmod %s. perms = 0%o.\n",
- fsp->fsp_name, (unsigned int)posix_perms ));
-
- if(SMB_VFS_CHMOD(conn,fsp->fsp_name, posix_perms) == -1) {
- int sret = -1;
- if (acl_group_override(conn, sbuf.st_gid, fsp->fsp_name)) {
- DEBUG(5,("set_nt_acl: acl group control on and "
- "current user in file %s primary group. Override chmod\n",
- fsp->fsp_name ));
-
- become_root();
- sret = SMB_VFS_CHMOD(conn,fsp->fsp_name, posix_perms);
- unbecome_root();
- }
-
- if (sret == -1) {
- DEBUG(3,("set_nt_acl: chmod %s, 0%o failed. Error = %s.\n",
- fsp->fsp_name, (unsigned int)posix_perms, strerror(errno) ));
- free_canon_ace_list(file_ace_list);
- free_canon_ace_list(dir_ace_list);
- return map_nt_error_from_unix(errno);
- }
- }
+ if (sret == -1) {
+ DEBUG(3,("set_nt_acl: chmod %s, 0%o failed. Error = %s.\n",
+ fsp->fsp_name, (unsigned int)posix_perms, strerror(errno) ));
+ free_canon_ace_list(file_ace_list);
+ free_canon_ace_list(dir_ace_list);
+ return map_nt_error_from_unix(errno);
}
}
}
-
- free_canon_ace_list(file_ace_list);
- free_canon_ace_list(dir_ace_list);
}
+ free_canon_ace_list(file_ace_list);
+ free_canon_ace_list(dir_ace_list);
+
return NT_STATUS_OK;
}
diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c
index 28836144c2..52dab0a013 100644
--- a/source3/smbd/reply.c
+++ b/source3/smbd/reply.c
@@ -1063,7 +1063,7 @@ void reply_getatr(struct smb_request *req)
void reply_setatr(struct smb_request *req)
{
- struct timespec ts[2];
+ struct smb_file_time ft;
connection_struct *conn = req->conn;
char *fname = NULL;
int mode;
@@ -1075,7 +1075,7 @@ void reply_setatr(struct smb_request *req)
START_PROFILE(SMBsetatr);
- ZERO_STRUCT(ts);
+ ZERO_STRUCT(ft);
if (req->wct < 2) {
reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
@@ -1133,9 +1133,9 @@ void reply_setatr(struct smb_request *req)
mode = SVAL(req->vwv+0, 0);
mtime = srv_make_unix_date3(req->vwv+1);
- ts[1] = convert_time_t_to_timespec(mtime);
+ ft.mtime = convert_time_t_to_timespec(mtime);
status = smb_set_file_time(conn, NULL, fname,
- &sbuf, ts, true);
+ &sbuf, &ft, true);
if (!NT_STATUS_IS_OK(status)) {
reply_unixerror(req, ERRDOS, ERRnoaccess);
END_PROFILE(SMBsetatr);
@@ -1924,7 +1924,7 @@ void reply_mknew(struct smb_request *req)
connection_struct *conn = req->conn;
char *fname = NULL;
uint32 fattr = 0;
- struct timespec ts[2];
+ struct smb_file_time ft;
files_struct *fsp;
int oplock_request = 0;
SMB_STRUCT_STAT sbuf;
@@ -1936,6 +1936,7 @@ void reply_mknew(struct smb_request *req)
TALLOC_CTX *ctx = talloc_tos();
START_PROFILE(SMBcreate);
+ ZERO_STRUCT(ft);
if (req->wct < 3) {
reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
@@ -1946,8 +1947,8 @@ void reply_mknew(struct smb_request *req)
fattr = SVAL(req->vwv+0, 0);
oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
- ts[1] = convert_time_t_to_timespec(srv_make_unix_date3(req->vwv+1));
- /* mtime. */
+ /* mtime. */
+ ft.mtime = convert_time_t_to_timespec(srv_make_unix_date3(req->vwv+1));
srvstr_get_path_req(ctx, req, &fname, (const char *)req->buf + 1,
STR_TERMINATE, &status);
@@ -1999,8 +2000,8 @@ void reply_mknew(struct smb_request *req)
return;
}
- ts[0] = get_atimespec(&sbuf); /* atime. */
- status = smb_set_file_time(conn, fsp, fsp->fsp_name, &sbuf, ts, true);
+ ft.atime = get_atimespec(&sbuf); /* atime. */
+ status = smb_set_file_time(conn, fsp, fsp->fsp_name, &sbuf, &ft, true);
if (!NT_STATUS_IS_OK(status)) {
END_PROFILE(SMBcreate);
reply_openerror(req, status);
@@ -7115,12 +7116,13 @@ void reply_readbs(struct smb_request *req)
void reply_setattrE(struct smb_request *req)
{
connection_struct *conn = req->conn;
- struct timespec ts[2];
+ struct smb_file_time ft;
files_struct *fsp;
SMB_STRUCT_STAT sbuf;
NTSTATUS status;
START_PROFILE(SMBsetattrE);
+ ZERO_STRUCT(ft);
if (req->wct < 7) {
reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
@@ -7138,14 +7140,15 @@ void reply_setattrE(struct smb_request *req)
/*
- * Convert the DOS times into unix times. Ignore create
- * time as UNIX can't set this.
+ * Convert the DOS times into unix times.
*/
- ts[0] = convert_time_t_to_timespec(
- srv_make_unix_date2(req->vwv+3)); /* atime. */
- ts[1] = convert_time_t_to_timespec(
- srv_make_unix_date2(req->vwv+5)); /* mtime. */
+ ft.atime = convert_time_t_to_timespec(
+ srv_make_unix_date2(req->vwv+3));
+ ft.mtime = convert_time_t_to_timespec(
+ srv_make_unix_date2(req->vwv+5));
+ ft.create_time = convert_time_t_to_timespec(
+ srv_make_unix_date2(req->vwv+1));
reply_outbuf(req, 0, 0);
@@ -7172,17 +7175,20 @@ void reply_setattrE(struct smb_request *req)
}
status = smb_set_file_time(conn, fsp, fsp->fsp_name,
- &sbuf, ts, true);
+ &sbuf, &ft, true);
if (!NT_STATUS_IS_OK(status)) {
reply_doserror(req, ERRDOS, ERRnoaccess);
END_PROFILE(SMBsetattrE);
return;
}
- DEBUG( 3, ( "reply_setattrE fnum=%d actime=%u modtime=%u\n",
+ DEBUG( 3, ( "reply_setattrE fnum=%d actime=%u modtime=%u "
+ " createtime=%u\n",
fsp->fnum,
- (unsigned int)ts[0].tv_sec,
- (unsigned int)ts[1].tv_sec));
+ (unsigned int)ft.atime.tv_sec,
+ (unsigned int)ft.mtime.tv_sec,
+ (unsigned int)ft.create_time.tv_sec
+ ));
END_PROFILE(SMBsetattrE);
return;
diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c
index 52340d5370..1b161d5338 100644
--- a/source3/smbd/trans2.c
+++ b/source3/smbd/trans2.c
@@ -1430,7 +1430,8 @@ static bool get_lanman2_dir_entry(TALLOC_CTX *ctx,
mdate_ts = get_mtimespec(&sbuf);
adate_ts = get_atimespec(&sbuf);
- create_date_ts = get_create_timespec(&sbuf,lp_fake_dir_create_times(SNUM(conn)));
+ create_date_ts = get_create_timespec(&sbuf,
+ lp_fake_dir_create_times(SNUM(conn)));
if (ask_sharemode) {
struct timespec write_time_ts;
@@ -1453,7 +1454,8 @@ static bool get_lanman2_dir_entry(TALLOC_CTX *ctx,
mdate = convert_timespec_to_time_t(mdate_ts);
adate = convert_timespec_to_time_t(adate_ts);
- DEBUG(5,("get_lanman2_dir_entry: found %s fname=%s\n",pathreal,fname));
+ DEBUG(5,("get_lanman2_dir_entry: found %s fname=%s\n",
+ pathreal,fname));
found = True;
@@ -4892,7 +4894,7 @@ NTSTATUS smb_set_file_time(connection_struct *conn,
files_struct *fsp,
const char *fname,
const SMB_STRUCT_STAT *psbuf,
- struct timespec ts[2],
+ struct smb_file_time *ft,
bool setting_write_time)
{
uint32 action =
@@ -4904,23 +4906,29 @@ NTSTATUS smb_set_file_time(connection_struct *conn,
}
/* get some defaults (no modifications) if any info is zero or -1. */
- if (null_timespec(ts[0])) {
- ts[0] = get_atimespec(psbuf);
+ if (null_timespec(ft->atime)) {
+ ft->atime= get_atimespec(psbuf);
action &= ~FILE_NOTIFY_CHANGE_LAST_ACCESS;
}
- if (null_timespec(ts[1])) {
- ts[1] = get_mtimespec(psbuf);
+ if (null_timespec(ft->mtime)) {
+ ft->mtime = get_mtimespec(psbuf);
action &= ~FILE_NOTIFY_CHANGE_LAST_WRITE;
}
if (!setting_write_time) {
- /* ts[1] comes from change time, not write time. */
+ /* ft->mtime comes from change time, not write time. */
action &= ~FILE_NOTIFY_CHANGE_LAST_WRITE;
}
- DEBUG(6,("smb_set_file_time: actime: %s " , time_to_asc(convert_timespec_to_time_t(ts[0])) ));
- DEBUG(6,("smb_set_file_time: modtime: %s ", time_to_asc(convert_timespec_to_time_t(ts[1])) ));
+ DEBUG(5,("smb_set_filetime: actime: %s\n ",
+ time_to_asc(convert_timespec_to_time_t(ft->atime))));
+ DEBUG(5,("smb_set_filetime: modtime: %s\n ",
+ time_to_asc(convert_timespec_to_time_t(ft->mtime))));
+ if (!null_timespec(ft->create_time)) {
+ DEBUG(5,("smb_set_file_time: createtime: %s\n ",
+ time_to_asc(convert_timespec_to_time_t(ft->create_time))));
+ }
/*
* Try and set the times of this file if
@@ -4930,7 +4938,8 @@ NTSTATUS smb_set_file_time(connection_struct *conn,
{
struct timespec mts = get_mtimespec(psbuf);
struct timespec ats = get_atimespec(psbuf);
- if ((timespec_compare(&ts[0], &ats) == 0) && (timespec_compare(&ts[1], &mts) == 0)) {
+ if ((timespec_compare(&ft->atime, &ats) == 0) &&
+ (timespec_compare(&ft->mtime, &mts) == 0)) {
return NT_STATUS_OK;
}
}
@@ -4947,18 +4956,19 @@ NTSTATUS smb_set_file_time(connection_struct *conn,
*/
DEBUG(10,("smb_set_file_time: setting pending modtime to %s\n",
- time_to_asc(convert_timespec_to_time_t(ts[1])) ));
+ time_to_asc(convert_timespec_to_time_t(ft->mtime))));
if (fsp != NULL) {
if (fsp->base_fsp) {
- set_sticky_write_time_fsp(fsp->base_fsp, ts[1]);
+ set_sticky_write_time_fsp(fsp->base_fsp,
+ ft->mtime);
} else {
- set_sticky_write_time_fsp(fsp, ts[1]);
+ set_sticky_write_time_fsp(fsp, ft->mtime);
}
} else {
set_sticky_write_time_path(conn, fname,
vfs_file_id_from_sbuf(conn, psbuf),
- ts[1]);
+ ft->mtime);
}
}
@@ -4968,7 +4978,7 @@ NTSTATUS smb_set_file_time(connection_struct *conn,
fname = fsp->base_fsp->fsp_name;
}
- if(file_ntimes(conn, fname, ts)!=0) {
+ if(file_ntimes(conn, fname, ft)!=0) {
return map_nt_error_from_unix(errno);
}
notify_fname(conn, NOTIFY_ACTION_MODIFIED, action, fname);
@@ -5677,16 +5687,21 @@ static NTSTATUS smb_set_info_standard(connection_struct *conn,
const char *fname,
const SMB_STRUCT_STAT *psbuf)
{
- struct timespec ts[2];
+ struct smb_file_time ft;
+ ZERO_STRUCT(ft);
if (total_data < 12) {
return NT_STATUS_INVALID_PARAMETER;
}
+ /* create time */
+ ft.create_time = interpret_long_date(pdata);
+
/* access time */
- ts[0] = convert_time_t_to_timespec(srv_make_unix_date2(pdata+l1_fdateLastAccess));
+ ft.atime = interpret_long_date(pdata + 8);
+
/* write time */
- ts[1] = convert_time_t_to_timespec(srv_make_unix_date2(pdata+l1_fdateLastWrite));
+ ft.mtime = interpret_long_date(pdata + 16);
DEBUG(10,("smb_set_info_standard: file %s\n",
fname ? fname : fsp->fsp_name ));
@@ -5695,7 +5710,7 @@ static NTSTATUS smb_set_info_standard(connection_struct *conn,
fsp,
fname,
psbuf,
- ts,
+ &ft,
true);
}
@@ -5713,47 +5728,49 @@ static NTSTATUS smb_set_file_basic_info(connection_struct *conn,
/* Patch to do this correctly from Paul Eggert <eggert@twinsun.com>. */
struct timespec write_time;
struct timespec changed_time;
+ struct smb_file_time ft;
uint32 dosmode = 0;
- struct timespec ts[2];
NTSTATUS status = NT_STATUS_OK;
bool setting_write_time = true;
+ ZERO_STRUCT(ft);
+
if (total_data < 36) {
return NT_STATUS_INVALID_PARAMETER;
}
/* Set the attributes */
dosmode = IVAL(pdata,32);
- status = smb_set_file_dosmode(conn,
- fname,
- psbuf,
- dosmode);
+ status = smb_set_file_dosmode(conn, fname, psbuf, dosmode);
if (!NT_STATUS_IS_OK(status)) {
return status;
}
- /* Ignore create time at offset pdata. */
/* access time */
- ts[0] = interpret_long_date(pdata+8);
+ ft.atime = interpret_long_date(pdata+8);
write_time = interpret_long_date(pdata+16);
changed_time = interpret_long_date(pdata+24);
/* mtime */
- ts[1] = timespec_min(&write_time, &changed_time);
+ ft.mtime = timespec_min(&write_time, &changed_time);
- if ((timespec_compare(&write_time, &ts[1]) == 1) && !null_timespec(write_time)) {
- ts[1] = write_time;
+ /* create time */
+ ft.create_time = interpret_long_date(pdata);
+
+ if ((timespec_compare(&write_time, &ft.mtime) == 1) &&
+ !null_timespec(write_time)) {
+ ft.mtime = write_time;
}
/* Prefer a defined time to an undefined one. */
- if (null_timespec(ts[1])) {
+ if (null_timespec(ft.mtime)) {
if (null_timespec(write_time)) {
- ts[1] = changed_time;
+ ft.mtime = changed_time;
setting_write_time = false;
} else {
- ts[1] = write_time;
+ ft.mtime = write_time;
}
}
@@ -5764,7 +5781,7 @@ static NTSTATUS smb_set_file_basic_info(connection_struct *conn,
fsp,
fname,
psbuf,
- ts,
+ &ft,
setting_write_time);
}
@@ -6012,7 +6029,7 @@ static NTSTATUS smb_set_file_unix_basic(connection_struct *conn,
const char *fname,
SMB_STRUCT_STAT *psbuf)
{
- struct timespec ts[2];
+ struct smb_file_time ft;
uint32 raw_unixmode;
mode_t unixmode;
SMB_OFF_T size = 0;
@@ -6022,6 +6039,8 @@ static NTSTATUS smb_set_file_unix_basic(connection_struct *conn,
bool delete_on_fail = False;
enum perm_type ptype;
+ ZERO_STRUCT(ft);
+
if (total_data < 100) {
return NT_STATUS_INVALID_PARAMETER;
}
@@ -6039,8 +6058,8 @@ static NTSTATUS smb_set_file_unix_basic(connection_struct *conn,
#endif /* LARGE_SMB_OFF_T */
}
- ts[0] = interpret_long_date(pdata+24); /* access_time */
- ts[1] = interpret_long_date(pdata+32); /* modification_time */
+ ft.atime = interpret_long_date(pdata+24); /* access_time */
+ ft.mtime = interpret_long_date(pdata+32); /* modification_time */
set_owner = (uid_t)IVAL(pdata,40);
set_grp = (gid_t)IVAL(pdata,48);
raw_unixmode = IVAL(pdata,84);
@@ -6083,8 +6102,8 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
/* Ensure we don't try and change anything else. */
raw_unixmode = SMB_MODE_NO_CHANGE;
size = get_file_size(*psbuf);
- ts[0] = get_atimespec(psbuf);
- ts[1] = get_mtimespec(psbuf);
+ ft.atime = get_atimespec(psbuf);
+ ft.mtime = get_mtimespec(psbuf);
/*
* We continue here as we might want to change the
* owner uid/gid.
@@ -6172,7 +6191,7 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
fsp,
fname,
psbuf,
- ts,
+ &ft,
true);
}
diff --git a/source3/torture/cmd_vfs.c b/source3/torture/cmd_vfs.c
index d984dd661c..31eb27b756 100644
--- a/source3/torture/cmd_vfs.c
+++ b/source3/torture/cmd_vfs.c
@@ -795,14 +795,17 @@ static NTSTATUS cmd_getwd(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc,
static NTSTATUS cmd_utime(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, const char **argv)
{
- struct timespec ts[2];
+ struct smb_file_time ft;
if (argc != 4) {
printf("Usage: utime <path> <access> <modify>\n");
return NT_STATUS_OK;
}
- ts[0] = convert_time_t_to_timespec(atoi(argv[2]));
- ts[1] = convert_time_t_to_timespec(atoi(argv[3]));
- if (SMB_VFS_NTIMES(vfs->conn, argv[1], ts) != 0) {
+
+ ZERO_STRUCT(ft);
+
+ ft.atime = convert_time_t_to_timespec(atoi(argv[2]));
+ ft.mtime = convert_time_t_to_timespec(atoi(argv[3]));
+ if (SMB_VFS_NTIMES(vfs->conn, argv[1], &ft) != 0) {
printf("utime: error=%d (%s)\n", errno, strerror(errno));
return NT_STATUS_UNSUCCESSFUL;
}