diff options
Diffstat (limited to 'source3')
66 files changed, 3358 insertions, 3027 deletions
diff --git a/source3/Makefile.in b/source3/Makefile.in index 9a97d8de64..80ebf0c84b 100644 --- a/source3/Makefile.in +++ b/source3/Makefile.in @@ -363,8 +363,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/async_req.o \ - ../lib/async_req/async_sock.o ../lib/async_req/async_req_ntstatus.o \ + lib/util_transfer_file.o ../lib/async_req/async_sock.o \ $(TDB_LIB_OBJ) \ $(VERSION_OBJ) lib/charcnv.o lib/debug.o lib/fault.o \ lib/interface.o lib/pidfile.o \ @@ -466,8 +465,6 @@ LIBCLI_LDAP_NDR_OBJ = ../libcli/ldap/ldap_ndr.o LIBTSOCKET_OBJ = ../lib/tsocket/tsocket.o \ ../lib/tsocket/tsocket_helpers.o \ ../lib/tsocket/tsocket_bsd.o \ - ../lib/tsocket/tsocket_recvfrom.o \ - ../lib/tsocket/tsocket_sendto.o \ ../lib/tsocket/tsocket_connect.o \ ../lib/tsocket/tsocket_writev.o \ ../lib/tsocket/tsocket_readv.o @@ -570,7 +567,7 @@ REG_FULL_OBJ = $(REG_SMBCONF_OBJ) \ registry/reg_perfcount.o \ registry/reg_util_legacy.o -LIB_EVENTLOG_OBJ = rpc_server/srv_eventlog_lib.o +LIB_EVENTLOG_OBJ = lib/eventlog/eventlog.o RPC_LSA_OBJ = rpc_server/srv_lsa_nt.o ../librpc/gen_ndr/srv_lsa.o diff --git a/source3/include/ads_protos.h b/source3/include/ads_protos.h index a372010b79..502eaa82d9 100644 --- a/source3/include/ads_protos.h +++ b/source3/include/ads_protos.h @@ -3,7 +3,7 @@ */ void ads_msgfree(ADS_STRUCT *ads, LDAPMessage *msg); -char *ads_get_dn(ADS_STRUCT *ads, LDAPMessage *msg); +char *ads_get_dn(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, LDAPMessage *msg); char *ads_get_dn_canonical(ADS_STRUCT *ads, LDAPMessage *msg); char *ads_pull_string(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, LDAPMessage *msg, diff --git a/source3/include/async_smb.h b/source3/include/async_smb.h index 2ac1101a1e..87ddca6677 100644 --- a/source3/include/async_smb.h +++ b/source3/include/async_smb.h @@ -22,123 +22,11 @@ #include "includes.h" -/** - * struct cli_request is the state holder for an async client request we sent - * to the server. It can consist of more than one struct async_req that we - * have to server if the application did a cli_chain_cork() and - * cli_chain_uncork() - */ - -struct cli_request { - /** - * "prev" and "next" form the doubly linked list in - * cli_state->outstanding_requests - */ - struct cli_request *prev, *next; - - /** - * num_async: How many chained requests do we serve? - */ - int num_async; - - /** - * async: This is the list of chained requests that were queued up by - * cli_request_chain before we sent out this request - */ - struct async_req **async; - - /** - * The client connection for this request - */ - struct cli_state *cli; - - /** - * The enc_state to decrypt the reply - */ - struct smb_trans_enc_state *enc_state; - - /** - * The mid we used for this request. Mainly used to demultiplex on - * receiving replies. - */ - uint16_t mid; - - uint32_t seqnum; - - /** - * The bytes we have to ship to the server - */ - uint8_t *outbuf; - - /** - * How much from "outbuf" did we already send - */ - size_t sent; - - /** - * The reply comes in here. Its intended size is implicit by - * smb_len(), its current size can be read via talloc_get_size() - */ - char *inbuf; - - /** - * Specific requests might add stuff here. Maybe convert this to a - * private_pointer at some point. - */ - union { - struct { - off_t ofs; - size_t size; - ssize_t received; - uint8_t *rcvbuf; - } read; - struct { - DATA_BLOB data; - uint16_t num_echos; - } echo; - } data; - - /** - * For requests that don't follow the strict request/reply pattern - * such as the transaction request family and echo requests it is - * necessary to break the standard procedure in - * handle_incoming_pdu(). For a simple example look at - * cli_echo_recv_helper(). - */ - struct { - void (*fn)(struct async_req *req); - void *priv; - } recv_helper; -}; - -/* - * Ship a new smb request to the server - */ - -struct async_req *cli_request_send(TALLOC_CTX *mem_ctx, - struct event_context *ev, - struct cli_state *cli, - uint8_t smb_command, - uint8_t additional_flags, - uint8_t wct, const uint16_t *vwv, - size_t bytes_alignment, - uint32_t num_bytes, const uint8_t *bytes); - -uint16_t cli_wct_ofs(const struct cli_state *cli); - -bool cli_chain_cork(struct cli_state *cli, struct event_context *ev, - size_t size_hint); -void cli_chain_uncork(struct cli_state *cli); -bool cli_in_chain(struct cli_state *cli); bool smb_splice_chain(uint8_t **poutbuf, uint8_t smb_command, uint8_t wct, const uint16_t *vwv, size_t bytes_alignment, uint32_t num_bytes, const uint8_t *bytes); -NTSTATUS cli_pull_reply(struct async_req *req, - uint8_t *pwct, uint16_t **pvwv, - uint16_t *pnum_bytes, uint8_t **pbytes); - /* * Fetch an error out of a NBT packet */ @@ -151,4 +39,38 @@ NTSTATUS cli_pull_error(char *buf); void cli_set_error(struct cli_state *cli, NTSTATUS status); +struct tevent_req *cli_smb_req_create(TALLOC_CTX *mem_ctx, + struct event_context *ev, + struct cli_state *cli, + uint8_t smb_command, + uint8_t additional_flags, + uint8_t wct, uint16_t *vwv, + int iov_count, + struct iovec *bytes_iov); +bool cli_smb_req_send(struct tevent_req *req); +size_t cli_smb_wct_ofs(struct tevent_req **reqs, int num_reqs); +bool cli_smb_chain_send(struct tevent_req **reqs, int num_reqs); +uint8_t *cli_smb_inbuf(struct tevent_req *req); +bool cli_has_async_calls(struct cli_state *cli); +void cli_smb_req_unset_pending(struct tevent_req *req); +bool cli_smb_req_set_pending(struct tevent_req *req); +uint16_t cli_smb_req_mid(struct tevent_req *req); +void cli_smb_req_set_mid(struct tevent_req *req, uint16_t mid); +struct tevent_req *cli_smb_send(TALLOC_CTX *mem_ctx, struct event_context *ev, + struct cli_state *cli, + uint8_t smb_command, uint8_t additional_flags, + uint8_t wct, uint16_t *vwv, + uint32_t num_bytes, + const uint8_t *bytes); +NTSTATUS cli_smb_recv(struct tevent_req *req, uint8_t min_wct, + uint8_t *pwct, uint16_t **pvwv, + uint32_t *pnum_bytes, uint8_t **pbytes); + +struct tevent_req *cli_smb_oplock_break_waiter_send(TALLOC_CTX *mem_ctx, + struct event_context *ev, + struct cli_state *cli); +NTSTATUS cli_smb_oplock_break_waiter_recv(struct tevent_req *req, + uint16_t *pfnum, + uint8_t *plevel); + #endif diff --git a/source3/include/client.h b/source3/include/client.h index 73a1d7b554..c314c9c6a9 100644 --- a/source3/include/client.h +++ b/source3/include/client.h @@ -264,33 +264,11 @@ struct cli_state { bool force_dos_errors; bool case_sensitive; /* False by default. */ - /** - * fd_event is around while we have async requests outstanding or are - * building a chained request. - * - * (fd_event!=NULL) && - * ((outstanding_request!=NULL)||(chain_accumulator!=NULL)) - * - * should always be true, as well as the reverse: If both cli_request - * pointers are NULL, no fd_event is around. - */ - struct fd_event *fd_event; - char *evt_inbuf; - - /** - * A linked list of requests that are waiting for a reply - */ - struct cli_request *outstanding_requests; - - /** - * The place to build up the list of chained requests. In CIFS, a - * single cli_request corresponds to a MID and can serve more than one - * chained async_req. - */ - struct cli_request *chain_accumulator; - /* Where (if anywhere) this is mounted under DFS. */ char *dfs_mountpoint; + + struct tevent_queue *outgoing; + struct tevent_req **pending; }; typedef struct file_info { @@ -311,5 +289,7 @@ typedef struct file_info { #define CLI_FULL_CONNECTION_USE_KERBEROS 0x0002 #define CLI_FULL_CONNECTION_ANONYMOUS_FALLBACK 0x0004 #define CLI_FULL_CONNECTION_FALLBACK_AFTER_KERBEROS 0x0008 +#define CLI_FULL_CONNECTION_OPLOCKS 0x0010 +#define CLI_FULL_CONNECTION_LEVEL_II_OPLOCKS 0x0020 #endif /* _CLIENT_H */ diff --git a/source3/include/includes.h b/source3/include/includes.h index c883e17713..433818d9ef 100644 --- a/source3/include/includes.h +++ b/source3/include/includes.h @@ -646,7 +646,6 @@ struct smb_iconv_convenience *lp_iconv_convenience(void *lp_ctx); #include "ctdbd_conn.h" #include "../lib/util/talloc_stack.h" #include "memcache.h" -#include "../lib/async_req/async_req_ntstatus.h" #include "async_smb.h" #include "../lib/async_req/async_sock.h" #include "services.h" @@ -901,9 +900,10 @@ krb5_error_code smb_krb5_parse_name(krb5_context context, const char *name, /* in unix charset */ krb5_principal *principal); -krb5_error_code smb_krb5_unparse_name(krb5_context context, - krb5_const_principal principal, - char **unix_name); +krb5_error_code smb_krb5_unparse_name(TALLOC_CTX *mem_ctx, + krb5_context context, + krb5_const_principal principal, + char **unix_name); #ifndef HAVE_KRB5_SET_REAL_TIME krb5_error_code krb5_set_real_time(krb5_context context, int32_t seconds, int32_t microseconds); diff --git a/source3/include/proto.h b/source3/include/proto.h index 0a2a8de4a9..678f087374 100644 --- a/source3/include/proto.h +++ b/source3/include/proto.h @@ -746,7 +746,6 @@ void smbldap_free_struct(struct smbldap_state **ldap_state) ; NTSTATUS smbldap_init(TALLOC_CTX *mem_ctx, struct event_context *event_ctx, const char *location, struct smbldap_state **smbldap_state); -char *smbldap_get_dn(LDAP *ld, LDAPMessage *entry); bool smbldap_has_control(LDAP *ld, const char *control); bool smbldap_has_extension(LDAP *ld, const char *extension); bool smbldap_has_naming_context(LDAP *ld, const char *naming_context); @@ -1421,6 +1420,11 @@ int create_pipe_sock(const char *socket_dir, mode_t dir_perms); const char *get_mydnsfullname(void); bool is_myname_or_ipaddr(const char *s); +struct tevent_req *read_smb_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + int fd); +ssize_t read_smb_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, + uint8_t **pbuf, int *perrno); /* The following definitions come from lib/util_str.c */ @@ -1556,13 +1560,8 @@ int rpcstr_pull_talloc(TALLOC_CTX *ctx, void *src, int src_len, int flags); -int rpcstr_pull_unistr2_fstring(char *dest, UNISTR2 *src); -char *rpcstr_pull_unistr2_talloc(TALLOC_CTX *ctx, const UNISTR2 *src); int rpcstr_push(void *dest, const char *src, size_t dest_len, int flags); int rpcstr_push_talloc(TALLOC_CTX *ctx, smb_ucs2_t **dest, const char *src); -void unistr2_to_ascii(char *dest, const UNISTR2 *str, size_t maxlen); -char *unistr2_to_ascii_talloc(TALLOC_CTX *ctx, const UNISTR2 *str); -const char *unistr2_static(const UNISTR2 *str); smb_ucs2_t toupper_w(smb_ucs2_t val); smb_ucs2_t tolower_w( smb_ucs2_t val ); bool islower_w(smb_ucs2_t c); @@ -1596,9 +1595,6 @@ int strcmp_wa(const smb_ucs2_t *a, const char *b); int strncmp_wa(const smb_ucs2_t *a, const char *b, size_t len); smb_ucs2_t *strpbrk_wa(const smb_ucs2_t *s, const char *p); smb_ucs2_t *strstr_wa(const smb_ucs2_t *s, const char *ins); -int unistrlen(uint16 *s); -int unistrcpy(uint16 *dst, uint16 *src); -UNISTR2* ucs2_to_unistr2(TALLOC_CTX *ctx, UNISTR2* dst, smb_ucs2_t* src); int toupper_ascii(int c); int tolower_ascii(int c); int isupper_ascii(int c); @@ -2299,26 +2295,26 @@ NTSTATUS cli_session_setup(struct cli_state *cli, const char *pass, int passlen, const char *ntpass, int ntpasslen, const char *workgroup); -struct async_req *cli_session_setup_guest_send(TALLOC_CTX *mem_ctx, - struct event_context *ev, - struct cli_state *cli); -NTSTATUS cli_session_setup_guest_recv(struct async_req *req); +struct tevent_req *cli_session_setup_guest_send(TALLOC_CTX *mem_ctx, + struct event_context *ev, + struct cli_state *cli); +NTSTATUS cli_session_setup_guest_recv(struct tevent_req *req); bool cli_ulogoff(struct cli_state *cli); -struct async_req *cli_tcon_andx_send(TALLOC_CTX *mem_ctx, - struct event_context *ev, - struct cli_state *cli, - const char *share, const char *dev, - const char *pass, int passlen); -NTSTATUS cli_tcon_andx_recv(struct async_req *req); +struct tevent_req *cli_tcon_andx_send(TALLOC_CTX *mem_ctx, + struct event_context *ev, + struct cli_state *cli, + const char *share, const char *dev, + const char *pass, int passlen); +NTSTATUS cli_tcon_andx_recv(struct tevent_req *req); NTSTATUS cli_tcon_andx(struct cli_state *cli, const char *share, const char *dev, const char *pass, int passlen); bool cli_tdis(struct cli_state *cli); void cli_negprot_sendsync(struct cli_state *cli); NTSTATUS cli_negprot(struct cli_state *cli); -struct async_req *cli_negprot_send(TALLOC_CTX *mem_ctx, - struct event_context *ev, - struct cli_state *cli); -NTSTATUS cli_negprot_recv(struct async_req *req); +struct tevent_req *cli_negprot_send(TALLOC_CTX *mem_ctx, + struct event_context *ev, + struct cli_state *cli); +NTSTATUS cli_negprot_recv(struct tevent_req *req); bool cli_session_request(struct cli_state *cli, struct nmb_name *calling, struct nmb_name *called); NTSTATUS cli_connect(struct cli_state *cli, @@ -2440,10 +2436,10 @@ void cli_sockopt(struct cli_state *cli, const char *options); uint16 cli_setpid(struct cli_state *cli, uint16 pid); bool cli_set_case_sensitive(struct cli_state *cli, bool case_sensitive); bool cli_send_keepalive(struct cli_state *cli); -struct async_req *cli_echo_send(TALLOC_CTX *mem_ctx, struct event_context *ev, - struct cli_state *cli, uint16_t num_echos, - DATA_BLOB data); -NTSTATUS cli_echo_recv(struct async_req *req); +struct tevent_req *cli_echo_send(TALLOC_CTX *mem_ctx, struct event_context *ev, + struct cli_state *cli, uint16_t num_echos, + DATA_BLOB data); +NTSTATUS cli_echo_recv(struct tevent_req *req); NTSTATUS cli_echo(struct cli_state *cli, uint16_t num_echos, DATA_BLOB data); bool cli_ucs2(struct cli_state *cli); bool is_andx_req(uint8_t cmd); @@ -2484,18 +2480,18 @@ int cli_nt_create_full(struct cli_state *cli, const char *fname, uint32 FileAttributes, uint32 ShareAccess, uint32 CreateDisposition, uint32 CreateOptions, uint8 SecuityFlags); -struct async_req *cli_ntcreate_send(TALLOC_CTX *mem_ctx, - struct event_context *ev, - struct cli_state *cli, - const char *fname, - uint32_t CreatFlags, - uint32_t DesiredAccess, - uint32_t FileAttributes, - uint32_t ShareAccess, - uint32_t CreateDisposition, - uint32_t CreateOptions, - uint8_t SecurityFlags); -NTSTATUS cli_ntcreate_recv(struct async_req *req, uint16_t *pfnum); +struct tevent_req *cli_ntcreate_send(TALLOC_CTX *mem_ctx, + struct event_context *ev, + struct cli_state *cli, + const char *fname, + uint32_t CreatFlags, + uint32_t DesiredAccess, + uint32_t FileAttributes, + uint32_t ShareAccess, + uint32_t CreateDisposition, + uint32_t CreateOptions, + uint8_t SecurityFlags); +NTSTATUS cli_ntcreate_recv(struct tevent_req *req, uint16_t *pfnum); NTSTATUS cli_ntcreate(struct cli_state *cli, const char *fname, uint32_t CreatFlags, @@ -2509,14 +2505,24 @@ NTSTATUS cli_ntcreate(struct cli_state *cli, int cli_nt_create(struct cli_state *cli, const char *fname, uint32 DesiredAccess); uint8_t *smb_bytes_push_str(uint8_t *buf, bool ucs2, const char *str, size_t str_len, size_t *pconverted_size); -struct async_req *cli_open_send(TALLOC_CTX *mem_ctx, struct event_context *ev, - struct cli_state *cli, - const char *fname, int flags, int share_mode); -NTSTATUS cli_open_recv(struct async_req *req, int *fnum); +struct tevent_req *cli_open_create(TALLOC_CTX *mem_ctx, + struct event_context *ev, + struct cli_state *cli, const char *fname, + int flags, int share_mode, + struct tevent_req **psmbreq); +struct tevent_req *cli_open_send(TALLOC_CTX *mem_ctx, struct event_context *ev, + struct cli_state *cli, const char *fname, + int flags, int share_mode); +NTSTATUS cli_open_recv(struct tevent_req *req, int *fnum); int cli_open(struct cli_state *cli, const char *fname, int flags, int share_mode); -struct async_req *cli_close_send(TALLOC_CTX *mem_ctx, struct event_context *ev, - struct cli_state *cli, int fnum); -NTSTATUS cli_close_recv(struct async_req *req); +struct tevent_req *cli_close_create(TALLOC_CTX *mem_ctx, + struct event_context *ev, + struct cli_state *cli, int fnum, + struct tevent_req **psubreq); +struct tevent_req *cli_close_send(TALLOC_CTX *mem_ctx, + struct event_context *ev, + struct cli_state *cli, int fnum); +NTSTATUS cli_close_recv(struct tevent_req *req); bool cli_close(struct cli_state *cli, int fnum); bool cli_ftruncate(struct cli_state *cli, int fnum, uint64_t size); NTSTATUS cli_locktype(struct cli_state *cli, int fnum, @@ -2630,6 +2636,11 @@ bool cli_message_end(struct cli_state *cli, int grp); /* The following definitions come from libsmb/clioplock.c */ +struct tevent_req *cli_oplock_ack_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct cli_state *cli, + uint16_t fnum, uint8_t level); +NTSTATUS cli_oplock_ack_recv(struct tevent_req *req); bool cli_oplock_ack(struct cli_state *cli, int fnum, unsigned char level); void cli_oplock_handler(struct cli_state *cli, bool (*handler)(struct cli_state *, int, unsigned char)); @@ -2757,21 +2768,26 @@ int cli_NetConnectionEnum(struct cli_state *cli, const char *qualifier, /* The following definitions come from libsmb/clireadwrite.c */ -struct async_req *cli_read_andx_send(TALLOC_CTX *mem_ctx, - struct event_context *ev, - struct cli_state *cli, int fnum, - off_t offset, size_t size); -NTSTATUS cli_read_andx_recv(struct async_req *req, ssize_t *received, +struct tevent_req *cli_read_andx_create(TALLOC_CTX *mem_ctx, + struct event_context *ev, + struct cli_state *cli, int fnum, + off_t offset, size_t size, + struct tevent_req **psmbreq); +struct tevent_req *cli_read_andx_send(TALLOC_CTX *mem_ctx, + struct event_context *ev, + struct cli_state *cli, int fnum, + off_t offset, size_t size); +NTSTATUS cli_read_andx_recv(struct tevent_req *req, ssize_t *received, uint8_t **rcvbuf); -struct async_req *cli_pull_send(TALLOC_CTX *mem_ctx, - struct event_context *ev, - struct cli_state *cli, - uint16_t fnum, off_t start_offset, - SMB_OFF_T size, size_t window_size, - NTSTATUS (*sink)(char *buf, size_t n, - void *priv), - void *priv); -NTSTATUS cli_pull_recv(struct async_req *req, SMB_OFF_T *received); +struct tevent_req *cli_pull_send(TALLOC_CTX *mem_ctx, + struct event_context *ev, + struct cli_state *cli, + uint16_t fnum, off_t start_offset, + SMB_OFF_T size, size_t window_size, + NTSTATUS (*sink)(char *buf, size_t n, + void *priv), + void *priv); +NTSTATUS cli_pull_recv(struct tevent_req *req, SMB_OFF_T *received); NTSTATUS cli_pull(struct cli_state *cli, uint16_t fnum, off_t start_offset, SMB_OFF_T size, size_t window_size, NTSTATUS (*sink)(char *buf, size_t n, void *priv), @@ -2784,21 +2800,29 @@ ssize_t cli_write(struct cli_state *cli, const char *buf, off_t offset, size_t size); ssize_t cli_smbwrite(struct cli_state *cli, int fnum, char *buf, off_t offset, size_t size1); -struct async_req *cli_write_andx_send(TALLOC_CTX *mem_ctx, - struct event_context *ev, - struct cli_state *cli, uint16_t fnum, - uint16_t mode, const uint8_t *buf, - off_t offset, size_t size); -NTSTATUS cli_write_andx_recv(struct async_req *req, size_t *pwritten); - -struct async_req *cli_push_send(TALLOC_CTX *mem_ctx, struct event_context *ev, - struct cli_state *cli, - uint16_t fnum, uint16_t mode, - off_t start_offset, size_t window_size, - size_t (*source)(uint8_t *buf, size_t n, - void *priv), - void *priv); -NTSTATUS cli_push_recv(struct async_req *req); +struct tevent_req *cli_write_andx_create(TALLOC_CTX *mem_ctx, + struct event_context *ev, + struct cli_state *cli, uint16_t fnum, + uint16_t mode, const uint8_t *buf, + off_t offset, size_t size, + struct tevent_req **reqs_before, + int num_reqs_before, + struct tevent_req **psmbreq); +struct tevent_req *cli_write_andx_send(TALLOC_CTX *mem_ctx, + struct event_context *ev, + struct cli_state *cli, uint16_t fnum, + uint16_t mode, const uint8_t *buf, + off_t offset, size_t size); +NTSTATUS cli_write_andx_recv(struct tevent_req *req, size_t *pwritten); + +struct tevent_req *cli_push_send(TALLOC_CTX *mem_ctx, struct event_context *ev, + struct cli_state *cli, + uint16_t fnum, uint16_t mode, + off_t start_offset, size_t window_size, + size_t (*source)(uint8_t *buf, size_t n, + void *priv), + void *priv); +NTSTATUS cli_push_recv(struct tevent_req *req); NTSTATUS cli_push(struct cli_state *cli, uint16_t fnum, uint16_t mode, off_t start_offset, size_t window_size, size_t (*source)(uint8_t *buf, size_t n, void *priv), @@ -2885,14 +2909,14 @@ bool cli_send_nt_trans(struct cli_state *cli, bool cli_receive_nt_trans(struct cli_state *cli, char **param, unsigned int *param_len, char **data, unsigned int *data_len); -struct async_req *cli_trans_send( +struct tevent_req *cli_trans_send( TALLOC_CTX *mem_ctx, struct event_context *ev, - struct cli_state *cli, uint8_t trans_cmd, + struct cli_state *cli, uint8_t cmd, const char *pipe_name, uint16_t fid, uint16_t function, int flags, uint16_t *setup, uint8_t num_setup, uint8_t max_setup, uint8_t *param, uint32_t num_param, uint32_t max_param, uint8_t *data, uint32_t num_data, uint32_t max_data); -NTSTATUS cli_trans_recv(struct async_req *req, TALLOC_CTX *mem_ctx, +NTSTATUS cli_trans_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, uint16_t **setup, uint8_t *num_setup, uint8_t **param, uint32_t *num_param, uint8_t **data, uint32_t *num_data); @@ -5367,11 +5391,11 @@ NTSTATUS rpc_pipe_open_local(TALLOC_CTX *mem_ctx, /* The following definitions come from rpc_client/rpc_transport_np.c */ -struct async_req *rpc_transport_np_init_send(TALLOC_CTX *mem_ctx, - struct event_context *ev, - struct cli_state *cli, - const struct ndr_syntax_id *abstract_syntax); -NTSTATUS rpc_transport_np_init_recv(struct async_req *req, +struct tevent_req *rpc_transport_np_init_send(TALLOC_CTX *mem_ctx, + struct event_context *ev, + struct cli_state *cli, + const struct ndr_syntax_id *abstract_syntax); +NTSTATUS rpc_transport_np_init_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, struct rpc_cli_transport **presult); NTSTATUS rpc_transport_np_init(TALLOC_CTX *mem_ctx, struct cli_state *cli, @@ -5381,13 +5405,13 @@ struct cli_state *rpc_pipe_np_smb_conn(struct rpc_pipe_client *p); /* The following definitions come from rpc_client/rpc_transport_smbd.c */ -struct async_req *rpc_cli_smbd_conn_init_send(TALLOC_CTX *mem_ctx, - struct event_context *ev, - void (*stdout_callback)(char *buf, - size_t len, - void *priv), - void *priv); -NTSTATUS rpc_cli_smbd_conn_init_recv(struct async_req *req, +struct tevent_req *rpc_cli_smbd_conn_init_send(TALLOC_CTX *mem_ctx, + struct event_context *ev, + void (*stdout_callback)(char *buf, + size_t len, + void *priv), + void *priv); +NTSTATUS rpc_cli_smbd_conn_init_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, struct rpc_cli_smbd_conn **pconn); NTSTATUS rpc_cli_smbd_conn_init(TALLOC_CTX *mem_ctx, @@ -5397,11 +5421,11 @@ NTSTATUS rpc_cli_smbd_conn_init(TALLOC_CTX *mem_ctx, void *priv), void *priv); -struct async_req *rpc_transport_smbd_init_send(TALLOC_CTX *mem_ctx, - struct event_context *ev, - struct rpc_cli_smbd_conn *conn, - const struct ndr_syntax_id *abstract_syntax); -NTSTATUS rpc_transport_smbd_init_recv(struct async_req *req, +struct tevent_req *rpc_transport_smbd_init_send(TALLOC_CTX *mem_ctx, + struct event_context *ev, + struct rpc_cli_smbd_conn *conn, + const struct ndr_syntax_id *abstract_syntax); +NTSTATUS rpc_transport_smbd_init_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, struct rpc_cli_transport **presult); NTSTATUS rpc_transport_smbd_init(TALLOC_CTX *mem_ctx, @@ -5756,7 +5780,6 @@ bool prs_uint8s(bool charmode, const char *name, prs_struct *ps, int depth, uint bool prs_uint16s(bool charmode, const char *name, prs_struct *ps, int depth, uint16 *data16s, int len); bool prs_uint16uni(bool charmode, const char *name, prs_struct *ps, int depth, uint16 *data16s, int len); bool prs_uint32s(bool charmode, const char *name, prs_struct *ps, int depth, uint32 *data32s, int len); -bool prs_unistr2(bool charmode, const char *name, prs_struct *ps, int depth, UNISTR2 *str); bool prs_unistr(const char *name, prs_struct *ps, int depth, UNISTR *str); bool prs_string(const char *name, prs_struct *ps, int depth, char *str, int max_buf_size); bool prs_string_alloc(const char *name, prs_struct *ps, int depth, const char **str); @@ -5821,7 +5844,7 @@ bool smb_io_rpc_auth_schannel_chk(const char *desc, int auth_len, RPC_AUTH_SCHANNEL_CHK * chk, prs_struct *ps, int depth); -/* The following definitions come from rpc_server/srv_eventlog_lib.c */ +/* The following definitions come from lib/eventlog/eventlog.c */ TDB_CONTEXT *elog_init_tdb( char *tdbfilename ); char *elog_tdbname(TALLOC_CTX *ctx, const char *name ); @@ -5851,6 +5874,10 @@ NTSTATUS evlog_evt_entry_to_tdb_entry(TALLOC_CTX *mem_ctx, NTSTATUS evlog_tdb_entry_to_evt_entry(TALLOC_CTX *mem_ctx, const struct eventlog_Record_tdb *t, struct EVENTLOGRECORD *e); +NTSTATUS evlog_convert_tdb_to_evt(TALLOC_CTX *mem_ctx, + ELOG_TDB *etdb, + DATA_BLOB *blob_p, + uint32_t *num_records_p); /* The following definitions come from rpc_server/srv_eventlog_nt.c */ @@ -6645,6 +6672,7 @@ void release_file_oplock(files_struct *fsp); bool remove_oplock(files_struct *fsp); bool downgrade_oplock(files_struct *fsp); bool should_notify_deferred_opens(void); +void break_level2_to_none_async(files_struct *fsp); void reply_to_oplock_break_requests(files_struct *fsp); void process_oplock_async_level2_break_message(struct messaging_context *msg_ctx, void *private_data, diff --git a/source3/include/smbldap.h b/source3/include/smbldap.h index a2cb8c5eea..353e01aba6 100644 --- a/source3/include/smbldap.h +++ b/source3/include/smbldap.h @@ -141,7 +141,6 @@ void smbldap_make_mod(LDAP *ldap_struct, LDAPMessage *existing, bool smbldap_get_single_attribute (LDAP * ldap_struct, LDAPMessage * entry, const char *attribute, char *value, int max_len); -char *smbldap_get_dn(LDAP *ld, LDAPMessage *entry); int smbldap_modify(struct smbldap_state *ldap_state, const char *dn, LDAPMod *attrs[]); @@ -214,7 +213,7 @@ char * smbldap_talloc_single_attribute(LDAP *ldap_struct, LDAPMessage *entry, TALLOC_CTX *mem_ctx); void talloc_autofree_ldapmsg(TALLOC_CTX *mem_ctx, LDAPMessage *result); void talloc_autofree_ldapmod(TALLOC_CTX *mem_ctx, LDAPMod **mod); -const char *smbldap_talloc_dn(TALLOC_CTX *mem_ctx, LDAP *ld, +char *smbldap_talloc_dn(TALLOC_CTX *mem_ctx, LDAP *ld, LDAPMessage *entry); diff --git a/source3/rpc_server/srv_eventlog_lib.c b/source3/lib/eventlog/eventlog.c index f83c4fc3b8..11cb28a120 100644 --- a/source3/rpc_server/srv_eventlog_lib.c +++ b/source3/lib/eventlog/eventlog.c @@ -958,3 +958,77 @@ NTSTATUS evlog_tdb_entry_to_evt_entry(TALLOC_CTX *mem_ctx, return NT_STATUS_OK; } + +/******************************************************************** + ********************************************************************/ + +NTSTATUS evlog_convert_tdb_to_evt(TALLOC_CTX *mem_ctx, + ELOG_TDB *etdb, + DATA_BLOB *blob_p, + uint32_t *num_records_p) +{ + NTSTATUS status = NT_STATUS_OK; + enum ndr_err_code ndr_err; + DATA_BLOB blob; + uint32_t num_records = 0; + struct EVENTLOG_EVT_FILE evt; + uint32_t count = 1; + size_t endoffset = 0; + + ZERO_STRUCT(evt); + + while (1) { + + struct eventlog_Record_tdb *r; + struct EVENTLOGRECORD e; + + r = evlog_pull_record_tdb(mem_ctx, etdb->tdb, count); + if (!r) { + break; + } + + status = evlog_tdb_entry_to_evt_entry(mem_ctx, r, &e); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + + endoffset += ndr_size_EVENTLOGRECORD(&e, NULL, 0); + + ADD_TO_ARRAY(mem_ctx, struct EVENTLOGRECORD, e, &evt.records, &num_records); + count++; + } + + evt.hdr.StartOffset = 0x30; + evt.hdr.EndOffset = evt.hdr.StartOffset + endoffset; + evt.hdr.CurrentRecordNumber = count; + evt.hdr.OldestRecordNumber = 1; + evt.hdr.MaxSize = tdb_fetch_int32(etdb->tdb, EVT_MAXSIZE); + evt.hdr.Flags = 0; + evt.hdr.Retention = tdb_fetch_int32(etdb->tdb, EVT_RETENTION); + + if (DEBUGLEVEL >= 10) { + NDR_PRINT_DEBUG(EVENTLOGHEADER, &evt.hdr); + } + + evt.eof.BeginRecord = 0x30; + evt.eof.EndRecord = evt.hdr.StartOffset + endoffset; + evt.eof.CurrentRecordNumber = evt.hdr.CurrentRecordNumber; + evt.eof.OldestRecordNumber = evt.hdr.OldestRecordNumber; + + if (DEBUGLEVEL >= 10) { + NDR_PRINT_DEBUG(EVENTLOGEOF, &evt.eof); + } + + ndr_err = ndr_push_struct_blob(&blob, mem_ctx, NULL, &evt, + (ndr_push_flags_fn_t)ndr_push_EVENTLOG_EVT_FILE); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + status = ndr_map_error2ntstatus(ndr_err); + goto done; + } + + *blob_p = blob; + *num_records_p = num_records; + + done: + return status; +} diff --git a/source3/lib/ms_fnmatch.c b/source3/lib/ms_fnmatch.c index ca534467fa..1eac9fa14a 100644 --- a/source3/lib/ms_fnmatch.c +++ b/source3/lib/ms_fnmatch.c @@ -170,12 +170,12 @@ int ms_fnmatch(const char *pattern, const char *string, bool translate_pattern, } } - if (!push_ucs2_allocate(&p, pattern, &converted_size)) { + if (!push_ucs2_talloc(talloc_tos(), &p, pattern, &converted_size)) { return -1; } - if (!push_ucs2_allocate(&s, string, &converted_size)) { - SAFE_FREE(p); + if (!push_ucs2_talloc(talloc_tos(), &s, string, &converted_size)) { + TALLOC_FREE(p); return -1; } @@ -214,8 +214,8 @@ int ms_fnmatch(const char *pattern, const char *string, bool translate_pattern, else { max_n = SMB_CALLOC_ARRAY(struct max_n, count); if (!max_n) { - SAFE_FREE(p); - SAFE_FREE(s); + TALLOC_FREE(p); + TALLOC_FREE(s); return -1; } max_n_free = max_n; @@ -225,8 +225,8 @@ int ms_fnmatch(const char *pattern, const char *string, bool translate_pattern, ret = ms_fnmatch_core(p, s, max_n, strrchr_w(s, UCS2_CHAR('.')), is_case_sensitive); SAFE_FREE(max_n_free); - SAFE_FREE(p); - SAFE_FREE(s); + TALLOC_FREE(p); + TALLOC_FREE(s); return ret; } diff --git a/source3/lib/smbconf/smbconf_reg.c b/source3/lib/smbconf/smbconf_reg.c index ae6a41151d..0ecac97575 100644 --- a/source3/lib/smbconf/smbconf_reg.c +++ b/source3/lib/smbconf/smbconf_reg.c @@ -193,7 +193,7 @@ static WERROR smbconf_reg_set_value(struct registry_key *key, if (!strequal(subkeyname, GLOBAL_NAME) && lp_parameter_is_global(valname)) { - DEBUG(5, ("Global paramter '%s' not allowed in " + DEBUG(5, ("Global parameter '%s' not allowed in " "service definition ('%s').\n", canon_valname, subkeyname)); werr = WERR_INVALID_PARAM; diff --git a/source3/lib/smbldap.c b/source3/lib/smbldap.c index e24d35818c..4f54f9ad58 100644 --- a/source3/lib/smbldap.c +++ b/source3/lib/smbldap.c @@ -1228,7 +1228,7 @@ static int smbldap_search_ext(struct smbldap_state *ldap_state, ZERO_STRUCT(ldap_state->last_rebind); } - if (!push_utf8_allocate(&utf8_filter, filter, &converted_size)) { + if (!push_utf8_talloc(talloc_tos(), &utf8_filter, filter, &converted_size)) { return LDAP_NO_MEMORY; } @@ -1276,7 +1276,7 @@ static int smbldap_search_ext(struct smbldap_state *ldap_state, } } - SAFE_FREE(utf8_filter); + TALLOC_FREE(utf8_filter); /* Teardown timeout. */ CatchSignal(SIGALRM, SIGNAL_CAST SIG_IGN); @@ -1400,7 +1400,7 @@ int smbldap_modify(struct smbldap_state *ldap_state, const char *dn, LDAPMod *at DEBUG(5,("smbldap_modify: dn => [%s]\n", dn )); - if (!push_utf8_allocate(&utf8_dn, dn, &converted_size)) { + if (!push_utf8_talloc(talloc_tos(), &utf8_dn, dn, &converted_size)) { return LDAP_NO_MEMORY; } @@ -1428,7 +1428,7 @@ int smbldap_modify(struct smbldap_state *ldap_state, const char *dn, LDAPMod *at } } - SAFE_FREE(utf8_dn); + TALLOC_FREE(utf8_dn); return rc; } @@ -1444,7 +1444,7 @@ int smbldap_add(struct smbldap_state *ldap_state, const char *dn, LDAPMod *attrs DEBUG(5,("smbldap_add: dn => [%s]\n", dn )); - if (!push_utf8_allocate(&utf8_dn, dn, &converted_size)) { + if (!push_utf8_talloc(talloc_tos(), &utf8_dn, dn, &converted_size)) { return LDAP_NO_MEMORY; } @@ -1472,7 +1472,7 @@ int smbldap_add(struct smbldap_state *ldap_state, const char *dn, LDAPMod *attrs } } - SAFE_FREE(utf8_dn); + TALLOC_FREE(utf8_dn); return rc; } @@ -1488,7 +1488,7 @@ int smbldap_delete(struct smbldap_state *ldap_state, const char *dn) DEBUG(5,("smbldap_delete: dn => [%s]\n", dn )); - if (!push_utf8_allocate(&utf8_dn, dn, &converted_size)) { + if (!push_utf8_talloc(talloc_tos(), &utf8_dn, dn, &converted_size)) { return LDAP_NO_MEMORY; } @@ -1516,7 +1516,7 @@ int smbldap_delete(struct smbldap_state *ldap_state, const char *dn) } } - SAFE_FREE(utf8_dn); + TALLOC_FREE(utf8_dn); return rc; } @@ -1649,41 +1649,19 @@ NTSTATUS smbldap_init(TALLOC_CTX *mem_ctx, struct event_context *event_ctx, return NT_STATUS_OK; } -/******************************************************************* - Return a copy of the DN for a LDAPMessage. Convert from utf8 to CH_UNIX. -********************************************************************/ -char *smbldap_get_dn(LDAP *ld, LDAPMessage *entry) -{ - char *utf8_dn, *unix_dn; - size_t converted_size; - - utf8_dn = ldap_get_dn(ld, entry); - if (!utf8_dn) { - DEBUG (5, ("smbldap_get_dn: ldap_get_dn failed\n")); - return NULL; - } - if (!pull_utf8_allocate(&unix_dn, utf8_dn, &converted_size)) { - DEBUG (0, ("smbldap_get_dn: String conversion failure utf8 " - "[%s]\n", utf8_dn)); - return NULL; - } - ldap_memfree(utf8_dn); - return unix_dn; -} - - const char *smbldap_talloc_dn(TALLOC_CTX *mem_ctx, LDAP *ld, - LDAPMessage *entry) + char *smbldap_talloc_dn(TALLOC_CTX *mem_ctx, LDAP *ld, + LDAPMessage *entry) { char *utf8_dn, *unix_dn; size_t converted_size; utf8_dn = ldap_get_dn(ld, entry); if (!utf8_dn) { - DEBUG (5, ("smbldap_get_dn: ldap_get_dn failed\n")); + DEBUG (5, ("smbldap_talloc_dn: ldap_get_dn failed\n")); return NULL; } if (!pull_utf8_talloc(mem_ctx, &unix_dn, utf8_dn, &converted_size)) { - DEBUG (0, ("smbldap_get_dn: String conversion failure utf8 " + DEBUG (0, ("smbldap_talloc_dn: String conversion failure utf8 " "[%s]\n", utf8_dn)); return NULL; } diff --git a/source3/lib/util_sock.c b/source3/lib/util_sock.c index a0dbca1a00..5f9d4768ba 100644 --- a/source3/lib/util_sock.c +++ b/source3/lib/util_sock.c @@ -1942,6 +1942,10 @@ bool is_myname_or_ipaddr(const char *s) return false; } + if (ismyaddr((struct sockaddr *)&ss)) { + return true; + } + if (is_zero_addr((struct sockaddr *)&ss) || is_loopback_addr((struct sockaddr *)&ss)) { return false; @@ -1965,3 +1969,90 @@ bool is_myname_or_ipaddr(const char *s) /* No match */ return false; } + +/* + * Read an smb packet asynchronously, discard keepalives + */ + +struct read_smb_state { + struct tevent_context *ev; + int fd; + uint8_t *buf; +}; + +static ssize_t read_smb_more(uint8_t *buf, size_t buflen, void *private_data); +static void read_smb_done(struct tevent_req *subreq); + +struct tevent_req *read_smb_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + int fd) +{ + struct tevent_req *result, *subreq; + struct read_smb_state *state; + + result = tevent_req_create(mem_ctx, &state, struct read_smb_state); + if (result == NULL) { + return NULL; + } + state->ev = ev; + state->fd = fd; + + subreq = read_packet_send(state, ev, fd, 4, read_smb_more, NULL); + if (subreq == NULL) { + goto fail; + } + tevent_req_set_callback(subreq, read_smb_done, result); + return result; + fail: + TALLOC_FREE(result); + return NULL; +} + +static ssize_t read_smb_more(uint8_t *buf, size_t buflen, void *private_data) +{ + if (buflen > 4) { + return 0; /* We've been here, we're done */ + } + return smb_len_large(buf); +} + +static void read_smb_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct read_smb_state *state = tevent_req_data( + req, struct read_smb_state); + ssize_t len; + int err; + + len = read_packet_recv(subreq, state, &state->buf, &err); + TALLOC_FREE(subreq); + if (len == -1) { + tevent_req_error(req, err); + return; + } + + if (CVAL(state->buf, 0) == SMBkeepalive) { + subreq = read_packet_send(state, state->ev, state->fd, 4, + read_smb_more, NULL); + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, read_smb_done, req); + return; + } + tevent_req_done(req); +} + +ssize_t read_smb_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, + uint8_t **pbuf, int *perrno) +{ + struct read_smb_state *state = tevent_req_data( + req, struct read_smb_state); + + if (tevent_req_is_unix_error(req, perrno)) { + return -1; + } + *pbuf = talloc_move(mem_ctx, &state->buf); + return talloc_get_size(*pbuf); +} diff --git a/source3/lib/util_unistr.c b/source3/lib/util_unistr.c index 840e8e06da..7d80b3cdea 100644 --- a/source3/lib/util_unistr.c +++ b/source3/lib/util_unistr.c @@ -291,64 +291,6 @@ int rpcstr_pull_talloc(TALLOC_CTX *ctx, } -/* Copy a string from a unistr2 source to internal samba format - destination. Use this instead of direct calls to rpcstr_pull() to avoid - having to determine whether the source string is null terminated. */ - -int rpcstr_pull_unistr2_fstring(char *dest, UNISTR2 *src) -{ - return pull_ucs2(NULL, dest, src->buffer, sizeof(fstring), - src->uni_str_len * 2, 0); -} - -/* Helper function to return a talloc'ed string. I have implemented it with a - * copy because I don't really know how pull_ucs2 and friends calculate the - * target size. If this turns out to be a major bottleneck someone with deeper - * multi-byte knowledge needs to revisit this. - * I just did (JRA :-). No longer uses copy. - * My (VL) use is dsr_getdcname, which returns 6 strings, the alternative would - * have been to manually talloc_strdup them in rpc_client/cli_netlogon.c. - */ - -char *rpcstr_pull_unistr2_talloc(TALLOC_CTX *ctx, const UNISTR2 *src) -{ - char *dest = NULL; - size_t dest_len; - - if (!convert_string_talloc(ctx, CH_UTF16LE, CH_UNIX, src->buffer, - src->uni_str_len * 2, (void *)&dest, - &dest_len, true)) - { - return NULL; - } - - /* Ensure we're returning a null terminated string. */ - if (dest_len) { - /* Did we already process the terminating zero ? */ - if (dest[dest_len-1] != 0) { - size_t size = talloc_get_size(dest); - /* Have we got space to append the '\0' ? */ - if (size <= dest_len) { - /* No, realloc. */ - dest = TALLOC_REALLOC_ARRAY(ctx, dest, char, - dest_len+1); - if (!dest) { - /* talloc fail. */ - dest_len = (size_t)-1; - return NULL; - } - } - /* Yay - space ! */ - dest[dest_len] = '\0'; - dest_len++; - } - } else if (dest) { - dest[0] = 0; - } - - return dest; -} - /* Converts a string from internal samba format to unicode */ @@ -371,64 +313,6 @@ int rpcstr_push_talloc(TALLOC_CTX *ctx, smb_ucs2_t **dest, const char *src) } /******************************************************************* - Convert a (little-endian) UNISTR2 structure to an ASCII string. -********************************************************************/ - -void unistr2_to_ascii(char *dest, const UNISTR2 *str, size_t maxlen) -{ - if ((str == NULL) || (str->uni_str_len == 0)) { - *dest='\0'; - return; - } - pull_ucs2(NULL, dest, str->buffer, maxlen, str->uni_str_len*2, STR_NOALIGN); -} - -/******************************************************************* - Duplicate a UNISTR2 string into a null terminated char* - using a talloc context. -********************************************************************/ - -char *unistr2_to_ascii_talloc(TALLOC_CTX *ctx, const UNISTR2 *str) -{ - char *s = NULL; - - if (!str || !str->buffer) { - return NULL; - } - if (pull_ucs2_base_talloc(ctx, - NULL, - &s, - str->buffer, - str->uni_str_len*2, - STR_NOALIGN) == (size_t)-1) { - return NULL; - } - return s; -} - -/******************************************************************* - Return a string for displaying a UNISTR2. Guarentees to return a - valid string - "" if nothing else. - Changed to use talloc_tos() under the covers.... JRA. -********************************************************************/ - -const char *unistr2_static(const UNISTR2 *str) -{ - char *dest = NULL; - - if ((str == NULL) || (str->uni_str_len == 0)) { - return ""; - } - - dest = unistr2_to_ascii_talloc(talloc_tos(), str); - if (!dest) { - return ""; - } - - return dest; -} - -/******************************************************************* Convert a wchar to upper case. ********************************************************************/ @@ -966,89 +850,6 @@ smb_ucs2_t *strstr_wa(const smb_ucs2_t *s, const char *ins) return NULL; } -/******************************************************************* - Returns the length in number of wide characters. -******************************************************************/ - -int unistrlen(uint16 *s) -{ - int len; - - if (!s) { - return -1; - } - - for (len=0; SVAL(s,0); s++,len++) { - ; - } - - return len; -} - -/******************************************************************* - Strcpy for unicode strings. Returns length (in num of wide chars). - Not odd align safe. -********************************************************************/ - -int unistrcpy(uint16 *dst, uint16 *src) -{ - int num_wchars = 0; - - while (SVAL(src,0)) { - *dst++ = *src++; - num_wchars++; - } - *dst = 0; - - return num_wchars; -} - -/** - * Samba ucs2 type to UNISTR2 conversion - * - * @param ctx Talloc context to create the dst strcture (if null) and the - * contents of the unicode string. - * @param dst UNISTR2 destination. If equals null, then it's allocated. - * @param src smb_ucs2_t source. - * @param max_len maximum number of unicode characters to copy. If equals - * null, then null-termination of src is taken - * - * @return copied UNISTR2 destination - **/ - -UNISTR2* ucs2_to_unistr2(TALLOC_CTX *ctx, UNISTR2* dst, smb_ucs2_t* src) -{ - size_t len; - - if (!src) { - return NULL; - } - - len = strlen_w(src); - - /* allocate UNISTR2 destination if not given */ - if (!dst) { - dst = TALLOC_P(ctx, UNISTR2); - if (!dst) - return NULL; - } - if (!dst->buffer) { - dst->buffer = TALLOC_ARRAY(ctx, uint16, len + 1); - if (!dst->buffer) - return NULL; - } - - /* set UNISTR2 parameters */ - dst->uni_max_len = len + 1; - dst->offset = 0; - dst->uni_str_len = len; - - /* copy the actual unicode string */ - strncpy_w(dst->buffer, src, dst->uni_max_len); - - return dst; -} - /************************************************************* ascii only toupper - saves the need for smbd to be in C locale. *************************************************************/ diff --git a/source3/libads/authdata.c b/source3/libads/authdata.c index 9f0f68ed7b..0032e9e4f6 100644 --- a/source3/libads/authdata.c +++ b/source3/libads/authdata.c @@ -469,7 +469,7 @@ out: data_blob_free(&sesskey1); data_blob_free(&sesskey2); - SAFE_FREE(client_princ_out); + TALLOC_FREE(client_princ_out); return status; } diff --git a/source3/libads/kerberos.c b/source3/libads/kerberos.c index 52cb975a6c..c476f59ff5 100644 --- a/source3/libads/kerberos.c +++ b/source3/libads/kerberos.c @@ -545,7 +545,7 @@ krb5_principal kerberos_fetch_salt_princ_for_host_princ(krb5_context context, /* look under the old key. If this fails, just use the standard key */ - if (smb_krb5_unparse_name(context, host_princ, &unparsed_name) != 0) { + if (smb_krb5_unparse_name(talloc_tos(), context, host_princ, &unparsed_name) != 0) { return (krb5_principal)NULL; } if ((salt_princ_s = kerberos_secrets_fetch_salting_principal(unparsed_name, enctype)) == NULL) { @@ -558,7 +558,7 @@ krb5_principal kerberos_fetch_salt_princ_for_host_princ(krb5_context context, ret_princ = NULL; } - SAFE_FREE(unparsed_name); + TALLOC_FREE(unparsed_name); SAFE_FREE(salt_princ_s); return ret_princ; @@ -603,7 +603,7 @@ bool kerberos_secrets_store_salting_principal(const char *service, goto out; } - if (smb_krb5_unparse_name(context, princ, &unparsed_name) != 0) { + if (smb_krb5_unparse_name(talloc_tos(), context, princ, &unparsed_name) != 0) { goto out; } @@ -623,7 +623,7 @@ bool kerberos_secrets_store_salting_principal(const char *service, SAFE_FREE(key); SAFE_FREE(princ_s); - SAFE_FREE(unparsed_name); + TALLOC_FREE(unparsed_name); if (princ) { krb5_free_principal(context, princ); diff --git a/source3/libads/kerberos_keytab.c b/source3/libads/kerberos_keytab.c index 7c028cb78f..4fede259ab 100644 --- a/source3/libads/kerberos_keytab.c +++ b/source3/libads/kerberos_keytab.c @@ -64,7 +64,7 @@ int smb_krb5_kt_add_entry_ext(krb5_context context, while(!krb5_kt_next_entry(context, keytab, &kt_entry, &cursor)) { bool compare_name_ok = False; - ret = smb_krb5_unparse_name(context, kt_entry.principal, &ktprinc); + ret = smb_krb5_unparse_name(talloc_tos(), context, kt_entry.principal, &ktprinc); if (ret) { DEBUG(1,("smb_krb5_kt_add_entry_ext: smb_krb5_unparse_name failed (%s)\n", error_message(ret))); @@ -91,7 +91,7 @@ int smb_krb5_kt_add_entry_ext(krb5_context context, ktprinc, kt_entry.vno)); } - SAFE_FREE(ktprinc); + TALLOC_FREE(ktprinc); if (compare_name_ok) { if (kt_entry.vno == kvno - 1) { @@ -549,13 +549,12 @@ int ads_keytab_create_default(ADS_STRUCT *ads) } } - TALLOC_FREE( ctx ); - /* Now loop through the keytab and update any other existing entries... */ kvno = (krb5_kvno) ads_get_machine_kvno(ads, machine_name); if (kvno == -1) { DEBUG(1,("ads_keytab_create_default: ads_get_machine_kvno failed to determine the system's kvno.\n")); + TALLOC_FREE(ctx); return -1; } @@ -569,6 +568,7 @@ int ads_keytab_create_default(ADS_STRUCT *ads) ret = krb5_init_context(&context); if (ret) { DEBUG(1,("ads_keytab_create_default: could not krb5_init_context: %s\n",error_message(ret))); + TALLOC_FREE(ctx); return ret; } @@ -599,7 +599,7 @@ int ads_keytab_create_default(ADS_STRUCT *ads) if (!found) { goto done; } - oldEntries = SMB_MALLOC_ARRAY(char *, found ); + oldEntries = talloc_array(ctx, char *, found ); if (!oldEntries) { DEBUG(1,("ads_keytab_create_default: Failed to allocate space to store the old keytab entries (malloc failed?).\n")); ret = -1; @@ -615,7 +615,7 @@ int ads_keytab_create_default(ADS_STRUCT *ads) char *p; /* This returns a malloc'ed string in ktprinc. */ - ret = smb_krb5_unparse_name(context, kt_entry.principal, &ktprinc); + ret = smb_krb5_unparse_name(oldEntries, context, kt_entry.principal, &ktprinc); if (ret) { DEBUG(1,("smb_krb5_unparse_name failed (%s)\n", error_message(ret))); goto done; @@ -640,12 +640,12 @@ int ads_keytab_create_default(ADS_STRUCT *ads) break; } if (!strcmp(oldEntries[i], ktprinc)) { - SAFE_FREE(ktprinc); + TALLOC_FREE(ktprinc); break; } } if (i == found) { - SAFE_FREE(ktprinc); + TALLOC_FREE(ktprinc); } } smb_krb5_kt_free_entry(context, &kt_entry); @@ -654,7 +654,7 @@ int ads_keytab_create_default(ADS_STRUCT *ads) ret = 0; for (i = 0; oldEntries[i]; i++) { ret |= ads_keytab_add_entry(ads, oldEntries[i]); - SAFE_FREE(oldEntries[i]); + TALLOC_FREE(oldEntries[i]); } krb5_kt_end_seq_get(context, keytab, &cursor); } @@ -662,7 +662,8 @@ int ads_keytab_create_default(ADS_STRUCT *ads) done: - SAFE_FREE(oldEntries); + TALLOC_FREE(oldEntries); + TALLOC_FREE(ctx); { krb5_keytab_entry zero_kt_entry; @@ -728,7 +729,7 @@ int ads_keytab_list(const char *keytab_name) char *etype_s = NULL; krb5_enctype enctype = 0; - ret = smb_krb5_unparse_name(context, kt_entry.principal, &princ_s); + ret = smb_krb5_unparse_name(talloc_tos(), context, kt_entry.principal, &princ_s); if (ret) { goto out; } @@ -739,14 +740,14 @@ int ads_keytab_list(const char *keytab_name) if (ret) { if (asprintf(&etype_s, "UNKNOWN: %d\n", enctype) == -1) { - SAFE_FREE(princ_s); + TALLOC_FREE(princ_s); goto out; } } printf("%3d %s\t\t %s\n", kt_entry.vno, etype_s, princ_s); - SAFE_FREE(princ_s); + TALLOC_FREE(princ_s); SAFE_FREE(etype_s); ret = smb_krb5_kt_free_entry(context, &kt_entry); diff --git a/source3/libads/kerberos_verify.c b/source3/libads/kerberos_verify.c index b903b2a6eb..8502902963 100644 --- a/source3/libads/kerberos_verify.c +++ b/source3/libads/kerberos_verify.c @@ -192,7 +192,7 @@ static bool ads_keytab_verify_ticket(krb5_context context, } while (!auth_ok && (krb5_kt_next_entry(context, keytab, &kt_entry, &kt_cursor) == 0)) { - ret = smb_krb5_unparse_name(context, kt_entry.principal, &entry_princ_s); + ret = smb_krb5_unparse_name(talloc_tos(), context, kt_entry.principal, &entry_princ_s); if (ret) { DEBUG(1, ("ads_keytab_verify_ticket: smb_krb5_unparse_name failed (%s)\n", error_message(ret))); @@ -242,7 +242,7 @@ static bool ads_keytab_verify_ticket(krb5_context context, } /* Free the name we parsed. */ - SAFE_FREE(entry_princ_s); + TALLOC_FREE(entry_princ_s); /* Free the entry we just read. */ smb_krb5_kt_free_entry(context, &kt_entry); @@ -636,7 +636,7 @@ NTSTATUS ads_verify_ticket(TALLOC_CTX *mem_ctx, #endif #endif - if ((ret = smb_krb5_unparse_name(context, client_principal, principal))) { + if ((ret = smb_krb5_unparse_name(mem_ctx, context, client_principal, principal))) { DEBUG(3,("ads_verify_ticket: smb_krb5_unparse_name failed (%s)\n", error_message(ret))); sret = NT_STATUS_LOGON_FAILURE; diff --git a/source3/libads/ldap.c b/source3/libads/ldap.c index edbd69392c..841ea8caae 100644 --- a/source3/libads/ldap.c +++ b/source3/libads/ldap.c @@ -1267,22 +1267,12 @@ ADS_STATUS ads_do_search_all_fn(ADS_STRUCT *ads, const char *bind_path, } /** - * Free up memory from various ads requests - * @param ads connection to ads server - * @param mem Area to free - **/ -void ads_memfree(ADS_STRUCT *ads, void *mem) -{ - SAFE_FREE(mem); -} - -/** * Get a dn from search results * @param ads connection to ads server * @param msg Search result * @return dn string **/ - char *ads_get_dn(ADS_STRUCT *ads, LDAPMessage *msg) + char *ads_get_dn(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, LDAPMessage *msg) { char *utf8_dn, *unix_dn; size_t converted_size; @@ -1294,7 +1284,7 @@ void ads_memfree(ADS_STRUCT *ads, void *mem) return NULL; } - if (!pull_utf8_allocate(&unix_dn, utf8_dn, &converted_size)) { + if (!pull_utf8_talloc(mem_ctx, &unix_dn, utf8_dn, &converted_size)) { DEBUG(0,("ads_get_dn: string conversion failure utf8 [%s]\n", utf8_dn )); return NULL; @@ -1639,7 +1629,7 @@ char *ads_default_ou_string(ADS_STRUCT *ads, const char *wknguid) } /* substitute the bind-path from the well-known-guid-search result */ - wkn_dn = ads_get_dn(ads, res); + wkn_dn = ads_get_dn(ads, talloc_tos(), res); if (!wkn_dn) { goto out; } @@ -1685,7 +1675,7 @@ char *ads_default_ou_string(ADS_STRUCT *ads, const char *wknguid) out: SAFE_FREE(base); ads_msgfree(ads, res); - ads_memfree(ads, wkn_dn); + TALLOC_FREE(wkn_dn); if (wkn_dn_exp) { ldap_value_free(wkn_dn_exp); } @@ -1741,14 +1731,14 @@ uint32 ads_get_kvno(ADS_STRUCT *ads, const char *account_name) return kvno; } - dn_string = ads_get_dn(ads, res); + dn_string = ads_get_dn(ads, talloc_tos(), res); if (!dn_string) { DEBUG(0,("ads_get_kvno: out of memory.\n")); ads_msgfree(ads, res); return kvno; } DEBUG(5,("ads_get_kvno: Using: %s\n", dn_string)); - ads_memfree(ads, dn_string); + TALLOC_FREE(dn_string); /* --------------------------------------------------------- * 0 is returned as a default KVNO from this point on... @@ -1836,14 +1826,14 @@ ADS_STATUS ads_clear_service_principal_names(ADS_STRUCT *ads, const char *machin talloc_destroy(ctx); return ret; } - dn_string = ads_get_dn(ads, res); + dn_string = ads_get_dn(ads, talloc_tos(), res); if (!dn_string) { talloc_destroy(ctx); ads_msgfree(ads, res); return ADS_ERROR(LDAP_NO_MEMORY); } ret = ads_gen_mod(ads, dn_string, mods); - ads_memfree(ads,dn_string); + TALLOC_FREE(dn_string); if (!ADS_ERR_OK(ret)) { DEBUG(1,("ads_clear_service_principal_names: Error: Updating Service Principals for machine %s in LDAP\n", machine_name)); @@ -1933,13 +1923,12 @@ ADS_STATUS ads_add_service_principal_name(ADS_STRUCT *ads, const char *machine_n goto out; } - if ( (dn_string = ads_get_dn(ads, res)) == NULL ) { + if ( (dn_string = ads_get_dn(ads, ctx, res)) == NULL ) { ret = ADS_ERROR(LDAP_NO_MEMORY); goto out; } ret = ads_gen_mod(ads, dn_string, mods); - ads_memfree(ads,dn_string); if (!ADS_ERR_OK(ret)) { DEBUG(1,("ads_add_service_principal_name: Error: Updating Service Principals in LDAP\n")); goto out; @@ -2052,7 +2041,7 @@ ADS_STATUS ads_move_machine_acct(ADS_STRUCT *ads, const char *machine_name, goto done; } - computer_dn = ads_get_dn(ads, res); + computer_dn = ads_get_dn(ads, talloc_tos(), res); if (!computer_dn) { rc = ADS_ERROR(LDAP_NO_MEMORY); goto done; @@ -3029,7 +3018,7 @@ ADS_STATUS ads_site_dn_for_machine(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, const c return ADS_ERROR(LDAP_NO_SUCH_OBJECT); } - dn = ads_get_dn(ads, res); + dn = ads_get_dn(ads, mem_ctx, res); if (dn == NULL) { ads_msgfree(ads, res); return ADS_ERROR(LDAP_NO_MEMORY); @@ -3039,18 +3028,18 @@ ADS_STATUS ads_site_dn_for_machine(ADS_STRUCT *ads, TALLOC_CTX *mem_ctx, const c parent = ads_parent_dn(ads_parent_dn(ads_parent_dn(dn))); if (parent == NULL) { ads_msgfree(ads, res); - ads_memfree(ads, dn); + TALLOC_FREE(dn); return ADS_ERROR(LDAP_NO_MEMORY); } *site_dn = talloc_strdup(mem_ctx, parent); if (*site_dn == NULL) { ads_msgfree(ads, res); - ads_memfree(ads, dn); + TALLOC_FREE(dn); return ADS_ERROR(LDAP_NO_MEMORY); } - ads_memfree(ads, dn); + TALLOC_FREE(dn); ads_msgfree(ads, res); return status; @@ -3140,7 +3129,7 @@ ADS_STATUS ads_get_joinable_ous(ADS_STRUCT *ads, char *dn = NULL; - dn = ads_get_dn(ads, msg); + dn = ads_get_dn(ads, talloc_tos(), msg); if (!dn) { ads_msgfree(ads, res); return ADS_ERROR(LDAP_NO_MEMORY); @@ -3149,12 +3138,12 @@ ADS_STATUS ads_get_joinable_ous(ADS_STRUCT *ads, if (!add_string_to_array(mem_ctx, dn, (const char ***)ous, (int *)num_ous)) { - ads_memfree(ads, dn); + TALLOC_FREE(dn); ads_msgfree(ads, res); return ADS_ERROR(LDAP_NO_MEMORY); } - ads_memfree(ads, dn); + TALLOC_FREE(dn); } ads_msgfree(ads, res); @@ -3494,7 +3483,7 @@ ADS_STATUS ads_leave_realm(ADS_STRUCT *ads, const char *hostname) return ADS_ERROR_SYSTEM(ENOENT); } - hostnameDN = ads_get_dn(ads, (LDAPMessage *)msg); + hostnameDN = ads_get_dn(ads, talloc_tos(), (LDAPMessage *)msg); rc = ldap_delete_ext_s(ads->ldap.ld, hostnameDN, pldap_control, NULL); if (rc) { @@ -3516,7 +3505,7 @@ ADS_STATUS ads_leave_realm(ADS_STRUCT *ads, const char *hostname) if (!ADS_ERR_OK(status)) { SAFE_FREE(host); - ads_memfree(ads, hostnameDN); + TALLOC_FREE(hostnameDN); return status; } @@ -3525,9 +3514,9 @@ ADS_STATUS ads_leave_realm(ADS_STRUCT *ads, const char *hostname) char *dn = NULL; - if ((dn = ads_get_dn(ads, msg_sub)) == NULL) { + if ((dn = ads_get_dn(ads, talloc_tos(), msg_sub)) == NULL) { SAFE_FREE(host); - ads_memfree(ads, hostnameDN); + TALLOC_FREE(hostnameDN); return ADS_ERROR(LDAP_NO_MEMORY); } @@ -3535,12 +3524,12 @@ ADS_STATUS ads_leave_realm(ADS_STRUCT *ads, const char *hostname) if (!ADS_ERR_OK(status)) { DEBUG(3,("failed to delete dn %s: %s\n", dn, ads_errstr(status))); SAFE_FREE(host); - ads_memfree(ads, dn); - ads_memfree(ads, hostnameDN); + TALLOC_FREE(dn); + TALLOC_FREE(hostnameDN); return status; } - ads_memfree(ads, dn); + TALLOC_FREE(dn); } /* there should be no subordinate objects anymore */ @@ -3550,7 +3539,7 @@ ADS_STATUS ads_leave_realm(ADS_STRUCT *ads, const char *hostname) if (!ADS_ERR_OK(status) || ( (ads_count_replies(ads, res)) > 0 ) ) { SAFE_FREE(host); - ads_memfree(ads, hostnameDN); + TALLOC_FREE(hostnameDN); return status; } @@ -3559,12 +3548,12 @@ ADS_STATUS ads_leave_realm(ADS_STRUCT *ads, const char *hostname) if (!ADS_ERR_OK(status)) { SAFE_FREE(host); DEBUG(3,("failed to delete dn %s: %s\n", hostnameDN, ads_errstr(status))); - ads_memfree(ads, hostnameDN); + TALLOC_FREE(hostnameDN); return status; } } - ads_memfree(ads, hostnameDN); + TALLOC_FREE(hostnameDN); status = ads_find_machine_acct(ads, &res, host); if (ADS_ERR_OK(status) && ads_count_replies(ads, res) == 1) { @@ -3723,7 +3712,7 @@ ADS_STATUS ads_find_samaccount(ADS_STRUCT *ads, goto out; } - dn = ads_get_dn(ads, res); + dn = ads_get_dn(ads, talloc_tos(), res); if (dn == NULL) { status = ADS_ERROR(LDAP_NO_MEMORY); goto out; @@ -3746,7 +3735,7 @@ ADS_STATUS ads_find_samaccount(ADS_STRUCT *ads, } } out: - ads_memfree(ads, dn); + TALLOC_FREE(dn); ads_msgfree(ads, res); return status; diff --git a/source3/libgpo/gpo_ldap.c b/source3/libgpo/gpo_ldap.c index 26813864e5..716b8729c3 100644 --- a/source3/libgpo/gpo_ldap.c +++ b/source3/libgpo/gpo_ldap.c @@ -415,7 +415,7 @@ ADS_STATUS ads_delete_gpo_link(ADS_STRUCT *ads, if (gpo_dn) { gpo->ds_path = talloc_strdup(mem_ctx, gpo_dn); } else { - gpo->ds_path = ads_get_dn(ads, res); + gpo->ds_path = ads_get_dn(ads, mem_ctx, res); } ADS_ERROR_HAVE_NO_MEMORY(gpo->ds_path); @@ -453,7 +453,7 @@ ADS_STATUS ads_delete_gpo_link(ADS_STRUCT *ads, } /**************************************************************** - get a GROUP_POLICY_OBJECT structure based on different input paramters + get a GROUP_POLICY_OBJECT structure based on different input parameters ****************************************************************/ ADS_STATUS ads_get_gpo(ADS_STRUCT *ads, @@ -523,7 +523,7 @@ ADS_STATUS ads_get_gpo(ADS_STRUCT *ads, return ADS_ERROR(LDAP_NO_SUCH_OBJECT); } - dn = ads_get_dn(ads, res); + dn = ads_get_dn(ads, mem_ctx, res); if (dn == NULL) { ads_msgfree(ads, res); return ADS_ERROR(LDAP_NO_MEMORY); @@ -531,7 +531,7 @@ ADS_STATUS ads_get_gpo(ADS_STRUCT *ads, status = ads_parse_gpo(ads, mem_ctx, res, dn, gpo); ads_msgfree(ads, res); - ads_memfree(ads, dn); + TALLOC_FREE(dn); return status; } diff --git a/source3/libnet/libnet_join.c b/source3/libnet/libnet_join.c index ccfd943a8d..fe9fd66fdc 100644 --- a/source3/libnet/libnet_join.c +++ b/source3/libnet/libnet_join.c @@ -303,7 +303,7 @@ static ADS_STATUS libnet_join_find_machine_acct(TALLOC_CTX *mem_ctx, goto done; } - dn = ads_get_dn(r->in.ads, res); + dn = ads_get_dn(r->in.ads, mem_ctx, res); if (!dn) { status = ADS_ERROR_LDAP(LDAP_NO_MEMORY); goto done; @@ -317,7 +317,7 @@ static ADS_STATUS libnet_join_find_machine_acct(TALLOC_CTX *mem_ctx, done: ads_msgfree(r->in.ads, res); - ads_memfree(r->in.ads, dn); + TALLOC_FREE(dn); return status; } diff --git a/source3/libnet/libnet_keytab.c b/source3/libnet/libnet_keytab.c index 81956942ca..589d4c2525 100644 --- a/source3/libnet/libnet_keytab.c +++ b/source3/libnet/libnet_keytab.c @@ -144,7 +144,7 @@ static krb5_error_code libnet_keytab_remove_entries(krb5_context context, goto cont; } - ret = smb_krb5_unparse_name(context, kt_entry.principal, + ret = smb_krb5_unparse_name(talloc_tos(), context, kt_entry.principal, &princ_s); if (ret) { DEBUG(5, ("smb_krb5_unparse_name failed (%s)\n", @@ -190,7 +190,7 @@ static krb5_error_code libnet_keytab_remove_entries(krb5_context context, cont: smb_krb5_kt_free_entry(context, &kt_entry); - SAFE_FREE(princ_s); + TALLOC_FREE(princ_s); } ret = krb5_kt_end_seq_get(context, keytab, &cursor); @@ -334,6 +334,8 @@ struct libnet_keytab_entry *libnet_keytab_search(struct libnet_keytab_context *c krb5_keyblock *keyp; char *princ_s = NULL; + entry = NULL; + if (kt_entry.vno != kvno) { goto cont; } @@ -344,7 +346,13 @@ struct libnet_keytab_entry *libnet_keytab_search(struct libnet_keytab_context *c goto cont; } - ret = smb_krb5_unparse_name(ctx->context, kt_entry.principal, + entry = talloc_zero(mem_ctx, struct libnet_keytab_entry); + if (!entry) { + DEBUG(3, ("talloc failed\n")); + goto fail; + } + + ret = smb_krb5_unparse_name(entry, ctx->context, kt_entry.principal, &princ_s); if (ret) { goto cont; @@ -354,24 +362,14 @@ struct libnet_keytab_entry *libnet_keytab_search(struct libnet_keytab_context *c goto cont; } - entry = talloc_zero(mem_ctx, struct libnet_keytab_entry); - if (!entry) { - DEBUG(3, ("talloc failed\n")); - goto fail; - } - - entry->name = talloc_strdup(entry, princ_s); - if (!entry->name) { - DEBUG(3, ("talloc_strdup_failed\n")); - goto fail; - } - entry->principal = talloc_strdup(entry, princ_s); if (!entry->principal) { DEBUG(3, ("talloc_strdup_failed\n")); goto fail; } + entry->name = talloc_move(entry, &princ_s); + entry->password = data_blob_talloc(entry, KRB5_KEY_DATA(keyp), KRB5_KEY_LENGTH(keyp)); if (!entry->password.data) { @@ -382,18 +380,16 @@ struct libnet_keytab_entry *libnet_keytab_search(struct libnet_keytab_context *c DEBUG(10, ("found entry\n")); smb_krb5_kt_free_entry(ctx->context, &kt_entry); - SAFE_FREE(princ_s); break; fail: smb_krb5_kt_free_entry(ctx->context, &kt_entry); - SAFE_FREE(princ_s); TALLOC_FREE(entry); break; cont: smb_krb5_kt_free_entry(ctx->context, &kt_entry); - SAFE_FREE(princ_s); + TALLOC_FREE(entry); continue; } diff --git a/source3/libsmb/async_smb.c b/source3/libsmb/async_smb.c index 86fd5c8bef..6faf96c207 100644 --- a/source3/libsmb/async_smb.c +++ b/source3/libsmb/async_smb.c @@ -19,9 +19,6 @@ #include "includes.h" -static void cli_state_handler(struct event_context *event_ctx, - struct fd_event *event, uint16 flags, void *p); - /** * Fetch an error out of a NBT packet * @param[in] buf The SMB packet @@ -69,89 +66,6 @@ void cli_set_error(struct cli_state *cli, NTSTATUS status) } /** - * Allocate a new mid - * @param[in] cli The client connection - * @retval The new, unused mid - */ - -static uint16_t cli_new_mid(struct cli_state *cli) -{ - uint16_t result; - struct cli_request *req; - - while (true) { - result = cli->mid++; - if (result == 0) { - continue; - } - - for (req = cli->outstanding_requests; req; req = req->next) { - if (result == req->mid) { - break; - } - } - - if (req == NULL) { - return result; - } - } -} - -/** - * Print an async req that happens to be a cli_request - * @param[in] mem_ctx The TALLOC_CTX to put the result on - * @param[in] req The request to print - * @retval The string representation of "req" - */ - -static char *cli_request_print(TALLOC_CTX *mem_ctx, struct async_req *req) -{ - char *result = async_req_print(mem_ctx, req); - struct cli_request *cli_req = talloc_get_type_abort( - req->private_data, struct cli_request); - - if (result == NULL) { - return NULL; - } - - return talloc_asprintf_append_buffer( - result, "mid=%d\n", cli_req->mid); -} - -/** - * Destroy a cli_request - * @param[in] req The cli_request to kill - * @retval Can't fail - */ - -static int cli_request_destructor(struct cli_request *req) -{ - if (req->enc_state != NULL) { - common_free_enc_buffer(req->enc_state, (char *)req->outbuf); - } - DLIST_REMOVE(req->cli->outstanding_requests, req); - if (req->cli->outstanding_requests == NULL) { - TALLOC_FREE(req->cli->fd_event); - } - return 0; -} - -/** - * Are there already requests waiting in the chain_accumulator? - * @param[in] cli The cli_state we want to check - * @retval reply :-) - */ - -bool cli_in_chain(struct cli_state *cli) -{ - if (cli->chain_accumulator == NULL) { - return false; - } - - return (cli->chain_accumulator->num_async != 0); -} - -/** * @brief Find the smb_cmd offset of the last command pushed * @param[in] buf The buffer we're building up * @retval Where can we put our next andx cmd? @@ -326,417 +240,614 @@ bool smb_splice_chain(uint8_t **poutbuf, uint8_t smb_command, } /** - * @brief Destroy an async_req that is the visible part of a cli_request - * @param[in] req The request to kill - * @retval Return 0 to make talloc happy - * - * This destructor is a bit tricky: Because a cli_request can host more than - * one async_req for chained requests, we need to make sure that the - * "cli_request" that we were part of is correctly destroyed at the right - * time. This is done by NULLing out ourself from the "async" member of our - * "cli_request". If there is none left, then also TALLOC_FREE() the - * cli_request, which was a talloc child of the client connection cli_state. + * Figure out if there is an andx command behind the current one + * @param[in] buf The smb buffer to look at + * @param[in] ofs The offset to the wct field that is followed by the cmd + * @retval Is there a command following? */ -static int cli_async_req_destructor(struct async_req *req) +static bool have_andx_command(const char *buf, uint16_t ofs) { - struct cli_request *cli_req = talloc_get_type_abort( - req->private_data, struct cli_request); - int i, pending; - bool found = false; + uint8_t wct; + size_t buflen = talloc_get_size(buf); - pending = 0; + if ((ofs == buflen-1) || (ofs == buflen)) { + return false; + } - for (i=0; i<cli_req->num_async; i++) { - if (cli_req->async[i] == req) { - cli_req->async[i] = NULL; - found = true; - } - if (cli_req->async[i] != NULL) { - pending += 1; - } + wct = CVAL(buf, ofs); + if (wct < 2) { + /* + * Not enough space for the command and a following pointer + */ + return false; } + return (CVAL(buf, ofs+1) != 0xff); +} - SMB_ASSERT(found); +#define MAX_SMB_IOV 5 - if (pending == 0) { - TALLOC_FREE(cli_req); - } +struct cli_smb_state { + struct tevent_context *ev; + struct cli_state *cli; + uint8_t header[smb_wct+1]; /* Space for the header including the wct */ - return 0; -} + /* + * For normal requests, cli_smb_req_send chooses a mid. Secondary + * trans requests need to use the mid of the primary request, so we + * need a place to store it. Assume it's set if != 0. + */ + uint16_t mid; -/** - * @brief Chain up a request - * @param[in] mem_ctx The TALLOC_CTX for the result - * @param[in] ev The event context that will call us back - * @param[in] cli The cli_state we queue the request up for - * @param[in] smb_command The command that we want to issue - * @param[in] additional_flags open_and_x wants to add oplock header flags - * @param[in] wct How many words? - * @param[in] vwv The words, already in network order - * @param[in] bytes_alignment How shall we align "bytes"? - * @param[in] num_bytes How many bytes? - * @param[in] bytes The data the request ships - * - * cli_request_chain() is the core of the SMB request marshalling routine. It - * will create a new async_req structure in the cli->chain_accumulator->async - * array and marshall the smb_cmd, the vwv array and the bytes into - * cli->chain_accumulator->outbuf. - */ + uint16_t *vwv; + uint8_t bytecount_buf[2]; + + struct iovec iov[MAX_SMB_IOV+3]; + int iov_count; -static struct async_req *cli_request_chain(TALLOC_CTX *mem_ctx, - struct event_context *ev, - struct cli_state *cli, - uint8_t smb_command, - uint8_t additional_flags, - uint8_t wct, const uint16_t *vwv, - size_t bytes_alignment, - uint32_t num_bytes, - const uint8_t *bytes) + uint8_t *inbuf; + uint32_t seqnum; + int chain_num; + struct tevent_req **chained_requests; +}; + +static uint16_t cli_alloc_mid(struct cli_state *cli) { - struct async_req **tmp_reqs; - struct cli_request *req; + int num_pending = talloc_array_length(cli->pending); + uint16_t result; - req = cli->chain_accumulator; + while (true) { + int i; - tmp_reqs = TALLOC_REALLOC_ARRAY(req, req->async, struct async_req *, - req->num_async + 1); - if (tmp_reqs == NULL) { - DEBUG(0, ("talloc failed\n")); - return NULL; + result = cli->mid++; + if ((result == 0) || (result == 0xffff)) { + continue; + } + + for (i=0; i<num_pending; i++) { + if (result == cli_smb_req_mid(cli->pending[i])) { + break; + } + } + + if (i == num_pending) { + return result; + } } - req->async = tmp_reqs; - req->num_async += 1; +} - req->async[req->num_async-1] = async_req_new(mem_ctx); - if (req->async[req->num_async-1] == NULL) { - DEBUG(0, ("async_req_new failed\n")); - req->num_async -= 1; - return NULL; +void cli_smb_req_unset_pending(struct tevent_req *req) +{ + struct cli_smb_state *state = tevent_req_data( + req, struct cli_smb_state); + struct cli_state *cli = state->cli; + int num_pending = talloc_array_length(cli->pending); + int i; + + if (num_pending == 1) { + /* + * The pending read_smb tevent_req is a child of + * cli->pending. So if nothing is pending anymore, we need to + * delete the socket read fde. + */ + TALLOC_FREE(cli->pending); + return; } - req->async[req->num_async-1]->private_data = req; - req->async[req->num_async-1]->print = cli_request_print; - talloc_set_destructor(req->async[req->num_async-1], - cli_async_req_destructor); - if (!smb_splice_chain(&req->outbuf, smb_command, wct, vwv, - bytes_alignment, num_bytes, bytes)) { - goto fail; + for (i=0; i<num_pending; i++) { + if (req == cli->pending[i]) { + break; + } + } + if (i == num_pending) { + /* + * Something's seriously broken. Just returning here is the + * right thing nevertheless, the point of this routine is to + * remove ourselves from cli->pending. + */ + return; + } + + /* + * Remove ourselves from the cli->pending array + */ + if (num_pending > 1) { + cli->pending[i] = cli->pending[num_pending-1]; } - return req->async[req->num_async-1]; + /* + * No NULL check here, we're shrinking by sizeof(void *), and + * talloc_realloc just adjusts the size for this. + */ + cli->pending = talloc_realloc(NULL, cli->pending, struct tevent_req *, + num_pending - 1); + return; +} - fail: - TALLOC_FREE(req->async[req->num_async-1]); - req->num_async -= 1; - return NULL; +static int cli_smb_req_destructor(struct tevent_req *req) +{ + cli_smb_req_unset_pending(req); + return 0; } -/** - * @brief prepare a cli_state to accept a chain of requests - * @param[in] cli The cli_state we want to queue up in - * @param[in] ev The event_context that will call us back for the socket - * @param[in] size_hint How many bytes are expected, just an optimization - * @retval Did we have enough memory? - * - * cli_chain_cork() sets up a new cli_request in cli->chain_accumulator. If - * cli is used in an async fashion, i.e. if we have outstanding requests, then - * we do not have to create a fd event. If cli is used only with the sync - * helpers, we need to create the fd_event here. - * - * If you want to issue a chained request to the server, do a - * cli_chain_cork(), then do you cli_open_send(), cli_read_and_x_send(), - * cli_close_send() and so on. The async requests that come out of - * cli_xxx_send() are normal async requests with the difference that they - * won't be shipped individually. But the event_context will still trigger the - * req->async.fn to be called on every single request. - * - * You have to take care yourself that you only issue chainable requests in - * the middle of the chain. - */ +static void cli_smb_received(struct tevent_req *subreq); -bool cli_chain_cork(struct cli_state *cli, struct event_context *ev, - size_t size_hint) +bool cli_smb_req_set_pending(struct tevent_req *req) { - struct cli_request *req = NULL; + struct cli_smb_state *state = tevent_req_data( + req, struct cli_smb_state); + struct cli_state *cli; + struct tevent_req **pending; + int num_pending; + struct tevent_req *subreq; + + cli = state->cli; + num_pending = talloc_array_length(cli->pending); + + pending = talloc_realloc(cli, cli->pending, struct tevent_req *, + num_pending+1); + if (pending == NULL) { + return false; + } + pending[num_pending] = req; + cli->pending = pending; + talloc_set_destructor(req, cli_smb_req_destructor); - SMB_ASSERT(cli->chain_accumulator == NULL); + if (num_pending > 0) { + return true; + } - if (cli->fd == -1) { - DEBUG(10, ("cli->fd closed\n")); + /* + * We're the first ones, add the read_smb request that waits for the + * answer from the server + */ + subreq = read_smb_send(cli->pending, state->ev, cli->fd); + if (subreq == NULL) { + cli_smb_req_unset_pending(req); return false; } + tevent_req_set_callback(subreq, cli_smb_received, cli); + return true; +} - if (cli->fd_event == NULL) { - SMB_ASSERT(cli->outstanding_requests == NULL); - cli->fd_event = event_add_fd(ev, cli, cli->fd, - EVENT_FD_READ, - cli_state_handler, cli); - if (cli->fd_event == NULL) { - return false; - } - } +/* + * Fetch a smb request's mid. Only valid after the request has been sent by + * cli_smb_req_send(). + */ +uint16_t cli_smb_req_mid(struct tevent_req *req) +{ + struct cli_smb_state *state = tevent_req_data( + req, struct cli_smb_state); + return SVAL(state->header, smb_mid); +} - req = talloc(cli, struct cli_request); - if (req == NULL) { - goto fail; +void cli_smb_req_set_mid(struct tevent_req *req, uint16_t mid) +{ + struct cli_smb_state *state = tevent_req_data( + req, struct cli_smb_state); + state->mid = mid; +} + +static size_t iov_len(const struct iovec *iov, int count) +{ + size_t result = 0; + int i; + for (i=0; i<count; i++) { + result += iov[i].iov_len; } - req->cli = cli; + return result; +} - if (size_hint == 0) { - size_hint = 100; +static uint8_t *iov_concat(TALLOC_CTX *mem_ctx, const struct iovec *iov, + int count) +{ + size_t len = iov_len(iov, count); + size_t copied; + uint8_t *buf; + int i; + + buf = talloc_array(mem_ctx, uint8_t, len); + if (buf == NULL) { + return NULL; } - req->outbuf = talloc_array(req, uint8_t, smb_wct + size_hint); - if (req->outbuf == NULL) { - goto fail; + copied = 0; + for (i=0; i<count; i++) { + memcpy(buf+copied, iov[i].iov_base, iov[i].iov_len); + copied += iov[i].iov_len; } - req->outbuf = TALLOC_REALLOC_ARRAY(NULL, req->outbuf, uint8_t, - smb_wct); + return buf; +} - req->num_async = 0; - req->async = NULL; +struct tevent_req *cli_smb_req_create(TALLOC_CTX *mem_ctx, + struct event_context *ev, + struct cli_state *cli, + uint8_t smb_command, + uint8_t additional_flags, + uint8_t wct, uint16_t *vwv, + int iov_count, + struct iovec *bytes_iov) +{ + struct tevent_req *result; + struct cli_smb_state *state; - req->enc_state = NULL; - req->recv_helper.fn = NULL; + if (iov_count > MAX_SMB_IOV) { + /* + * Should not happen :-) + */ + return NULL; + } - SSVAL(req->outbuf, smb_tid, cli->cnum); - cli_setup_packet_buf(cli, (char *)req->outbuf); + result = tevent_req_create(mem_ctx, &state, struct cli_smb_state); + if (result == NULL) { + return NULL; + } + state->ev = ev; + state->cli = cli; + state->mid = 0; /* Set to auto-choose in cli_smb_req_send */ + state->chain_num = 0; + state->chained_requests = NULL; + + cli_setup_packet_buf(cli, (char *)state->header); + SCVAL(state->header, smb_com, smb_command); + SSVAL(state->header, smb_tid, cli->cnum); + SCVAL(state->header, smb_wct, wct); + + state->vwv = vwv; + + SSVAL(state->bytecount_buf, 0, iov_len(bytes_iov, iov_count)); + + state->iov[0].iov_base = state->header; + state->iov[0].iov_len = sizeof(state->header); + state->iov[1].iov_base = state->vwv; + state->iov[1].iov_len = wct * sizeof(uint16_t); + state->iov[2].iov_base = state->bytecount_buf; + state->iov[2].iov_len = sizeof(uint16_t); + + if (iov_count != 0) { + memcpy(&state->iov[3], bytes_iov, + iov_count * sizeof(*bytes_iov)); + } + state->iov_count = iov_count + 3; - req->mid = cli_new_mid(cli); + return result; +} - cli->chain_accumulator = req; +static bool cli_signv(struct cli_state *cli, struct iovec *iov, int count, + uint32_t *seqnum) +{ + uint8_t *buf; - DEBUG(10, ("cli_chain_cork: mid=%d\n", req->mid)); + /* + * Obvious optimization: Make cli_calculate_sign_mac work with struct + * iovec directly. MD5Update would do that just fine. + */ - return true; - fail: - TALLOC_FREE(req); - if (cli->outstanding_requests == NULL) { - TALLOC_FREE(cli->fd_event); + if ((count <= 0) || (iov[0].iov_len < smb_wct)) { + return false; } - return false; -} -/** - * Ship a request queued up via cli_request_chain() - * @param[in] cl The connection - */ + buf = iov_concat(talloc_tos(), iov, count); + if (buf == NULL) { + return false; + } -void cli_chain_uncork(struct cli_state *cli) -{ - struct cli_request *req = cli->chain_accumulator; - size_t smblen; + cli_calculate_sign_mac(cli, (char *)buf, seqnum); + memcpy(iov[0].iov_base, buf, iov[0].iov_len); - SMB_ASSERT(req != NULL); + TALLOC_FREE(buf); + return true; +} - DLIST_ADD_END(cli->outstanding_requests, req, struct cli_request *); - talloc_set_destructor(req, cli_request_destructor); +static void cli_smb_sent(struct tevent_req *subreq); - cli->chain_accumulator = NULL; +static bool cli_smb_req_iov_send(struct tevent_req *req, + struct cli_smb_state *state, + struct iovec *iov, int iov_count) +{ + struct tevent_req *subreq; - SSVAL(req->outbuf, smb_mid, req->mid); + if (iov[0].iov_len < smb_wct) { + return false; + } - smblen = talloc_get_size(req->outbuf) - 4; + if (state->mid != 0) { + SSVAL(iov[0].iov_base, smb_mid, state->mid); + } else { + SSVAL(iov[0].iov_base, smb_mid, cli_alloc_mid(state->cli)); + } - smb_setlen((char *)req->outbuf, smblen); + smb_setlen((char *)iov[0].iov_base, iov_len(iov, iov_count) - 4); - if (smblen > 0x1ffff) { - /* - * This is a POSIX 14 word large write. Overwrite just the - * size field, the '0xFFSMB' has been set by smb_setlen which - * _smb_setlen_large does not do. - */ - _smb_setlen_large(((char *)req->outbuf), smblen); + if (!cli_signv(state->cli, iov, iov_count, &state->seqnum)) { + return false; } - cli_calculate_sign_mac(cli, (char *)req->outbuf, &req->seqnum); - - if (cli_encryption_on(cli)) { + if (cli_encryption_on(state->cli)) { NTSTATUS status; - char *enc_buf; + char *buf, *enc_buf; - status = cli_encrypt_message(cli, (char *)req->outbuf, + buf = (char *)iov_concat(talloc_tos(), iov, iov_count); + if (buf == NULL) { + return false; + } + status = cli_encrypt_message(state->cli, (char *)buf, &enc_buf); + TALLOC_FREE(buf); if (!NT_STATUS_IS_OK(status)) { - DEBUG(0, ("Error in encrypting client message. " - "Error %s\n", nt_errstr(status))); - TALLOC_FREE(req); - return; + DEBUG(0, ("Error in encrypting client message: %s\n", + nt_errstr(status))); + return false; } - req->outbuf = (uint8_t *)enc_buf; - req->enc_state = cli->trans_enc_state; + buf = (char *)talloc_memdup(state, enc_buf, + smb_len(enc_buf)+4); + SAFE_FREE(enc_buf); + if (buf == NULL) { + return false; + } + iov[0].iov_base = buf; + iov[0].iov_len = talloc_get_size(buf); + subreq = writev_send(state, state->ev, state->cli->outgoing, + state->cli->fd, iov, 1); + } else { + subreq = writev_send(state, state->ev, state->cli->outgoing, + state->cli->fd, iov, iov_count); + } + if (subreq == NULL) { + return false; } + tevent_req_set_callback(subreq, cli_smb_sent, req); + return true; +} - req->sent = 0; +bool cli_smb_req_send(struct tevent_req *req) +{ + struct cli_smb_state *state = tevent_req_data( + req, struct cli_smb_state); - event_fd_set_writeable(cli->fd_event); + return cli_smb_req_iov_send(req, state, state->iov, state->iov_count); } -/** - * @brief Send a request to the server - * @param[in] mem_ctx The TALLOC_CTX for the result - * @param[in] ev The event context that will call us back - * @param[in] cli The cli_state we queue the request up for - * @param[in] smb_command The command that we want to issue - * @param[in] additional_flags open_and_x wants to add oplock header flags - * @param[in] wct How many words? - * @param[in] vwv The words, already in network order - * @param[in] bytes_alignment How shall we align "bytes"? - * @param[in] num_bytes How many bytes? - * @param[in] bytes The data the request ships - * - * This is the generic routine to be used by the cli_xxx_send routines. - */ - -struct async_req *cli_request_send(TALLOC_CTX *mem_ctx, - struct event_context *ev, - struct cli_state *cli, - uint8_t smb_command, - uint8_t additional_flags, - uint8_t wct, const uint16_t *vwv, - size_t bytes_alignment, - uint32_t num_bytes, const uint8_t *bytes) +struct tevent_req *cli_smb_send(TALLOC_CTX *mem_ctx, + struct event_context *ev, + struct cli_state *cli, + uint8_t smb_command, + uint8_t additional_flags, + uint8_t wct, uint16_t *vwv, + uint32_t num_bytes, + const uint8_t *bytes) { - struct async_req *result; - bool uncork = false; - - if (cli->chain_accumulator == NULL) { - if (!cli_chain_cork(cli, ev, - wct * sizeof(uint16_t) + num_bytes + 3)) { - DEBUG(1, ("cli_chain_cork failed\n")); - return NULL; - } - uncork = true; - } + struct tevent_req *req; + struct iovec iov; - result = cli_request_chain(mem_ctx, ev, cli, smb_command, - additional_flags, wct, vwv, bytes_alignment, - num_bytes, bytes); + iov.iov_base = CONST_DISCARD(char *, bytes); + iov.iov_len = num_bytes; - if (result == NULL) { - DEBUG(1, ("cli_request_chain failed\n")); + req = cli_smb_req_create(mem_ctx, ev, cli, smb_command, + additional_flags, wct, vwv, 1, &iov); + if (req == NULL) { + return NULL; } + if (!cli_smb_req_send(req)) { + TALLOC_FREE(req); + } + return req; +} - if (uncork) { - cli_chain_uncork(cli); +static void cli_smb_sent(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct cli_smb_state *state = tevent_req_data( + req, struct cli_smb_state); + ssize_t nwritten; + int err; + + nwritten = writev_recv(subreq, &err); + TALLOC_FREE(subreq); + if (nwritten == -1) { + tevent_req_nterror(req, map_nt_error_from_unix(err)); + return; } - return result; -} + switch (CVAL(state->header, smb_com)) { + case SMBtranss: + case SMBtranss2: + case SMBnttranss: + case SMBntcancel: + state->inbuf = NULL; + tevent_req_done(req); + return; + case SMBlockingX: + if ((CVAL(state->header, smb_wct) == 8) && + (CVAL(state->vwv+3, 0) == LOCKING_ANDX_OPLOCK_RELEASE)) { + state->inbuf = NULL; + tevent_req_done(req); + return; + } + } -/** - * Calculate the current ofs to wct for requests like write&x - * @param[in] req The smb request we're currently building - * @retval how many bytes offset have we accumulated? - */ + if (!cli_smb_req_set_pending(req)) { + tevent_req_nterror(req, NT_STATUS_NO_MEMORY); + return; + } +} -uint16_t cli_wct_ofs(const struct cli_state *cli) +static void cli_smb_received(struct tevent_req *subreq) { - size_t buf_size; + struct cli_state *cli = tevent_req_callback_data( + subreq, struct cli_state); + struct tevent_req *req; + struct cli_smb_state *state; + struct tevent_context *ev; + NTSTATUS status; + uint8_t *inbuf; + ssize_t received; + int num_pending; + int i, err; + uint16_t mid; + bool oplock_break; + + received = read_smb_recv(subreq, talloc_tos(), &inbuf, &err); + TALLOC_FREE(subreq); + if (received == -1) { + status = map_nt_error_from_unix(err); + goto fail; + } - if (cli->chain_accumulator == NULL) { - return smb_wct - 4; + if ((IVAL(inbuf, 4) != 0x424d53ff) /* 0xFF"SMB" */ + && (SVAL(inbuf, 4) != 0x45ff)) /* 0xFF"E" */ { + DEBUG(10, ("Got non-SMB PDU\n")); + status = NT_STATUS_INVALID_NETWORK_RESPONSE; + goto fail; } - buf_size = talloc_get_size(cli->chain_accumulator->outbuf); + if (cli_encryption_on(cli) && (CVAL(inbuf, 0) == 0)) { + uint16_t enc_ctx_num; + + status = get_enc_ctx_num(inbuf, &enc_ctx_num); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(10, ("get_enc_ctx_num returned %s\n", + nt_errstr(status))); + goto fail; + } + + if (enc_ctx_num != cli->trans_enc_state->enc_ctx_num) { + DEBUG(10, ("wrong enc_ctx %d, expected %d\n", + enc_ctx_num, + cli->trans_enc_state->enc_ctx_num)); + status = NT_STATUS_INVALID_HANDLE; + goto fail; + } - if (buf_size == smb_wct) { - return smb_wct - 4; + status = common_decrypt_buffer(cli->trans_enc_state, + (char *)inbuf); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(10, ("common_decrypt_buffer returned %s\n", + nt_errstr(status))); + goto fail; + } } - /* - * Add alignment for subsequent requests - */ + mid = SVAL(inbuf, smb_mid); + num_pending = talloc_array_length(cli->pending); - if ((buf_size % 4) != 0) { - buf_size += (4 - (buf_size % 4)); + for (i=0; i<num_pending; i++) { + if (mid == cli_smb_req_mid(cli->pending[i])) { + break; + } + } + if (i == num_pending) { + /* Dump unexpected reply */ + TALLOC_FREE(inbuf); + goto done; } - return buf_size - 4; -} + oplock_break = false; -/** - * Figure out if there is an andx command behind the current one - * @param[in] buf The smb buffer to look at - * @param[in] ofs The offset to the wct field that is followed by the cmd - * @retval Is there a command following? - */ + if (mid == 0xffff) { + /* + * Paranoia checks that this is really an oplock break request. + */ + oplock_break = (smb_len(inbuf) == 51); /* hdr + 8 words */ + oplock_break &= ((CVAL(inbuf, smb_flg) & FLAG_REPLY) == 0); + oplock_break &= (CVAL(inbuf, smb_com) == SMBlockingX); + oplock_break &= (SVAL(inbuf, smb_vwv6) == 0); + oplock_break &= (SVAL(inbuf, smb_vwv7) == 0); + + if (!oplock_break) { + /* Dump unexpected reply */ + TALLOC_FREE(inbuf); + goto done; + } + } -static bool have_andx_command(const char *buf, uint16_t ofs) -{ - uint8_t wct; - size_t buflen = talloc_get_size(buf); + req = cli->pending[i]; + state = tevent_req_data(req, struct cli_smb_state); + ev = state->ev; - if ((ofs == buflen-1) || (ofs == buflen)) { - return false; + if (!oplock_break /* oplock breaks are not signed */ + && !cli_check_sign_mac(cli, (char *)inbuf, state->seqnum+1)) { + DEBUG(10, ("cli_check_sign_mac failed\n")); + TALLOC_FREE(inbuf); + status = NT_STATUS_ACCESS_DENIED; + goto fail; } - wct = CVAL(buf, ofs); - if (wct < 2) { + if (state->chained_requests == NULL) { + state->inbuf = talloc_move(state, &inbuf); + talloc_set_destructor(req, NULL); + cli_smb_req_destructor(req); + tevent_req_done(req); + } else { + struct tevent_req **chain = talloc_move( + talloc_tos(), &state->chained_requests); + int num_chained = talloc_array_length(chain); + + for (i=0; i<num_chained; i++) { + state = tevent_req_data(chain[i], struct + cli_smb_state); + state->inbuf = inbuf; + state->chain_num = i; + tevent_req_done(chain[i]); + } + TALLOC_FREE(inbuf); + TALLOC_FREE(chain); + } + done: + if (talloc_array_length(cli->pending) > 0) { /* - * Not enough space for the command and a following pointer + * Set up another read request for the other pending cli_smb + * requests */ - return false; + state = tevent_req_data(cli->pending[0], struct cli_smb_state); + subreq = read_smb_send(cli->pending, state->ev, cli->fd); + if (subreq == NULL) { + status = NT_STATUS_NO_MEMORY; + goto fail; + } + tevent_req_set_callback(subreq, cli_smb_received, cli); + } + return; + fail: + /* + * Cancel all pending requests. We don't do a for-loop walking + * cli->pending because that array changes in + * cli_smb_req_destructor(). + */ + while (talloc_array_length(cli->pending) > 0) { + req = cli->pending[0]; + talloc_set_destructor(req, NULL); + cli_smb_req_destructor(req); + tevent_req_nterror(req, status); } - return (CVAL(buf, ofs+1) != 0xff); } -/** - * @brief Pull reply data out of a request - * @param[in] req The request that we just received a reply for - * @param[out] pwct How many words did the server send? - * @param[out] pvwv The words themselves - * @param[out] pnum_bytes How many bytes did the server send? - * @param[out] pbytes The bytes themselves - * @retval Was the reply formally correct? - */ - -NTSTATUS cli_pull_reply(struct async_req *req, - uint8_t *pwct, uint16_t **pvwv, - uint16_t *pnum_bytes, uint8_t **pbytes) +NTSTATUS cli_smb_recv(struct tevent_req *req, uint8_t min_wct, + uint8_t *pwct, uint16_t **pvwv, + uint32_t *pnum_bytes, uint8_t **pbytes) { - struct cli_request *cli_req = talloc_get_type_abort( - req->private_data, struct cli_request); - uint8_t wct, cmd; + struct cli_smb_state *state = tevent_req_data( + req, struct cli_smb_state); + NTSTATUS status = NT_STATUS_OK; + uint8_t cmd, wct; uint16_t num_bytes; size_t wct_ofs, bytes_offset; - int i, j; - NTSTATUS status; - - for (i = 0; i < cli_req->num_async; i++) { - if (req == cli_req->async[i]) { - break; - } - } + int i; - if (i == cli_req->num_async) { - cli_set_error(cli_req->cli, NT_STATUS_INVALID_PARAMETER); - return NT_STATUS_INVALID_PARAMETER; + if (tevent_req_is_nterror(req, &status)) { + return status; } - /** - * The status we pull here is only relevant for the last reply in the - * chain. - */ - - status = cli_pull_error(cli_req->inbuf); - - if (i == 0) { - if (NT_STATUS_IS_ERR(status) - && !have_andx_command(cli_req->inbuf, smb_wct)) { - cli_set_error(cli_req->cli, status); - return status; - } - wct_ofs = smb_wct; - goto done; + if (state->inbuf == NULL) { + /* This was a request without a reply */ + return NT_STATUS_OK; } - cmd = CVAL(cli_req->inbuf, smb_com); wct_ofs = smb_wct; + cmd = CVAL(state->inbuf, smb_com); - for (j = 0; j < i; j++) { - if (j < i-1) { + for (i=0; i<state->chain_num; i++) { + if (i < state->chain_num-1) { if (cmd == 0xff) { return NT_STATUS_REQUEST_ABORTED; } @@ -745,7 +856,7 @@ NTSTATUS cli_pull_reply(struct async_req *req, } } - if (!have_andx_command(cli_req->inbuf, wct_ofs)) { + if (!have_andx_command((char *)state->inbuf, wct_ofs)) { /* * This request was not completed because a previous * request in the chain had received an error. @@ -753,7 +864,7 @@ NTSTATUS cli_pull_reply(struct async_req *req, return NT_STATUS_REQUEST_ABORTED; } - wct_ofs = SVAL(cli_req->inbuf, wct_ofs + 3); + wct_ofs = SVAL(state->inbuf, wct_ofs + 3); /* * Skip the all-present length field. No overflow, we've just @@ -761,14 +872,16 @@ NTSTATUS cli_pull_reply(struct async_req *req, */ wct_ofs += 4; - if (wct_ofs+2 > talloc_get_size(cli_req->inbuf)) { + if (wct_ofs+2 > talloc_get_size(state->inbuf)) { return NT_STATUS_INVALID_NETWORK_RESPONSE; } - cmd = CVAL(cli_req->inbuf, wct_ofs + 1); + cmd = CVAL(state->inbuf, wct_ofs + 1); } - if (!have_andx_command(cli_req->inbuf, wct_ofs) + status = cli_pull_error((char *)state->inbuf); + + if (!have_andx_command((char *)state->inbuf, wct_ofs) && NT_STATUS_IS_ERR(status)) { /* * The last command takes the error code. All further commands @@ -778,358 +891,241 @@ NTSTATUS cli_pull_reply(struct async_req *req, return status; } - done: - wct = CVAL(cli_req->inbuf, wct_ofs); - + wct = CVAL(state->inbuf, wct_ofs); bytes_offset = wct_ofs + 1 + wct * sizeof(uint16_t); - num_bytes = SVAL(cli_req->inbuf, bytes_offset); + num_bytes = SVAL(state->inbuf, bytes_offset); + + if (wct < min_wct) { + return NT_STATUS_INVALID_NETWORK_RESPONSE; + } /* * wct_ofs is a 16-bit value plus 4, wct is a 8-bit value, num_bytes * is a 16-bit value. So bytes_offset being size_t should be far from * wrapping. */ - - if ((bytes_offset + 2 > talloc_get_size(cli_req->inbuf)) + if ((bytes_offset + 2 > talloc_get_size(state->inbuf)) || (bytes_offset > 0xffff)) { return NT_STATUS_INVALID_NETWORK_RESPONSE; } - *pwct = wct; - *pvwv = (uint16_t *)(cli_req->inbuf + wct_ofs + 1); - *pnum_bytes = num_bytes; - *pbytes = (uint8_t *)cli_req->inbuf + bytes_offset + 2; - - return NT_STATUS_OK; -} - -/** - * Decrypt a PDU, check the signature - * @param[in] cli The cli_state that received something - * @param[in] pdu The incoming bytes - * @retval error code - */ - - -static NTSTATUS validate_smb_crypto(struct cli_state *cli, char *pdu, - struct cli_request **_req, - uint16_t *_mid) -{ - NTSTATUS status; - struct cli_request *req = NULL; - uint16_t mid; - - *_req = NULL; - *_mid = 0; - - if ((IVAL(pdu, 4) != 0x424d53ff) /* 0xFF"SMB" */ - && (SVAL(pdu, 4) != 0x45ff)) /* 0xFF"E" */ { - DEBUG(10, ("Got non-SMB PDU\n")); - return NT_STATUS_INVALID_NETWORK_RESPONSE; - } - - if (cli_encryption_on(cli) && CVAL(pdu, 0) == 0) { - uint16_t enc_ctx_num; - - status = get_enc_ctx_num((uint8_t *)pdu, &enc_ctx_num); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(10, ("get_enc_ctx_num returned %s\n", - nt_errstr(status))); - return status; - } - - if (enc_ctx_num != cli->trans_enc_state->enc_ctx_num) { - DEBUG(10, ("wrong enc_ctx %d, expected %d\n", - enc_ctx_num, - cli->trans_enc_state->enc_ctx_num)); - return NT_STATUS_INVALID_HANDLE; - } - - status = common_decrypt_buffer(cli->trans_enc_state, pdu); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(10, ("common_decrypt_buffer returned %s\n", - nt_errstr(status))); - return status; - } + if (pwct != NULL) { + *pwct = wct; } - - mid = SVAL(pdu, smb_mid); - - for (req = cli->outstanding_requests; req; req = req->next) { - if (req->mid == mid) { - break; - } + if (pvwv != NULL) { + *pvwv = (uint16_t *)(state->inbuf + wct_ofs + 1); } - - if (!req) { - /* oplock breaks are not signed */ - goto done; + if (pnum_bytes != NULL) { + *pnum_bytes = num_bytes; } - - if (!cli_check_sign_mac(cli, pdu, req->seqnum+1)) { - DEBUG(10, ("cli_check_sign_mac failed\n")); - return NT_STATUS_ACCESS_DENIED; + if (pbytes != NULL) { + *pbytes = (uint8_t *)state->inbuf + bytes_offset + 2; } -done: - *_req = req; - *_mid = mid; return NT_STATUS_OK; } -/** - * A PDU has arrived on cli->evt_inbuf - * @param[in] cli The cli_state that received something - */ - -static void handle_incoming_pdu(struct cli_state *cli) +size_t cli_smb_wct_ofs(struct tevent_req **reqs, int num_reqs) { - struct cli_request *req, *next; - uint16_t mid; - size_t raw_pdu_len, buf_len, rest_len; - char *pdu; + size_t wct_ofs; int i; - NTSTATUS status; - - int num_async; - /* - * The encrypted PDU len might differ from the unencrypted one - */ - raw_pdu_len = smb_len(cli->evt_inbuf) + 4; - buf_len = talloc_get_size(cli->evt_inbuf); - rest_len = buf_len - raw_pdu_len; + wct_ofs = smb_wct - 4; - if (buf_len == raw_pdu_len) { - /* - * Optimal case: Exactly one PDU was in the socket buffer - */ - pdu = cli->evt_inbuf; - cli->evt_inbuf = NULL; + for (i=0; i<num_reqs; i++) { + struct cli_smb_state *state; + state = tevent_req_data(reqs[i], struct cli_smb_state); + wct_ofs += iov_len(state->iov+1, state->iov_count-1); + wct_ofs = (wct_ofs + 3) & ~3; } - else { - DEBUG(11, ("buf_len = %d, raw_pdu_len = %d, splitting " - "buffer\n", (int)buf_len, (int)raw_pdu_len)); - - if (raw_pdu_len < rest_len) { - /* - * The PDU is shorter, talloc_memdup that one. - */ - pdu = (char *)talloc_memdup( - cli, cli->evt_inbuf, raw_pdu_len); - - memmove(cli->evt_inbuf, cli->evt_inbuf + raw_pdu_len, - buf_len - raw_pdu_len); - - cli->evt_inbuf = TALLOC_REALLOC_ARRAY( - NULL, cli->evt_inbuf, char, rest_len); - - if (pdu == NULL) { - status = NT_STATUS_NO_MEMORY; - goto invalidate_requests; - } - } - else { - /* - * The PDU is larger than the rest, talloc_memdup the - * rest - */ - pdu = cli->evt_inbuf; - - cli->evt_inbuf = (char *)talloc_memdup( - cli, pdu + raw_pdu_len, rest_len); + return wct_ofs; +} - if (cli->evt_inbuf == NULL) { - status = NT_STATUS_NO_MEMORY; - goto invalidate_requests; - } - } +bool cli_smb_chain_send(struct tevent_req **reqs, int num_reqs) +{ + struct cli_smb_state *first_state = tevent_req_data( + reqs[0], struct cli_smb_state); + struct cli_smb_state *last_state = tevent_req_data( + reqs[num_reqs-1], struct cli_smb_state); + struct cli_smb_state *state; + size_t wct_offset; + size_t chain_padding = 0; + int i, iovlen; + struct iovec *iov = NULL; + struct iovec *this_iov; + + iovlen = 0; + for (i=0; i<num_reqs; i++) { + state = tevent_req_data(reqs[i], struct cli_smb_state); + iovlen += state->iov_count; } - status = validate_smb_crypto(cli, pdu, &req, &mid); - if (!NT_STATUS_IS_OK(status)) { - goto invalidate_requests; + iov = talloc_array(last_state, struct iovec, iovlen); + if (iov == NULL) { + goto fail; } - DEBUG(10, ("handle_incoming_pdu: got mid %d\n", mid)); - - if (req == NULL) { - DEBUG(3, ("Request for mid %d not found, dumping PDU\n", mid)); - - TALLOC_FREE(pdu); - return; + first_state->chained_requests = (struct tevent_req **)talloc_memdup( + last_state, reqs, sizeof(*reqs) * num_reqs); + if (first_state->chained_requests == NULL) { + goto fail; } - req->inbuf = talloc_move(req, &pdu); + wct_offset = smb_wct - 4; + this_iov = iov; - /* - * Freeing the last async_req will free the req (see - * cli_async_req_destructor). So make a copy of req->num_async, we - * can't reference it in the last round. - */ + for (i=0; i<num_reqs; i++) { + size_t next_padding = 0; + uint16_t *vwv; - num_async = req->num_async; + state = tevent_req_data(reqs[i], struct cli_smb_state); - for (i=0; i<num_async; i++) { - /** - * A request might have been talloc_free()'ed before we arrive - * here. It will have removed itself from req->async via its - * destructor cli_async_req_destructor(). - */ - if (req->async[i] != NULL) { - if (req->recv_helper.fn != NULL) { - req->recv_helper.fn(req->async[i]); - } else { - async_req_done(req->async[i]); + if (i < num_reqs-1) { + if (!is_andx_req(CVAL(state->header, smb_com)) + || CVAL(state->header, smb_wct) < 2) { + goto fail; } } - } - return; - invalidate_requests: - - DEBUG(10, ("handle_incoming_pdu: Aborting with %s\n", - nt_errstr(status))); - - for (req = cli->outstanding_requests; req; req = next) { - next = req->next; - if (req->num_async) { - async_req_nterror(req->async[0], status); + wct_offset += iov_len(state->iov+1, state->iov_count-1) + 1; + if ((wct_offset % 4) != 0) { + next_padding = 4 - (wct_offset % 4); } - } - return; -} - -/** - * fd event callback. This is the basic connection to the socket - * @param[in] event_ctx The event context that called us - * @param[in] event The event that fired - * @param[in] flags EVENT_FD_READ | EVENT_FD_WRITE - * @param[in] p private_data, in this case the cli_state - */ - -static void cli_state_handler(struct event_context *event_ctx, - struct fd_event *event, uint16 flags, void *p) -{ - struct cli_state *cli = (struct cli_state *)p; - struct cli_request *req, *next; - NTSTATUS status; - - DEBUG(11, ("cli_state_handler called with flags %d\n", flags)); - - if (flags & EVENT_FD_WRITE) { - size_t to_send; - ssize_t sent; - - for (req = cli->outstanding_requests; req; req = req->next) { - to_send = smb_len(req->outbuf)+4; - if (to_send > req->sent) { - break; - } + wct_offset += next_padding; + vwv = state->vwv; + + if (i < num_reqs-1) { + struct cli_smb_state *next_state = tevent_req_data( + reqs[i+1], struct cli_smb_state); + SCVAL(vwv+0, 0, CVAL(next_state->header, smb_com)); + SCVAL(vwv+0, 1, 0); + SSVAL(vwv+1, 0, wct_offset); + } else if (is_andx_req(CVAL(state->header, smb_com))) { + /* properly end the chain */ + SCVAL(vwv+0, 0, 0xff); + SCVAL(vwv+0, 1, 0xff); + SSVAL(vwv+1, 0, 0); } - if (req == NULL) { - if (cli->fd_event != NULL) { - event_fd_set_not_writeable(cli->fd_event); - } - return; - } - - sent = sys_send(cli->fd, req->outbuf + req->sent, - to_send - req->sent, 0); - - if (sent < 0) { - status = map_nt_error_from_unix(errno); - goto sock_error; - } - - req->sent += sent; - - if (req->sent == to_send) { - return; + if (i == 0) { + this_iov[0] = state->iov[0]; + } else { + /* + * This one is a bit subtle. We have to add + * chain_padding bytes between the requests, and we + * have to also include the wct field of the + * subsequent requests. We use the subsequent header + * for the padding, it contains the wct field in its + * last byte. + */ + this_iov[0].iov_len = chain_padding+1; + this_iov[0].iov_base = &state->header[ + sizeof(state->header) - this_iov[0].iov_len]; + memset(this_iov[0].iov_base, 0, this_iov[0].iov_len-1); } + memcpy(this_iov+1, state->iov+1, + sizeof(struct iovec) * (state->iov_count-1)); + this_iov += state->iov_count; + chain_padding = next_padding; } - if (flags & EVENT_FD_READ) { - int res, available; - size_t old_size, new_size; - char *tmp; - - res = ioctl(cli->fd, FIONREAD, &available); - if (res == -1) { - DEBUG(10, ("ioctl(FIONREAD) failed: %s\n", - strerror(errno))); - status = map_nt_error_from_unix(errno); - goto sock_error; - } - - if (available == 0) { - /* EOF */ - status = NT_STATUS_END_OF_FILE; - goto sock_error; - } - - old_size = talloc_get_size(cli->evt_inbuf); - new_size = old_size + available; + if (!cli_smb_req_iov_send(reqs[0], last_state, iov, iovlen)) { + goto fail; + } + return true; + fail: + TALLOC_FREE(iov); + return false; +} - if (new_size < old_size) { - /* wrap */ - status = NT_STATUS_UNEXPECTED_IO_ERROR; - goto sock_error; - } +uint8_t *cli_smb_inbuf(struct tevent_req *req) +{ + struct cli_smb_state *state = tevent_req_data( + req, struct cli_smb_state); + return state->inbuf; +} - tmp = TALLOC_REALLOC_ARRAY(cli, cli->evt_inbuf, char, - new_size); - if (tmp == NULL) { - /* nomem */ - status = NT_STATUS_NO_MEMORY; - goto sock_error; - } - cli->evt_inbuf = tmp; +bool cli_has_async_calls(struct cli_state *cli) +{ + return ((tevent_queue_length(cli->outgoing) != 0) + || (talloc_array_length(cli->pending) != 0)); +} - res = sys_recv(cli->fd, cli->evt_inbuf + old_size, available, 0); - if (res == -1) { - DEBUG(10, ("recv failed: %s\n", strerror(errno))); - status = map_nt_error_from_unix(errno); - goto sock_error; - } +struct cli_smb_oplock_break_waiter_state { + uint16_t fnum; + uint8_t level; +}; - DEBUG(11, ("cli_state_handler: received %d bytes, " - "smb_len(evt_inbuf) = %d\n", (int)res, - smb_len(cli->evt_inbuf))); +static void cli_smb_oplock_break_waiter_done(struct tevent_req *subreq); - /* recv *might* have returned less than announced */ - new_size = old_size + res; +struct tevent_req *cli_smb_oplock_break_waiter_send(TALLOC_CTX *mem_ctx, + struct event_context *ev, + struct cli_state *cli) +{ + struct tevent_req *req, *subreq; + struct cli_smb_oplock_break_waiter_state *state; + struct cli_smb_state *smb_state; - /* shrink, so I don't expect errors here */ - cli->evt_inbuf = TALLOC_REALLOC_ARRAY(cli, cli->evt_inbuf, - char, new_size); + req = tevent_req_create(mem_ctx, &state, + struct cli_smb_oplock_break_waiter_state); + if (req == NULL) { + return NULL; + } - while ((cli->evt_inbuf != NULL) - && ((smb_len(cli->evt_inbuf) + 4) <= new_size)) { - /* - * we've got a complete NBT level PDU in evt_inbuf - */ - handle_incoming_pdu(cli); - new_size = talloc_get_size(cli->evt_inbuf); - } + /* + * Create a fake SMB request that we will never send out. This is only + * used to be set into the pending queue with the right mid. + */ + subreq = cli_smb_req_create(mem_ctx, ev, cli, 0, 0, 0, NULL, 0, NULL); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); } + smb_state = tevent_req_data(subreq, struct cli_smb_state); + SSVAL(smb_state->header, smb_mid, 0xffff); - return; + if (!cli_smb_req_set_pending(subreq)) { + tevent_req_nterror(req, NT_STATUS_NO_MEMORY); + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, cli_smb_oplock_break_waiter_done, req); + return req; +} - sock_error: +static void cli_smb_oplock_break_waiter_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct cli_smb_oplock_break_waiter_state *state = tevent_req_data( + req, struct cli_smb_oplock_break_waiter_state); + uint8_t wct; + uint16_t *vwv; + uint32_t num_bytes; + uint8_t *bytes; + NTSTATUS status; - for (req = cli->outstanding_requests; req; req = next) { - int i, num_async; + status = cli_smb_recv(subreq, 8, &wct, &vwv, &num_bytes, &bytes); + if (!NT_STATUS_IS_OK(status)) { + TALLOC_FREE(subreq); + tevent_req_nterror(req, status); + return; + } + state->fnum = SVAL(vwv+2, 0); + state->level = CVAL(vwv+3, 1); + tevent_req_done(req); +} - next = req->next; - num_async = req->num_async; +NTSTATUS cli_smb_oplock_break_waiter_recv(struct tevent_req *req, + uint16_t *pfnum, + uint8_t *plevel) +{ + struct cli_smb_oplock_break_waiter_state *state = tevent_req_data( + req, struct cli_smb_oplock_break_waiter_state); + NTSTATUS status; - for (i=0; i<num_async; i++) { - async_req_nterror(req->async[i], status); - } + if (tevent_req_is_nterror(req, &status)) { + return status; } - TALLOC_FREE(cli->fd_event); - close(cli->fd); - cli->fd = -1; + *pfnum = state->fnum; + *plevel = state->level; + return NT_STATUS_OK; } diff --git a/source3/libsmb/cliconnect.c b/source3/libsmb/cliconnect.c index aa1ca595a7..53a812d222 100644 --- a/source3/libsmb/cliconnect.c +++ b/source3/libsmb/cliconnect.c @@ -165,14 +165,30 @@ static uint32 cli_session_setup_capabilities(struct cli_state *cli) Do a NT1 guest session setup. ****************************************************************************/ -struct async_req *cli_session_setup_guest_send(TALLOC_CTX *mem_ctx, - struct event_context *ev, - struct cli_state *cli) +struct cli_session_setup_guest_state { + struct cli_state *cli; + uint16_t vwv[16]; +}; + +static void cli_session_setup_guest_done(struct tevent_req *subreq); + +struct tevent_req *cli_session_setup_guest_send(TALLOC_CTX *mem_ctx, + struct event_context *ev, + struct cli_state *cli) { - struct async_req *result; - uint16_t vwv[13]; + struct tevent_req *req, *subreq; + struct cli_session_setup_guest_state *state; + uint16_t *vwv; uint8_t *bytes; + req = tevent_req_create(mem_ctx, &state, + struct cli_session_setup_guest_state); + if (req == NULL) { + return NULL; + } + state->cli = cli; + vwv = state->vwv; + SCVAL(vwv+0, 0, 0xFF); SCVAL(vwv+0, 1, 0); SSVAL(vwv+1, 0, 0); @@ -186,7 +202,7 @@ struct async_req *cli_session_setup_guest_send(TALLOC_CTX *mem_ctx, SSVAL(vwv+10, 0, 0); SIVAL(vwv+11, 0, cli_session_setup_capabilities(cli)); - bytes = talloc_array(talloc_tos(), uint8_t, 0); + bytes = talloc_array(state, uint8_t, 0); bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), "", 1, /* username */ NULL); @@ -195,68 +211,78 @@ struct async_req *cli_session_setup_guest_send(TALLOC_CTX *mem_ctx, bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), "Unix", 5, NULL); bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), "Samba", 6, NULL); - if (bytes == NULL) { - return NULL; + if (tevent_req_nomem(bytes, req)) { + return tevent_req_post(req, ev); } - result = cli_request_send(mem_ctx, ev, cli, SMBsesssetupX, 0, - 13, vwv, 0, talloc_get_size(bytes), bytes); - TALLOC_FREE(bytes); - return result; + subreq = cli_smb_send(state, ev, cli, SMBsesssetupX, 0, 13, vwv, + talloc_get_size(bytes), bytes); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, cli_session_setup_guest_done, req); + return req; } -NTSTATUS cli_session_setup_guest_recv(struct async_req *req) +static void cli_session_setup_guest_done(struct tevent_req *subreq) { - struct cli_request *cli_req = talloc_get_type_abort( - req->private_data, struct cli_request); - struct cli_state *cli = cli_req->cli; - uint8_t wct; - uint16_t *vwv; - uint16_t num_bytes; + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct cli_session_setup_guest_state *state = tevent_req_data( + req, struct cli_session_setup_guest_state); + struct cli_state *cli = state->cli; + uint32_t num_bytes; + char *inbuf; uint8_t *bytes; uint8_t *p; NTSTATUS status; - if (async_req_is_nterror(req, &status)) { - return status; - } - - status = cli_pull_reply(req, &wct, &vwv, &num_bytes, &bytes); + status = cli_smb_recv(subreq, 0, NULL, NULL, &num_bytes, &bytes); if (!NT_STATUS_IS_OK(status)) { - return status; + TALLOC_FREE(subreq); + tevent_req_nterror(req, status); + return; } + inbuf = (char *)cli_smb_inbuf(subreq); p = bytes; - cli->vuid = SVAL(cli_req->inbuf, smb_uid); + cli->vuid = SVAL(inbuf, smb_uid); - p += clistr_pull(cli_req->inbuf, cli->server_os, (char *)p, - sizeof(fstring), bytes+num_bytes-p, STR_TERMINATE); - p += clistr_pull(cli_req->inbuf, cli->server_type, (char *)p, - sizeof(fstring), bytes+num_bytes-p, STR_TERMINATE); - p += clistr_pull(cli_req->inbuf, cli->server_domain, (char *)p, - sizeof(fstring), bytes+num_bytes-p, STR_TERMINATE); + p += clistr_pull(inbuf, cli->server_os, (char *)p, sizeof(fstring), + bytes+num_bytes-p, STR_TERMINATE); + p += clistr_pull(inbuf, cli->server_type, (char *)p, sizeof(fstring), + bytes+num_bytes-p, STR_TERMINATE); + p += clistr_pull(inbuf, cli->server_domain, (char *)p, sizeof(fstring), + bytes+num_bytes-p, STR_TERMINATE); if (strstr(cli->server_type, "Samba")) { cli->is_samba = True; } + TALLOC_FREE(subreq); + status = cli_set_username(cli, ""); if (!NT_STATUS_IS_OK(status)) { - return status; + tevent_req_nterror(req, status); + return; } + tevent_req_done(req); +} - return NT_STATUS_OK; +NTSTATUS cli_session_setup_guest_recv(struct tevent_req *req) +{ + return tevent_req_simple_recv_ntstatus(req); } static NTSTATUS cli_session_setup_guest(struct cli_state *cli) { TALLOC_CTX *frame = talloc_stackframe(); struct event_context *ev; - struct async_req *req; - NTSTATUS status; + struct tevent_req *req; + NTSTATUS status = NT_STATUS_OK; - if (cli->fd_event != NULL) { + if (cli_has_async_calls(cli)) { /* * Can't use sync call while an async call is in flight */ @@ -276,13 +302,17 @@ static NTSTATUS cli_session_setup_guest(struct cli_state *cli) goto fail; } - while (req->state < ASYNC_REQ_DONE) { - event_loop_once(ev); + if (!tevent_req_poll(req, ev)) { + status = map_nt_error_from_unix(errno); + goto fail; } status = cli_session_setup_guest_recv(req); fail: TALLOC_FREE(frame); + if (!NT_STATUS_IS_OK(status)) { + cli_set_error(cli, status); + } return status; } @@ -1189,18 +1219,33 @@ bool cli_ulogoff(struct cli_state *cli) Send a tconX. ****************************************************************************/ -struct async_req *cli_tcon_andx_send(TALLOC_CTX *mem_ctx, - struct event_context *ev, - struct cli_state *cli, - const char *share, const char *dev, - const char *pass, int passlen) +struct cli_tcon_andx_state { + struct cli_state *cli; + uint16_t vwv[4]; +}; + +static void cli_tcon_andx_done(struct tevent_req *subreq); + +struct tevent_req *cli_tcon_andx_send(TALLOC_CTX *mem_ctx, + struct event_context *ev, + struct cli_state *cli, + const char *share, const char *dev, + const char *pass, int passlen) { + struct tevent_req *req, *subreq; + struct cli_tcon_andx_state *state; fstring pword; + uint16_t *vwv; char *tmp = NULL; - struct async_req *result; - uint16_t vwv[4]; uint8_t *bytes; + req = tevent_req_create(mem_ctx, &state, struct cli_tcon_andx_state); + if (req == NULL) { + return NULL; + } + state->cli = cli; + vwv = state->vwv; + fstrcpy(cli->share, share); /* in user level security don't send a password now */ @@ -1263,9 +1308,9 @@ struct async_req *cli_tcon_andx_send(TALLOC_CTX *mem_ctx, SSVAL(vwv+3, 0, passlen); if (passlen) { - bytes = (uint8_t *)talloc_memdup(talloc_tos(), pword, passlen); + bytes = (uint8_t *)talloc_memdup(state, pword, passlen); } else { - bytes = talloc_array(talloc_tos(), uint8_t, 0); + bytes = talloc_array(state, uint8_t, 0); } /* @@ -1273,9 +1318,8 @@ struct async_req *cli_tcon_andx_send(TALLOC_CTX *mem_ctx, */ tmp = talloc_asprintf_strupper_m(talloc_tos(), "\\\\%s\\%s", cli->desthost, share); - if (tmp == NULL) { - TALLOC_FREE(bytes); - return NULL; + if (tevent_req_nomem(tmp, req)) { + return tevent_req_post(req, ev); } bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), tmp, strlen(tmp)+1, NULL); @@ -1285,60 +1329,52 @@ struct async_req *cli_tcon_andx_send(TALLOC_CTX *mem_ctx, * Add the devicetype */ tmp = talloc_strdup_upper(talloc_tos(), dev); - if (tmp == NULL) { - TALLOC_FREE(bytes); - return NULL; + if (tevent_req_nomem(tmp, req)) { + return tevent_req_post(req, ev); } bytes = smb_bytes_push_str(bytes, false, tmp, strlen(tmp)+1, NULL); TALLOC_FREE(tmp); - if (bytes == NULL) { - return NULL; + if (tevent_req_nomem(bytes, req)) { + return tevent_req_post(req, ev); } - result = cli_request_send(mem_ctx, ev, cli, SMBtconX, 0, - 4, vwv, 0, talloc_get_size(bytes), bytes); - TALLOC_FREE(bytes); - return result; + subreq = cli_smb_send(state, ev, cli, SMBtconX, 0, 4, vwv, + talloc_get_size(bytes), bytes); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, cli_tcon_andx_done, req); + return req; access_denied: - { - struct cli_request *state; - if (!async_req_setup(mem_ctx, &result, &state, - struct cli_request)) { - goto fail; - } - if (async_post_ntstatus(result, ev, NT_STATUS_ACCESS_DENIED)) { - return result; - } - } - fail: - TALLOC_FREE(result); - return NULL; + tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED); + return tevent_req_post(req, ev); } -NTSTATUS cli_tcon_andx_recv(struct async_req *req) +static void cli_tcon_andx_done(struct tevent_req *subreq) { - struct cli_request *cli_req = talloc_get_type_abort( - req->private_data, struct cli_request); - struct cli_state *cli = cli_req->cli; + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct cli_tcon_andx_state *state = tevent_req_data( + req, struct cli_tcon_andx_state); + struct cli_state *cli = state->cli; + char *inbuf = (char *)cli_smb_inbuf(subreq); uint8_t wct; uint16_t *vwv; - uint16_t num_bytes; + uint32_t num_bytes; uint8_t *bytes; NTSTATUS status; - if (async_req_is_nterror(req, &status)) { - return status; - } - - status = cli_pull_reply(req, &wct, &vwv, &num_bytes, &bytes); + status = cli_smb_recv(subreq, 0, &wct, &vwv, &num_bytes, &bytes); if (!NT_STATUS_IS_OK(status)) { - return status; + TALLOC_FREE(subreq); + tevent_req_nterror(req, status); + return; } - clistr_pull(cli_req->inbuf, cli->dev, bytes, sizeof(fstring), - num_bytes, STR_TERMINATE|STR_ASCII); + clistr_pull(inbuf, cli->dev, bytes, sizeof(fstring), num_bytes, + STR_TERMINATE|STR_ASCII); if ((cli->protocol >= PROTOCOL_NT1) && (num_bytes == 3)) { /* almost certainly win95 - enable bug fixes */ @@ -1356,8 +1392,13 @@ NTSTATUS cli_tcon_andx_recv(struct async_req *req) cli->dfsroot = ((SVAL(vwv+2, 0) & SMB_SHARE_IN_DFS) != 0); } - cli->cnum = SVAL(cli_req->inbuf,smb_tid); - return NT_STATUS_OK; + cli->cnum = SVAL(inbuf,smb_tid); + tevent_req_done(req); +} + +NTSTATUS cli_tcon_andx_recv(struct tevent_req *req) +{ + return tevent_req_simple_recv_ntstatus(req); } NTSTATUS cli_tcon_andx(struct cli_state *cli, const char *share, @@ -1365,10 +1406,10 @@ NTSTATUS cli_tcon_andx(struct cli_state *cli, const char *share, { TALLOC_CTX *frame = talloc_stackframe(); struct event_context *ev; - struct async_req *req; - NTSTATUS status; + struct tevent_req *req; + NTSTATUS status = NT_STATUS_OK; - if (cli->fd_event != NULL) { + if (cli_has_async_calls(cli)) { /* * Can't use sync call while an async call is in flight */ @@ -1388,13 +1429,17 @@ NTSTATUS cli_tcon_andx(struct cli_state *cli, const char *share, goto fail; } - while (req->state < ASYNC_REQ_DONE) { - event_loop_once(ev); + if (!tevent_req_poll(req, ev)) { + status = map_nt_error_from_unix(errno); + goto fail; } status = cli_tcon_andx_recv(req); fail: TALLOC_FREE(frame); + if (!NT_STATUS_IS_OK(status)) { + cli_set_error(cli, status); + } return status; } @@ -1461,14 +1506,27 @@ void cli_negprot_sendsync(struct cli_state *cli) Send a negprot command. ****************************************************************************/ -struct async_req *cli_negprot_send(TALLOC_CTX *mem_ctx, - struct event_context *ev, - struct cli_state *cli) +struct cli_negprot_state { + struct cli_state *cli; +}; + +static void cli_negprot_done(struct tevent_req *subreq); + +struct tevent_req *cli_negprot_send(TALLOC_CTX *mem_ctx, + struct event_context *ev, + struct cli_state *cli) { - struct async_req *result; + struct tevent_req *req, *subreq; + struct cli_negprot_state *state; uint8_t *bytes = NULL; int numprots; + req = tevent_req_create(mem_ctx, &state, struct cli_negprot_state); + if (req == NULL) { + return NULL; + } + state->cli = cli; + if (cli->protocol < PROTOCOL_NT1) cli->use_spnego = False; @@ -1479,51 +1537,54 @@ struct async_req *cli_negprot_send(TALLOC_CTX *mem_ctx, break; } bytes = (uint8_t *)talloc_append_blob( - talloc_tos(), bytes, data_blob_const(&c, sizeof(c))); - if (bytes == NULL) { - return NULL; + state, bytes, data_blob_const(&c, sizeof(c))); + if (tevent_req_nomem(bytes, req)) { + return tevent_req_post(req, ev); } bytes = smb_bytes_push_str(bytes, false, prots[numprots].name, strlen(prots[numprots].name)+1, NULL); - if (bytes == NULL) { - return NULL; + if (tevent_req_nomem(bytes, req)) { + return tevent_req_post(req, ev); } } - result = cli_request_send(mem_ctx, ev, cli, SMBnegprot, 0, 0, NULL, 0, - talloc_get_size(bytes), bytes); - TALLOC_FREE(bytes); - return result; + subreq = cli_smb_send(state, ev, cli, SMBnegprot, 0, 0, NULL, + talloc_get_size(bytes), bytes); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, cli_negprot_done, req); + return req; } -NTSTATUS cli_negprot_recv(struct async_req *req) +static void cli_negprot_done(struct tevent_req *subreq) { - struct cli_request *cli_req = talloc_get_type_abort( - req->private_data, struct cli_request); - struct cli_state *cli = cli_req->cli; + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct cli_negprot_state *state = tevent_req_data( + req, struct cli_negprot_state); + struct cli_state *cli = state->cli; uint8_t wct; uint16_t *vwv; - uint16_t num_bytes; + uint32_t num_bytes; uint8_t *bytes; NTSTATUS status; uint16_t protnum; - if (async_req_is_nterror(req, &status)) { - return status; - } - - status = cli_pull_reply(req, &wct, &vwv, &num_bytes, &bytes); + status = cli_smb_recv(subreq, 1, &wct, &vwv, &num_bytes, &bytes); if (!NT_STATUS_IS_OK(status)) { - return status; + TALLOC_FREE(subreq); + return; } protnum = SVAL(vwv, 0); if ((protnum >= ARRAY_SIZE(prots)) - || (prots[protnum].prot > cli_req->cli->protocol)) { - return NT_STATUS_INVALID_NETWORK_RESPONSE; + || (prots[protnum].prot > cli->protocol)) { + tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE); + return; } cli->protocol = prots[protnum].prot; @@ -1531,7 +1592,8 @@ NTSTATUS cli_negprot_recv(struct async_req *req) if ((cli->protocol < PROTOCOL_NT1) && client_is_signing_mandatory(cli)) { DEBUG(0,("cli_negprot: SMB signing is mandatory and the selected protocol level doesn't support it.\n")); - return NT_STATUS_ACCESS_DENIED; + tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED); + return; } if (cli->protocol >= PROTOCOL_NT1) { @@ -1572,14 +1634,18 @@ NTSTATUS cli_negprot_recv(struct async_req *req) /* Fail if server says signing is mandatory and we don't want to support it. */ if (!client_is_signing_allowed(cli)) { DEBUG(0,("cli_negprot: SMB signing is mandatory and we have disabled it.\n")); - return NT_STATUS_ACCESS_DENIED; + tevent_req_nterror(req, + NT_STATUS_ACCESS_DENIED); + return; } negotiated_smb_signing = true; } else if (client_is_signing_mandatory(cli) && client_is_signing_allowed(cli)) { /* Fail if client says signing is mandatory and the server doesn't support it. */ if (!(cli->sec_mode & NEGOTIATE_SECURITY_SIGNATURES_ENABLED)) { DEBUG(1,("cli_negprot: SMB signing is mandatory and the server doesn't support it.\n")); - return NT_STATUS_ACCESS_DENIED; + tevent_req_nterror(req, + NT_STATUS_ACCESS_DENIED); + return; } negotiated_smb_signing = true; } else if (cli->sec_mode & NEGOTIATE_SECURITY_SIGNATURES_ENABLED) { @@ -1625,41 +1691,52 @@ NTSTATUS cli_negprot_recv(struct async_req *req) if (getenv("CLI_FORCE_ASCII")) cli->capabilities &= ~CAP_UNICODE; - return NT_STATUS_OK; + tevent_req_done(req); +} + +NTSTATUS cli_negprot_recv(struct tevent_req *req) +{ + return tevent_req_simple_recv_ntstatus(req); } NTSTATUS cli_negprot(struct cli_state *cli) { TALLOC_CTX *frame = talloc_stackframe(); struct event_context *ev; - struct async_req *req; - NTSTATUS status = NT_STATUS_NO_MEMORY; + struct tevent_req *req; + NTSTATUS status = NT_STATUS_OK; - if (cli->fd_event != NULL) { + if (cli_has_async_calls(cli)) { /* * Can't use sync call while an async call is in flight */ - cli_set_error(cli, NT_STATUS_INVALID_PARAMETER); + status = NT_STATUS_INVALID_PARAMETER; goto fail; } ev = event_context_init(frame); if (ev == NULL) { + status = NT_STATUS_NO_MEMORY; goto fail; } req = cli_negprot_send(frame, ev, cli); if (req == NULL) { + status = NT_STATUS_NO_MEMORY; goto fail; } - while (req->state < ASYNC_REQ_DONE) { - event_loop_once(ev); + if (!tevent_req_poll(req, ev)) { + status = map_nt_error_from_unix(errno); + goto fail; } status = cli_negprot_recv(req); fail: TALLOC_FREE(frame); + if (!NT_STATUS_IS_OK(status)) { + cli_set_error(cli, status); + } return status; } @@ -2092,6 +2169,10 @@ NTSTATUS cli_full_connection(struct cli_state **output_cli, return nt_status; } + cli->use_oplocks = ((flags & CLI_FULL_CONNECTION_OPLOCKS) != 0); + cli->use_level_II_oplocks = + ((flags & CLI_FULL_CONNECTION_LEVEL_II_OPLOCKS) != 0); + nt_status = cli_session_setup(cli, user, password, pw_len, password, pw_len, domain); if (!NT_STATUS_IS_OK(nt_status)) { diff --git a/source3/libsmb/clientgen.c b/source3/libsmb/clientgen.c index 6186387076..45addc2163 100644 --- a/source3/libsmb/clientgen.c +++ b/source3/libsmb/clientgen.c @@ -650,6 +650,12 @@ struct cli_state *cli_initialise_ex(int signing_state) goto error; } + cli->outgoing = tevent_queue_create(cli, "cli_outgoing"); + if (cli->outgoing == NULL) { + goto error; + } + cli->pending = NULL; + cli->initialised = 1; return cli; @@ -740,6 +746,12 @@ void cli_shutdown(struct cli_state *cli) cli->fd = -1; cli->smb_rw_error = SMB_READ_OK; + /* + * Need to free pending first, they remove themselves + */ + while (cli->pending) { + talloc_free(cli->pending[0]); + } TALLOC_FREE(cli); } @@ -793,90 +805,72 @@ bool cli_send_keepalive(struct cli_state *cli) return true; } -/** - * @brief: Collect a echo reply - * @param[in] req The corresponding async request - * - * There might be more than one echo reply. This helper pulls the reply out of - * the data stream. If all expected replies have arrived, declare the - * async_req done. - */ - -static void cli_echo_recv_helper(struct async_req *req) -{ - struct cli_request *cli_req; - uint8_t wct; - uint16_t *vwv; - uint16_t num_bytes; - uint8_t *bytes; - NTSTATUS status; +struct cli_echo_state { + uint16_t vwv[1]; + DATA_BLOB data; + int num_echos; +}; - status = cli_pull_reply(req, &wct, &vwv, &num_bytes, &bytes); - if (!NT_STATUS_IS_OK(status)) { - async_req_nterror(req, status); - return; - } +static void cli_echo_done(struct tevent_req *subreq); - cli_req = talloc_get_type_abort(req->private_data, struct cli_request); +struct tevent_req *cli_echo_send(TALLOC_CTX *mem_ctx, struct event_context *ev, + struct cli_state *cli, uint16_t num_echos, + DATA_BLOB data) +{ + struct tevent_req *req, *subreq; + struct cli_echo_state *state; - if ((num_bytes != cli_req->data.echo.data.length) - || (memcmp(cli_req->data.echo.data.data, bytes, - num_bytes) != 0)) { - async_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE); - return; + req = tevent_req_create(mem_ctx, &state, struct cli_echo_state); + if (req == NULL) { + return NULL; } + SSVAL(state->vwv, 0, num_echos); + state->data = data; + state->num_echos = num_echos; - cli_req->data.echo.num_echos -= 1; - - if (cli_req->data.echo.num_echos == 0) { - async_req_done(req); - return; + subreq = cli_smb_send(state, ev, cli, SMBecho, 0, 1, state->vwv, + data.length, data.data); + if (subreq == NULL) { + goto fail; } - - return; + tevent_req_set_callback(subreq, cli_echo_done, req); + return req; + fail: + TALLOC_FREE(req); + return NULL; } -/** - * @brief Send SMBEcho requests - * @param[in] mem_ctx The memory context to put the async_req on - * @param[in] ev The event context that will call us back - * @param[in] cli The connection to send the echo to - * @param[in] num_echos How many times do we want to get the reply? - * @param[in] data The data we want to get back - * @retval The async request - */ - -struct async_req *cli_echo_send(TALLOC_CTX *mem_ctx, struct event_context *ev, - struct cli_state *cli, uint16_t num_echos, - DATA_BLOB data) +static void cli_echo_done(struct tevent_req *subreq) { - uint16_t vwv[1]; - uint8_t *data_copy; - struct async_req *result; - struct cli_request *req; - - SSVAL(vwv, 0, num_echos); + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct cli_echo_state *state = tevent_req_data( + req, struct cli_echo_state); + NTSTATUS status; + uint32_t num_bytes; + uint8_t *bytes; - data_copy = (uint8_t *)talloc_memdup(mem_ctx, data.data, data.length); - if (data_copy == NULL) { - return NULL; + status = cli_smb_recv(subreq, 0, NULL, NULL, &num_bytes, &bytes); + if (!NT_STATUS_IS_OK(status)) { + tevent_req_nterror(req, status); + return; } - - result = cli_request_send(mem_ctx, ev, cli, SMBecho, 0, 1, vwv, 0, - data.length, data.data); - if (result == NULL) { - TALLOC_FREE(data_copy); - return NULL; + if ((num_bytes != state->data.length) + || (memcmp(bytes, state->data.data, num_bytes) != 0)) { + tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE); + return; } - req = talloc_get_type_abort(result->private_data, struct cli_request); - req->data.echo.num_echos = num_echos; - req->data.echo.data.data = talloc_move(req, &data_copy); - req->data.echo.data.length = data.length; - - req->recv_helper.fn = cli_echo_recv_helper; + state->num_echos -=1; + if (state->num_echos == 0) { + tevent_req_done(req); + return; + } - return result; + if (!cli_smb_req_set_pending(subreq)) { + tevent_req_nterror(req, NT_STATUS_NO_MEMORY); + return; + } } /** @@ -885,9 +879,9 @@ struct async_req *cli_echo_send(TALLOC_CTX *mem_ctx, struct event_context *ev, * @retval Did the server reply correctly? */ -NTSTATUS cli_echo_recv(struct async_req *req) +NTSTATUS cli_echo_recv(struct tevent_req *req) { - return async_req_simple_recv_ntstatus(req); + return tevent_req_simple_recv_ntstatus(req); } /** @@ -904,35 +898,40 @@ NTSTATUS cli_echo(struct cli_state *cli, uint16_t num_echos, DATA_BLOB data) { TALLOC_CTX *frame = talloc_stackframe(); struct event_context *ev; - struct async_req *req; - NTSTATUS status = NT_STATUS_NO_MEMORY; + struct tevent_req *req; + NTSTATUS status = NT_STATUS_OK; - if (cli->fd_event != NULL) { + if (cli_has_async_calls(cli)) { /* * Can't use sync call while an async call is in flight */ - cli_set_error(cli, NT_STATUS_INVALID_PARAMETER); + status = NT_STATUS_INVALID_PARAMETER; goto fail; } ev = event_context_init(frame); if (ev == NULL) { + status = NT_STATUS_NO_MEMORY; goto fail; } req = cli_echo_send(frame, ev, cli, num_echos, data); if (req == NULL) { + status = NT_STATUS_NO_MEMORY; goto fail; } - while (req->state < ASYNC_REQ_DONE) { - event_loop_once(ev); + if (!tevent_req_poll(req, ev)) { + status = map_nt_error_from_unix(errno); + goto fail; } status = cli_echo_recv(req); - fail: TALLOC_FREE(frame); + if (!NT_STATUS_IS_OK(status)) { + cli_set_error(cli, status); + } return status; } diff --git a/source3/libsmb/clifile.c b/source3/libsmb/clifile.c index 0703f04c5f..4293828214 100644 --- a/source3/libsmb/clifile.c +++ b/source3/libsmb/clifile.c @@ -771,22 +771,36 @@ int cli_nt_create_full(struct cli_state *cli, const char *fname, return SVAL(cli->inbuf,smb_vwv2 + 1); } -struct async_req *cli_ntcreate_send(TALLOC_CTX *mem_ctx, - struct event_context *ev, - struct cli_state *cli, - const char *fname, - uint32_t CreatFlags, - uint32_t DesiredAccess, - uint32_t FileAttributes, - uint32_t ShareAccess, - uint32_t CreateDisposition, - uint32_t CreateOptions, - uint8_t SecurityFlags) -{ - struct async_req *result; +struct cli_ntcreate_state { + uint16_t vwv[24]; + uint16_t fnum; +}; + +static void cli_ntcreate_done(struct tevent_req *subreq); + +struct tevent_req *cli_ntcreate_send(TALLOC_CTX *mem_ctx, + struct event_context *ev, + struct cli_state *cli, + const char *fname, + uint32_t CreatFlags, + uint32_t DesiredAccess, + uint32_t FileAttributes, + uint32_t ShareAccess, + uint32_t CreateDisposition, + uint32_t CreateOptions, + uint8_t SecurityFlags) +{ + struct tevent_req *req, *subreq; + struct cli_ntcreate_state *state; + uint16_t *vwv; uint8_t *bytes; size_t converted_len; - uint16_t vwv[24]; + + req = tevent_req_create(mem_ctx, &state, struct cli_ntcreate_state); + if (req == NULL) { + return NULL; + } + vwv = state->vwv; SCVAL(vwv+0, 0, 0xFF); SCVAL(vwv+0, 1, 0); @@ -808,7 +822,7 @@ struct async_req *cli_ntcreate_send(TALLOC_CTX *mem_ctx, SIVAL(vwv+21, 1, 0x02); /* ImpersonationLevel */ SCVAL(vwv+23, 1, SecurityFlags); - bytes = talloc_array(talloc_tos(), uint8_t, 0); + bytes = talloc_array(state, uint8_t, 0); bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname, strlen(fname)+1, &converted_len); @@ -816,41 +830,53 @@ struct async_req *cli_ntcreate_send(TALLOC_CTX *mem_ctx, /* sigh. this copes with broken netapp filer behaviour */ bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), "", 1, NULL); - if (bytes == NULL) { - return NULL; + if (tevent_req_nomem(bytes, req)) { + return tevent_req_post(req, ev); } SIVAL(vwv+2, 1, converted_len); - result = cli_request_send(mem_ctx, ev, cli, SMBntcreateX, 0, - 24, vwv, 0, talloc_get_size(bytes), bytes); - TALLOC_FREE(bytes); - return result; + subreq = cli_smb_send(state, ev, cli, SMBntcreateX, 0, 24, vwv, + talloc_get_size(bytes), bytes); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, cli_ntcreate_done, req); + return req; } -NTSTATUS cli_ntcreate_recv(struct async_req *req, uint16_t *pfnum) +static void cli_ntcreate_done(struct tevent_req *subreq) { + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct cli_ntcreate_state *state = tevent_req_data( + req, struct cli_ntcreate_state); uint8_t wct; uint16_t *vwv; - uint16_t num_bytes; + uint32_t num_bytes; uint8_t *bytes; NTSTATUS status; - if (async_req_is_nterror(req, &status)) { - return status; - } - - status = cli_pull_reply(req, &wct, &vwv, &num_bytes, &bytes); + status = cli_smb_recv(subreq, 3, &wct, &vwv, &num_bytes, &bytes); if (!NT_STATUS_IS_OK(status)) { - return status; - } - - if (wct < 3) { - return NT_STATUS_INVALID_NETWORK_RESPONSE; + TALLOC_FREE(subreq); + tevent_req_nterror(req, status); + return; } + state->fnum = SVAL(vwv+2, 1); + tevent_req_done(req); +} - *pfnum = SVAL(vwv+2, 1); +NTSTATUS cli_ntcreate_recv(struct tevent_req *req, uint16_t *pfnum) +{ + struct cli_ntcreate_state *state = tevent_req_data( + req, struct cli_ntcreate_state); + NTSTATUS status; + if (tevent_req_is_nterror(req, &status)) { + return status; + } + *pfnum = state->fnum; return NT_STATUS_OK; } @@ -867,10 +893,10 @@ NTSTATUS cli_ntcreate(struct cli_state *cli, { TALLOC_CTX *frame = talloc_stackframe(); struct event_context *ev; - struct async_req *req; - NTSTATUS status; + struct tevent_req *req; + NTSTATUS status = NT_STATUS_OK; - if (cli->fd_event != NULL) { + if (cli_has_async_calls(cli)) { /* * Can't use sync call while an async call is in flight */ @@ -893,13 +919,17 @@ NTSTATUS cli_ntcreate(struct cli_state *cli, goto fail; } - while (req->state < ASYNC_REQ_DONE) { - event_loop_once(ev); + if (!tevent_req_poll(req, ev)) { + status = map_nt_error_from_unix(errno); + goto fail; } status = cli_ntcreate_recv(req, pfid); fail: TALLOC_FREE(frame); + if (!NT_STATUS_IS_OK(status)) { + cli_set_error(cli, status); + } return status; } @@ -968,17 +998,33 @@ uint8_t *smb_bytes_push_str(uint8_t *buf, bool ucs2, WARNING: if you open with O_WRONLY then getattrE won't work! ****************************************************************************/ -struct async_req *cli_open_send(TALLOC_CTX *mem_ctx, struct event_context *ev, - struct cli_state *cli, - const char *fname, int flags, int share_mode) +struct cli_open_state { + uint16_t vwv[15]; + int fnum; + struct iovec bytes; +}; + +static void cli_open_done(struct tevent_req *subreq); + +struct tevent_req *cli_open_create(TALLOC_CTX *mem_ctx, + struct event_context *ev, + struct cli_state *cli, const char *fname, + int flags, int share_mode, + struct tevent_req **psmbreq) { - unsigned openfn = 0; - unsigned accessmode = 0; - uint8_t additional_flags = 0; + struct tevent_req *req, *subreq; + struct cli_open_state *state; + unsigned openfn; + unsigned accessmode; + uint8_t additional_flags; uint8_t *bytes; - uint16_t vwv[15]; - struct async_req *result; + req = tevent_req_create(mem_ctx, &state, struct cli_open_state); + if (req == NULL) { + return NULL; + } + + openfn = 0; if (flags & O_CREAT) { openfn |= (1<<4); } @@ -1007,63 +1053,96 @@ struct async_req *cli_open_send(TALLOC_CTX *mem_ctx, struct event_context *ev, accessmode = 0xFF; } - SCVAL(vwv + 0, 0, 0xFF); - SCVAL(vwv + 0, 1, 0); - SSVAL(vwv + 1, 0, 0); - SSVAL(vwv + 2, 0, 0); /* no additional info */ - SSVAL(vwv + 3, 0, accessmode); - SSVAL(vwv + 4, 0, aSYSTEM | aHIDDEN); - SSVAL(vwv + 5, 0, 0); - SIVAL(vwv + 6, 0, 0); - SSVAL(vwv + 8, 0, openfn); - SIVAL(vwv + 9, 0, 0); - SIVAL(vwv + 11, 0, 0); - SIVAL(vwv + 13, 0, 0); + SCVAL(state->vwv + 0, 0, 0xFF); + SCVAL(state->vwv + 0, 1, 0); + SSVAL(state->vwv + 1, 0, 0); + SSVAL(state->vwv + 2, 0, 0); /* no additional info */ + SSVAL(state->vwv + 3, 0, accessmode); + SSVAL(state->vwv + 4, 0, aSYSTEM | aHIDDEN); + SSVAL(state->vwv + 5, 0, 0); + SIVAL(state->vwv + 6, 0, 0); + SSVAL(state->vwv + 8, 0, openfn); + SIVAL(state->vwv + 9, 0, 0); + SIVAL(state->vwv + 11, 0, 0); + SIVAL(state->vwv + 13, 0, 0); + + additional_flags = 0; if (cli->use_oplocks) { /* if using oplocks then ask for a batch oplock via core and extended methods */ additional_flags = FLAG_REQUEST_OPLOCK|FLAG_REQUEST_BATCH_OPLOCK; - SSVAL(vwv+2, 0, SVAL(vwv+2, 0) | 6); + SSVAL(state->vwv+2, 0, SVAL(state->vwv+2, 0) | 6); } - bytes = talloc_array(talloc_tos(), uint8_t, 0); + bytes = talloc_array(state, uint8_t, 0); bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), fname, strlen(fname)+1, NULL); - if (bytes == NULL) { + + if (tevent_req_nomem(bytes, req)) { + return tevent_req_post(req, ev); + } + + state->bytes.iov_base = bytes; + state->bytes.iov_len = talloc_get_size(bytes); + + subreq = cli_smb_req_create(state, ev, cli, SMBopenX, additional_flags, + 15, state->vwv, 1, &state->bytes); + if (subreq == NULL) { + TALLOC_FREE(req); return NULL; } + tevent_req_set_callback(subreq, cli_open_done, req); + *psmbreq = subreq; + return req; +} - result = cli_request_send(mem_ctx, ev, cli, SMBopenX, additional_flags, - 15, vwv, 0, talloc_get_size(bytes), bytes); - TALLOC_FREE(bytes); - return result; +struct tevent_req *cli_open_send(TALLOC_CTX *mem_ctx, struct event_context *ev, + struct cli_state *cli, const char *fname, + int flags, int share_mode) +{ + struct tevent_req *req, *subreq; + + req = cli_open_create(mem_ctx, ev, cli, fname, flags, share_mode, + &subreq); + if ((req == NULL) || !cli_smb_req_send(subreq)) { + TALLOC_FREE(req); + return NULL; + } + return req; } -NTSTATUS cli_open_recv(struct async_req *req, int *fnum) +static void cli_open_done(struct tevent_req *subreq) { + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct cli_open_state *state = tevent_req_data( + req, struct cli_open_state); uint8_t wct; uint16_t *vwv; - uint16_t num_bytes; - uint8_t *bytes; NTSTATUS status; - if (async_req_is_nterror(req, &status)) { - return status; - } - - status = cli_pull_reply(req, &wct, &vwv, &num_bytes, &bytes); + status = cli_smb_recv(subreq, 3, &wct, &vwv, NULL, NULL); if (!NT_STATUS_IS_OK(status)) { - return status; - } - - if (wct < 3) { - return NT_STATUS_INVALID_NETWORK_RESPONSE; + TALLOC_FREE(subreq); + tevent_req_nterror(req, status); + return; } + state->fnum = SVAL(vwv+2, 0); + tevent_req_done(req); +} - *fnum = SVAL(vwv+2, 0); +NTSTATUS cli_open_recv(struct tevent_req *req, int *fnum) +{ + struct cli_open_state *state = tevent_req_data( + req, struct cli_open_state); + NTSTATUS status; + if (tevent_req_is_nterror(req, &status)) { + return status; + } + *fnum = state->fnum; return NT_STATUS_OK; } @@ -1072,34 +1151,41 @@ int cli_open(struct cli_state *cli, const char *fname, int flags, { TALLOC_CTX *frame = talloc_stackframe(); struct event_context *ev; - struct async_req *req; + struct tevent_req *req; + NTSTATUS status = NT_STATUS_OK; int result = -1; - if (cli->fd_event != NULL) { + if (cli_has_async_calls(cli)) { /* * Can't use sync call while an async call is in flight */ - cli_set_error(cli, NT_STATUS_INVALID_PARAMETER); + status = NT_STATUS_INVALID_PARAMETER; goto fail; } ev = event_context_init(frame); if (ev == NULL) { + status = NT_STATUS_NO_MEMORY; goto fail; } req = cli_open_send(frame, ev, cli, fname, flags, share_mode); if (req == NULL) { + status = NT_STATUS_NO_MEMORY; goto fail; } - while (req->state < ASYNC_REQ_DONE) { - event_loop_once(ev); + if (!tevent_req_poll(req, ev)) { + status = map_nt_error_from_unix(errno); + goto fail; } cli_open_recv(req, &result); fail: TALLOC_FREE(frame); + if (!NT_STATUS_IS_OK(status)) { + cli_set_error(cli, status); + } return result; } @@ -1107,65 +1193,111 @@ int cli_open(struct cli_state *cli, const char *fname, int flags, Close a file. ****************************************************************************/ -struct async_req *cli_close_send(TALLOC_CTX *mem_ctx, struct event_context *ev, - struct cli_state *cli, int fnum) -{ +struct cli_close_state { uint16_t vwv[3]; +}; + +static void cli_close_done(struct tevent_req *subreq); + +struct tevent_req *cli_close_create(TALLOC_CTX *mem_ctx, + struct event_context *ev, + struct cli_state *cli, int fnum, + struct tevent_req **psubreq) +{ + struct tevent_req *req, *subreq; + struct cli_close_state *state; + + req = tevent_req_create(mem_ctx, &state, struct cli_close_state); + if (req == NULL) { + return NULL; + } + SSVAL(state->vwv+0, 0, fnum); + SIVALS(state->vwv+1, 0, -1); + + subreq = cli_smb_req_create(state, ev, cli, SMBclose, 0, 3, state->vwv, + 0, NULL); + if (subreq == NULL) { + TALLOC_FREE(req); + return NULL; + } + tevent_req_set_callback(subreq, cli_close_done, req); + *psubreq = subreq; + return req; +} - SSVAL(vwv+0, 0, fnum); - SIVALS(vwv+1, 0, -1); +struct tevent_req *cli_close_send(TALLOC_CTX *mem_ctx, + struct event_context *ev, + struct cli_state *cli, int fnum) +{ + struct tevent_req *req, *subreq; - return cli_request_send(mem_ctx, ev, cli, SMBclose, 0, 3, vwv, 0, - 0, NULL); + req = cli_close_create(mem_ctx, ev, cli, fnum, &subreq); + if ((req == NULL) || !cli_smb_req_send(subreq)) { + TALLOC_FREE(req); + return NULL; + } + return req; } -NTSTATUS cli_close_recv(struct async_req *req) +static void cli_close_done(struct tevent_req *subreq) { - uint8_t wct; - uint16_t *vwv; - uint16_t num_bytes; - uint8_t *bytes; + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); NTSTATUS status; - if (async_req_is_nterror(req, &status)) { - return status; + status = cli_smb_recv(subreq, 0, NULL, NULL, NULL, NULL); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + tevent_req_nterror(req, status); + return; } + tevent_req_done(req); +} - return cli_pull_reply(req, &wct, &vwv, &num_bytes, &bytes); +NTSTATUS cli_close_recv(struct tevent_req *req) +{ + return tevent_req_simple_recv_ntstatus(req); } bool cli_close(struct cli_state *cli, int fnum) { TALLOC_CTX *frame = talloc_stackframe(); struct event_context *ev; - struct async_req *req; + struct tevent_req *req; + NTSTATUS status = NT_STATUS_OK; bool result = false; - if (cli->fd_event != NULL) { + if (cli_has_async_calls(cli)) { /* * Can't use sync call while an async call is in flight */ - cli_set_error(cli, NT_STATUS_INVALID_PARAMETER); + status = NT_STATUS_INVALID_PARAMETER; goto fail; } ev = event_context_init(frame); if (ev == NULL) { + status = NT_STATUS_NO_MEMORY; goto fail; } req = cli_close_send(frame, ev, cli, fnum); if (req == NULL) { + status = NT_STATUS_NO_MEMORY; goto fail; } - while (req->state < ASYNC_REQ_DONE) { - event_loop_once(ev); + if (!tevent_req_poll(req, ev)) { + status = map_nt_error_from_unix(errno); + goto fail; } result = NT_STATUS_IS_OK(cli_close_recv(req)); fail: TALLOC_FREE(frame); + if (!NT_STATUS_IS_OK(status)) { + cli_set_error(cli, status); + } return result; } diff --git a/source3/libsmb/clikrb5.c b/source3/libsmb/clikrb5.c index 4ab31374e2..aa98d7668f 100644 --- a/source3/libsmb/clikrb5.c +++ b/source3/libsmb/clikrb5.c @@ -56,12 +56,12 @@ static krb5_error_code ads_krb5_get_fwd_ticket( krb5_context context, char *utf8_name; size_t converted_size; - if (!push_utf8_allocate(&utf8_name, name, &converted_size)) { + if (!push_utf8_talloc(talloc_tos(), &utf8_name, name, &converted_size)) { return ENOMEM; } ret = krb5_parse_name(context, utf8_name, principal); - SAFE_FREE(utf8_name); + TALLOC_FREE(utf8_name); return ret; } @@ -79,24 +79,25 @@ static krb5_error_code smb_krb5_parse_name_norealm_conv(krb5_context context, size_t converted_size; *principal = NULL; - if (!push_utf8_allocate(&utf8_name, name, &converted_size)) { + if (!push_utf8_talloc(talloc_tos(), &utf8_name, name, &converted_size)) { return ENOMEM; } ret = krb5_parse_name_norealm(context, utf8_name, principal); - SAFE_FREE(utf8_name); + TALLOC_FREE(utf8_name); return ret; } #endif /************************************************************** krb5_parse_name that returns a UNIX charset name. Must - be freed with normal free() call. + be freed with talloc_free() call. **************************************************************/ - krb5_error_code smb_krb5_unparse_name(krb5_context context, - krb5_const_principal principal, - char **unix_name) +krb5_error_code smb_krb5_unparse_name(TALLOC_CTX *mem_ctx, + krb5_context context, + krb5_const_principal principal, + char **unix_name) { krb5_error_code ret; char *utf8_name; @@ -108,7 +109,7 @@ static krb5_error_code smb_krb5_parse_name_norealm_conv(krb5_context context, return ret; } - if (!pull_utf8_allocate(unix_name, utf8_name, &converted_size)) { + if (!pull_utf8_talloc(mem_ctx, unix_name, utf8_name, &converted_size)) { krb5_free_unparsed_name(context, utf8_name); return ENOMEM; } @@ -1081,10 +1082,10 @@ get_key_from_keytab(krb5_context context, } if ( DEBUGLEVEL >= 10 ) { - if (smb_krb5_unparse_name(context, server, &name) == 0) { + if (smb_krb5_unparse_name(talloc_tos(), context, server, &name) == 0) { DEBUG(10,("get_key_from_keytab: will look for kvno %d, enctype %d and name: %s\n", kvno, enctype, name)); - SAFE_FREE(name); + TALLOC_FREE(name); } } diff --git a/source3/libsmb/clioplock.c b/source3/libsmb/clioplock.c index ef8b396461..e3fb66aba0 100644 --- a/source3/libsmb/clioplock.c +++ b/source3/libsmb/clioplock.c @@ -23,38 +23,103 @@ send an ack for an oplock break request ****************************************************************************/ -bool cli_oplock_ack(struct cli_state *cli, int fnum, unsigned char level) +struct cli_oplock_ack_state { + uint16_t vwv[8]; +}; + +static void cli_oplock_ack_done(struct tevent_req *subreq); + +struct tevent_req *cli_oplock_ack_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct cli_state *cli, + uint16_t fnum, uint8_t level) +{ + struct tevent_req *req, *subreq; + struct cli_oplock_ack_state *state; + + req = tevent_req_create(mem_ctx, &state, struct cli_oplock_ack_state);; + if (req == NULL) { + return NULL; + } + SCVAL(state->vwv+0, 0, 0xff); + SCVAL(state->vwv+0, 1, 0); + SSVAL(state->vwv+1, 0, 0); + SSVAL(state->vwv+2, 0, fnum); + SCVAL(state->vwv+3, 0, LOCKING_ANDX_OPLOCK_RELEASE); + SCVAL(state->vwv+3, 1, level); + SIVAL(state->vwv+4, 0, 0); /* timeout */ + SSVAL(state->vwv+6, 0, 0); /* unlockcount */ + SSVAL(state->vwv+7, 0, 0); /* lockcount */ + + subreq = cli_smb_send(state, ev, cli, SMBlockingX, 0, 8, state->vwv, + 0, NULL); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, cli_oplock_ack_done, req); + return req; +} + +static void cli_oplock_ack_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + NTSTATUS status; + + status = cli_smb_recv(subreq, 0, NULL, NULL, NULL, NULL); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + tevent_req_nterror(req, status); + return; + } + tevent_req_done(req); +} + +NTSTATUS cli_oplock_ack_recv(struct tevent_req *req) { - char *oldbuf = cli->outbuf; - char buf[smb_size+16]; - bool ret; - - cli->outbuf = buf; - - memset(buf,'\0',smb_size); - cli_set_message(buf,8,0,True); - - SCVAL(buf,smb_com,SMBlockingX); - SSVAL(buf,smb_tid, cli->cnum); - cli_setup_packet(cli); - SSVAL(buf,smb_vwv0,0xFF); - SSVAL(buf,smb_vwv1,0); - SSVAL(buf,smb_vwv2,fnum); - if (level == 1) - SSVAL(buf,smb_vwv3,0x102); /* levelII oplock break ack */ - else - SSVAL(buf,smb_vwv3,2); /* exclusive oplock break ack */ - SIVAL(buf,smb_vwv4,0); /* timoeut */ - SSVAL(buf,smb_vwv6,0); /* unlockcount */ - SSVAL(buf,smb_vwv7,0); /* lockcount */ - - ret = cli_send_smb(cli); - - cli->outbuf = oldbuf; - - return ret; + return tevent_req_simple_recv_ntstatus(req); } +bool cli_oplock_ack(struct cli_state *cli, int fnum, unsigned char level) +{ + TALLOC_CTX *frame = talloc_stackframe(); + struct event_context *ev; + struct tevent_req *req; + NTSTATUS status = NT_STATUS_OK; + + if (cli_has_async_calls(cli)) { + /* + * Can't use sync call while an async call is in flight + */ + status = NT_STATUS_INVALID_PARAMETER; + goto fail; + } + + ev = event_context_init(frame); + if (ev == NULL) { + status = NT_STATUS_NO_MEMORY; + goto fail; + } + + req = cli_oplock_ack_send(frame, ev, cli, fnum, level); + if (req == NULL) { + status = NT_STATUS_NO_MEMORY; + goto fail; + } + + if (!tevent_req_poll(req, ev)) { + status = map_nt_error_from_unix(errno); + goto fail; + } + + status = cli_oplock_ack_recv(req); + fail: + TALLOC_FREE(frame); + if (!NT_STATUS_IS_OK(status)) { + cli_set_error(cli, status); + } + return NT_STATUS_IS_OK(status); +} /**************************************************************************** set the oplock handler for a connection diff --git a/source3/libsmb/clireadwrite.c b/source3/libsmb/clireadwrite.c index f2f447b4c9..1d2f5f79ec 100644 --- a/source3/libsmb/clireadwrite.c +++ b/source3/libsmb/clireadwrite.c @@ -70,21 +70,25 @@ static size_t cli_write_max_bufsize(struct cli_state *cli, uint16_t write_mode) return CLI_WINDOWS_MAX_LARGE_WRITEX_SIZE; } +struct cli_read_andx_state { + size_t size; + uint16_t vwv[12]; + NTSTATUS status; + size_t received; + uint8_t *buf; +}; -/* - * Send a read&x request - */ +static void cli_read_andx_done(struct tevent_req *subreq); -struct async_req *cli_read_andx_send(TALLOC_CTX *mem_ctx, - struct event_context *ev, - struct cli_state *cli, int fnum, - off_t offset, size_t size) +struct tevent_req *cli_read_andx_create(TALLOC_CTX *mem_ctx, + struct event_context *ev, + struct cli_state *cli, int fnum, + off_t offset, size_t size, + struct tevent_req **psmbreq) { - struct async_req *result; - struct cli_request *req; + struct tevent_req *req, *subreq; + struct cli_read_andx_state *state; bool bigoffset = False; - - uint16_t vwv[12]; uint8_t wct = 10; if (size > cli_read_max_bufsize(cli)) { @@ -94,82 +98,85 @@ struct async_req *cli_read_andx_send(TALLOC_CTX *mem_ctx, return NULL; } - SCVAL(vwv + 0, 0, 0xFF); - SCVAL(vwv + 0, 1, 0); - SSVAL(vwv + 1, 0, 0); - SSVAL(vwv + 2, 0, fnum); - SIVAL(vwv + 3, 0, offset); - SSVAL(vwv + 5, 0, size); - SSVAL(vwv + 6, 0, size); - SSVAL(vwv + 7, 0, (size >> 16)); - SSVAL(vwv + 8, 0, 0); - SSVAL(vwv + 9, 0, 0); + req = tevent_req_create(mem_ctx, &state, struct cli_read_andx_state); + if (req == NULL) { + return NULL; + } + state->size = size; + + SCVAL(state->vwv + 0, 0, 0xFF); + SCVAL(state->vwv + 0, 1, 0); + SSVAL(state->vwv + 1, 0, 0); + SSVAL(state->vwv + 2, 0, fnum); + SIVAL(state->vwv + 3, 0, offset); + SSVAL(state->vwv + 5, 0, size); + SSVAL(state->vwv + 6, 0, size); + SSVAL(state->vwv + 7, 0, (size >> 16)); + SSVAL(state->vwv + 8, 0, 0); + SSVAL(state->vwv + 9, 0, 0); if ((uint64_t)offset >> 32) { - bigoffset = True; - SIVAL(vwv + 10, 0, + bigoffset = true; + SIVAL(state->vwv + 10, 0, (((uint64_t)offset)>>32) & 0xffffffff); wct += 2; } - result = cli_request_send(mem_ctx, ev, cli, SMBreadX, 0, wct, vwv, 0, - 0, NULL); - if (result == NULL) { + subreq = cli_smb_req_create(state, ev, cli, SMBreadX, 0, wct, + state->vwv, 0, NULL); + if (subreq == NULL) { + TALLOC_FREE(req); return NULL; } + tevent_req_set_callback(subreq, cli_read_andx_done, req); + *psmbreq = subreq; + return req; +} - req = talloc_get_type_abort(result->private_data, struct cli_request); - - req->data.read.ofs = offset; - req->data.read.size = size; - req->data.read.received = 0; - req->data.read.rcvbuf = NULL; +struct tevent_req *cli_read_andx_send(TALLOC_CTX *mem_ctx, + struct event_context *ev, + struct cli_state *cli, int fnum, + off_t offset, size_t size) +{ + struct tevent_req *req, *subreq; - return result; + req = cli_read_andx_create(mem_ctx, ev, cli, fnum, offset, size, + &subreq); + if ((req == NULL) || !cli_smb_req_send(subreq)) { + TALLOC_FREE(req); + return NULL; + } + return req; } -/* - * Pull the data out of a finished async read_and_x request. rcvbuf is - * talloced from the request, so better make sure that you copy it away before - * you talloc_free(req). "rcvbuf" is NOT a talloc_ctx of its own, so do not - * talloc_move it! - */ - -NTSTATUS cli_read_andx_recv(struct async_req *req, ssize_t *received, - uint8_t **rcvbuf) +static void cli_read_andx_done(struct tevent_req *subreq) { - struct cli_request *cli_req = talloc_get_type_abort( - req->private_data, struct cli_request); + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct cli_read_andx_state *state = tevent_req_data( + req, struct cli_read_andx_state); + uint8_t *inbuf; uint8_t wct; uint16_t *vwv; - uint16_t num_bytes; + uint32_t num_bytes; uint8_t *bytes; - uint8_t *buf; - NTSTATUS status; - size_t size; - - if (async_req_is_nterror(req, &status)) { - return status; - } - - status = cli_pull_reply(req, &wct, &vwv, &num_bytes, &bytes); - - if (NT_STATUS_IS_ERR(status)) { - return status; - } - if (wct < 12) { - return NT_STATUS_INVALID_NETWORK_RESPONSE; + state->status = cli_smb_recv(subreq, 12, &wct, &vwv, &num_bytes, + &bytes); + if (NT_STATUS_IS_ERR(state->status)) { + tevent_req_nterror(req, state->status); + return; } /* size is the number of bytes the server returned. * Might be zero. */ - size = SVAL(vwv + 5, 0); - size |= (((unsigned int)SVAL(vwv + 7, 0)) << 16); + state->received = SVAL(vwv + 5, 0); + state->received |= (((unsigned int)SVAL(vwv + 7, 0)) << 16); - if (size > cli_req->data.read.size) { + if (state->received > state->size) { DEBUG(5,("server returned more than we wanted!\n")); - return NT_STATUS_UNEXPECTED_IO_ERROR; + tevent_req_nterror(req, NT_STATUS_UNEXPECTED_IO_ERROR); + return; } /* @@ -177,24 +184,52 @@ NTSTATUS cli_read_andx_recv(struct async_req *req, ssize_t *received, * bcc field can't be correct. */ - if ((size < 0xffff) && (size > num_bytes)) { + if ((state->received < 0xffff) && (state->received > num_bytes)) { DEBUG(5, ("server announced more bytes than sent\n")); - return NT_STATUS_INVALID_NETWORK_RESPONSE; + tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE); + return; } - buf = (uint8_t *)smb_base(cli_req->inbuf) + SVAL(vwv+6, 0); + inbuf = cli_smb_inbuf(subreq); + state->buf = (uint8_t *)smb_base(inbuf) + SVAL(vwv+6, 0); - if (trans_oob(smb_len(cli_req->inbuf), SVAL(vwv+6, 0), size) - || (buf < bytes)) { + if (trans_oob(smb_len(inbuf), SVAL(vwv+6, 0), state->received) + || (state->buf < bytes)) { DEBUG(5, ("server returned invalid read&x data offset\n")); - return NT_STATUS_INVALID_NETWORK_RESPONSE; + tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE); + return; } + tevent_req_done(req); +} + +/* + * Pull the data out of a finished async read_and_x request. rcvbuf is + * talloced from the request, so better make sure that you copy it away before + * you talloc_free(req). "rcvbuf" is NOT a talloc_ctx of its own, so do not + * talloc_move it! + */ + +NTSTATUS cli_read_andx_recv(struct tevent_req *req, ssize_t *received, + uint8_t **rcvbuf) +{ + struct cli_read_andx_state *state = tevent_req_data( + req, struct cli_read_andx_state); + NTSTATUS status; - *rcvbuf = (uint8_t *)(smb_base(cli_req->inbuf) + SVAL(vwv + 6, 0)); - *received = size; + if (tevent_req_is_nterror(req, &status)) { + return status; + } + *received = state->received; + *rcvbuf = state->buf; return NT_STATUS_OK; } +struct cli_pull_subreq { + struct tevent_req *req; + ssize_t received; + uint8_t *buf; +}; + /* * Parallel read support. * @@ -204,7 +239,7 @@ NTSTATUS cli_read_andx_recv(struct async_req *req, ssize_t *received, */ struct cli_pull_state { - struct async_req *req; + struct tevent_req *req; struct event_context *ev; struct cli_state *cli; @@ -221,7 +256,7 @@ struct cli_pull_state { * Outstanding requests */ int num_reqs; - struct async_req **reqs; + struct cli_pull_subreq *reqs; /* * For how many bytes did we send requests already? @@ -243,13 +278,13 @@ struct cli_pull_state { SMB_OFF_T pushed; }; -static char *cli_pull_print(TALLOC_CTX *mem_ctx, struct async_req *req) +static char *cli_pull_print(struct tevent_req *req, TALLOC_CTX *mem_ctx) { - struct cli_pull_state *state = talloc_get_type_abort( - req->private_data, struct cli_pull_state); + struct cli_pull_state *state = tevent_req_data( + req, struct cli_pull_state); char *result; - result = async_req_print(mem_ctx, req); + result = tevent_req_print(mem_ctx, req); if (result == NULL) { return NULL; } @@ -259,31 +294,31 @@ static char *cli_pull_print(TALLOC_CTX *mem_ctx, struct async_req *req) state->num_reqs, state->top_req); } -static void cli_pull_read_done(struct async_req *read_req); +static void cli_pull_read_done(struct tevent_req *read_req); /* * Prepare an async pull request */ -struct async_req *cli_pull_send(TALLOC_CTX *mem_ctx, - struct event_context *ev, - struct cli_state *cli, - uint16_t fnum, off_t start_offset, - SMB_OFF_T size, size_t window_size, - NTSTATUS (*sink)(char *buf, size_t n, - void *priv), - void *priv) +struct tevent_req *cli_pull_send(TALLOC_CTX *mem_ctx, + struct event_context *ev, + struct cli_state *cli, + uint16_t fnum, off_t start_offset, + SMB_OFF_T size, size_t window_size, + NTSTATUS (*sink)(char *buf, size_t n, + void *priv), + void *priv) { - struct async_req *result; + struct tevent_req *req; struct cli_pull_state *state; int i; - if (!async_req_setup(mem_ctx, &result, &state, - struct cli_pull_state)) { + req = tevent_req_create(mem_ctx, &state, struct cli_pull_state); + if (req == NULL) { return NULL; } - result->print = cli_pull_print; - state->req = result; + tevent_req_set_print_fn(req, cli_pull_print); + state->req = req; state->cli = cli; state->ev = ev; @@ -297,10 +332,8 @@ struct async_req *cli_pull_send(TALLOC_CTX *mem_ctx, state->top_req = 0; if (size == 0) { - if (!async_post_ntstatus(result, ev, NT_STATUS_OK)) { - goto failed; - } - return result; + tevent_req_done(req); + return tevent_req_post(req, ev); } state->chunk_size = cli_read_max_bufsize(cli); @@ -308,7 +341,7 @@ struct async_req *cli_pull_send(TALLOC_CTX *mem_ctx, state->num_reqs = MAX(window_size/state->chunk_size, 1); state->num_reqs = MIN(state->num_reqs, cli->max_mux); - state->reqs = TALLOC_ZERO_ARRAY(state, struct async_req *, + state->reqs = TALLOC_ZERO_ARRAY(state, struct cli_pull_subreq, state->num_reqs); if (state->reqs == NULL) { goto failed; @@ -317,6 +350,7 @@ struct async_req *cli_pull_send(TALLOC_CTX *mem_ctx, state->requested = 0; for (i=0; i<state->num_reqs; i++) { + struct cli_pull_subreq *subreq = &state->reqs[i]; SMB_OFF_T size_left; size_t request_thistime; @@ -328,24 +362,21 @@ struct async_req *cli_pull_send(TALLOC_CTX *mem_ctx, size_left = size - state->requested; request_thistime = MIN(size_left, state->chunk_size); - state->reqs[i] = cli_read_andx_send( + subreq->req = cli_read_andx_send( state->reqs, ev, cli, fnum, state->start_offset + state->requested, request_thistime); - if (state->reqs[i] == NULL) { + if (subreq->req == NULL) { goto failed; } - - state->reqs[i]->async.fn = cli_pull_read_done; - state->reqs[i]->async.priv = result; - + tevent_req_set_callback(subreq->req, cli_pull_read_done, req); state->requested += request_thistime; } - return result; + return req; failed: - TALLOC_FREE(result); + TALLOC_FREE(req); return NULL; } @@ -354,20 +385,32 @@ failed: * requests if necessary. */ -static void cli_pull_read_done(struct async_req *read_req) +static void cli_pull_read_done(struct tevent_req *subreq) { - struct async_req *pull_req = talloc_get_type_abort( - read_req->async.priv, struct async_req); - struct cli_pull_state *state = talloc_get_type_abort( - pull_req->private_data, struct cli_pull_state); - struct cli_request *read_state = talloc_get_type_abort( - read_req->private_data, struct cli_request); + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct cli_pull_state *state = tevent_req_data( + req, struct cli_pull_state); + struct cli_pull_subreq *pull_subreq = NULL; NTSTATUS status; + int i; - status = cli_read_andx_recv(read_req, &read_state->data.read.received, - &read_state->data.read.rcvbuf); + for (i = 0; i < state->num_reqs; i++) { + pull_subreq = &state->reqs[i]; + if (subreq == pull_subreq->req) { + break; + } + } + if (i == state->num_reqs) { + /* Huh -- received something we did not send?? */ + tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR); + return; + } + + status = cli_read_andx_recv(subreq, &pull_subreq->received, + &pull_subreq->buf); if (!NT_STATUS_IS_OK(status)) { - async_req_nterror(state->req, status); + tevent_req_nterror(state->req, status); return; } @@ -380,39 +423,36 @@ static void cli_pull_read_done(struct async_req *read_req) * requests. */ - while (state->reqs[state->top_req] != NULL) { - struct cli_request *top_read; + while (state->reqs[state->top_req].req != NULL) { + struct cli_pull_subreq *top_subreq; DEBUG(11, ("cli_pull_read_done: top_req = %d\n", state->top_req)); - if (state->reqs[state->top_req]->state < ASYNC_REQ_DONE) { + top_subreq = &state->reqs[state->top_req]; + + if (tevent_req_is_in_progress(top_subreq->req)) { DEBUG(11, ("cli_pull_read_done: top request not yet " "done\n")); return; } - top_read = talloc_get_type_abort( - state->reqs[state->top_req]->private_data, - struct cli_request); - DEBUG(10, ("cli_pull_read_done: Pushing %d bytes, %d already " - "pushed\n", (int)top_read->data.read.received, + "pushed\n", (int)top_subreq->received, (int)state->pushed)); - status = state->sink((char *)top_read->data.read.rcvbuf, - top_read->data.read.received, - state->priv); + status = state->sink((char *)top_subreq->buf, + top_subreq->received, state->priv); if (!NT_STATUS_IS_OK(status)) { - async_req_nterror(state->req, status); + tevent_req_nterror(state->req, status); return; } - state->pushed += top_read->data.read.received; + state->pushed += top_subreq->received; - TALLOC_FREE(state->reqs[state->top_req]); + TALLOC_FREE(state->reqs[state->top_req].req); if (state->requested < state->size) { - struct async_req *new_req; + struct tevent_req *new_req; SMB_OFF_T size_left; size_t request_thistime; @@ -432,30 +472,29 @@ static void cli_pull_read_done(struct async_req *read_req) state->start_offset + state->requested, request_thistime); - if (async_req_nomem(new_req, state->req)) { + if (tevent_req_nomem(new_req, state->req)) { return; } + tevent_req_set_callback(new_req, cli_pull_read_done, + req); - new_req->async.fn = cli_pull_read_done; - new_req->async.priv = pull_req; - - state->reqs[state->top_req] = new_req; + state->reqs[state->top_req].req = new_req; state->requested += request_thistime; } state->top_req = (state->top_req+1) % state->num_reqs; } - async_req_done(pull_req); + tevent_req_done(req); } -NTSTATUS cli_pull_recv(struct async_req *req, SMB_OFF_T *received) +NTSTATUS cli_pull_recv(struct tevent_req *req, SMB_OFF_T *received) { - struct cli_pull_state *state = talloc_get_type_abort( - req->private_data, struct cli_pull_state); + struct cli_pull_state *state = tevent_req_data( + req, struct cli_pull_state); NTSTATUS status; - if (async_req_is_nterror(req, &status)) { + if (tevent_req_is_nterror(req, &status)) { return status; } *received = state->pushed; @@ -469,35 +508,42 @@ NTSTATUS cli_pull(struct cli_state *cli, uint16_t fnum, { TALLOC_CTX *frame = talloc_stackframe(); struct event_context *ev; - struct async_req *req; - NTSTATUS result = NT_STATUS_NO_MEMORY; + struct tevent_req *req; + NTSTATUS status = NT_STATUS_OK; - if (cli->fd_event != NULL) { + if (cli_has_async_calls(cli)) { /* * Can't use sync call while an async call is in flight */ - return NT_STATUS_INVALID_PARAMETER; + status = NT_STATUS_INVALID_PARAMETER; + goto fail; } ev = event_context_init(frame); if (ev == NULL) { - goto nomem; + status = NT_STATUS_NO_MEMORY; + goto fail; } req = cli_pull_send(frame, ev, cli, fnum, start_offset, size, window_size, sink, priv); if (req == NULL) { - goto nomem; + status = NT_STATUS_NO_MEMORY; + goto fail; } - while (req->state < ASYNC_REQ_DONE) { - event_loop_once(ev); + if (!tevent_req_poll(req, ev)) { + status = map_nt_error_from_unix(errno); + goto fail; } - result = cli_pull_recv(req, received); - nomem: + status = cli_pull_recv(req, received); + fail: TALLOC_FREE(frame); - return result; + if (!NT_STATUS_IS_OK(status)) { + cli_set_error(cli, status); + } + return status; } static NTSTATUS cli_read_sink(char *buf, size_t n, void *priv) @@ -744,19 +790,41 @@ ssize_t cli_smbwrite(struct cli_state *cli, * Send a write&x request */ -struct async_req *cli_write_andx_send(TALLOC_CTX *mem_ctx, - struct event_context *ev, - struct cli_state *cli, uint16_t fnum, - uint16_t mode, const uint8_t *buf, - off_t offset, size_t size) +struct cli_write_andx_state { + size_t size; + uint16_t vwv[14]; + size_t written; + uint8_t pad; + struct iovec iov[2]; +}; + +static void cli_write_andx_done(struct tevent_req *subreq); + +struct tevent_req *cli_write_andx_create(TALLOC_CTX *mem_ctx, + struct event_context *ev, + struct cli_state *cli, uint16_t fnum, + uint16_t mode, const uint8_t *buf, + off_t offset, size_t size, + struct tevent_req **reqs_before, + int num_reqs_before, + struct tevent_req **psmbreq) { + struct tevent_req *req, *subreq; + struct cli_write_andx_state *state; bool bigoffset = ((cli->capabilities & CAP_LARGE_FILES) != 0); uint8_t wct = bigoffset ? 14 : 12; size_t max_write = cli_write_max_bufsize(cli, mode); - uint16_t vwv[14]; + uint16_t *vwv; + + req = tevent_req_create(mem_ctx, &state, struct cli_write_andx_state); + if (req == NULL) { + return NULL; + } size = MIN(size, max_write); + vwv = state->vwv; + SCVAL(vwv+0, 0, 0xFF); SCVAL(vwv+0, 1, 0); SSVAL(vwv+1, 0, 0); @@ -769,7 +837,7 @@ struct async_req *cli_write_andx_send(TALLOC_CTX *mem_ctx, SSVAL(vwv+10, 0, size); SSVAL(vwv+11, 0, - cli_wct_ofs(cli) + cli_smb_wct_ofs(reqs_before, num_reqs_before) + 1 /* the wct field */ + wct * 2 /* vwv */ + 2 /* num_bytes field */ @@ -779,37 +847,70 @@ struct async_req *cli_write_andx_send(TALLOC_CTX *mem_ctx, SIVAL(vwv+12, 0, (((uint64_t)offset)>>32) & 0xffffffff); } - return cli_request_send(mem_ctx, ev, cli, SMBwriteX, 0, wct, vwv, - 2, size, buf); + state->pad = 0; + state->iov[0].iov_base = &state->pad; + state->iov[0].iov_len = 1; + state->iov[1].iov_base = CONST_DISCARD(uint8_t *, buf); + state->iov[1].iov_len = size; + + subreq = cli_smb_req_create(state, ev, cli, SMBwriteX, 0, wct, vwv, + 2, state->iov); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, cli_write_andx_done, req); + *psmbreq = subreq; + return req; } -NTSTATUS cli_write_andx_recv(struct async_req *req, size_t *pwritten) +struct tevent_req *cli_write_andx_send(TALLOC_CTX *mem_ctx, + struct event_context *ev, + struct cli_state *cli, uint16_t fnum, + uint16_t mode, const uint8_t *buf, + off_t offset, size_t size) { + struct tevent_req *req, *subreq; + + req = cli_write_andx_create(mem_ctx, ev, cli, fnum, mode, buf, offset, + size, NULL, 0, &subreq); + if ((req == NULL) || !cli_smb_req_send(subreq)) { + TALLOC_FREE(req); + return NULL; + } + return req; +} + +static void cli_write_andx_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct cli_write_andx_state *state = tevent_req_data( + req, struct cli_write_andx_state); uint8_t wct; uint16_t *vwv; - uint16_t num_bytes; - uint8_t *bytes; NTSTATUS status; - size_t written; - if (async_req_is_nterror(req, &status)) { - return status; + status = cli_smb_recv(subreq, 6, &wct, &vwv, NULL, NULL); + if (NT_STATUS_IS_ERR(status)) { + TALLOC_FREE(subreq); + tevent_req_nterror(req, status); + return; } + state->written = SVAL(vwv+2, 0); + state->written |= SVAL(vwv+4, 0)<<16; + tevent_req_done(req); +} - status = cli_pull_reply(req, &wct, &vwv, &num_bytes, &bytes); +NTSTATUS cli_write_andx_recv(struct tevent_req *req, size_t *pwritten) +{ + struct cli_write_andx_state *state = tevent_req_data( + req, struct cli_write_andx_state); + NTSTATUS status; - if (NT_STATUS_IS_ERR(status)) { + if (tevent_req_is_nterror(req, &status)) { return status; } - - if (wct < 6) { - return NT_STATUS_INVALID_NETWORK_RESPONSE; - } - - written = SVAL(vwv+2, 0); - written |= SVAL(vwv+4, 0)<<16; - *pwritten = written; - + *pwritten = state->written; return NT_STATUS_OK; } @@ -824,22 +925,21 @@ struct cli_writeall_state { size_t written; }; -static void cli_writeall_written(struct async_req *req); +static void cli_writeall_written(struct tevent_req *req); -static struct async_req *cli_writeall_send(TALLOC_CTX *mem_ctx, - struct event_context *ev, - struct cli_state *cli, - uint16_t fnum, - uint16_t mode, - const uint8_t *buf, - off_t offset, size_t size) +static struct tevent_req *cli_writeall_send(TALLOC_CTX *mem_ctx, + struct event_context *ev, + struct cli_state *cli, + uint16_t fnum, + uint16_t mode, + const uint8_t *buf, + off_t offset, size_t size) { - struct async_req *result; - struct async_req *subreq; + struct tevent_req *req, *subreq; struct cli_writeall_state *state; - if (!async_req_setup(mem_ctx, &result, &state, - struct cli_writeall_state)) { + req = tevent_req_create(mem_ctx, &state, struct cli_writeall_state); + if (req == NULL) { return NULL; } state->ev = ev; @@ -854,46 +954,40 @@ static struct async_req *cli_writeall_send(TALLOC_CTX *mem_ctx, subreq = cli_write_andx_send(state, state->ev, state->cli, state->fnum, state->mode, state->buf, state->offset, state->size); - if (subreq == NULL) { - goto fail; + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); } - - subreq->async.fn = cli_writeall_written; - subreq->async.priv = result; - return result; - - fail: - TALLOC_FREE(result); - return NULL; + tevent_req_set_callback(subreq, cli_writeall_written, req); + return req; } -static void cli_writeall_written(struct async_req *subreq) +static void cli_writeall_written(struct tevent_req *subreq) { - struct async_req *req = talloc_get_type_abort( - subreq->async.priv, struct async_req); - struct cli_writeall_state *state = talloc_get_type_abort( - req->private_data, struct cli_writeall_state); + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct cli_writeall_state *state = tevent_req_data( + req, struct cli_writeall_state); NTSTATUS status; size_t written, to_write; status = cli_write_andx_recv(subreq, &written); TALLOC_FREE(subreq); if (!NT_STATUS_IS_OK(status)) { - async_req_nterror(req, status); + tevent_req_nterror(req, status); return; } state->written += written; if (state->written > state->size) { - async_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE); + tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE); return; } to_write = state->size - state->written; if (to_write == 0) { - async_req_done(req); + tevent_req_done(req); return; } @@ -901,22 +995,19 @@ static void cli_writeall_written(struct async_req *subreq) state->mode, state->buf + state->written, state->offset + state->written, to_write); - if (subreq == NULL) { - async_req_nterror(req, NT_STATUS_NO_MEMORY); + if (tevent_req_nomem(subreq, req)) { return; } - - subreq->async.fn = cli_writeall_written; - subreq->async.priv = req; + tevent_req_set_callback(subreq, cli_writeall_written, req); } -static NTSTATUS cli_writeall_recv(struct async_req *req) +static NTSTATUS cli_writeall_recv(struct tevent_req *req) { - return async_req_simple_recv_ntstatus(req); + return tevent_req_simple_recv_ntstatus(req); } struct cli_push_write_state { - struct async_req *req;/* This is the main request! Not the subreq */ + struct tevent_req *req;/* This is the main request! Not the subreq */ uint32_t idx; off_t ofs; uint8_t *buf; @@ -947,14 +1038,14 @@ struct cli_push_state { struct cli_push_write_state **reqs; }; -static void cli_push_written(struct async_req *req); +static void cli_push_written(struct tevent_req *req); -static bool cli_push_write_setup(struct async_req *req, +static bool cli_push_write_setup(struct tevent_req *req, struct cli_push_state *state, uint32_t idx) { struct cli_push_write_state *substate; - struct async_req *subreq; + struct tevent_req *subreq; substate = talloc(state->reqs, struct cli_push_write_state); if (!substate) { @@ -988,8 +1079,7 @@ static bool cli_push_write_setup(struct async_req *req, talloc_free(substate); return false; } - subreq->async.fn = cli_push_written; - subreq->async.priv = substate; + tevent_req_set_callback(subreq, cli_push_written, substate); state->reqs[idx] = substate; state->pending += 1; @@ -998,20 +1088,20 @@ static bool cli_push_write_setup(struct async_req *req, return true; } -struct async_req *cli_push_send(TALLOC_CTX *mem_ctx, struct event_context *ev, - struct cli_state *cli, - uint16_t fnum, uint16_t mode, - off_t start_offset, size_t window_size, - size_t (*source)(uint8_t *buf, size_t n, - void *priv), - void *priv) +struct tevent_req *cli_push_send(TALLOC_CTX *mem_ctx, struct event_context *ev, + struct cli_state *cli, + uint16_t fnum, uint16_t mode, + off_t start_offset, size_t window_size, + size_t (*source)(uint8_t *buf, size_t n, + void *priv), + void *priv) { - struct async_req *req; + struct tevent_req *req; struct cli_push_state *state; uint32_t i; - if (!async_req_setup(mem_ctx, &req, &state, - struct cli_push_state)) { + req = tevent_req_create(mem_ctx, &state, struct cli_push_state); + if (req == NULL) { return NULL; } state->cli = cli; @@ -1054,26 +1144,24 @@ struct async_req *cli_push_send(TALLOC_CTX *mem_ctx, struct event_context *ev, } if (state->pending == 0) { - if (!async_post_ntstatus(req, ev, NT_STATUS_OK)) { - goto failed; - } - return req; + tevent_req_done(req); + return tevent_req_post(req, ev); } return req; failed: - TALLOC_FREE(req); - return NULL; + tevent_req_nterror(req, NT_STATUS_NO_MEMORY); + return tevent_req_post(req, ev); } -static void cli_push_written(struct async_req *subreq) +static void cli_push_written(struct tevent_req *subreq) { - struct cli_push_write_state *substate = talloc_get_type_abort( - subreq->async.priv, struct cli_push_write_state); - struct async_req *req = substate->req; - struct cli_push_state *state = talloc_get_type_abort( - req->private_data, struct cli_push_state); + struct cli_push_write_state *substate = tevent_req_callback_data( + subreq, struct cli_push_write_state); + struct tevent_req *req = substate->req; + struct cli_push_state *state = tevent_req_data( + req, struct cli_push_state); NTSTATUS status; uint32_t idx = substate->idx; @@ -1084,26 +1172,26 @@ static void cli_push_written(struct async_req *subreq) TALLOC_FREE(subreq); TALLOC_FREE(substate); if (!NT_STATUS_IS_OK(status)) { - async_req_nterror(req, status); + tevent_req_nterror(req, status); return; } if (!state->eof) { if (!cli_push_write_setup(req, state, idx)) { - async_req_nomem(NULL, req); + tevent_req_nterror(req, NT_STATUS_NO_MEMORY); return; } } if (state->pending == 0) { - async_req_done(req); + tevent_req_done(req); return; } } -NTSTATUS cli_push_recv(struct async_req *req) +NTSTATUS cli_push_recv(struct tevent_req *req) { - return async_req_simple_recv_ntstatus(req); + return tevent_req_simple_recv_ntstatus(req); } NTSTATUS cli_push(struct cli_state *cli, uint16_t fnum, uint16_t mode, @@ -1113,33 +1201,40 @@ NTSTATUS cli_push(struct cli_state *cli, uint16_t fnum, uint16_t mode, { TALLOC_CTX *frame = talloc_stackframe(); struct event_context *ev; - struct async_req *req; - NTSTATUS result = NT_STATUS_NO_MEMORY; + struct tevent_req *req; + NTSTATUS status = NT_STATUS_OK; - if (cli->fd_event != NULL) { + if (cli_has_async_calls(cli)) { /* * Can't use sync call while an async call is in flight */ - return NT_STATUS_INVALID_PARAMETER; + status = NT_STATUS_INVALID_PARAMETER; + goto fail; } ev = event_context_init(frame); if (ev == NULL) { - goto nomem; + status = NT_STATUS_NO_MEMORY; + goto fail; } req = cli_push_send(frame, ev, cli, fnum, mode, start_offset, window_size, source, priv); if (req == NULL) { - goto nomem; + status = NT_STATUS_NO_MEMORY; + goto fail; } - while (req->state < ASYNC_REQ_DONE) { - event_loop_once(ev); + if (!tevent_req_poll(req, ev)) { + status = map_nt_error_from_unix(errno); + goto fail; } - result = cli_push_recv(req); - nomem: + status = cli_push_recv(req); + fail: TALLOC_FREE(frame); - return result; + if (!NT_STATUS_IS_OK(status)) { + cli_set_error(cli, status); + } + return status; } diff --git a/source3/libsmb/clitrans.c b/source3/libsmb/clitrans.c index 91fb6e6296..3a6aa9e72c 100644 --- a/source3/libsmb/clitrans.c +++ b/source3/libsmb/clitrans.c @@ -704,6 +704,8 @@ struct cli_trans_state { uint16_t mid; uint32_t seqnum; const char *pipe_name; + uint8_t *pipe_name_conv; + size_t pipe_name_conv_len; uint16_t fid; uint16_t function; int flags; @@ -720,27 +722,131 @@ struct cli_trans_state { struct trans_recvblob rdata; TALLOC_CTX *secondary_request_ctx; + + struct iovec iov[4]; + uint8_t pad[4]; + uint16_t vwv[32]; }; -static void cli_trans_recv_helper(struct async_req *req); +static NTSTATUS cli_pull_trans(uint8_t *inbuf, + uint8_t wct, uint16_t *vwv, + uint16_t num_bytes, uint8_t *bytes, + uint8_t smb_cmd, bool expect_first_reply, + uint8_t *pnum_setup, uint16_t **psetup, + uint32_t *ptotal_param, uint32_t *pnum_param, + uint32_t *pparam_disp, uint8_t **pparam, + uint32_t *ptotal_data, uint32_t *pnum_data, + uint32_t *pdata_disp, uint8_t **pdata) +{ + uint32_t param_ofs, data_ofs; + + if (expect_first_reply) { + if ((wct != 0) || (num_bytes != 0)) { + return NT_STATUS_INVALID_NETWORK_RESPONSE; + } + return NT_STATUS_OK; + } + + switch (smb_cmd) { + case SMBtrans: + case SMBtrans2: + if (wct < 10) { + return NT_STATUS_INVALID_NETWORK_RESPONSE; + } + *ptotal_param = SVAL(vwv + 0, 0); + *ptotal_data = SVAL(vwv + 1, 0); + *pnum_param = SVAL(vwv + 3, 0); + param_ofs = SVAL(vwv + 4, 0); + *pparam_disp = SVAL(vwv + 5, 0); + *pnum_data = SVAL(vwv + 6, 0); + data_ofs = SVAL(vwv + 7, 0); + *pdata_disp = SVAL(vwv + 8, 0); + *pnum_setup = CVAL(vwv + 9, 0); + if (wct < 10 + (*pnum_setup)) { + return NT_STATUS_INVALID_NETWORK_RESPONSE; + } + *psetup = vwv + 10; -static struct async_req *cli_ship_trans(TALLOC_CTX *mem_ctx, - struct cli_trans_state *state) + break; + case SMBnttrans: + if (wct < 18) { + return NT_STATUS_INVALID_NETWORK_RESPONSE; + } + *ptotal_param = IVAL(vwv, 3); + *ptotal_data = IVAL(vwv, 7); + *pnum_param = IVAL(vwv, 11); + param_ofs = IVAL(vwv, 15); + *pparam_disp = IVAL(vwv, 19); + *pnum_data = IVAL(vwv, 23); + data_ofs = IVAL(vwv, 27); + *pdata_disp = IVAL(vwv, 31); + *pnum_setup = CVAL(vwv, 35); + *psetup = vwv + 18; + break; + + default: + return NT_STATUS_INTERNAL_ERROR; + } + + /* + * Check for buffer overflows. data_ofs needs to be checked against + * the incoming buffer length, data_disp against the total + * length. Likewise for param_ofs/param_disp. + */ + + if (trans_oob(smb_len(inbuf), param_ofs, *pnum_param) + || trans_oob(*ptotal_param, *pparam_disp, *pnum_param) + || trans_oob(smb_len(inbuf), data_ofs, *pnum_data) + || trans_oob(*ptotal_data, *pdata_disp, *pnum_data)) { + return NT_STATUS_INVALID_NETWORK_RESPONSE; + } + + *pparam = (uint8_t *)inbuf + 4 + param_ofs; + *pdata = (uint8_t *)inbuf + 4 + data_ofs; + + return NT_STATUS_OK; +} + +static NTSTATUS cli_trans_pull_blob(TALLOC_CTX *mem_ctx, + struct trans_recvblob *blob, + uint32_t total, uint32_t thistime, + uint8_t *buf, uint32_t displacement) { - TALLOC_CTX *frame; - struct async_req *result = NULL; - struct cli_request *cli_req; - uint8_t wct; - uint16_t *vwv; - uint8_t *bytes = NULL; + if (blob->data == NULL) { + if (total > blob->max) { + return NT_STATUS_INVALID_NETWORK_RESPONSE; + } + blob->total = total; + blob->data = TALLOC_ARRAY(mem_ctx, uint8_t, total); + if (blob->data == NULL) { + return NT_STATUS_NO_MEMORY; + } + } + + if (total > blob->total) { + return NT_STATUS_INVALID_NETWORK_RESPONSE; + } + + if (thistime) { + memcpy(blob->data + displacement, buf, thistime); + blob->received += thistime; + } + + return NT_STATUS_OK; +} + +static void cli_trans_format(struct cli_trans_state *state, uint8_t *pwct, + int *piov_count) +{ + uint8_t wct = 0; + struct iovec *iov = state->iov; + uint8_t *pad = state->pad; + uint16_t *vwv = state->vwv; uint16_t param_offset; uint16_t this_param = 0; uint16_t this_data = 0; uint32_t useable_space; uint8_t cmd; - uint8_t pad[3]; - - frame = talloc_stackframe(); cmd = state->cmd; @@ -751,39 +857,26 @@ static struct async_req *cli_ship_trans(TALLOC_CTX *mem_ctx, param_offset = smb_size - 4; - bytes = TALLOC_ARRAY(talloc_tos(), uint8_t, 0); /* padding */ - if (bytes == NULL) { - goto fail; - } - switch (cmd) { case SMBtrans: pad[0] = 0; - bytes = (uint8_t *)talloc_append_blob(talloc_tos(), bytes, - data_blob_const(pad, 1)); - if (bytes == NULL) { - goto fail; - } - bytes = smb_bytes_push_str(bytes, cli_ucs2(state->cli), - state->pipe_name, - strlen(state->pipe_name)+1, NULL); - if (bytes == NULL) { - goto fail; - } + iov[0].iov_base = pad; + iov[0].iov_len = 1; + iov[1].iov_base = state->pipe_name_conv; + iov[1].iov_len = state->pipe_name_conv_len; wct = 14 + state->num_setup; - param_offset += talloc_get_size(bytes); + param_offset += iov[0].iov_len + iov[1].iov_len; + iov += 2; break; case SMBtrans2: pad[0] = 0; pad[1] = 'D'; /* Copy this from "old" 3.0 behaviour */ pad[2] = ' '; - bytes = (uint8_t *)talloc_append_blob(talloc_tos(), bytes, - data_blob_const(pad, 3)); - if (bytes == NULL) { - goto fail; - } + iov[0].iov_base = pad; + iov[0].iov_len = 3; wct = 14 + state->num_setup; - param_offset += talloc_get_size(bytes); + param_offset += 3; + iov += 1; break; case SMBtranss: wct = 8; @@ -797,8 +890,6 @@ static struct async_req *cli_ship_trans(TALLOC_CTX *mem_ctx, case SMBnttranss: wct = 18; break; - default: - goto fail; } useable_space = state->cli->max_xmit - smb_size - sizeof(uint16_t)*wct; @@ -806,17 +897,19 @@ static struct async_req *cli_ship_trans(TALLOC_CTX *mem_ctx, if (state->param_sent < state->num_param) { this_param = MIN(state->num_param - state->param_sent, useable_space); + iov[0].iov_base = state->param + state->param_sent; + iov[0].iov_len = this_param; + iov += 1; } if (state->data_sent < state->num_data) { this_data = MIN(state->num_data - state->data_sent, useable_space - this_param); + iov[0].iov_base = state->data + state->data_sent; + iov[0].iov_len = this_data; + iov += 1; } - vwv = TALLOC_ARRAY(talloc_tos(), uint16_t, wct); - if (vwv == NULL) { - goto fail; - } param_offset += wct * sizeof(uint16_t); DEBUG(10, ("num_setup=%u, max_setup=%u, " @@ -897,221 +990,120 @@ static struct async_req *cli_ship_trans(TALLOC_CTX *mem_ctx, break; } - bytes = (uint8_t *)talloc_append_blob( - talloc_tos(), bytes, - data_blob_const(state->param + state->param_sent, this_param)); - if (bytes == NULL) { - goto fail; - } state->param_sent += this_param; - - bytes = (uint8_t *)talloc_append_blob( - talloc_tos(), bytes, - data_blob_const(state->data + state->data_sent, this_data)); - if (bytes == NULL) { - goto fail; - } state->data_sent += this_data; - if ((cmd == SMBtrans) || (cmd == SMBtrans2) || (cmd == SMBnttrans)) { - /* - * Primary request, retrieve our mid - */ - result = cli_request_send(mem_ctx, state->ev, state->cli, - cmd, 0, wct, vwv, 0, - talloc_get_size(bytes), bytes); - if (result == NULL) { - goto fail; - } - cli_req = talloc_get_type_abort(result->private_data, - struct cli_request); - state->mid = cli_req->mid; - state->seqnum = cli_req->seqnum; - } else { - uint16_t num_bytes = talloc_get_size(bytes); - /* - * Secondary request, we have to fix up the mid. Thus we do - * the chain_cork/chain/uncork ourselves. - */ - if (!cli_chain_cork(state->cli, state->ev, - wct * sizeof(uint16_t) + num_bytes + 3)) { - goto fail; - } - result = cli_request_send(mem_ctx, state->ev, state->cli, cmd, - 0, wct, vwv, 0, num_bytes, bytes); - if (result == NULL) { - goto fail; - } - cli_req = talloc_get_type_abort(result->private_data, - struct cli_request); - cli_req->recv_helper.fn = cli_trans_recv_helper; - cli_req->recv_helper.priv = state; - cli_req->mid = state->mid; - cli_chain_uncork(state->cli); - state->seqnum = cli_req->seqnum; - } - - fail: - TALLOC_FREE(frame); - return result; + *pwct = wct; + *piov_count = iov - state->iov; } -static void cli_trans_ship_rest(struct async_req *req, - struct cli_trans_state *state) +static void cli_trans_done(struct tevent_req *subreq); + +struct tevent_req *cli_trans_send( + TALLOC_CTX *mem_ctx, struct event_context *ev, + struct cli_state *cli, uint8_t cmd, + const char *pipe_name, uint16_t fid, uint16_t function, int flags, + uint16_t *setup, uint8_t num_setup, uint8_t max_setup, + uint8_t *param, uint32_t num_param, uint32_t max_param, + uint8_t *data, uint32_t num_data, uint32_t max_data) { - struct cli_request *cli_req; + struct tevent_req *req, *subreq; + struct cli_trans_state *state; + int iov_count; + uint8_t wct; - state->secondary_request_ctx = talloc_new(state); - if (state->secondary_request_ctx == NULL) { - async_req_nterror(req, NT_STATUS_NO_MEMORY); - return; + req = tevent_req_create(mem_ctx, &state, struct cli_trans_state); + if (req == NULL) { + return NULL; } - while ((state->param_sent < state->num_param) - || (state->data_sent < state->num_data)) { - struct async_req *subreq; - - subreq = cli_ship_trans(state->secondary_request_ctx, state); - if (subreq == NULL) { - async_req_nterror(req, NT_STATUS_NO_MEMORY); - return; + if ((cmd == SMBtrans) || (cmd == SMBtrans2)) { + if ((num_param > 0xffff) || (max_param > 0xffff) + || (num_data > 0xffff) || (max_data > 0xffff)) { + DEBUG(3, ("Attempt to send invalid trans2 request " + "(setup %u, params %u/%u, data %u/%u)\n", + (unsigned)num_setup, + (unsigned)num_param, (unsigned)max_param, + (unsigned)num_data, (unsigned)max_data)); + tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); + return tevent_req_post(req, ev); } } - cli_req = talloc_get_type_abort(req->private_data, - struct cli_request); - - cli_req->seqnum = state->seqnum; -} - -static NTSTATUS cli_pull_trans(struct async_req *req, - struct cli_request *cli_req, - uint8_t smb_cmd, bool expect_first_reply, - uint8_t *pnum_setup, uint16_t **psetup, - uint32_t *ptotal_param, uint32_t *pnum_param, - uint32_t *pparam_disp, uint8_t **pparam, - uint32_t *ptotal_data, uint32_t *pnum_data, - uint32_t *pdata_disp, uint8_t **pdata) -{ - uint32_t param_ofs, data_ofs; - uint8_t wct; - uint16_t *vwv; - uint16_t num_bytes; - uint8_t *bytes; - NTSTATUS status; - - status = cli_pull_reply(req, &wct, &vwv, &num_bytes, &bytes); - /* - * We can receive something like STATUS_MORE_ENTRIES, so don't use - * !NT_STATUS_IS_OK(status) here. + * The largest wct will be for nttrans (19+num_setup). Make sure we + * don't overflow state->vwv in cli_trans_format. */ - if (NT_STATUS_IS_ERR(status)) { - return status; + if ((num_setup + 19) > ARRAY_SIZE(state->vwv)) { + tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER); + return tevent_req_post(req, ev); } - if (expect_first_reply) { - if ((wct != 0) || (num_bytes != 0)) { - return NT_STATUS_INVALID_NETWORK_RESPONSE; - } - return NT_STATUS_OK; - } - - switch (smb_cmd) { - case SMBtrans: - case SMBtrans2: - if (wct < 10) { - return NT_STATUS_INVALID_NETWORK_RESPONSE; - } - *ptotal_param = SVAL(vwv + 0, 0); - *ptotal_data = SVAL(vwv + 1, 0); - *pnum_param = SVAL(vwv + 3, 0); - param_ofs = SVAL(vwv + 4, 0); - *pparam_disp = SVAL(vwv + 5, 0); - *pnum_data = SVAL(vwv + 6, 0); - data_ofs = SVAL(vwv + 7, 0); - *pdata_disp = SVAL(vwv + 8, 0); - *pnum_setup = CVAL(vwv + 9, 0); - if (wct < 10 + (*pnum_setup)) { - return NT_STATUS_INVALID_NETWORK_RESPONSE; - } - *psetup = vwv + 10; - - break; - case SMBnttrans: - if (wct < 18) { - return NT_STATUS_INVALID_NETWORK_RESPONSE; - } - *ptotal_param = IVAL(vwv, 3); - *ptotal_data = IVAL(vwv, 7); - *pnum_param = IVAL(vwv, 11); - param_ofs = IVAL(vwv, 15); - *pparam_disp = IVAL(vwv, 19); - *pnum_data = IVAL(vwv, 23); - data_ofs = IVAL(vwv, 27); - *pdata_disp = IVAL(vwv, 31); - *pnum_setup = CVAL(vwv, 35); - *psetup = vwv + 18; - break; + state->cli = cli; + state->ev = ev; + state->cmd = cmd; + state->flags = flags; + state->num_rsetup = 0; + state->rsetup = NULL; + ZERO_STRUCT(state->rparam); + ZERO_STRUCT(state->rdata); - default: - return NT_STATUS_INTERNAL_ERROR; + if ((pipe_name != NULL) + && (!convert_string_allocate(state, CH_UNIX, + cli_ucs2(cli) ? CH_UTF16LE : CH_DOS, + pipe_name, strlen(pipe_name) + 1, + &state->pipe_name_conv, + &state->pipe_name_conv_len, true))) { + tevent_req_nterror(req, NT_STATUS_NO_MEMORY); + return tevent_req_post(req, ev); } + state->fid = fid; /* trans2 */ + state->function = function; /* nttrans */ - /* - * Check for buffer overflows. data_ofs needs to be checked against - * the incoming buffer length, data_disp against the total - * length. Likewise for param_ofs/param_disp. - */ - - if (trans_oob(smb_len(cli_req->inbuf), param_ofs, *pnum_param) - || trans_oob(*ptotal_param, *pparam_disp, *pnum_param) - || trans_oob(smb_len(cli_req->inbuf), data_ofs, *pnum_data) - || trans_oob(*ptotal_data, *pdata_disp, *pnum_data)) { - return NT_STATUS_INVALID_NETWORK_RESPONSE; - } + state->setup = setup; + state->num_setup = num_setup; + state->max_setup = max_setup; - *pparam = (uint8_t *)cli_req->inbuf + 4 + param_ofs; - *pdata = (uint8_t *)cli_req->inbuf + 4 + data_ofs; + state->param = param; + state->num_param = num_param; + state->param_sent = 0; + state->rparam.max = max_param; - return NT_STATUS_OK; -} + state->data = data; + state->num_data = num_data; + state->data_sent = 0; + state->rdata.max = max_data; -static NTSTATUS cli_trans_pull_blob(TALLOC_CTX *mem_ctx, - struct trans_recvblob *blob, - uint32_t total, uint32_t thistime, - uint8_t *buf, uint32_t displacement) -{ - if (blob->data == NULL) { - if (total > blob->max) { - return NT_STATUS_INVALID_NETWORK_RESPONSE; - } - blob->total = total; - blob->data = TALLOC_ARRAY(mem_ctx, uint8_t, total); - if (blob->data == NULL) { - return NT_STATUS_NO_MEMORY; - } - } + cli_trans_format(state, &wct, &iov_count); - if (total > blob->total) { - return NT_STATUS_INVALID_NETWORK_RESPONSE; + subreq = cli_smb_req_create(state, ev, cli, cmd, 0, wct, state->vwv, + iov_count, state->iov); + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); } - - if (thistime) { - memcpy(blob->data + displacement, buf, thistime); - blob->received += thistime; + state->mid = cli_smb_req_mid(subreq); + if (!cli_smb_req_send(subreq)) { + tevent_req_nterror(req, NT_STATUS_NO_MEMORY); + return tevent_req_post(req, state->ev); } - - return NT_STATUS_OK; + cli_state_seqnum_persistent(cli, state->mid); + tevent_req_set_callback(subreq, cli_trans_done, req); + return req; } -static void cli_trans_recv_helper(struct async_req *req) +static void cli_trans_done(struct tevent_req *subreq) { - struct cli_request *cli_req = talloc_get_type_abort( - req->private_data, struct cli_request); - struct cli_trans_state *state = talloc_get_type_abort( - cli_req->recv_helper.priv, struct cli_trans_state); + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct cli_trans_state *state = tevent_req_data( + req, struct cli_trans_state); + NTSTATUS status; + bool sent_all; + uint8_t wct; + uint16_t *vwv; + uint32_t num_bytes; + uint8_t *bytes; uint8_t num_setup = 0; uint16_t *setup = NULL; uint32_t total_param = 0; @@ -1122,16 +1114,8 @@ static void cli_trans_recv_helper(struct async_req *req) uint32_t data_disp = 0; uint8_t *param = NULL; uint8_t *data = NULL; - bool sent_all; - NTSTATUS status; - sent_all = (state->param_sent == state->num_param) - && (state->data_sent == state->num_data); - - status = cli_pull_trans( - req, cli_req, state->cmd, !sent_all, &num_setup, &setup, - &total_param, &num_param, ¶m_disp, ¶m, - &total_data, &num_data, &data_disp, &data); + status = cli_smb_recv(subreq, 0, &wct, &vwv, &num_bytes, &bytes); /* * We can receive something like STATUS_MORE_ENTRIES, so don't use @@ -1139,30 +1123,43 @@ static void cli_trans_recv_helper(struct async_req *req) */ if (NT_STATUS_IS_ERR(status)) { - async_req_nterror(req, status); - return; + goto fail; } - if (!sent_all) { - cli_trans_ship_rest(req, state); - return; + sent_all = ((state->param_sent == state->num_param) + && (state->data_sent == state->num_data)); + + status = cli_pull_trans( + cli_smb_inbuf(subreq), wct, vwv, num_bytes, bytes, + state->cmd, !sent_all, &num_setup, &setup, + &total_param, &num_param, ¶m_disp, ¶m, + &total_data, &num_data, &data_disp, &data); + + if (!NT_STATUS_IS_OK(status)) { + goto fail; } - /* - * We've just received a real response. This means that we don't need - * the secondary cli_request structures anymore, they have all been - * shipped to the server. - */ - TALLOC_FREE(state->secondary_request_ctx); + if (!sent_all) { + int iov_count; - if (num_setup != 0) { - TALLOC_FREE(state->rsetup); - state->rsetup = (uint16_t *)TALLOC_MEMDUP( - state, setup, sizeof(uint16_t) * num_setup); - if (state->rsetup == NULL) { - async_req_nterror(req, NT_STATUS_NO_MEMORY); + TALLOC_FREE(subreq); + + cli_trans_format(state, &wct, &iov_count); + + subreq = cli_smb_req_create(state, state->ev, state->cli, + state->cmd + 1, 0, wct, state->vwv, + iov_count, state->iov); + if (tevent_req_nomem(subreq, req)) { return; } + cli_smb_req_set_mid(subreq, state->mid); + + if (!cli_smb_req_send(subreq)) { + status = NT_STATUS_NO_MEMORY; + goto fail; + } + tevent_req_set_callback(subreq, cli_trans_done, req); + return; } status = cli_trans_pull_blob( @@ -1171,8 +1168,7 @@ static void cli_trans_recv_helper(struct async_req *req) if (!NT_STATUS_IS_OK(status)) { DEBUG(10, ("Pulling params failed: %s\n", nt_errstr(status))); - async_req_nterror(req, status); - return; + goto fail; } status = cli_trans_pull_blob( @@ -1181,149 +1177,39 @@ static void cli_trans_recv_helper(struct async_req *req) if (!NT_STATUS_IS_OK(status)) { DEBUG(10, ("Pulling data failed: %s\n", nt_errstr(status))); - async_req_nterror(req, status); - return; + goto fail; } if ((state->rparam.total == state->rparam.received) && (state->rdata.total == state->rdata.received)) { - async_req_done(req); - } -} - -struct async_req *cli_trans_send( - TALLOC_CTX *mem_ctx, struct event_context *ev, - struct cli_state *cli, uint8_t trans_cmd, - const char *pipe_name, uint16_t fid, uint16_t function, int flags, - uint16_t *setup, uint8_t num_setup, uint8_t max_setup, - uint8_t *param, uint32_t num_param, uint32_t max_param, - uint8_t *data, uint32_t num_data, uint32_t max_data) -{ - struct async_req *req; - struct cli_request *cli_req; - struct cli_trans_state *state; - - /* - * We can't use it in a chained request chain, we'd get the offset - * calculations wrong. - */ - - if (cli_in_chain(cli)) { - return NULL; - } - - if ((trans_cmd == SMBtrans) || (trans_cmd == SMBtrans2)) { - if ((num_param > 0xffff) || (max_param > 0xffff) - || (num_data > 0xffff) || (max_data > 0xffff)) { - DEBUG(3, ("Attempt to send invalid trans2 request " - "(setup %u, params %u/%u, data %u/%u)\n", - (unsigned)num_setup, - (unsigned)num_param, (unsigned)max_param, - (unsigned)num_data, (unsigned)max_data)); - return NULL; - } - } - - state = talloc(mem_ctx, struct cli_trans_state); - if (state == NULL) { - goto nomem; - } - - state->cli = cli; - state->ev = ev; - state->cmd = trans_cmd; - state->num_rsetup = 0; - state->rsetup = NULL; - ZERO_STRUCT(state->rparam); - ZERO_STRUCT(state->rdata); - state->secondary_request_ctx = NULL; - - if (trans_cmd == SMBtrans) { - state->pipe_name = talloc_strdup(state, pipe_name); - if (state->pipe_name == NULL) { - goto nomem; - } - } - if (trans_cmd == SMBtrans2) { - state->fid = fid; - } - if (trans_cmd == SMBnttrans) { - state->function = function; - } - - state->flags = flags; - - if (setup != NULL) { - state->setup = (uint16_t *)TALLOC_MEMDUP( - state, setup, sizeof(*setup) * num_setup); - if (state->setup == NULL) { - goto nomem; - } - state->num_setup = num_setup; - } else { - state->setup = NULL; - state->num_setup = 0; - } - - state->max_setup = max_setup; - - if (param != NULL) { - state->param = (uint8_t *)TALLOC_MEMDUP(state, param, - num_param); - if (state->param == NULL) { - goto nomem; - } - state->num_param = num_param; - } else { - state->param = NULL; - state->num_param = 0; - } - - state->param_sent = 0; - state->rparam.max = max_param; - - if (data != NULL) { - state->data = (uint8_t *)TALLOC_MEMDUP(state, data, num_data); - if (state->data == NULL) { - goto nomem; - } - state->num_data = num_data; - } else { - state->data = NULL; - state->num_data = 0; + TALLOC_FREE(subreq); + cli_state_seqnum_remove(state->cli, state->mid); + tevent_req_done(req); + return; } - state->data_sent = 0; - state->rdata.max = max_data; - - req = cli_ship_trans(state, state); - if (req == NULL) { - goto nomem; + if (!cli_smb_req_set_pending(subreq)) { + status = NT_STATUS_NO_MEMORY; + goto fail; } + return; - cli_req = talloc_get_type_abort(req->private_data, struct cli_request); - cli_req->recv_helper.fn = cli_trans_recv_helper; - cli_req->recv_helper.priv = state; - - return req; - - nomem: - TALLOC_FREE(state); - return NULL; + fail: + cli_state_seqnum_remove(state->cli, state->mid); + TALLOC_FREE(subreq); + tevent_req_nterror(req, status); } -NTSTATUS cli_trans_recv(struct async_req *req, TALLOC_CTX *mem_ctx, +NTSTATUS cli_trans_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, uint16_t **setup, uint8_t *num_setup, uint8_t **param, uint32_t *num_param, uint8_t **data, uint32_t *num_data) { - struct cli_request *cli_req = talloc_get_type_abort( - req->private_data, struct cli_request); - struct cli_trans_state *state = talloc_get_type_abort( - cli_req->recv_helper.priv, struct cli_trans_state); + struct cli_trans_state *state = tevent_req_data( + req, struct cli_trans_state); NTSTATUS status; - if (async_req_is_nterror(req, &status)) { + if (tevent_req_is_nterror(req, &status)) { return status; } @@ -1364,19 +1250,20 @@ NTSTATUS cli_trans(TALLOC_CTX *mem_ctx, struct cli_state *cli, { TALLOC_CTX *frame = talloc_stackframe(); struct event_context *ev; - struct async_req *req; - NTSTATUS status = NT_STATUS_NO_MEMORY; + struct tevent_req *req; + NTSTATUS status = NT_STATUS_OK; - if (cli->fd_event != NULL) { + if (cli_has_async_calls(cli)) { /* * Can't use sync call while an async call is in flight */ - cli_set_error(cli, NT_STATUS_INVALID_PARAMETER); + status = NT_STATUS_INVALID_PARAMETER; goto fail; } ev = event_context_init(frame); if (ev == NULL) { + status = NT_STATUS_NO_MEMORY; goto fail; } @@ -1386,16 +1273,21 @@ NTSTATUS cli_trans(TALLOC_CTX *mem_ctx, struct cli_state *cli, param, num_param, max_param, data, num_data, max_data); if (req == NULL) { + status = NT_STATUS_NO_MEMORY; goto fail; } - while (req->state < ASYNC_REQ_DONE) { - event_loop_once(ev); + if (!tevent_req_poll(req, ev)) { + status = map_nt_error_from_unix(errno); + goto fail; } status = cli_trans_recv(req, mem_ctx, rsetup, num_rsetup, rparam, num_rparam, rdata, num_rdata); fail: TALLOC_FREE(frame); + if (!NT_STATUS_IS_OK(status)) { + cli_set_error(cli, status); + } return status; } diff --git a/source3/locking/brlock.c b/source3/locking/brlock.c index aa522ac780..be2948c531 100644 --- a/source3/locking/brlock.c +++ b/source3/locking/brlock.c @@ -41,11 +41,11 @@ static struct db_context *brlock_db; static void print_lock_struct(unsigned int i, struct lock_struct *pls) { - DEBUG(10,("[%u]: smbpid = %u, tid = %u, pid = %u, ", + DEBUG(10,("[%u]: smbpid = %u, tid = %u, pid = %s, ", i, (unsigned int)pls->context.smbpid, (unsigned int)pls->context.tid, - (unsigned int)procid_to_pid(&pls->context.pid) )); + procid_str(debug_ctx(), &pls->context.pid) )); DEBUG(10,("start = %.0f, size = %.0f, fnum = %d, %s %s\n", (double)pls->start, diff --git a/source3/modules/vfs_gpfs.c b/source3/modules/vfs_gpfs.c index 3c061ece79..b304d8bdc2 100644 --- a/source3/modules/vfs_gpfs.c +++ b/source3/modules/vfs_gpfs.c @@ -341,7 +341,7 @@ static bool gpfsacl_process_smbacl(files_struct *fsp, SMB4ACL_T *smbacl) gacl_len = sizeof(struct gpfs_acl) + (smb_get_naces(smbacl)-1)*sizeof(gpfs_ace_v4_t); - gacl = TALLOC_SIZE(mem_ctx, gacl_len); + gacl = (struct gpfs_acl *)TALLOC_SIZE(mem_ctx, gacl_len); if (gacl == NULL) { DEBUG(0, ("talloc failed\n")); errno = ENOMEM; @@ -556,9 +556,9 @@ static SMB_ACL_T gpfsacl_get_posix_acl(const char *path, gpfs_aclType_t type) return result; } -SMB_ACL_T gpfsacl_sys_acl_get_file(vfs_handle_struct *handle, - const char *path_p, - SMB_ACL_TYPE_T type) +static SMB_ACL_T gpfsacl_sys_acl_get_file(vfs_handle_struct *handle, + const char *path_p, + SMB_ACL_TYPE_T type) { gpfs_aclType_t gpfs_type; @@ -577,8 +577,8 @@ SMB_ACL_T gpfsacl_sys_acl_get_file(vfs_handle_struct *handle, return gpfsacl_get_posix_acl(path_p, gpfs_type); } -SMB_ACL_T gpfsacl_sys_acl_get_fd(vfs_handle_struct *handle, - files_struct *fsp) +static SMB_ACL_T gpfsacl_sys_acl_get_fd(vfs_handle_struct *handle, + files_struct *fsp) { return gpfsacl_get_posix_acl(fsp->fsp_name, GPFS_ACL_TYPE_ACCESS); } @@ -600,7 +600,7 @@ static struct gpfs_acl *smb2gpfs_acl(const SMB_ACL_T pacl, len = sizeof(struct gpfs_acl) - sizeof(union gpfs_ace_union) + (pacl->count)*sizeof(gpfs_ace_v1_t); - result = SMB_MALLOC(len); + result = (struct gpfs_acl *)SMB_MALLOC(len); if (result == NULL) { errno = ENOMEM; return result; @@ -670,10 +670,10 @@ static struct gpfs_acl *smb2gpfs_acl(const SMB_ACL_T pacl, return result; } -int gpfsacl_sys_acl_set_file(vfs_handle_struct *handle, - const char *name, - SMB_ACL_TYPE_T type, - SMB_ACL_T theacl) +static int gpfsacl_sys_acl_set_file(vfs_handle_struct *handle, + const char *name, + SMB_ACL_TYPE_T type, + SMB_ACL_T theacl) { struct gpfs_acl *gpfs_acl; int result; @@ -689,15 +689,15 @@ int gpfsacl_sys_acl_set_file(vfs_handle_struct *handle, return result; } -int gpfsacl_sys_acl_set_fd(vfs_handle_struct *handle, - files_struct *fsp, - SMB_ACL_T theacl) +static int gpfsacl_sys_acl_set_fd(vfs_handle_struct *handle, + files_struct *fsp, + SMB_ACL_T theacl) { return gpfsacl_sys_acl_set_file(handle, fsp->fsp_name, SMB_ACL_TYPE_ACCESS, theacl); } -int gpfsacl_sys_acl_delete_def_file(vfs_handle_struct *handle, - const char *path) +static int gpfsacl_sys_acl_delete_def_file(vfs_handle_struct *handle, + const char *path) { errno = ENOTSUP; return -1; diff --git a/source3/modules/vfs_gpfs.h b/source3/modules/vfs_gpfs.h index 3c499b0850..efca5603aa 100644 --- a/source3/modules/vfs_gpfs.h +++ b/source3/modules/vfs_gpfs.h @@ -29,4 +29,6 @@ bool set_gpfs_sharemode(files_struct *fsp, uint32 access_mask, int set_gpfs_lease(int fd, int leasetype); int smbd_gpfs_getacl(char *pathname, int flags, void *acl); int smbd_gpfs_putacl(char *pathname, int flags, void *acl); +int smbd_gpfs_get_realfilename_path(char *pathname, char *filenamep, + int *buflen); void init_gpfs(void); diff --git a/source3/modules/vfs_onefs.c b/source3/modules/vfs_onefs.c index ad59c2b32d..e4a0febbec 100644 --- a/source3/modules/vfs_onefs.c +++ b/source3/modules/vfs_onefs.c @@ -153,10 +153,21 @@ static int onefs_get_real_filename(vfs_handle_struct *handle, const char *path, char **found_name) { SMB_STRUCT_STAT sb; + struct connection_struct *conn = handle->conn; struct stat_extra se; int result; + char *unmangled_name = NULL; char *full_name = NULL; + /* First demangle the name if necessary. */ + if (!conn->case_sensitive && mangle_is_mangled(name, conn->params) && + mangle_lookup_name_from_8_3(mem_ctx, name, &unmangled_name, + conn->params)) { + /* Name is now unmangled. */ + name = unmangled_name; + } + + /* Do the case insensitive stat. */ ZERO_STRUCT(se); se.se_version = ESTAT_CURRENT_VERSION; se.se_flags = ESTAT_CASE_INSENSITIVE | ESTAT_SYMLINK_NOFOLLOW; @@ -184,6 +195,7 @@ static int onefs_get_real_filename(vfs_handle_struct *handle, const char *path, done: TALLOC_FREE(full_name); + TALLOC_FREE(unmangled_name); return result; } diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c index 8da1f6348f..4b14b80339 100644 --- a/source3/param/loadparm.c +++ b/source3/param/loadparm.c @@ -885,7 +885,7 @@ static const struct enum_list enum_kerberos_method[] = { /* Note: We do not initialise the defaults union - it is not allowed in ANSI C * - * The FLAG_HIDE is explicit. Paramters set this way do NOT appear in any edit + * The FLAG_HIDE is explicit. Parameters set this way do NOT appear in any edit * screen in SWAT. This is used to exclude parameters as well as to squash all * parameters that have been duplicated by pseudonyms. * @@ -894,7 +894,7 @@ static const struct enum_list enum_kerberos_method[] = { * Set FLAG_SHARE and FLAG_PRINT to specifically display parameters in * respective views. * - * NOTE2: Handling of duplicated (synonym) paramters: + * NOTE2: Handling of duplicated (synonym) parameters: * Only the first occurance of a parameter should be enabled by FLAG_BASIC * and/or FLAG_ADVANCED. All duplicates following the first mention should be * set to FLAG_HIDE. ie: Make you must place the parameter that has the preferred diff --git a/source3/passdb/pdb_ldap.c b/source3/passdb/pdb_ldap.c index 77b19e3de9..b706721e77 100644 --- a/source3/passdb/pdb_ldap.c +++ b/source3/passdb/pdb_ldap.c @@ -840,27 +840,27 @@ static bool init_sam_from_ldap(struct ldapsam_privates *ldap_state, /* Make call to Novell eDirectory ldap extension to get clear text password. NOTE: This will only work if we have an SSL connection to eDirectory. */ - user_dn = smbldap_get_dn(ldap_state->smbldap_state->ldap_struct, entry); + user_dn = smbldap_talloc_dn(ctx, ldap_state->smbldap_state->ldap_struct, entry); if (user_dn != NULL) { - DEBUG(3, ("init_sam_from_ldap: smbldap_get_dn(%s) returned '%s'\n", username, user_dn)); + DEBUG(3, ("init_sam_from_ldap: smbldap_talloc_dn(ctx, %s) returned '%s'\n", username, user_dn)); pwd_len = sizeof(clear_text_pw); if (pdb_nds_get_password(ldap_state->smbldap_state, user_dn, &pwd_len, clear_text_pw) == LDAP_SUCCESS) { nt_lm_owf_gen(clear_text_pw, smbntpwd, smblmpwd); if (!pdb_set_lanman_passwd(sampass, smblmpwd, PDB_SET)) { - SAFE_FREE(user_dn); + TALLOC_FREE(user_dn); return False; } ZERO_STRUCT(smblmpwd); if (!pdb_set_nt_passwd(sampass, smbntpwd, PDB_SET)) { - SAFE_FREE(user_dn); + TALLOC_FREE(user_dn); return False; } ZERO_STRUCT(smbntpwd); use_samba_attrs = False; } - SAFE_FREE(user_dn); + TALLOC_FREE(user_dn); } else { DEBUG(0, ("init_sam_from_ldap: failed to get user_dn for '%s'\n", username)); @@ -1908,7 +1908,7 @@ static NTSTATUS ldapsam_update_sam_account(struct pdb_methods *my_methods, struc } entry = ldap_first_entry(ldap_state->smbldap_state->ldap_struct, result); - dn = smbldap_get_dn(ldap_state->smbldap_state->ldap_struct, entry); + dn = smbldap_talloc_dn(NULL, ldap_state->smbldap_state->ldap_struct, entry); if (!dn) { return NT_STATUS_UNSUCCESSFUL; } @@ -1918,7 +1918,7 @@ static NTSTATUS ldapsam_update_sam_account(struct pdb_methods *my_methods, struc if (!init_ldap_from_sam(ldap_state, entry, &mods, newpwd, element_is_changed)) { DEBUG(0, ("ldapsam_update_sam_account: init_ldap_from_sam failed!\n")); - SAFE_FREE(dn); + TALLOC_FREE(dn); if (mods != NULL) ldap_mods_free(mods,True); return NT_STATUS_UNSUCCESSFUL; @@ -1928,7 +1928,7 @@ static NTSTATUS ldapsam_update_sam_account(struct pdb_methods *my_methods, struc && (mods == NULL)) { DEBUG(4,("ldapsam_update_sam_account: mods is empty: nothing to update for user: %s\n", pdb_get_username(newpwd))); - SAFE_FREE(dn); + TALLOC_FREE(dn); return NT_STATUS_OK; } @@ -1938,7 +1938,7 @@ static NTSTATUS ldapsam_update_sam_account(struct pdb_methods *my_methods, struc ldap_mods_free(mods,True); } - SAFE_FREE(dn); + TALLOC_FREE(dn); /* * We need to set the backend private data to NULL here. For example @@ -2147,17 +2147,10 @@ static NTSTATUS ldapsam_add_sam_account(struct pdb_methods *my_methods, struct s /* Check if we need to update an existing entry */ if (num_result == 1) { - char *tmp; - DEBUG(3,("ldapsam_add_sam_account: User exists without samba attributes: adding them\n")); ldap_op = LDAP_MOD_REPLACE; entry = ldap_first_entry (ldap_state->smbldap_state->ldap_struct, result); - tmp = smbldap_get_dn(ldap_state->smbldap_state->ldap_struct, entry); - if (!tmp) { - goto fn_exit; - } - dn = talloc_asprintf(ctx, "%s", tmp); - SAFE_FREE(tmp); + dn = smbldap_talloc_dn(ctx, ldap_state->smbldap_state->ldap_struct, entry); if (!dn) { status = NT_STATUS_NO_MEMORY; goto fn_exit; @@ -2200,17 +2193,11 @@ static NTSTATUS ldapsam_add_sam_account(struct pdb_methods *my_methods, struct s /* Check if we need to update an existing entry */ if (num_result == 1) { - char *tmp; DEBUG(3,("ldapsam_add_sam_account: User exists without samba attributes: adding them\n")); ldap_op = LDAP_MOD_REPLACE; entry = ldap_first_entry (ldap_state->smbldap_state->ldap_struct, result); - tmp = smbldap_get_dn (ldap_state->smbldap_state->ldap_struct, entry); - if (!tmp) { - goto fn_exit; - } - dn = talloc_asprintf(ctx, "%s", tmp); - SAFE_FREE(tmp); + dn = smbldap_talloc_dn (ctx, ldap_state->smbldap_state->ldap_struct, entry); if (!dn) { status = NT_STATUS_NO_MEMORY; goto fn_exit; @@ -3525,7 +3512,7 @@ static NTSTATUS ldapsam_modify_aliasmem(struct pdb_methods *methods, return NT_STATUS_UNSUCCESSFUL; } - dn = smbldap_get_dn(ldap_state->smbldap_state->ldap_struct, entry); + dn = smbldap_talloc_dn(NULL, ldap_state->smbldap_state->ldap_struct, entry); if (!dn) { ldap_msgfree(result); return NT_STATUS_UNSUCCESSFUL; @@ -3540,7 +3527,7 @@ static NTSTATUS ldapsam_modify_aliasmem(struct pdb_methods *methods, ldap_mods_free(mods, True); ldap_msgfree(result); - SAFE_FREE(dn); + TALLOC_FREE(dn); if (rc == LDAP_TYPE_OR_VALUE_EXISTS) { return NT_STATUS_MEMBER_IN_ALIAS; @@ -6307,14 +6294,14 @@ NTSTATUS pdb_init_ldapsam(struct pdb_methods **pdb_method, const char *location) return NT_STATUS_UNSUCCESSFUL; } - dn = smbldap_get_dn(ldap_state->smbldap_state->ldap_struct, entry); + dn = smbldap_talloc_dn(talloc_tos(), ldap_state->smbldap_state->ldap_struct, entry); if (!dn) { ldap_msgfree(result); return NT_STATUS_UNSUCCESSFUL; } ldap_state->domain_dn = smb_xstrdup(dn); - ldap_memfree(dn); + TALLOC_FREE(dn); domain_sid_string = smbldap_talloc_single_attribute( ldap_state->smbldap_state->ldap_struct, diff --git a/source3/passdb/pdb_nds.c b/source3/passdb/pdb_nds.c index 1edd665d54..08665e4617 100644 --- a/source3/passdb/pdb_nds.c +++ b/source3/passdb/pdb_nds.c @@ -788,7 +788,7 @@ static NTSTATUS pdb_nds_update_login_attempts(struct pdb_methods *methods, } entry = ldap_first_entry(ldap_state->smbldap_state->ldap_struct, result); - dn = smbldap_get_dn(ldap_state->smbldap_state->ldap_struct, entry); + dn = smbldap_talloc_dn(NULL, ldap_state->smbldap_state->ldap_struct, entry); if (!dn) { return NT_STATUS_OBJECT_NAME_NOT_FOUND; } @@ -811,6 +811,7 @@ static NTSTATUS pdb_nds_update_login_attempts(struct pdb_methods *methods, rc = smb_ldap_setup_full_conn(&ld, ldap_state->location); if (rc) { + TALLOC_FREE(dn); return NT_STATUS_INVALID_CONNECTION; } @@ -841,6 +842,7 @@ static NTSTATUS pdb_nds_update_login_attempts(struct pdb_methods *methods, return nt_status; } } + TALLOC_FREE(dn); } return NT_STATUS_OK; diff --git a/source3/printing/nt_printing.c b/source3/printing/nt_printing.c index a99485d381..c20171b049 100644 --- a/source3/printing/nt_printing.c +++ b/source3/printing/nt_printing.c @@ -3243,7 +3243,12 @@ static WERROR nt_printer_publish_ads(ADS_STRUCT *ads, struct GUID guid; WERROR win_rc = WERR_OK; size_t converted_size; - int ret; + + /* build the ads mods */ + ctx = talloc_init("nt_printer_publish_ads"); + if (ctx == NULL) { + return WERR_NOMEM; + } DEBUG(5, ("publishing printer %s\n", printer->info_2->printername)); @@ -3255,24 +3260,28 @@ static WERROR nt_printer_publish_ads(ADS_STRUCT *ads, srv_dn_utf8 = ldap_get_dn((LDAP *)ads->ldap.ld, (LDAPMessage *)res); if (!srv_dn_utf8) { + TALLOC_FREE(ctx); return WERR_SERVER_UNAVAILABLE; } ads_msgfree(ads, res); srv_cn_utf8 = ldap_explode_dn(srv_dn_utf8, 1); if (!srv_cn_utf8) { + TALLOC_FREE(ctx); ldap_memfree(srv_dn_utf8); return WERR_SERVER_UNAVAILABLE; } /* Now convert to CH_UNIX. */ - if (!pull_utf8_allocate(&srv_dn, srv_dn_utf8, &converted_size)) { + if (!pull_utf8_talloc(ctx, &srv_dn, srv_dn_utf8, &converted_size)) { + TALLOC_FREE(ctx); ldap_memfree(srv_dn_utf8); ldap_memfree(srv_cn_utf8); return WERR_SERVER_UNAVAILABLE; } - if (!pull_utf8_allocate(&srv_cn_0, srv_cn_utf8[0], &converted_size)) { + if (!pull_utf8_talloc(ctx, &srv_cn_0, srv_cn_utf8[0], &converted_size)) { + TALLOC_FREE(ctx); ldap_memfree(srv_dn_utf8); ldap_memfree(srv_cn_utf8); - SAFE_FREE(srv_dn); + TALLOC_FREE(srv_dn); return WERR_SERVER_UNAVAILABLE; } @@ -3281,41 +3290,26 @@ static WERROR nt_printer_publish_ads(ADS_STRUCT *ads, srv_cn_escaped = escape_rdn_val_string_alloc(srv_cn_0); if (!srv_cn_escaped) { - SAFE_FREE(srv_cn_0); - SAFE_FREE(srv_dn); + TALLOC_FREE(ctx); return WERR_SERVER_UNAVAILABLE; } sharename_escaped = escape_rdn_val_string_alloc(printer->info_2->sharename); if (!sharename_escaped) { SAFE_FREE(srv_cn_escaped); - SAFE_FREE(srv_cn_0); - SAFE_FREE(srv_dn); + TALLOC_FREE(ctx); return WERR_SERVER_UNAVAILABLE; } - ret = asprintf(&prt_dn, "cn=%s-%s,%s", srv_cn_escaped, sharename_escaped, srv_dn); + prt_dn = talloc_asprintf(ctx, "cn=%s-%s,%s", srv_cn_escaped, sharename_escaped, srv_dn); - SAFE_FREE(srv_dn); - SAFE_FREE(srv_cn_0); SAFE_FREE(srv_cn_escaped); SAFE_FREE(sharename_escaped); - if (ret == -1) { - return WERR_NOMEM; - } - - /* build the ads mods */ - ctx = talloc_init("nt_printer_publish_ads"); - if (ctx == NULL) { - SAFE_FREE(prt_dn); - return WERR_NOMEM; - } - mods = ads_init_mods(ctx); if (mods == NULL) { SAFE_FREE(prt_dn); - talloc_destroy(ctx); + TALLOC_FREE(ctx); return WERR_NOMEM; } @@ -3336,8 +3330,6 @@ static WERROR nt_printer_publish_ads(ADS_STRUCT *ads, if (!ADS_ERR_OK(ads_rc)) DEBUG(3, ("error publishing %s: %s\n", printer->info_2->sharename, ads_errstr(ads_rc))); - talloc_destroy(ctx); - /* retreive the guid and store it locally */ if (ADS_ERR_OK(ads_search_dn(ads, &res, prt_dn, attrs))) { ZERO_STRUCT(guid); @@ -3346,8 +3338,8 @@ static WERROR nt_printer_publish_ads(ADS_STRUCT *ads, store_printer_guid(printer->info_2, guid); win_rc = mod_a_printer(printer, 2); } + TALLOC_FREE(ctx); - SAFE_FREE(prt_dn); return win_rc; } @@ -3365,13 +3357,13 @@ static WERROR nt_printer_unpublish_ads(ADS_STRUCT *ads, printer->info_2->sharename, global_myname()); if (ADS_ERR_OK(ads_rc) && res && ads_count_replies(ads, res)) { - prt_dn = ads_get_dn(ads, res); + prt_dn = ads_get_dn(ads, talloc_tos(), res); if (!prt_dn) { ads_msgfree(ads, res); return WERR_NOMEM; } ads_rc = ads_del_dn(ads, prt_dn); - ads_memfree(ads, prt_dn); + TALLOC_FREE(prt_dn); } if (res) { diff --git a/source3/rpc_client/cli_pipe.c b/source3/rpc_client/cli_pipe.c index 6b83c170f5..a8cc33f585 100644 --- a/source3/rpc_client/cli_pipe.c +++ b/source3/rpc_client/cli_pipe.c @@ -2291,19 +2291,24 @@ NTSTATUS rpc_api_pipe_req(TALLOC_CTX *mem_ctx, struct rpc_pipe_client *cli, TALLOC_CTX *frame = talloc_stackframe(); struct event_context *ev; struct tevent_req *req; - NTSTATUS status = NT_STATUS_NO_MEMORY; + NTSTATUS status = NT_STATUS_OK; ev = event_context_init(frame); if (ev == NULL) { + status = NT_STATUS_NO_MEMORY; goto fail; } req = rpc_api_pipe_req_send(frame, ev, cli, op_num, in_data); if (req == NULL) { + status = NT_STATUS_NO_MEMORY; goto fail; } - tevent_req_poll(req, ev); + if (!tevent_req_poll(req, ev)) { + status = map_nt_error_from_unix(errno); + goto fail; + } status = rpc_api_pipe_req_recv(req, mem_ctx, out_data); fail: @@ -2905,19 +2910,24 @@ NTSTATUS rpc_pipe_bind(struct rpc_pipe_client *cli, TALLOC_CTX *frame = talloc_stackframe(); struct event_context *ev; struct tevent_req *req; - NTSTATUS status = NT_STATUS_NO_MEMORY; + NTSTATUS status = NT_STATUS_OK; ev = event_context_init(frame); if (ev == NULL) { + status = NT_STATUS_NO_MEMORY; goto fail; } req = rpc_pipe_bind_send(frame, ev, cli, auth); if (req == NULL) { + status = NT_STATUS_NO_MEMORY; goto fail; } - tevent_req_poll(req, ev); + if (!tevent_req_poll(req, ev)) { + status = map_nt_error_from_unix(errno); + goto fail; + } status = rpc_pipe_bind_recv(req); fail: diff --git a/source3/rpc_client/rpc_transport_np.c b/source3/rpc_client/rpc_transport_np.c index 8b45cb4e9c..40d68dd2ea 100644 --- a/source3/rpc_client/rpc_transport_np.c +++ b/source3/rpc_client/rpc_transport_np.c @@ -49,7 +49,7 @@ struct rpc_np_write_state { size_t written; }; -static void rpc_np_write_done(struct async_req *subreq); +static void rpc_np_write_done(struct tevent_req *subreq); static struct tevent_req *rpc_np_write_send(TALLOC_CTX *mem_ctx, struct event_context *ev, @@ -58,8 +58,7 @@ static struct tevent_req *rpc_np_write_send(TALLOC_CTX *mem_ctx, { struct rpc_transport_np_state *np_transport = talloc_get_type_abort( priv, struct rpc_transport_np_state); - struct tevent_req *req; - struct async_req *subreq; + struct tevent_req *req, *subreq; struct rpc_np_write_state *state; req = tevent_req_create(mem_ctx, &state, struct rpc_np_write_state); @@ -72,21 +71,17 @@ static struct tevent_req *rpc_np_write_send(TALLOC_CTX *mem_ctx, np_transport->fnum, 8, /* 8 means message mode. */ data, 0, size); - if (subreq == NULL) { - goto fail; + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); } - subreq->async.fn = rpc_np_write_done; - subreq->async.priv = req; + tevent_req_set_callback(subreq, rpc_np_write_done, req); return req; - fail: - TALLOC_FREE(req); - return NULL; } -static void rpc_np_write_done(struct async_req *subreq) +static void rpc_np_write_done(struct tevent_req *subreq) { - struct tevent_req *req = talloc_get_type_abort( - subreq->async.priv, struct tevent_req); + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); struct rpc_np_write_state *state = tevent_req_data( req, struct rpc_np_write_state); NTSTATUS status; @@ -119,7 +114,7 @@ struct rpc_np_read_state { ssize_t received; }; -static void rpc_np_read_done(struct async_req *subreq); +static void rpc_np_read_done(struct tevent_req *subreq); static struct tevent_req *rpc_np_read_send(TALLOC_CTX *mem_ctx, struct event_context *ev, @@ -128,8 +123,7 @@ static struct tevent_req *rpc_np_read_send(TALLOC_CTX *mem_ctx, { struct rpc_transport_np_state *np_transport = talloc_get_type_abort( priv, struct rpc_transport_np_state); - struct tevent_req *req; - struct async_req *subreq; + struct tevent_req *req, *subreq; struct rpc_np_read_state *state; req = tevent_req_create(mem_ctx, &state, struct rpc_np_read_state); @@ -144,18 +138,17 @@ static struct tevent_req *rpc_np_read_send(TALLOC_CTX *mem_ctx, if (subreq == NULL) { goto fail; } - subreq->async.fn = rpc_np_read_done; - subreq->async.priv = req; + tevent_req_set_callback(subreq, rpc_np_read_done, req); return req; fail: TALLOC_FREE(req); return NULL; } -static void rpc_np_read_done(struct async_req *subreq) +static void rpc_np_read_done(struct tevent_req *subreq) { - struct tevent_req *req = talloc_get_type_abort( - subreq->async.priv, struct tevent_req); + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); struct rpc_np_read_state *state = tevent_req_data( req, struct rpc_np_read_state); NTSTATUS status; @@ -204,7 +197,7 @@ struct rpc_np_trans_state { uint32_t rdata_len; }; -static void rpc_np_trans_done(struct async_req *subreq); +static void rpc_np_trans_done(struct tevent_req *subreq); static struct tevent_req *rpc_np_trans_send(TALLOC_CTX *mem_ctx, struct event_context *ev, @@ -214,8 +207,7 @@ static struct tevent_req *rpc_np_trans_send(TALLOC_CTX *mem_ctx, { struct rpc_transport_np_state *np_transport = talloc_get_type_abort( priv, struct rpc_transport_np_state); - struct tevent_req *req; - struct async_req *subreq; + struct tevent_req *req, *subreq; struct rpc_np_trans_state *state; req = tevent_req_create(mem_ctx, &state, struct rpc_np_trans_state); @@ -233,8 +225,7 @@ static struct tevent_req *rpc_np_trans_send(TALLOC_CTX *mem_ctx, if (subreq == NULL) { goto fail; } - subreq->async.fn = rpc_np_trans_done; - subreq->async.priv = req; + tevent_req_set_callback(subreq, rpc_np_trans_done, req); return req; fail: @@ -242,10 +233,10 @@ static struct tevent_req *rpc_np_trans_send(TALLOC_CTX *mem_ctx, return NULL; } -static void rpc_np_trans_done(struct async_req *subreq) +static void rpc_np_trans_done(struct tevent_req *subreq) { - struct tevent_req *req = talloc_get_type_abort( - subreq->async.priv, struct tevent_req); + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); struct rpc_np_trans_state *state = tevent_req_data( req, struct rpc_np_trans_state); NTSTATUS status; @@ -280,29 +271,30 @@ struct rpc_transport_np_init_state { struct rpc_transport_np_state *transport_np; }; -static void rpc_transport_np_init_pipe_open(struct async_req *subreq); +static void rpc_transport_np_init_pipe_open(struct tevent_req *subreq); -struct async_req *rpc_transport_np_init_send(TALLOC_CTX *mem_ctx, - struct event_context *ev, - struct cli_state *cli, - const struct ndr_syntax_id *abstract_syntax) +struct tevent_req *rpc_transport_np_init_send(TALLOC_CTX *mem_ctx, + struct event_context *ev, + struct cli_state *cli, + const struct ndr_syntax_id *abstract_syntax) { - struct async_req *result, *subreq; + struct tevent_req *req, *subreq; struct rpc_transport_np_init_state *state; - if (!async_req_setup(mem_ctx, &result, &state, - struct rpc_transport_np_init_state)) { + req = tevent_req_create(mem_ctx, &state, + struct rpc_transport_np_init_state); + if (req == NULL) { return NULL; } state->transport = talloc(state, struct rpc_cli_transport); - if (state->transport == NULL) { - goto fail; + if (tevent_req_nomem(state->transport, req)) { + return tevent_req_post(req, ev); } state->transport_np = talloc(state->transport, struct rpc_transport_np_state); - if (state->transport_np == NULL) { - goto fail; + if (tevent_req_nomem(state->transport_np, req)) { + return tevent_req_post(req, ev); } state->transport->priv = state->transport_np; @@ -314,47 +306,43 @@ struct async_req *rpc_transport_np_init_send(TALLOC_CTX *mem_ctx, state, ev, cli, state->transport_np->pipe_name, 0, DESIRED_ACCESS_PIPE, 0, FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN, 0, 0); - if (subreq == NULL) { - goto fail; + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); } - subreq->async.fn = rpc_transport_np_init_pipe_open; - subreq->async.priv = result; - return result; - - fail: - TALLOC_FREE(result); - return NULL; + tevent_req_set_callback(subreq, rpc_transport_np_init_pipe_open, + req); + return req; } -static void rpc_transport_np_init_pipe_open(struct async_req *subreq) +static void rpc_transport_np_init_pipe_open(struct tevent_req *subreq) { - struct async_req *req = talloc_get_type_abort( - subreq->async.priv, struct async_req); - struct rpc_transport_np_init_state *state = talloc_get_type_abort( - req->private_data, struct rpc_transport_np_init_state); + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct rpc_transport_np_init_state *state = tevent_req_data( + req, struct rpc_transport_np_init_state); NTSTATUS status; status = cli_ntcreate_recv(subreq, &state->transport_np->fnum); TALLOC_FREE(subreq); if (!NT_STATUS_IS_OK(status)) { - async_req_nterror(req, status); + tevent_req_nterror(req, status); return; } talloc_set_destructor(state->transport_np, rpc_transport_np_state_destructor); - async_req_done(req); + tevent_req_done(req); } -NTSTATUS rpc_transport_np_init_recv(struct async_req *req, +NTSTATUS rpc_transport_np_init_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, struct rpc_cli_transport **presult) { - struct rpc_transport_np_init_state *state = talloc_get_type_abort( - req->private_data, struct rpc_transport_np_init_state); + struct rpc_transport_np_init_state *state = tevent_req_data( + req, struct rpc_transport_np_init_state); NTSTATUS status; - if (async_req_is_nterror(req, &status)) { + if (tevent_req_is_nterror(req, &status)) { return status; } @@ -375,8 +363,8 @@ NTSTATUS rpc_transport_np_init(TALLOC_CTX *mem_ctx, struct cli_state *cli, { TALLOC_CTX *frame = talloc_stackframe(); struct event_context *ev; - struct async_req *req; - NTSTATUS status; + struct tevent_req *req; + NTSTATUS status = NT_STATUS_OK; ev = event_context_init(frame); if (ev == NULL) { @@ -390,8 +378,9 @@ NTSTATUS rpc_transport_np_init(TALLOC_CTX *mem_ctx, struct cli_state *cli, goto fail; } - while (req->state < ASYNC_REQ_DONE) { - event_loop_once(ev); + if (!tevent_req_poll(req, ev)) { + status = map_nt_error_from_unix(errno); + goto fail; } status = rpc_transport_np_init_recv(req, mem_ctx, presult); diff --git a/source3/rpc_client/rpc_transport_smbd.c b/source3/rpc_client/rpc_transport_smbd.c index bde8d04208..171048ae29 100644 --- a/source3/rpc_client/rpc_transport_smbd.c +++ b/source3/rpc_client/rpc_transport_smbd.c @@ -88,6 +88,7 @@ static void rpc_cli_smbd_stdout_reader(struct event_context *ev, TALLOC_FREE(fde); return; } + buf[nread] = '\0'; if (conn->stdout_callback.fn != NULL) { conn->stdout_callback.fn(buf, nread, @@ -127,102 +128,95 @@ struct get_anon_ipc_state { struct cli_state *cli; }; -static void get_anon_ipc_negprot_done(struct async_req *subreq); -static void get_anon_ipc_sesssetup_done(struct async_req *subreq); -static void get_anon_ipc_tcon_done(struct async_req *subreq); +static void get_anon_ipc_negprot_done(struct tevent_req *subreq); +static void get_anon_ipc_sesssetup_done(struct tevent_req *subreq); +static void get_anon_ipc_tcon_done(struct tevent_req *subreq); -static struct async_req *get_anon_ipc_send(TALLOC_CTX *mem_ctx, - struct event_context *ev, - struct cli_state *cli) +static struct tevent_req *get_anon_ipc_send(TALLOC_CTX *mem_ctx, + struct event_context *ev, + struct cli_state *cli) { - struct async_req *result, *subreq; + struct tevent_req *req, *subreq; struct get_anon_ipc_state *state; - if (!async_req_setup(mem_ctx, &result, &state, - struct get_anon_ipc_state)) { + req = tevent_req_create(mem_ctx, &state, struct get_anon_ipc_state); + if (req == NULL) { return NULL; } - state->ev = ev; state->cli = cli; subreq = cli_negprot_send(state, ev, cli); - if (subreq == NULL) { - goto fail; + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); } - subreq->async.fn = get_anon_ipc_negprot_done; - subreq->async.priv = result; - return result; - fail: - TALLOC_FREE(result); - return NULL; + tevent_req_set_callback(subreq, get_anon_ipc_negprot_done, req); + return req; } -static void get_anon_ipc_negprot_done(struct async_req *subreq) +static void get_anon_ipc_negprot_done(struct tevent_req *subreq) { - struct async_req *req = talloc_get_type_abort( - subreq->async.priv, struct async_req); - struct get_anon_ipc_state *state = talloc_get_type_abort( - req->private_data, struct get_anon_ipc_state); + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct get_anon_ipc_state *state = tevent_req_data( + req, struct get_anon_ipc_state); NTSTATUS status; status = cli_negprot_recv(subreq); TALLOC_FREE(subreq); if (!NT_STATUS_IS_OK(status)) { - async_req_nterror(req, status); + tevent_req_nterror(req, status); return; } subreq = cli_session_setup_guest_send(state, state->ev, state->cli); - if (async_req_nomem(subreq, req)) { + if (tevent_req_nomem(subreq, req)) { return; } - subreq->async.fn = get_anon_ipc_sesssetup_done; - subreq->async.priv = req; + tevent_req_set_callback(subreq, get_anon_ipc_sesssetup_done, req); } -static void get_anon_ipc_sesssetup_done(struct async_req *subreq) +static void get_anon_ipc_sesssetup_done(struct tevent_req *subreq) { - struct async_req *req = talloc_get_type_abort( - subreq->async.priv, struct async_req); - struct get_anon_ipc_state *state = talloc_get_type_abort( - req->private_data, struct get_anon_ipc_state); + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct get_anon_ipc_state *state = tevent_req_data( + req, struct get_anon_ipc_state); NTSTATUS status; status = cli_session_setup_guest_recv(subreq); TALLOC_FREE(subreq); if (!NT_STATUS_IS_OK(status)) { - async_req_nterror(req, status); + tevent_req_nterror(req, status); return; } subreq = cli_tcon_andx_send(state, state->ev, state->cli, "IPC$", "IPC", NULL, 0); - if (async_req_nomem(subreq, req)) { + if (tevent_req_nomem(subreq, req)) { return; } - subreq->async.fn = get_anon_ipc_tcon_done; - subreq->async.priv = req; + tevent_req_set_callback(subreq, get_anon_ipc_tcon_done, req); } -static void get_anon_ipc_tcon_done(struct async_req *subreq) +static void get_anon_ipc_tcon_done(struct tevent_req *subreq) { - struct async_req *req = talloc_get_type_abort( - subreq->async.priv, struct async_req); + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); NTSTATUS status; status = cli_tcon_andx_recv(subreq); TALLOC_FREE(subreq); if (!NT_STATUS_IS_OK(status)) { - async_req_nterror(req, status); + tevent_req_nterror(req, status); return; } - async_req_done(req); + tevent_req_done(req); } -static NTSTATUS get_anon_ipc_recv(struct async_req *req) +static NTSTATUS get_anon_ipc_recv(struct tevent_req *req) { - return async_req_simple_recv_ntstatus(req); + return tevent_req_simple_recv_ntstatus(req); } struct rpc_cli_smbd_conn_init_state { @@ -230,16 +224,16 @@ struct rpc_cli_smbd_conn_init_state { struct rpc_cli_smbd_conn *conn; }; -static void rpc_cli_smbd_conn_init_done(struct async_req *subreq); +static void rpc_cli_smbd_conn_init_done(struct tevent_req *subreq); -struct async_req *rpc_cli_smbd_conn_init_send(TALLOC_CTX *mem_ctx, - struct event_context *ev, - void (*stdout_callback)(char *buf, - size_t len, - void *priv), - void *priv) +struct tevent_req *rpc_cli_smbd_conn_init_send(TALLOC_CTX *mem_ctx, + struct event_context *ev, + void (*stdout_callback)(char *buf, + size_t len, + void *priv), + void *priv) { - struct async_req *result, *subreq; + struct tevent_req *req, *subreq; struct rpc_cli_smbd_conn_init_state *state; int smb_sock[2]; int stdout_pipe[2]; @@ -249,20 +243,21 @@ struct async_req *rpc_cli_smbd_conn_init_send(TALLOC_CTX *mem_ctx, smb_sock[0] = smb_sock[1] = stdout_pipe[0] = stdout_pipe[1] = -1; - if (!async_req_setup(mem_ctx, &result, &state, - struct rpc_cli_smbd_conn_init_state)) { + req = tevent_req_create(mem_ctx, &state, + struct rpc_cli_smbd_conn_init_state); + if (req == NULL) { return NULL; } state->ev = ev; state->conn = talloc(state, struct rpc_cli_smbd_conn); - if (state->conn == NULL) { - goto nomem; + if (tevent_req_nomem(state->conn, req)) { + return tevent_req_post(req, ev); } state->conn->cli = cli_initialise(); - if (state->conn->cli == NULL) { - goto nomem; + if (tevent_req_nomem(state->conn->cli, req)) { + return tevent_req_post(req, ev); } state->conn->stdout_fd = -1; state->conn->stdout_callback.fn = stdout_callback; @@ -309,7 +304,8 @@ struct async_req *rpc_cli_smbd_conn_init_send(TALLOC_CTX *mem_ctx, printf("no memory"); exit(1); } - if (asprintf(&smbd_cmd, "%s -F -S", smbd_cmd) == -1) { + if (asprintf(&smbd_cmd, "%s -F -S -d %d", smbd_cmd, + DEBUGLEVEL) == -1) { printf("no memory"); exit(1); } @@ -328,21 +324,19 @@ struct async_req *rpc_cli_smbd_conn_init_send(TALLOC_CTX *mem_ctx, stdout_pipe[1] = -1; subreq = get_anon_ipc_send(state, ev, state->conn->cli); - if (subreq == NULL) { - goto nomem; + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); } - if (event_add_fd(ev, subreq, state->conn->stdout_fd, EVENT_FD_READ, + if (event_add_fd(ev, state, state->conn->stdout_fd, EVENT_FD_READ, rpc_cli_smbd_stdout_reader, state->conn) == NULL) { - goto nomem; + status = NT_STATUS_NO_MEMORY; + goto post_status; } - subreq->async.fn = rpc_cli_smbd_conn_init_done; - subreq->async.priv = result; - return result; + tevent_req_set_callback(subreq, rpc_cli_smbd_conn_init_done, req); + return req; - nomem: - status = NT_STATUS_NO_MEMORY; post_status: if (smb_sock[0] != -1) { close(smb_sock[0]); @@ -356,37 +350,34 @@ struct async_req *rpc_cli_smbd_conn_init_send(TALLOC_CTX *mem_ctx, if (stdout_pipe[1] != -1) { close(stdout_pipe[1]); } - if (async_post_ntstatus(result, ev, status)) { - return result; - } - TALLOC_FREE(result); - return NULL; + tevent_req_nterror(req, status); + return tevent_req_post(req, ev); } -static void rpc_cli_smbd_conn_init_done(struct async_req *subreq) +static void rpc_cli_smbd_conn_init_done(struct tevent_req *subreq) { - struct async_req *req = talloc_get_type_abort( - subreq->async.priv, struct async_req); + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); NTSTATUS status; status = get_anon_ipc_recv(subreq); TALLOC_FREE(subreq); if (!NT_STATUS_IS_OK(status)) { - async_req_nterror(req, status); + tevent_req_nterror(req, status); return; } - async_req_done(req); + tevent_req_done(req); } -NTSTATUS rpc_cli_smbd_conn_init_recv(struct async_req *req, +NTSTATUS rpc_cli_smbd_conn_init_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, struct rpc_cli_smbd_conn **pconn) { - struct rpc_cli_smbd_conn_init_state *state = talloc_get_type_abort( - req->private_data, struct rpc_cli_smbd_conn_init_state); + struct rpc_cli_smbd_conn_init_state *state = tevent_req_data( + req, struct rpc_cli_smbd_conn_init_state); NTSTATUS status; - if (async_req_is_nterror(req, &status)) { + if (tevent_req_is_nterror(req, &status)) { return status; } *pconn = talloc_move(mem_ctx, &state->conn); @@ -402,7 +393,7 @@ NTSTATUS rpc_cli_smbd_conn_init(TALLOC_CTX *mem_ctx, { TALLOC_CTX *frame = talloc_stackframe(); struct event_context *ev; - struct async_req *req; + struct tevent_req *req; NTSTATUS status; ev = event_context_init(frame); @@ -417,8 +408,9 @@ NTSTATUS rpc_cli_smbd_conn_init(TALLOC_CTX *mem_ctx, goto fail; } - while (req->state < ASYNC_REQ_DONE) { - event_loop_once(ev); + if (!tevent_req_poll(req, ev)) { + status = map_nt_error_from_unix(errno); + goto fail; } status = rpc_cli_smbd_conn_init_recv(req, mem_ctx, pconn); @@ -456,7 +448,7 @@ static struct tevent_req *rpc_smbd_write_send(TALLOC_CTX *mem_ctx, goto fail; } - if (event_add_fd(ev, subreq, transp->conn->stdout_fd, EVENT_FD_READ, + if (event_add_fd(ev, state, transp->conn->stdout_fd, EVENT_FD_READ, rpc_cli_smbd_stdout_reader, transp->conn) == NULL) { goto fail; } @@ -527,7 +519,7 @@ static struct tevent_req *rpc_smbd_read_send(TALLOC_CTX *mem_ctx, goto fail; } - if (event_add_fd(ev, subreq, transp->conn->stdout_fd, EVENT_FD_READ, + if (event_add_fd(ev, state, transp->conn->stdout_fd, EVENT_FD_READ, rpc_cli_smbd_stdout_reader, transp->conn) == NULL) { goto fail; } @@ -573,53 +565,55 @@ struct rpc_transport_smbd_init_state { struct rpc_transport_smbd_state *transport_smbd; }; -static void rpc_transport_smbd_init_done(struct async_req *subreq); +static void rpc_transport_smbd_init_done(struct tevent_req *subreq); -struct async_req *rpc_transport_smbd_init_send(TALLOC_CTX *mem_ctx, - struct event_context *ev, - struct rpc_cli_smbd_conn *conn, - const struct ndr_syntax_id *abstract_syntax) +struct tevent_req *rpc_transport_smbd_init_send(TALLOC_CTX *mem_ctx, + struct event_context *ev, + struct rpc_cli_smbd_conn *conn, + const struct ndr_syntax_id *abstract_syntax) { - struct async_req *result, *subreq; + struct tevent_req *req, *subreq; struct rpc_transport_smbd_init_state *state; - if (!async_req_setup(mem_ctx, &result, &state, - struct rpc_transport_smbd_init_state)) { + req = tevent_req_create(mem_ctx, &state, + struct rpc_transport_smbd_init_state); + if (req == NULL) { return NULL; } state->transport = talloc(state, struct rpc_cli_transport); - if (state->transport == NULL) { - goto fail; + if (tevent_req_nomem(state->transport, req)) { + return tevent_req_post(req, ev); } state->transport_smbd = talloc(state->transport, struct rpc_transport_smbd_state); - if (state->transport_smbd == NULL) { - goto fail; + if (tevent_req_nomem(state->transport_smbd, req)) { + return tevent_req_post(req, ev); } state->transport_smbd->conn = conn; state->transport->priv = state->transport_smbd; + if (event_add_fd(ev, state, conn->stdout_fd, EVENT_FD_READ, + rpc_cli_smbd_stdout_reader, conn) == NULL) { + tevent_req_nterror(req, NT_STATUS_NO_MEMORY); + return tevent_req_post(req, ev); + } + subreq = rpc_transport_np_init_send(state, ev, conn->cli, abstract_syntax); - if (subreq == NULL) { - goto fail; + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); } - subreq->async.fn = rpc_transport_smbd_init_done; - subreq->async.priv = result; - return result; - - fail: - TALLOC_FREE(result); - return NULL; + tevent_req_set_callback(subreq, rpc_transport_smbd_init_done, req); + return req; } -static void rpc_transport_smbd_init_done(struct async_req *subreq) +static void rpc_transport_smbd_init_done(struct tevent_req *subreq) { - struct async_req *req = talloc_get_type_abort( - subreq->async.priv, struct async_req); - struct rpc_transport_smbd_init_state *state = talloc_get_type_abort( - req->private_data, struct rpc_transport_smbd_init_state); + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct rpc_transport_smbd_init_state *state = tevent_req_data( + req, struct rpc_transport_smbd_init_state); NTSTATUS status; status = rpc_transport_np_init_recv( @@ -627,21 +621,21 @@ static void rpc_transport_smbd_init_done(struct async_req *subreq) &state->transport_smbd->sub_transp); TALLOC_FREE(subreq); if (!NT_STATUS_IS_OK(status)) { - async_req_nterror(req, status); + tevent_req_nterror(req, status); return; } - async_req_done(req); + tevent_req_done(req); } -NTSTATUS rpc_transport_smbd_init_recv(struct async_req *req, +NTSTATUS rpc_transport_smbd_init_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, struct rpc_cli_transport **presult) { - struct rpc_transport_smbd_init_state *state = talloc_get_type_abort( - req->private_data, struct rpc_transport_smbd_init_state); + struct rpc_transport_smbd_init_state *state = tevent_req_data( + req, struct rpc_transport_smbd_init_state); NTSTATUS status; - if (async_req_is_nterror(req, &status)) { + if (tevent_req_is_nterror(req, &status)) { return status; } @@ -663,7 +657,7 @@ NTSTATUS rpc_transport_smbd_init(TALLOC_CTX *mem_ctx, { TALLOC_CTX *frame = talloc_stackframe(); struct event_context *ev; - struct async_req *req; + struct tevent_req *req; NTSTATUS status; ev = event_context_init(frame); @@ -678,8 +672,9 @@ NTSTATUS rpc_transport_smbd_init(TALLOC_CTX *mem_ctx, goto fail; } - while (req->state < ASYNC_REQ_DONE) { - event_loop_once(ev); + if (!tevent_req_poll(req, ev)) { + status = map_nt_error_from_unix(errno); + goto fail; } status = rpc_transport_smbd_init_recv(req, mem_ctx, presult); diff --git a/source3/rpc_parse/parse_prs.c b/source3/rpc_parse/parse_prs.c index 94732b0a74..dfbd6dac74 100644 --- a/source3/rpc_parse/parse_prs.c +++ b/source3/rpc_parse/parse_prs.c @@ -1048,44 +1048,6 @@ bool prs_uint32s(bool charmode, const char *name, prs_struct *ps, int depth, uin return True; } -/****************************************************************** - Stream a unicode string, length/buffer specified separately, - in uint16 chars. The unicode string is already in little-endian format. - ********************************************************************/ - -bool prs_unistr2(bool charmode, const char *name, prs_struct *ps, int depth, UNISTR2 *str) -{ - char *p; - char *q = prs_mem_get(ps, str->uni_str_len * sizeof(uint16)); - if (q == NULL) - return False; - - /* If the string is empty, we don't have anything to stream */ - if (str->uni_str_len==0) - return True; - - if (UNMARSHALLING(ps)) { - if (str->uni_str_len > str->uni_max_len) { - return False; - } - if (str->uni_max_len) { - str->buffer = PRS_ALLOC_MEM(ps,uint16,str->uni_max_len); - if (str->buffer == NULL) - return False; - } else { - str->buffer = NULL; - } - } - - p = (char *)str->buffer; - - dbg_rw_punival(charmode, name, depth, ps, q, p, str->uni_str_len); - - ps->data_offset += (str->uni_str_len * sizeof(uint16)); - - return True; -} - /******************************************************************* Stream a unicode null-terminated string. As the string is already in little-endian format then do it as a stream of bytes. diff --git a/source3/rpc_server/srv_lsa_nt.c b/source3/rpc_server/srv_lsa_nt.c index 5fdcaf2d4a..0ce2b40f65 100644 --- a/source3/rpc_server/srv_lsa_nt.c +++ b/source3/rpc_server/srv_lsa_nt.c @@ -648,14 +648,14 @@ NTSTATUS _lsa_QueryInfoPolicy(pipes_struct *p, * only a BDC is a backup controller * of the domain, it controls. */ - info->role.role = 2; + info->role.role = LSA_ROLE_BACKUP; break; default: /* * any other role is a primary * of the domain, it controls. */ - info->role.role = 3; + info->role.role = LSA_ROLE_PRIMARY; break; } break; @@ -1434,14 +1434,14 @@ NTSTATUS _lsa_EnumAccounts(pipes_struct *p, sids = TALLOC_ZERO_ARRAY(p->mem_ctx, struct lsa_SidPtr, num_entries - *r->in.resume_handle); if (!sids) { - SAFE_FREE(sid_list); + talloc_free(sid_list); return NT_STATUS_NO_MEMORY; } for (i = *r->in.resume_handle, j = 0; i < num_entries; i++, j++) { sids[j].sid = sid_dup_talloc(p->mem_ctx, &sid_list[i]); if (!sids[j].sid) { - SAFE_FREE(sid_list); + talloc_free(sid_list); return NT_STATUS_NO_MEMORY; } } diff --git a/source3/rpc_server/srv_ntsvcs_nt.c b/source3/rpc_server/srv_ntsvcs_nt.c index 681c543c24..7b8dc93a6e 100644 --- a/source3/rpc_server/srv_ntsvcs_nt.c +++ b/source3/rpc_server/srv_ntsvcs_nt.c @@ -3,6 +3,7 @@ * RPC Pipe client / server routines * * Copyright (C) Gerald (Jerry) Carter 2005. + * Copyright (C) Guenther Deschner 2008,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 @@ -50,8 +51,9 @@ WERROR _PNP_GetDeviceListSize(pipes_struct *p, { char *devicepath; - if (!r->in.devicename) { - return WERR_ACCESS_DENIED; + if ((r->in.flags & CM_GETIDLIST_FILTER_SERVICE) && + (!r->in.devicename)) { + return WERR_CM_INVALID_POINTER; } if (!(devicepath = get_device_path(p->mem_ctx, r->in.devicename))) { @@ -74,13 +76,14 @@ WERROR _PNP_GetDeviceList(pipes_struct *p, { char *devicepath; uint32_t size = 0; + char **multi_sz = NULL; + size_t multi_sz_len; + uint16_t *multi_sz_buf; - DATA_BLOB blob; - struct lsa_StringLarge s; - enum ndr_err_code ndr_err; - - if ( !r->in.filter ) - return WERR_ACCESS_DENIED; + if ((r->in.flags & CM_GETIDLIST_FILTER_SERVICE) && + (!r->in.filter)) { + return WERR_CM_INVALID_POINTER; + } if (!(devicepath = get_device_path(p->mem_ctx, r->in.filter))) { return WERR_NOMEM; @@ -92,20 +95,24 @@ WERROR _PNP_GetDeviceList(pipes_struct *p, return WERR_CM_BUFFER_SMALL; } - s.string = r->in.filter; - - /* This has to be DOUBLE NULL terminated */ - ndr_err = ndr_push_struct_blob(&blob, p->mem_ctx, NULL, &s, - (ndr_push_flags_fn_t)ndr_push_lsa_StringLarge); - if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { - return ntstatus_to_werror(ndr_map_error2ntstatus(ndr_err)); + multi_sz = talloc_zero_array(p->mem_ctx, char *, 2); + if (!multi_sz) { + return WERR_NOMEM; } - r->out.buffer = (uint16_t *)talloc_memdup(p->mem_ctx, blob.data, blob.length); - if (!r->out.buffer) { + multi_sz[0] = devicepath; + + multi_sz_len = regval_build_multi_sz(multi_sz, &multi_sz_buf); + if (!multi_sz_len) { return WERR_NOMEM; } + if (*r->in.length < multi_sz_len/2) { + return WERR_CM_BUFFER_SMALL; + } + + memcpy(r->out.buffer, multi_sz_buf, multi_sz_len); + return WERR_OK; } diff --git a/source3/rpc_server/srv_samr_nt.c b/source3/rpc_server/srv_samr_nt.c index c60d904b18..7881ca62ea 100644 --- a/source3/rpc_server/srv_samr_nt.c +++ b/source3/rpc_server/srv_samr_nt.c @@ -3245,6 +3245,9 @@ NTSTATUS _samr_Connect2(pipes_struct *p, case NDR_SAMR_CONNECT2: fn = "_samr_Connect2"; break; + case NDR_SAMR_CONNECT3: + fn = "_samr_Connect3"; + break; case NDR_SAMR_CONNECT4: fn = "_samr_Connect4"; break; @@ -3289,6 +3292,22 @@ NTSTATUS _samr_Connect2(pipes_struct *p, return nt_status; } +/**************************************************************** + _samr_Connect3 +****************************************************************/ + +NTSTATUS _samr_Connect3(pipes_struct *p, + struct samr_Connect3 *r) +{ + struct samr_Connect2 c; + + c.in.system_name = r->in.system_name; + c.in.access_mask = r->in.access_mask; + c.out.connect_handle = r->out.connect_handle; + + return _samr_Connect2(p, &c); +} + /******************************************************************* _samr_Connect4 ********************************************************************/ @@ -3667,8 +3686,9 @@ static bool set_user_info_20(struct samr_UserInfo20 *id20, set_user_info_21 ********************************************************************/ -static NTSTATUS set_user_info_21(TALLOC_CTX *mem_ctx, - struct samr_UserInfo21 *id21, +static NTSTATUS set_user_info_21(struct samr_UserInfo21 *id21, + TALLOC_CTX *mem_ctx, + DATA_BLOB *session_key, struct samu *pwd) { NTSTATUS status; @@ -3686,6 +3706,52 @@ static NTSTATUS set_user_info_21(TALLOC_CTX *mem_ctx, return NT_STATUS_ACCESS_DENIED; } + if (id21->fields_present & SAMR_FIELD_NT_PASSWORD_PRESENT) { + if (id21->nt_password_set) { + DATA_BLOB in, out; + + if ((id21->nt_owf_password.length != 16) || + (id21->nt_owf_password.size != 16)) { + return NT_STATUS_INVALID_PARAMETER; + } + + if (!session_key->length) { + return NT_STATUS_NO_USER_SESSION_KEY; + } + + in = data_blob_const(id21->nt_owf_password.array, 16); + out = data_blob_talloc_zero(mem_ctx, 16); + + sess_crypt_blob(&out, &in, session_key, false); + + pdb_set_nt_passwd(pwd, out.data, PDB_CHANGED); + pdb_set_pass_last_set_time(pwd, time(NULL), PDB_CHANGED); + } + } + + if (id21->fields_present & SAMR_FIELD_LM_PASSWORD_PRESENT) { + if (id21->lm_password_set) { + DATA_BLOB in, out; + + if ((id21->lm_owf_password.length != 16) || + (id21->lm_owf_password.size != 16)) { + return NT_STATUS_INVALID_PARAMETER; + } + + if (!session_key->length) { + return NT_STATUS_NO_USER_SESSION_KEY; + } + + in = data_blob_const(id21->lm_owf_password.array, 16); + out = data_blob_talloc_zero(mem_ctx, 16); + + sess_crypt_blob(&out, &in, session_key, false); + + pdb_set_lanman_passwd(pwd, out.data, PDB_CHANGED); + pdb_set_pass_last_set_time(pwd, time(NULL), PDB_CHANGED); + } + } + /* we need to separately check for an account rename first */ if (id21->account_name.string && @@ -4147,8 +4213,10 @@ NTSTATUS _samr_SetUserInfo(pipes_struct *p, break; case 21: - status = set_user_info_21(p->mem_ctx, - &info->info21, pwd); + status = set_user_info_21(&info->info21, + p->mem_ctx, + &p->server_info->user_session_key, + pwd); break; case 23: @@ -5852,16 +5920,6 @@ NTSTATUS _samr_GetBootKeyInformation(pipes_struct *p, /**************************************************************** ****************************************************************/ -NTSTATUS _samr_Connect3(pipes_struct *p, - struct samr_Connect3 *r) -{ - p->rng_fault_state = true; - return NT_STATUS_NOT_IMPLEMENTED; -} - -/**************************************************************** -****************************************************************/ - NTSTATUS _samr_RidToSid(pipes_struct *p, struct samr_RidToSid *r) { diff --git a/source3/rpc_server/srv_spoolss_nt.c b/source3/rpc_server/srv_spoolss_nt.c index 15c137a88c..098e59216b 100644 --- a/source3/rpc_server/srv_spoolss_nt.c +++ b/source3/rpc_server/srv_spoolss_nt.c @@ -445,7 +445,7 @@ static bool set_printer_hnd_name(Printer_entry *Printer, const char *handlename) aprinter++; } } else { - servername = ""; + servername = global_myname(); } /* save the servername to fill in replies on this handle */ @@ -4890,6 +4890,174 @@ static WERROR fill_printer_driver_info6(TALLOC_CTX *mem_ctx, } /******************************************************************** + ********************************************************************/ + +static WERROR fill_spoolss_DriverFileInfo(TALLOC_CTX *mem_ctx, + struct spoolss_DriverFileInfo *r, + const char *cservername, + const char *file_name, + enum spoolss_DriverFileType file_type, + uint32_t file_version) +{ + r->file_name = talloc_asprintf(mem_ctx, "\\\\%s%s", + cservername, file_name); + W_ERROR_HAVE_NO_MEMORY(r->file_name); + r->file_type = file_type; + r->file_version = file_version; + + return WERR_OK; +} + +/******************************************************************** + ********************************************************************/ + +static WERROR spoolss_DriverFileInfo_from_driver(TALLOC_CTX *mem_ctx, + const NT_PRINTER_DRIVER_INFO_LEVEL *driver, + const char *cservername, + struct spoolss_DriverFileInfo **info_p, + uint32_t *count_p) +{ + struct spoolss_DriverFileInfo *info = NULL; + uint32_t count = 0; + WERROR result; + uint32_t i; + + *info_p = NULL; + *count_p = 0; + + if (strlen(driver->info_3->driverpath)) { + info = TALLOC_REALLOC_ARRAY(mem_ctx, info, + struct spoolss_DriverFileInfo, + count + 1); + W_ERROR_HAVE_NO_MEMORY(info); + result = fill_spoolss_DriverFileInfo(info, + &info[count], + cservername, + driver->info_3->driverpath, + SPOOLSS_DRIVER_FILE_TYPE_RENDERING, + 0); + W_ERROR_NOT_OK_RETURN(result); + count++; + } + + if (strlen(driver->info_3->configfile)) { + info = TALLOC_REALLOC_ARRAY(mem_ctx, info, + struct spoolss_DriverFileInfo, + count + 1); + W_ERROR_HAVE_NO_MEMORY(info); + result = fill_spoolss_DriverFileInfo(info, + &info[count], + cservername, + driver->info_3->configfile, + SPOOLSS_DRIVER_FILE_TYPE_CONFIGURATION, + 0); + W_ERROR_NOT_OK_RETURN(result); + count++; + } + + if (strlen(driver->info_3->datafile)) { + info = TALLOC_REALLOC_ARRAY(mem_ctx, info, + struct spoolss_DriverFileInfo, + count + 1); + W_ERROR_HAVE_NO_MEMORY(info); + result = fill_spoolss_DriverFileInfo(info, + &info[count], + cservername, + driver->info_3->datafile, + SPOOLSS_DRIVER_FILE_TYPE_DATA, + 0); + W_ERROR_NOT_OK_RETURN(result); + count++; + } + + if (strlen(driver->info_3->helpfile)) { + info = TALLOC_REALLOC_ARRAY(mem_ctx, info, + struct spoolss_DriverFileInfo, + count + 1); + W_ERROR_HAVE_NO_MEMORY(info); + result = fill_spoolss_DriverFileInfo(info, + &info[count], + cservername, + driver->info_3->helpfile, + SPOOLSS_DRIVER_FILE_TYPE_HELP, + 0); + W_ERROR_NOT_OK_RETURN(result); + count++; + } + + for (i=0; driver->info_3->dependentfiles[i][0] != '\0'; i++) { + info = TALLOC_REALLOC_ARRAY(mem_ctx, info, + struct spoolss_DriverFileInfo, + count + 1); + W_ERROR_HAVE_NO_MEMORY(info); + result = fill_spoolss_DriverFileInfo(info, + &info[count], + cservername, + driver->info_3->dependentfiles[i], + SPOOLSS_DRIVER_FILE_TYPE_OTHER, + 0); + W_ERROR_NOT_OK_RETURN(result); + count++; + } + + *info_p = info; + *count_p = count; + + return WERR_OK; +} + +/******************************************************************** + * fill a spoolss_DriverInfo101 sttruct + ********************************************************************/ + +static WERROR fill_printer_driver_info101(TALLOC_CTX *mem_ctx, + struct spoolss_DriverInfo101 *r, + const NT_PRINTER_DRIVER_INFO_LEVEL *driver, + const char *servername) +{ + const char *cservername = canon_servername(servername); + WERROR result; + + r->version = driver->info_3->cversion; + + r->driver_name = talloc_strdup(mem_ctx, driver->info_3->name); + W_ERROR_HAVE_NO_MEMORY(r->driver_name); + r->architecture = talloc_strdup(mem_ctx, driver->info_3->environment); + W_ERROR_HAVE_NO_MEMORY(r->architecture); + + result = spoolss_DriverFileInfo_from_driver(mem_ctx, driver, + cservername, + &r->file_info, + &r->file_count); + if (!W_ERROR_IS_OK(result)) { + return result; + } + + r->monitor_name = talloc_strdup(mem_ctx, driver->info_3->monitorname); + W_ERROR_HAVE_NO_MEMORY(r->monitor_name); + + r->default_datatype = talloc_strdup(mem_ctx, driver->info_3->defaultdatatype); + W_ERROR_HAVE_NO_MEMORY(r->default_datatype); + + r->previous_names = string_array_from_driver_info(mem_ctx, + NULL, + cservername); + r->driver_date = 0; + r->driver_version = 0; + + r->manufacturer_name = talloc_strdup(mem_ctx, ""); + W_ERROR_HAVE_NO_MEMORY(r->manufacturer_name); + r->manufacturer_url = talloc_strdup(mem_ctx, ""); + W_ERROR_HAVE_NO_MEMORY(r->manufacturer_url); + r->hardware_id = talloc_strdup(mem_ctx, ""); + W_ERROR_HAVE_NO_MEMORY(r->hardware_id); + r->provider = talloc_strdup(mem_ctx, ""); + W_ERROR_HAVE_NO_MEMORY(r->provider); + + return WERR_OK; +} + +/******************************************************************** * construct_printer_driver_info_1 ********************************************************************/ @@ -5077,6 +5245,69 @@ static WERROR construct_printer_driver_info_6(TALLOC_CTX *mem_ctx, return status; } +/******************************************************************** + * construct_printer_info_101 + * fill a printer_info_101 struct + ********************************************************************/ + +static WERROR construct_printer_driver_info_101(TALLOC_CTX *mem_ctx, + struct spoolss_DriverInfo101 *r, + int snum, + const char *servername, + const char *architecture, + uint32_t version) +{ + NT_PRINTER_INFO_LEVEL *printer = NULL; + NT_PRINTER_DRIVER_INFO_LEVEL driver; + WERROR result; + + ZERO_STRUCT(driver); + + result = get_a_printer(NULL, &printer, 2, lp_const_servicename(snum)); + + DEBUG(8,("construct_printer_driver_info_101: status: %s\n", + win_errstr(result))); + + if (!W_ERROR_IS_OK(result)) { + return WERR_INVALID_PRINTER_NAME; + } + + result = get_a_printer_driver(&driver, 3, printer->info_2->drivername, + architecture, version); + + DEBUG(8,("construct_printer_driver_info_101: status: %s\n", + win_errstr(result))); + + if (!W_ERROR_IS_OK(result)) { + /* + * Is this a W2k client ? + */ + + if (version < 3) { + free_a_printer(&printer, 2); + return WERR_UNKNOWN_PRINTER_DRIVER; + } + + /* Yes - try again with a WinNT driver. */ + version = 2; + result = get_a_printer_driver(&driver, 3, printer->info_2->drivername, + architecture, version); + DEBUG(8,("construct_printer_driver_info_6: status: %s\n", + win_errstr(result))); + if (!W_ERROR_IS_OK(result)) { + free_a_printer(&printer, 2); + return WERR_UNKNOWN_PRINTER_DRIVER; + } + } + + result = fill_printer_driver_info101(mem_ctx, r, &driver, servername); + + free_a_printer(&printer, 2); + free_a_printer_driver(driver, 3); + + return result; +} + /**************************************************************** _spoolss_GetPrinterDriver2 ****************************************************************/ @@ -5146,13 +5377,15 @@ WERROR _spoolss_GetPrinterDriver2(pipes_struct *p, r->in.architecture, r->in.client_major_version); break; - default: -#if 0 /* JERRY */ case 101: - /* apparently this call is the equivalent of - EnumPrinterDataEx() for the DsDriver key */ + result = construct_printer_driver_info_101(p->mem_ctx, + &r->out.info->info101, + snum, + servername, + r->in.architecture, + r->in.client_major_version); break; -#endif + default: result = WERR_UNKNOWN_LEVEL; break; } diff --git a/source3/rpc_server/srv_svcctl_nt.c b/source3/rpc_server/srv_svcctl_nt.c index 3ca85aa755..0b0ef83bee 100644 --- a/source3/rpc_server/srv_svcctl_nt.c +++ b/source3/rpc_server/srv_svcctl_nt.c @@ -32,8 +32,6 @@ struct service_control_op { SERVICE_CONTROL_OPS *ops; }; -#define SVCCTL_NUM_INTERNAL_SERVICES 4 - /* handle external services */ extern SERVICE_CONTROL_OPS rcinit_svc_ops; @@ -446,7 +444,7 @@ WERROR _svcctl_EnumServicesStatusW(pipes_struct *p, buffer_size += buffer_size % 4; - if (buffer_size > r->in.buf_size ) { + if (buffer_size > r->in.offered) { num_services = 0; result = WERR_MORE_DATA; } @@ -468,10 +466,10 @@ WERROR _svcctl_EnumServicesStatusW(pipes_struct *p, } blob = ndr_push_blob(ndr); + memcpy(r->out.service, blob.data, r->in.offered); } - r->out.service = blob.data; - *r->out.bytes_needed = (buffer_size > r->in.buf_size) ? buffer_size : r->in.buf_size; + *r->out.needed = (buffer_size > r->in.offered) ? buffer_size : r->in.offered; *r->out.services_returned = (uint32)num_services; *r->out.resume_handle = 0x0; @@ -548,11 +546,20 @@ WERROR _svcctl_EnumDependentServicesW(pipes_struct *p, if ( !(info->access_granted & SC_RIGHT_SVC_ENUMERATE_DEPENDENTS) ) return WERR_ACCESS_DENIED; + switch (r->in.state) { + case SERVICE_STATE_ACTIVE: + case SERVICE_STATE_INACTIVE: + case SERVICE_STATE_ALL: + break; + default: + return WERR_INVALID_PARAM; + } + /* we have to set the outgoing buffer size to the same as the incoming buffer size (even in the case of failure */ /* this is done in the autogenerated server already - gd */ - *r->out.bytes_needed = r->in.buf_size; + *r->out.needed = r->in.offered; /* no dependent services...basically a stub function */ *r->out.services_returned = 0; @@ -580,7 +587,7 @@ WERROR _svcctl_QueryServiceStatusEx(pipes_struct *p, /* we have to set the outgoing buffer size to the same as the incoming buffer size (even in the case of failure) */ - *r->out.bytes_needed = r->in.buf_size; + *r->out.needed = r->in.offered; switch ( r->in.info_level ) { case SVC_STATUS_PROCESS_INFO: @@ -612,9 +619,9 @@ WERROR _svcctl_QueryServiceStatusEx(pipes_struct *p, buffer_size += buffer_size % 4; - *r->out.bytes_needed = (buffer_size > r->in.buf_size) ? buffer_size : r->in.buf_size; + *r->out.needed = (buffer_size > r->in.offered) ? buffer_size : r->in.offered; - if (buffer_size > r->in.buf_size ) { + if (buffer_size > r->in.offered ) { return WERR_INSUFFICIENT_BUFFER; } @@ -697,7 +704,7 @@ WERROR _svcctl_QueryServiceConfigW(pipes_struct *p, /* we have to set the outgoing buffer size to the same as the incoming buffer size (even in the case of failure */ - *r->out.bytes_needed = r->in.buf_size; + *r->out.needed = r->in.offered; wresult = fill_svc_config( p->mem_ctx, info->name, r->out.query, p->server_info->ptok); @@ -705,9 +712,9 @@ WERROR _svcctl_QueryServiceConfigW(pipes_struct *p, return wresult; buffer_size = ndr_size_QUERY_SERVICE_CONFIG(r->out.query, NULL, 0); - *r->out.bytes_needed = (buffer_size > r->in.buf_size) ? buffer_size : r->in.buf_size; + *r->out.needed = (buffer_size > r->in.offered) ? buffer_size : r->in.offered; - if (buffer_size > r->in.buf_size ) { + if (buffer_size > r->in.offered ) { ZERO_STRUCTP(r->out.query); return WERR_INSUFFICIENT_BUFFER; } @@ -735,7 +742,7 @@ WERROR _svcctl_QueryServiceConfig2W(pipes_struct *p, /* we have to set the outgoing buffer size to the same as the incoming buffer size (even in the case of failure */ - *r->out.bytes_needed = r->in.buf_size; + *r->out.needed = r->in.offered; switch ( r->in.info_level ) { case SERVICE_CONFIG_DESCRIPTION: @@ -792,9 +799,9 @@ WERROR _svcctl_QueryServiceConfig2W(pipes_struct *p, } buffer_size += buffer_size % 4; - *r->out.bytes_needed = (buffer_size > r->in.buf_size) ? buffer_size : r->in.buf_size; + *r->out.needed = (buffer_size > r->in.offered) ? buffer_size : r->in.offered; - if (buffer_size > r->in.buf_size ) + if (buffer_size > r->in.offered) return WERR_INSUFFICIENT_BUFFER; return WERR_OK; @@ -874,8 +881,7 @@ WERROR _svcctl_QueryServiceObjectSecurity(pipes_struct *p, *r->out.needed = ndr_size_security_descriptor( sec_desc, NULL, 0 ); - if ( *r->out.needed > r->in.buffer_size ) { - ZERO_STRUCTP( &r->out.buffer ); + if ( *r->out.needed > r->in.offered) { return WERR_INSUFFICIENT_BUFFER; } @@ -934,7 +940,8 @@ WERROR _svcctl_SetServiceObjectSecurity(pipes_struct *p, /* read the security descfriptor */ status = unmarshall_sec_desc(p->mem_ctx, - r->in.buffer, r->in.buffer_size, + r->in.buffer, + r->in.offered, &sec_desc); if (!NT_STATUS_IS_OK(status)) { return ntstatus_to_werror(status); diff --git a/source3/rpc_server/srv_util.c b/source3/rpc_server/srv_util.c deleted file mode 100644 index b276e75faa..0000000000 --- a/source3/rpc_server/srv_util.c +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Unix SMB/CIFS implementation. - * RPC Pipe client / server routines - * Copyright (C) Andrew Tridgell 1992-1998 - * Copyright (C) Luke Kenneth Casson Leighton 1996-1998, - * Copyright (C) Paul Ashton 1997-1998, - * Copyright (C) Andrew Bartlett 2004. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 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/>. - */ - -/* this module apparently provides an implementation of DCE/RPC over a - * named pipe (IPC$ connection using SMBtrans). details of DCE/RPC - * documentation are available (in on-line form) from the X-Open group. - * - * this module should provide a level of abstraction between SMB - * and DCE/RPC, while minimising the amount of mallocs, unnecessary - * data copies, and network traffic. - * - * in this version, which takes a "let's learn what's going on and - * get something running" approach, there is additional network - * traffic generated, but the code should be easier to understand... - * - * ... if you read the docs. or stare at packets for weeks on end. - * - */ - -#include "includes.h" - -#undef DBGC_CLASS -#define DBGC_CLASS DBGC_RPC_SRV - -#if 0 /* these aren't used currently but are here if you need them */ - -typedef struct { - uint32 rid; - const char *name; -} rid_name; - -/* - * A list of the rids of well known BUILTIN and Domain users - * and groups. - */ - -static const rid_name builtin_alias_rids[] = -{ - { BUILTIN_ALIAS_RID_ADMINS , "Administrators" }, - { BUILTIN_ALIAS_RID_USERS , "Users" }, - { BUILTIN_ALIAS_RID_GUESTS , "Guests" }, - { BUILTIN_ALIAS_RID_POWER_USERS , "Power Users" }, - - { BUILTIN_ALIAS_RID_ACCOUNT_OPS , "Account Operators" }, - { BUILTIN_ALIAS_RID_SYSTEM_OPS , "System Operators" }, - { BUILTIN_ALIAS_RID_PRINT_OPS , "Print Operators" }, - { BUILTIN_ALIAS_RID_BACKUP_OPS , "Backup Operators" }, - { BUILTIN_ALIAS_RID_REPLICATOR , "Replicator" }, - { 0 , NULL } -}; - -/* array lookup of well-known Domain RID users. */ -static const rid_name domain_user_rids[] = -{ - { DOMAIN_USER_RID_ADMIN , "Administrator" }, - { DOMAIN_USER_RID_GUEST , "Guest" }, - { 0 , NULL } -}; - -/* array lookup of well-known Domain RID groups. */ -static const rid_name domain_group_rids[] = -{ - { DOMAIN_GROUP_RID_ADMINS , "Domain Admins" }, - { DOMAIN_GROUP_RID_USERS , "Domain Users" }, - { DOMAIN_GROUP_RID_GUESTS , "Domain Guests" }, - { 0 , NULL } -}; -#endif - diff --git a/source3/rpcclient/cmd_ntsvcs.c b/source3/rpcclient/cmd_ntsvcs.c index eb620d06b2..a345cdc8bf 100644 --- a/source3/rpcclient/cmd_ntsvcs.c +++ b/source3/rpcclient/cmd_ntsvcs.c @@ -235,17 +235,21 @@ static WERROR cmd_ntsvcs_get_dev_list(struct rpc_pipe_client *cli, uint32_t length = 0; uint32_t flags = 0; - if (argc > 3) { - printf("usage: %s [length] [filter]\n", argv[0]); + if (argc > 4) { + printf("usage: %s [filter] [length] [flags]\n", argv[0]); return WERR_OK; } if (argc >= 2) { - length = atoi(argv[1]); + filter = argv[1]; } if (argc >= 3) { - filter = argv[2]; + length = atoi(argv[2]); + } + + if (argc >= 4) { + flags = atoi(argv[3]); } buffer = talloc(mem_ctx, uint16_t); diff --git a/source3/script/tests/selftest.sh b/source3/script/tests/selftest.sh index a430d01a0e..60b71a5adc 100755 --- a/source3/script/tests/selftest.sh +++ b/source3/script/tests/selftest.sh @@ -268,6 +268,7 @@ EOF ## cat >$NSS_WRAPPER_PASSWD<<EOF +root:x:65533:65532:root gecos:$PREFIX_ABS:/bin/false nobody:x:65534:65533:nobody gecos:$PREFIX_ABS:/bin/false $USERNAME:x:$USERID:$GROUPID:$USERNAME gecos:$PREFIX_ABS:/bin/false EOF @@ -282,7 +283,7 @@ MAKE_TEST_BINARY="bin/smbpasswd" export MAKE_TEST_BINARY (echo $PASSWORD; echo $PASSWORD) | \ - bin/smbpasswd -c $CONFFILE -L -s -a $USERNAME >/dev/null || exit 1 + bin/smbpasswd -c $SERVERCONFFILE -L -s -a $USERNAME >/dev/null || exit 1 echo "DONE"; diff --git a/source3/script/tests/test_posix_s3.sh b/source3/script/tests/test_posix_s3.sh index 0885b139bb..b3a66e1db7 100755 --- a/source3/script/tests/test_posix_s3.sh +++ b/source3/script/tests/test_posix_s3.sh @@ -40,6 +40,7 @@ raw="$raw RAW-SAMBA3ROOTDIRFID" rpc="RPC-AUTHCONTEXT RPC-BINDSAMBA3 RPC-SAMBA3-SRVSVC RPC-SAMBA3-SHARESEC" rpc="$rpc RPC-SAMBA3-SPOOLSS RPC-SAMBA3-WKSSVC" rpc="$rpc RPC-NETLOGSAMBA3 RPC-SAMBA3SESSIONKEY RPC-SAMBA3-GETUSERNAME" +rpc="$rpc RPC-SVCCTL RPC-SPOOLSS-WIN RPC-NTSVCS" # NOTE: to enable the UNIX-WHOAMI test, we need to change the default share # config to allow guest access. I'm not sure whether this would break other diff --git a/source3/smbd/ipc.c b/source3/smbd/ipc.c index d39aab4f47..2d5713590d 100644 --- a/source3/smbd/ipc.c +++ b/source3/smbd/ipc.c @@ -754,6 +754,8 @@ void reply_trans(struct smb_request *req) return; } + talloc_steal(talloc_tos(), state); + handle_trans(conn, req, state); SAFE_FREE(state->data); @@ -852,6 +854,8 @@ void reply_transs(struct smb_request *req) return; } + talloc_steal(talloc_tos(), state); + handle_trans(conn, req, state); DLIST_REMOVE(conn->pending_trans, state); diff --git a/source3/smbd/oplock.c b/source3/smbd/oplock.c index ce00397bbd..b937e8e07d 100644 --- a/source3/smbd/oplock.c +++ b/source3/smbd/oplock.c @@ -344,6 +344,54 @@ static void add_oplock_timeout_handler(files_struct *fsp) } } +void break_level2_to_none_async(files_struct *fsp) +{ + char *break_msg; + + if (fsp->oplock_type == NO_OPLOCK) { + /* We already got a "break to none" message and we've handled + * it. just ignore. */ + DEBUG(3, ("process_oplock_async_level2_break_message: already " + "broken to none, ignoring.\n")); + return; + } + + if (fsp->oplock_type == FAKE_LEVEL_II_OPLOCK) { + /* Don't tell the client, just downgrade. */ + DEBUG(3, ("process_oplock_async_level2_break_message: " + "downgrading fake level 2 oplock.\n")); + remove_oplock(fsp); + return; + } + + /* Ensure we're really at level2 state. */ + SMB_ASSERT(fsp->oplock_type == LEVEL_II_OPLOCK); + + DEBUG(10,("process_oplock_async_level2_break_message: sending break " + "to none message for fid %d, file %s\n", fsp->fnum, + fsp->fsp_name)); + + /* Now send a break to none message to our client. */ + break_msg = new_break_smb_message(NULL, fsp, OPLOCKLEVEL_NONE); + if (break_msg == NULL) { + exit_server("Could not talloc break_msg\n"); + } + + show_msg(break_msg); + if (!srv_send_smb(smbd_server_fd(), + break_msg, false, 0, + IS_CONN_ENCRYPTED(fsp->conn), + NULL)) { + exit_server_cleanly("oplock_break: srv_send_smb failed."); + } + + TALLOC_FREE(break_msg); + + /* Async level2 request, don't send a reply, just remove the oplock. */ + remove_oplock(fsp); + +} + /******************************************************************* This handles the case of a write triggering a break to none message on a level2 oplock. @@ -360,7 +408,6 @@ void process_oplock_async_level2_break_message(struct messaging_context *msg_ctx { struct share_mode_entry msg; files_struct *fsp; - char *break_msg; if (data->data == NULL) { DEBUG(0, ("Got NULL buffer\n")); @@ -375,8 +422,9 @@ void process_oplock_async_level2_break_message(struct messaging_context *msg_ctx /* De-linearize incoming message. */ message_to_share_mode_entry(&msg, (char *)data->data); - DEBUG(10, ("Got oplock async level 2 break message from pid %d: %s/%lu\n", - (int)procid_to_pid(&src), file_id_string_tos(&msg.id), msg.share_file_id)); + DEBUG(10, ("Got oplock async level 2 break message from pid %s: " + "%s/%lu\n", procid_str(debug_ctx(), &src), + file_id_string_tos(&msg.id), msg.share_file_id)); fsp = initial_break_processing(msg.id, msg.share_file_id); @@ -388,52 +436,7 @@ void process_oplock_async_level2_break_message(struct messaging_context *msg_ctx return; } - if (fsp->oplock_type == NO_OPLOCK) { - /* We already got a "break to none" message and we've handled it. - * just ignore. */ - DEBUG(3, ("process_oplock_async_level2_break_message: already broken to none, ignoring.\n")); - return; - } - - if (fsp->oplock_type == FAKE_LEVEL_II_OPLOCK) { - /* Don't tell the client, just downgrade. */ - DEBUG(3, ("process_oplock_async_level2_break_message: downgrading fake level 2 oplock.\n")); - remove_oplock(fsp); - return; - } - - /* Ensure we're really at level2 state. */ - SMB_ASSERT(fsp->oplock_type == LEVEL_II_OPLOCK); - - DEBUG(10,("process_oplock_async_level2_break_message: sending break to " - "none message for fid %d, file %s\n", - fsp->fnum, - fsp->fsp_name)); - - /* Now send a break to none message to our client. */ - - break_msg = new_break_smb_message(NULL, fsp, OPLOCKLEVEL_NONE); - if (break_msg == NULL) { - exit_server("Could not talloc break_msg\n"); - } - - /* Need to wait before sending a break message if we sent ourselves this message. */ - if (procid_to_pid(&src) == sys_getpid()) { - wait_before_sending_break(); - } - - show_msg(break_msg); - if (!srv_send_smb(smbd_server_fd(), - break_msg, false, 0, - IS_CONN_ENCRYPTED(fsp->conn), - NULL)) { - exit_server_cleanly("oplock_break: srv_send_smb failed."); - } - - TALLOC_FREE(break_msg); - - /* Async level2 request, don't send a reply, just remove the oplock. */ - remove_oplock(fsp); + break_level2_to_none_async(fsp); } /******************************************************************* @@ -464,8 +467,9 @@ static void process_oplock_break_message(struct messaging_context *msg_ctx, /* De-linearize incoming message. */ message_to_share_mode_entry(&msg, (char *)data->data); - DEBUG(10, ("Got oplock break message from pid %d: %s/%lu\n", - (int)procid_to_pid(&src), file_id_string_tos(&msg.id), msg.share_file_id)); + DEBUG(10, ("Got oplock break message from pid %s: %s/%lu\n", + procid_str(debug_ctx(), &src), file_id_string_tos(&msg.id), + msg.share_file_id)); fsp = initial_break_processing(msg.id, msg.share_file_id); @@ -518,7 +522,7 @@ static void process_oplock_break_message(struct messaging_context *msg_ctx, } /* Need to wait before sending a break message if we sent ourselves this message. */ - if (procid_to_pid(&src) == sys_getpid()) { + if (procid_is_me(&src)) { wait_before_sending_break(); } @@ -571,8 +575,8 @@ static void process_kernel_oplock_break(struct messaging_context *msg_ctx, pull_file_id_24((char *)data->data, &id); file_id = (unsigned long)IVAL(data->data, 24); - DEBUG(10, ("Got kernel oplock break message from pid %d: %s/%u\n", - (int)procid_to_pid(&src), file_id_string_tos(&id), + DEBUG(10, ("Got kernel oplock break message from pid %s: %s/%u\n", + procid_str(debug_ctx(), &src), file_id_string_tos(&id), (unsigned int)file_id)); fsp = initial_break_processing(id, file_id); @@ -667,9 +671,9 @@ static void process_oplock_break_response(struct messaging_context *msg_ctx, /* De-linearize incoming message. */ message_to_share_mode_entry(&msg, (char *)data->data); - DEBUG(10, ("Got oplock break response from pid %d: %s/%lu mid %u\n", - (int)procid_to_pid(&src), file_id_string_tos(&msg.id), msg.share_file_id, - (unsigned int)msg.op_mid)); + DEBUG(10, ("Got oplock break response from pid %s: %s/%lu mid %u\n", + procid_str(debug_ctx(), &src), file_id_string_tos(&msg.id), + msg.share_file_id, (unsigned int)msg.op_mid)); /* Here's the hack from open.c, store the mid in the 'port' field */ schedule_deferred_open_smb_message(msg.op_mid); @@ -696,8 +700,8 @@ static void process_open_retry_message(struct messaging_context *msg_ctx, /* De-linearize incoming message. */ message_to_share_mode_entry(&msg, (char *)data->data); - DEBUG(10, ("Got open retry msg from pid %d: %s mid %u\n", - (int)procid_to_pid(&src), file_id_string_tos(&msg.id), + DEBUG(10, ("Got open retry msg from pid %s: %s mid %u\n", + procid_str(debug_ctx(), &src), file_id_string_tos(&msg.id), (unsigned int)msg.op_mid)); schedule_deferred_open_smb_message(msg.op_mid); @@ -788,13 +792,8 @@ static void contend_level2_oplocks_begin_default(files_struct *fsp, */ if (procid_is_me(&share_entry->pid)) { - DATA_BLOB blob = data_blob_const(msg, - MSG_SMB_SHARE_MODE_ENTRY_SIZE); - process_oplock_async_level2_break_message(smbd_messaging_context(), - NULL, - MSG_SMB_ASYNC_LEVEL2_BREAK, - share_entry->pid, - &blob); + wait_before_sending_break(); + break_level2_to_none_async(fsp); } else { messaging_send_buf(smbd_messaging_context(), share_entry->pid, diff --git a/source3/smbd/oplock_onefs.c b/source3/smbd/oplock_onefs.c index d4f181fc47..b69d937915 100644 --- a/source3/smbd/oplock_onefs.c +++ b/source3/smbd/oplock_onefs.c @@ -550,87 +550,18 @@ static void onefs_semlock_write(int fd, enum level2_contention_type type, * the cluster except the fsp's own level 2 oplock. This lack of * self-contention is a limitation of the current OneFS kernel oplocks * implementation. Luckily it is easy to contend our own level 2 oplock by - * iterating the share mode entries and only breaking the oplock if the pid - * matches our's. + * checking the the fsp's oplock_type. If it's a level2, send a break message + * to the client and remove the oplock. */ static void onefs_contend_level2_oplocks_begin(files_struct *fsp, enum level2_contention_type type) { - int i; - struct share_mode_lock *lck; - /* Take care of level 2 kernel contention. */ onefs_semlock_write(fsp->fh->fd, type, SEMLOCK_LOCK); - /* - * If this file is level II oplocked then we need - * to grab the shared memory lock and inform all - * other files with a level II lock that they need - * to flush their read caches. We keep the lock over - * the shared memory area whilst doing this. - */ - - if (!LEVEL_II_OPLOCK_TYPE(fsp->oplock_type)) - return; - - lck = get_share_mode_lock(talloc_tos(), fsp->file_id, NULL, NULL, - NULL); - if (lck == NULL) { - DEBUG(0,("onefs_contend_level2_oplocks_begin: failed to lock " - "share mode entry for file %s.\n", fsp->fsp_name )); - return; - } - - DEBUG(10,("onefs_contend_level2_oplocks_begin: num_share_modes = %d\n", - lck->num_share_modes )); - - for(i = 0; i < lck->num_share_modes; i++) { - struct share_mode_entry *share_entry = &lck->share_modes[i]; - char msg[MSG_SMB_SHARE_MODE_ENTRY_SIZE]; - - if (!is_valid_share_mode_entry(share_entry)) { - continue; - } - - DEBUG(10,("onefs_contend_level2_oplocks_begin: " - "share_entry[%i]->op_type == %d\n", - i, share_entry->op_type )); - - if (share_entry->op_type == NO_OPLOCK) { - continue; - } - - /* Paranoia .... */ - if (EXCLUSIVE_OPLOCK_TYPE(share_entry->op_type)) { - DEBUG(0,("onefs_contend_level2_oplocks_begin: PANIC. " - "share mode entry %d is an exlusive " - "oplock !\n", i )); - TALLOC_FREE(lck); - abort(); - } - - share_mode_entry_to_message(msg, share_entry); - - /* - * Only contend our own level 2 oplock. The other processes - * will be get break events from the kernel. - */ - if (procid_is_me(&share_entry->pid)) { - DATA_BLOB blob = data_blob_const(msg, - MSG_SMB_SHARE_MODE_ENTRY_SIZE); - process_oplock_async_level2_break_message( - smbd_messaging_context(), - NULL, - MSG_SMB_ASYNC_LEVEL2_BREAK, - share_entry->pid, - &blob); - } - } - - /* We let the message receivers handle removing the oplock state - in the share mode lock db. */ - - TALLOC_FREE(lck); + /* Take care of level 2 self contention. */ + if (LEVEL_II_OPLOCK_TYPE(fsp->oplock_type)) + break_level2_to_none_async(fsp); } /** diff --git a/source3/smbd/sesssetup.c b/source3/smbd/sesssetup.c index e8878a29ab..d524f21817 100644 --- a/source3/smbd/sesssetup.c +++ b/source3/smbd/sesssetup.c @@ -333,7 +333,6 @@ static void reply_spnego_kerberos(struct smb_request *req, DEBUG(3,("Doesn't look like a valid principal\n")); data_blob_free(&ap_rep); data_blob_free(&session_key); - SAFE_FREE(client); talloc_destroy(mem_ctx); reply_nterror(req,nt_status_squash(NT_STATUS_LOGON_FAILURE)); return; @@ -355,7 +354,6 @@ static void reply_spnego_kerberos(struct smb_request *req, if (!lp_allow_trusted_domains()) { data_blob_free(&ap_rep); data_blob_free(&session_key); - SAFE_FREE(client); talloc_destroy(mem_ctx); reply_nterror(req, nt_status_squash( NT_STATUS_LOGON_FAILURE)); @@ -445,7 +443,6 @@ static void reply_spnego_kerberos(struct smb_request *req, if ( !pw ) { DEBUG(1,("Username %s is invalid on this system\n", user)); - SAFE_FREE(client); data_blob_free(&ap_rep); data_blob_free(&session_key); TALLOC_FREE(mem_ctx); @@ -471,7 +468,6 @@ static void reply_spnego_kerberos(struct smb_request *req, if ( !NT_STATUS_IS_OK(ret) ) { DEBUG(1,("make_server_info_info3 failed: %s!\n", nt_errstr(ret))); - SAFE_FREE(client); data_blob_free(&ap_rep); data_blob_free(&session_key); TALLOC_FREE(mem_ctx); @@ -485,7 +481,6 @@ static void reply_spnego_kerberos(struct smb_request *req, if ( !NT_STATUS_IS_OK(ret) ) { DEBUG(1,("make_server_info_pw failed: %s!\n", nt_errstr(ret))); - SAFE_FREE(client); data_blob_free(&ap_rep); data_blob_free(&session_key); TALLOC_FREE(mem_ctx); @@ -513,7 +508,6 @@ static void reply_spnego_kerberos(struct smb_request *req, if ( !NT_STATUS_IS_OK(ret) ) { DEBUG(10,("failed to create local token: %s\n", nt_errstr(ret))); - SAFE_FREE(client); data_blob_free(&ap_rep); data_blob_free(&session_key); TALLOC_FREE( mem_ctx ); @@ -541,8 +535,6 @@ static void reply_spnego_kerberos(struct smb_request *req, nullblob, client); - SAFE_FREE(client); - reply_outbuf(req, 4, 0); SSVAL(req->outbuf,smb_uid,sess_vuid); diff --git a/source3/torture/t_push_ucs2.c b/source3/torture/t_push_ucs2.c index b9bf87ba54..2bd91dafde 100644 --- a/source3/torture/t_push_ucs2.c +++ b/source3/torture/t_push_ucs2.c @@ -14,16 +14,16 @@ static int check_push_ucs2(const char *orig) int ret; size_t converted_size; - push_ucs2_allocate(&dest, orig, &converted_size); - pull_ucs2_allocate(&orig2, dest, &converted_size); + push_ucs2_talloc(NULL, &dest, orig, &converted_size); + pull_ucs2_talloc(NULL, &orig2, dest, &converted_size); ret = strcmp(orig, orig2); if (ret) { fprintf(stderr, "orig: %s\n", orig); fprintf(stderr, "orig (UNIX -> UCS2 -> UNIX): %s\n", orig2); } - SAFE_FREE(dest); - SAFE_FREE(orig2); + TALLOC_FREE(dest); + TALLOC_FREE(orig2); return ret; } diff --git a/source3/torture/torture.c b/source3/torture/torture.c index 1b9e394a68..804e772516 100644 --- a/source3/torture/torture.c +++ b/source3/torture/torture.c @@ -273,6 +273,10 @@ static bool torture_open_connection_share(struct cli_state **c, if (use_kerberos) flags |= CLI_FULL_CONNECTION_USE_KERBEROS; + if (use_oplocks) + flags |= CLI_FULL_CONNECTION_OPLOCKS; + if (use_level_II_oplocks) + flags |= CLI_FULL_CONNECTION_LEVEL_II_OPLOCKS; status = cli_full_connection(c, myname, hostname, NULL, port_to_use, @@ -285,8 +289,6 @@ static bool torture_open_connection_share(struct cli_state **c, return False; } - if (use_oplocks) (*c)->use_oplocks = True; - if (use_level_II_oplocks) (*c)->use_level_II_oplocks = True; (*c)->timeout = 120000; /* set a really long timeout (2 minutes) */ if (do_encrypt) { @@ -5023,11 +5025,10 @@ static bool subst_test(const char *str, const char *user, const char *domain, return result; } -static void chain1_open_completion(struct async_req *req) +static void chain1_open_completion(struct tevent_req *req) { int fnum; NTSTATUS status; - status = cli_open_recv(req, &fnum); TALLOC_FREE(req); @@ -5036,48 +5037,25 @@ static void chain1_open_completion(struct async_req *req) NT_STATUS_IS_OK(status) ? fnum : -1); } -static void chain1_read_completion(struct async_req *req) +static void chain1_write_completion(struct tevent_req *req) { - NTSTATUS status; - ssize_t received; - uint8_t *rcvbuf; - - status = cli_read_andx_recv(req, &received, &rcvbuf); - if (!NT_STATUS_IS_OK(status)) { - TALLOC_FREE(req); - d_printf("cli_read_andx_recv returned %s\n", - nt_errstr(status)); - return; - } - - d_printf("got %d bytes: %.*s\n", (int)received, (int)received, - (char *)rcvbuf); - TALLOC_FREE(req); -} - -static void chain1_write_completion(struct async_req *req) -{ - NTSTATUS status; size_t written; - + NTSTATUS status; status = cli_write_andx_recv(req, &written); - if (!NT_STATUS_IS_OK(status)) { - TALLOC_FREE(req); - d_printf("cli_write_andx_recv returned %s\n", - nt_errstr(status)); - return; - } - - d_printf("wrote %d bytes\n", (int)written); TALLOC_FREE(req); + + d_printf("cli_write_andx_recv returned %s: %d\n", + nt_errstr(status), + NT_STATUS_IS_OK(status) ? (int)written : -1); } -static void chain1_close_completion(struct async_req *req) +static void chain1_close_completion(struct tevent_req *req) { NTSTATUS status; + bool *done = (bool *)tevent_req_callback_data_void(req); status = cli_close_recv(req); - *((bool *)(req->async.priv)) = true; + *done = true; TALLOC_FREE(req); @@ -5088,9 +5066,9 @@ static bool run_chain1(int dummy) { struct cli_state *cli1; struct event_context *evt = event_context_init(NULL); - struct async_req *reqs[4]; + struct tevent_req *reqs[3], *smbreqs[3]; bool done = false; - const char *text = "hallo"; + const char *str = "foobar"; printf("starting chain1 test\n"); if (!torture_open_connection(&cli1, 0)) { @@ -5099,19 +5077,25 @@ static bool run_chain1(int dummy) cli_sockopt(cli1, sockops); - cli_chain_cork(cli1, evt, 0); - reqs[0] = cli_open_send(talloc_tos(), evt, cli1, "\\test", - O_CREAT|O_RDWR, 0); - reqs[0]->async.fn = chain1_open_completion; - reqs[1] = cli_write_andx_send(talloc_tos(), evt, cli1, 0, 0, - (uint8_t *)text, 0, strlen(text)); - reqs[1]->async.fn = chain1_write_completion; - reqs[2] = cli_read_andx_send(talloc_tos(), evt, cli1, 0, 1, 10); - reqs[2]->async.fn = chain1_read_completion; - reqs[3] = cli_close_send(talloc_tos(), evt, cli1, 0); - reqs[3]->async.fn = chain1_close_completion; - reqs[3]->async.priv = (void *)&done; - cli_chain_uncork(cli1); + reqs[0] = cli_open_create(talloc_tos(), evt, cli1, "\\test", + O_CREAT|O_RDWR, 0, &smbreqs[0]); + if (reqs[0] == NULL) return false; + tevent_req_set_callback(reqs[0], chain1_open_completion, NULL); + + + reqs[1] = cli_write_andx_create(talloc_tos(), evt, cli1, 0, 0, + (uint8_t *)str, 0, strlen(str)+1, + smbreqs, 1, &smbreqs[1]); + if (reqs[1] == NULL) return false; + tevent_req_set_callback(reqs[1], chain1_write_completion, NULL); + + reqs[2] = cli_close_create(talloc_tos(), evt, cli1, 0, &smbreqs[2]); + if (reqs[2] == NULL) return false; + tevent_req_set_callback(reqs[2], chain1_close_completion, &done); + + if (!cli_smb_chain_send(smbreqs, ARRAY_SIZE(smbreqs))) { + return false; + } while (!done) { event_loop_once(evt); @@ -5199,8 +5183,6 @@ static bool run_windows_write(int dummy) static bool run_cli_echo(int dummy) { struct cli_state *cli; - struct event_context *ev = event_context_init(NULL); - struct async_req *req; NTSTATUS status; printf("starting cli_echo test\n"); @@ -5209,21 +5191,10 @@ static bool run_cli_echo(int dummy) } cli_sockopt(cli, sockops); - req = cli_echo_send(ev, ev, cli, 5, data_blob_const("hello", 5)); - if (req == NULL) { - d_printf("cli_echo_send failed\n"); - return false; - } - - while (req->state < ASYNC_REQ_DONE) { - event_loop_once(ev); - } + status = cli_echo(cli, 5, data_blob_const("hello", 5)); - status = cli_echo_recv(req); d_printf("cli_echo returned %s\n", nt_errstr(status)); - TALLOC_FREE(req); - torture_close_connection(cli); return NT_STATUS_IS_OK(status); } diff --git a/source3/utils/net_ads.c b/source3/utils/net_ads.c index 2a66619438..8e927becbe 100644 --- a/source3/utils/net_ads.c +++ b/source3/utils/net_ads.c @@ -503,9 +503,9 @@ static int ads_user_add(struct net_context *c, int argc, const char **argv) ads_msgfree(ads, res); status=ads_find_user_acct(ads, &res, argv[0]); if (ADS_ERR_OK(status)) { - userdn = ads_get_dn(ads, res); + userdn = ads_get_dn(ads, talloc_tos(), res); ads_del_dn(ads, userdn); - ads_memfree(ads, userdn); + TALLOC_FREE(userdn); } done: @@ -598,10 +598,10 @@ static int ads_user_delete(struct net_context *c, int argc, const char **argv) ads_destroy(&ads); return -1; } - userdn = ads_get_dn(ads, res); + userdn = ads_get_dn(ads, talloc_tos(), res); ads_msgfree(ads, res); rc = ads_del_dn(ads, userdn); - ads_memfree(ads, userdn); + TALLOC_FREE(userdn); if (ADS_ERR_OK(rc)) { d_printf("User %s deleted\n", argv[0]); ads_destroy(&ads); @@ -757,10 +757,10 @@ static int ads_group_delete(struct net_context *c, int argc, const char **argv) ads_destroy(&ads); return -1; } - groupdn = ads_get_dn(ads, res); + groupdn = ads_get_dn(ads, talloc_tos(), res); ads_msgfree(ads, res); rc = ads_del_dn(ads, groupdn); - ads_memfree(ads, groupdn); + TALLOC_FREE(groupdn); if (ADS_ERR_OK(rc)) { d_printf("Group %s deleted\n", argv[0]); ads_destroy(&ads); @@ -1740,10 +1740,10 @@ static int net_ads_printer_remove(struct net_context *c, int argc, const char ** return -1; } - prt_dn = ads_get_dn(ads, res); + prt_dn = ads_get_dn(ads, talloc_tos(), res); ads_msgfree(ads, res); rc = ads_del_dn(ads, prt_dn); - ads_memfree(ads, prt_dn); + TALLOC_FREE(prt_dn); if (!ADS_ERR_OK(rc)) { d_fprintf(stderr, "ads_del_dn: %s\n", ads_errstr(rc)); diff --git a/source3/utils/net_ads_gpo.c b/source3/utils/net_ads_gpo.c index 181cba221d..910c78d05a 100644 --- a/source3/utils/net_ads_gpo.c +++ b/source3/utils/net_ads_gpo.c @@ -257,7 +257,7 @@ static int net_ads_gpo_list_all(struct net_context *c, int argc, const char **ar msg; msg = ads_next_entry(ads, msg)) { - if ((dn = ads_get_dn(ads, msg)) == NULL) { + if ((dn = ads_get_dn(ads, mem_ctx, msg)) == NULL) { goto out; } @@ -266,18 +266,16 @@ static int net_ads_gpo_list_all(struct net_context *c, int argc, const char **ar if (!ADS_ERR_OK(status)) { d_printf("ads_parse_gpo failed: %s\n", ads_errstr(status)); - ads_memfree(ads, dn); goto out; } dump_gpo(ads, mem_ctx, &gpo, 0); - ads_memfree(ads, dn); } out: ads_msgfree(ads, res); - talloc_destroy(mem_ctx); + TALLOC_FREE(mem_ctx); ads_destroy(&ads); return 0; diff --git a/source3/utils/net_eventlog.c b/source3/utils/net_eventlog.c index 197a7cd330..b86be6d48b 100644 --- a/source3/utils/net_eventlog.c +++ b/source3/utils/net_eventlog.c @@ -182,13 +182,9 @@ static int net_eventlog_export(struct net_context *c, int argc, int ret = -1; NTSTATUS status; TALLOC_CTX *ctx = talloc_stackframe(); - enum ndr_err_code ndr_err; DATA_BLOB blob; uint32_t num_records = 0; - struct EVENTLOG_EVT_FILE evt; ELOG_TDB *etdb = NULL; - uint32_t count = 1; - size_t endoffset = 0; if (argc < 2 || c->display_usage) { d_fprintf(stderr, "usage: net eventlog export <file> <eventlog>\n"); @@ -201,54 +197,8 @@ static int net_eventlog_export(struct net_context *c, int argc, goto done; } - ZERO_STRUCT(evt); - - while (1) { - - struct eventlog_Record_tdb *r; - struct EVENTLOGRECORD e; - - r = evlog_pull_record_tdb(ctx, etdb->tdb, count); - if (!r) { - break; - } - - status = evlog_tdb_entry_to_evt_entry(ctx, r, &e); - if (!NT_STATUS_IS_OK(status)) { - goto done; - } - - endoffset += ndr_size_EVENTLOGRECORD(&e, NULL, 0); - - ADD_TO_ARRAY(ctx, struct EVENTLOGRECORD, e, &evt.records, &num_records); - count++; - } - - evt.hdr.StartOffset = 0x30; - evt.hdr.EndOffset = evt.hdr.StartOffset + endoffset; - evt.hdr.CurrentRecordNumber = count; - evt.hdr.OldestRecordNumber = 1; - evt.hdr.MaxSize = tdb_fetch_int32(etdb->tdb, EVT_MAXSIZE); - evt.hdr.Flags = 0; - evt.hdr.Retention = tdb_fetch_int32(etdb->tdb, EVT_RETENTION); - - if (DEBUGLEVEL >= 10) { - NDR_PRINT_DEBUG(EVENTLOGHEADER, &evt.hdr); - } - - evt.eof.BeginRecord = 0x30; - evt.eof.EndRecord = evt.hdr.StartOffset + endoffset; - evt.eof.CurrentRecordNumber = evt.hdr.CurrentRecordNumber; - evt.eof.OldestRecordNumber = evt.hdr.OldestRecordNumber; - - if (DEBUGLEVEL >= 10) { - NDR_PRINT_DEBUG(EVENTLOGEOF, &evt.eof); - } - - ndr_err = ndr_push_struct_blob(&blob, ctx, NULL, &evt, - (ndr_push_flags_fn_t)ndr_push_EVENTLOG_EVT_FILE); - if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { - d_fprintf(stderr, "evt push failed: %s\n", ndr_errstr(ndr_err)); + status = evlog_convert_tdb_to_evt(ctx, etdb, &blob, &num_records); + if (!NT_STATUS_IS_OK(status)) { goto done; } diff --git a/source3/utils/net_rpc_service.c b/source3/utils/net_rpc_service.c index bcb1a00dab..57a721e55b 100644 --- a/source3/utils/net_rpc_service.c +++ b/source3/utils/net_rpc_service.c @@ -631,6 +631,161 @@ done: /******************************************************************** ********************************************************************/ +static NTSTATUS rpc_service_delete_internal(struct net_context *c, + const DOM_SID *domain_sid, + const char *domain_name, + struct cli_state *cli, + struct rpc_pipe_client *pipe_hnd, + TALLOC_CTX *mem_ctx, + int argc, + const char **argv) +{ + struct policy_handle hSCM, hService; + WERROR result = WERR_GENERAL_FAILURE; + NTSTATUS status; + + if (argc != 1 ) { + d_printf("Usage: net rpc service delete <service>\n"); + return NT_STATUS_OK; + } + + /* Open the Service Control Manager */ + status = rpccli_svcctl_OpenSCManagerW(pipe_hnd, mem_ctx, + pipe_hnd->srv_name_slash, + NULL, + SC_RIGHT_MGR_ENUMERATE_SERVICE, + &hSCM, + &result); + if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(result)) { + d_fprintf(stderr, "Failed to open Service Control Manager. [%s]\n", + win_errstr(result)); + return werror_to_ntstatus(result); + } + + /* Open the Service */ + + status = rpccli_svcctl_OpenServiceW(pipe_hnd, mem_ctx, + &hSCM, + argv[0], + SERVICE_ALL_ACCESS, + &hService, + &result); + + if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(result) ) { + d_fprintf(stderr, "Failed to open service. [%s]\n", + win_errstr(result)); + goto done; + } + + /* Delete the Service */ + + status = rpccli_svcctl_DeleteService(pipe_hnd, mem_ctx, + &hService, + &result); + + if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(result) ) { + d_fprintf(stderr, "Delete service request failed. [%s]\n", + win_errstr(result)); + goto done; + } + + d_printf("Successfully deleted Service: %s\n", argv[0]); + + done: + if (is_valid_policy_hnd(&hService)) { + rpccli_svcctl_CloseServiceHandle(pipe_hnd, mem_ctx, &hService, NULL); + } + if (is_valid_policy_hnd(&hSCM)) { + rpccli_svcctl_CloseServiceHandle(pipe_hnd, mem_ctx, &hSCM, NULL); + } + + return werror_to_ntstatus(result); +} + +/******************************************************************** +********************************************************************/ + +static NTSTATUS rpc_service_create_internal(struct net_context *c, + const DOM_SID *domain_sid, + const char *domain_name, + struct cli_state *cli, + struct rpc_pipe_client *pipe_hnd, + TALLOC_CTX *mem_ctx, + int argc, + const char **argv) +{ + struct policy_handle hSCM, hService; + WERROR result = WERR_GENERAL_FAILURE; + NTSTATUS status; + const char *ServiceName; + const char *DisplayName; + const char *binary_path; + + if (argc != 3) { + d_printf("Usage: net rpc service create <service> <displayname> <binarypath>\n"); + return NT_STATUS_OK; + } + + /* Open the Service Control Manager */ + status = rpccli_svcctl_OpenSCManagerW(pipe_hnd, mem_ctx, + pipe_hnd->srv_name_slash, + NULL, + SC_RIGHT_MGR_CREATE_SERVICE, + &hSCM, + &result); + if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(result)) { + d_fprintf(stderr, "Failed to open Service Control Manager. [%s]\n", + win_errstr(result)); + return werror_to_ntstatus(result); + } + + /* Create the service */ + + ServiceName = argv[0]; + DisplayName = argv[1]; + binary_path = argv[2]; + + status = rpccli_svcctl_CreateServiceW(pipe_hnd, mem_ctx, + &hSCM, + ServiceName, + DisplayName, + SERVICE_ALL_ACCESS, + SERVICE_TYPE_WIN32_OWN_PROCESS, + SVCCTL_DEMAND_START, + SVCCTL_SVC_ERROR_NORMAL, + binary_path, + NULL, /* LoadOrderGroupKey */ + NULL, /* TagId */ + NULL, /* dependencies */ + 0, /* dependencies_size */ + NULL, /* service_start_name */ + NULL, /* password */ + 0, /* password_size */ + &hService, + &result); + + if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(result) ) { + d_fprintf(stderr, "Create service request failed. [%s]\n", + win_errstr(result)); + goto done; + } + + d_printf("Successfully created Service: %s\n", argv[0]); + + done: + if (is_valid_policy_hnd(&hService)) { + rpccli_svcctl_CloseServiceHandle(pipe_hnd, mem_ctx, &hService, NULL); + } + if (is_valid_policy_hnd(&hSCM)) { + rpccli_svcctl_CloseServiceHandle(pipe_hnd, mem_ctx, &hSCM, NULL); + } + + return werror_to_ntstatus(result); +} + +/******************************************************************** +********************************************************************/ + static int rpc_service_list(struct net_context *c, int argc, const char **argv ) { if (c->display_usage) { @@ -727,6 +882,38 @@ static int rpc_service_status(struct net_context *c, int argc, const char **argv /******************************************************************** ********************************************************************/ +static int rpc_service_delete(struct net_context *c, int argc, const char **argv) +{ + if (c->display_usage) { + d_printf("Usage:\n" + "net rpc service delete <service>\n" + " Delete a Win32 service\n"); + return 0; + } + + return run_rpc_command(c, NULL, &ndr_table_svcctl.syntax_id, 0, + rpc_service_delete_internal, argc, argv); +} + +/******************************************************************** +********************************************************************/ + +static int rpc_service_create(struct net_context *c, int argc, const char **argv) +{ + if (c->display_usage) { + d_printf("Usage:\n" + "net rpc service create <service>\n" + " Create a Win32 service\n"); + return 0; + } + + return run_rpc_command(c, NULL, &ndr_table_svcctl.syntax_id, 0, + rpc_service_create_internal, argc, argv); +} + +/******************************************************************** +********************************************************************/ + int net_rpc_service(struct net_context *c, int argc, const char **argv) { struct functable func[] = { @@ -778,6 +965,23 @@ int net_rpc_service(struct net_context *c, int argc, const char **argv) "net rpc service status\n" " View current status of a service" }, + { + "delete", + rpc_service_delete, + NET_TRANSPORT_RPC, + "Delete a service", + "net rpc service delete\n" + " Deletes a service" + }, + { + "create", + rpc_service_create, + NET_TRANSPORT_RPC, + "Create a service", + "net rpc service create\n" + " Creates a service" + }, + {NULL, NULL, 0, NULL, NULL} }; diff --git a/source3/utils/ntlm_auth.c b/source3/utils/ntlm_auth.c index 9bc0c60b7b..7899bd0d07 100644 --- a/source3/utils/ntlm_auth.c +++ b/source3/utils/ntlm_auth.c @@ -1251,8 +1251,6 @@ static void manage_gss_spnego_request(struct ntlm_auth_state *state, &principal, &pac_data, &ap_rep, &session_key, True); - talloc_destroy(mem_ctx); - /* Now in "principal" we have the name we are authenticated as. */ @@ -1274,9 +1272,9 @@ static void manage_gss_spnego_request(struct ntlm_auth_state *state, user = SMB_STRDUP(principal); data_blob_free(&ap_rep); - - SAFE_FREE(principal); } + + TALLOC_FREE(mem_ctx); } #endif diff --git a/source3/utils/pdbedit.c b/source3/utils/pdbedit.c index a5bc0c9bd4..328b2cb1f4 100644 --- a/source3/utils/pdbedit.c +++ b/source3/utils/pdbedit.c @@ -847,13 +847,6 @@ int main (int argc, char **argv) POPT_TABLEEND }; - /* we shouldn't have silly checks like this */ - if (getuid() != 0) { - d_fprintf(stderr, "You must be root to use pdbedit\n"); - TALLOC_FREE(frame); - return -1; - } - bin = bout = bdef = NULL; load_case_tables(); diff --git a/source3/winbindd/idmap_adex/gc_util.c b/source3/winbindd/idmap_adex/gc_util.c index 6dc02336d5..58e641b630 100644 --- a/source3/winbindd/idmap_adex/gc_util.c +++ b/source3/winbindd/idmap_adex/gc_util.c @@ -592,11 +592,11 @@ done: while (e) { struct winbindd_tdc_domain *domain_rec; - dn = ads_get_dn(ads, e); + dn = ads_get_dn(ads, frame, e); BAIL_ON_PTR_ERROR(dn, nt_status); dns_domain = cell_dn_to_dns(dn); - SAFE_FREE(dn); + TALLOC_FREE(dn); BAIL_ON_PTR_ERROR(dns_domain, nt_status); domain_rec = wcache_tdc_fetch_domain(frame, dns_domain); @@ -666,13 +666,13 @@ static NTSTATUS get_object_account_name(ADS_STRUCT *ads, /* get the name and domain */ - dn = ads_get_dn(ads, msg); + dn = ads_get_dn(ads, frame, msg); BAIL_ON_PTR_ERROR(dn, nt_status); DEBUG(10,("get_object_account_name: dn = \"%s\"\n", dn)); dns_domain = cell_dn_to_dns(dn); - SAFE_FREE(dn); + TALLOC_FREE(dn); BAIL_ON_PTR_ERROR(dns_domain, nt_status); domain_rec = wcache_tdc_fetch_domain(frame, dns_domain); diff --git a/source3/winbindd/idmap_adex/likewise_cell.c b/source3/winbindd/idmap_adex/likewise_cell.c index 7723b3e015..d666d8c01a 100644 --- a/source3/winbindd/idmap_adex/likewise_cell.c +++ b/source3/winbindd/idmap_adex/likewise_cell.c @@ -400,10 +400,10 @@ done: e!=NULL; e = ads_next_entry(c->conn, e)) { - char *dn = ads_get_dn(c->conn, e); + char *dn = ads_get_dn(c->conn, talloc_tos(), e); DEBUGADD(10,(" dn: %s\n", dn ? dn : "<NULL>")); - SAFE_FREE(dn); + TALLOC_FREE(dn); } } diff --git a/source3/winbindd/idmap_adex/provider_unified.c b/source3/winbindd/idmap_adex/provider_unified.c index f18534797e..f9d73f5f95 100644 --- a/source3/winbindd/idmap_adex/provider_unified.c +++ b/source3/winbindd/idmap_adex/provider_unified.c @@ -368,7 +368,7 @@ static NTSTATUS check_result_unique_scoped(ADS_STRUCT **ads_list, LDAPMessage *e = ads_first_entry(ads_list[i], msg_list[i]); while (e) { - entry_dn = ads_get_dn(ads_list[i], e); + entry_dn = ads_get_dn(ads_list[i], talloc_tos(), e); BAIL_ON_PTR_ERROR(entry_dn, nt_status); if (check_forest_scope(entry_dn)) { @@ -389,7 +389,7 @@ static NTSTATUS check_result_unique_scoped(ADS_STRUCT **ads_list, } e = ads_next_entry(ads_list[i], e); - SAFE_FREE(entry_dn); + TALLOC_FREE(entry_dn); } } @@ -439,7 +439,7 @@ done: } talloc_destroy(frame); - SAFE_FREE(entry_dn); + TALLOC_FREE(entry_dn); return nt_status; } diff --git a/source3/winbindd/winbindd_ads.c b/source3/winbindd/winbindd_ads.c index a76faa7a25..dcf5623d29 100644 --- a/source3/winbindd/winbindd_ads.c +++ b/source3/winbindd/winbindd_ads.c @@ -865,7 +865,7 @@ static NTSTATUS lookup_usergroups(struct winbindd_domain *domain, goto done; } - user_dn = ads_get_dn(ads, msg); + user_dn = ads_get_dn(ads, mem_ctx, msg); if (user_dn == NULL) { status = NT_STATUS_NO_MEMORY; goto done; @@ -942,7 +942,7 @@ static NTSTATUS lookup_usergroups(struct winbindd_domain *domain, DEBUG(3,("ads lookup_usergroups (tokenGroups) succeeded for sid=%s\n", sid_string_dbg(sid))); done: - ads_memfree(ads, user_dn); + TALLOC_FREE(user_dn); ads_msgfree(ads, msg); return status; } |