diff options
Diffstat (limited to 'source3')
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, ¶ms, 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, ¶ms, 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(®_module_name, NULL); + + status = rpccli_eventlog_RegisterEventSourceW(cli, mem_ctx, + &unknown0, + &module_name, + ®_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; } |