diff options
author | Jelmer Vernooij <jelmer@samba.org> | 2009-01-04 22:48:23 +0100 |
---|---|---|
committer | Jelmer Vernooij <jelmer@samba.org> | 2009-01-04 22:48:23 +0100 |
commit | af744e0954bbe9ddfa2e3da173e79de65e640a4c (patch) | |
tree | 78b98c28e6d54c5339c12f2f942883d5088fda84 /source3/lib | |
parent | ce47b69d8e318bbb3642d27aa0451e2914c92be7 (diff) | |
parent | 2c0faaf5d921fe57a88d3b999067458e8774c6f6 (diff) | |
download | samba-af744e0954bbe9ddfa2e3da173e79de65e640a4c.tar.gz samba-af744e0954bbe9ddfa2e3da173e79de65e640a4c.tar.bz2 samba-af744e0954bbe9ddfa2e3da173e79de65e640a4c.zip |
Merge branch 'master' of ssh://git.samba.org/data/git/samba
Diffstat (limited to 'source3/lib')
-rw-r--r-- | source3/lib/async_req.c | 129 | ||||
-rw-r--r-- | source3/lib/async_sock.c | 245 | ||||
-rw-r--r-- | source3/lib/ctdbd_conn.c | 49 | ||||
-rw-r--r-- | source3/lib/ldb/include/ldb.h | 2 | ||||
-rw-r--r-- | source3/lib/ldb/tools/ldbadd.c | 13 | ||||
-rw-r--r-- | source3/lib/ldb/tools/ldbmodify.c | 12 | ||||
-rw-r--r-- | source3/lib/packet.c | 44 | ||||
-rw-r--r-- | source3/lib/util_sock.c | 341 | ||||
-rw-r--r-- | source3/lib/wb_reqtrans.c | 542 | ||||
-rw-r--r-- | source3/lib/wbclient.c | 774 |
10 files changed, 1925 insertions, 226 deletions
diff --git a/source3/lib/async_req.c b/source3/lib/async_req.c index 159666f15c..ac06df65a3 100644 --- a/source3/lib/async_req.c +++ b/source3/lib/async_req.c @@ -49,7 +49,7 @@ char *async_req_print(TALLOC_CTX *mem_ctx, struct async_req *req) * The new async request will be initialized in state ASYNC_REQ_IN_PROGRESS */ -struct async_req *async_req_new(TALLOC_CTX *mem_ctx, struct event_context *ev) +struct async_req *async_req_new(TALLOC_CTX *mem_ctx) { struct async_req *result; @@ -58,7 +58,6 @@ struct async_req *async_req_new(TALLOC_CTX *mem_ctx, struct event_context *ev) return NULL; } result->state = ASYNC_REQ_IN_PROGRESS; - result->event_ctx = ev; result->print = async_req_print; return result; } @@ -135,12 +134,12 @@ static void async_trigger(struct event_context *ev, struct timed_event *te, * conventions, independent of whether the request was actually deferred. */ -bool async_post_status(struct async_req *req, NTSTATUS status) +bool async_post_status(struct async_req *req, struct event_context *ev, + NTSTATUS status) { req->status = status; - if (event_add_timed(req->event_ctx, req, timeval_zero(), - "async_trigger", + if (event_add_timed(ev, req, timeval_zero(), "async_trigger", async_trigger, req) == NULL) { return false; } @@ -195,3 +194,123 @@ NTSTATUS async_req_simple_recv(struct async_req *req) } return NT_STATUS_OK; } + +static void async_req_timedout(struct event_context *ev, + struct timed_event *te, + const struct timeval *now, + void *priv) +{ + struct async_req *req = talloc_get_type_abort( + priv, struct async_req); + TALLOC_FREE(te); + async_req_error(req, NT_STATUS_IO_TIMEOUT); +} + +bool async_req_set_timeout(struct async_req *req, struct event_context *ev, + struct timeval to) +{ + return (event_add_timed(ev, req, + timeval_current_ofs(to.tv_sec, to.tv_usec), + "async_req_timedout", async_req_timedout, req) + != NULL); +} + +struct async_req *async_wait_send(TALLOC_CTX *mem_ctx, + struct event_context *ev, + struct timeval to) +{ + struct async_req *result; + + result = async_req_new(mem_ctx); + if (result == NULL) { + return result; + } + if (!async_req_set_timeout(result, ev, to)) { + TALLOC_FREE(result); + return NULL; + } + return result; +} + +NTSTATUS async_wait_recv(struct async_req *req) +{ + return NT_STATUS_OK; +} + +struct async_queue_entry { + struct async_queue_entry *prev, *next; + struct async_req_queue *queue; + struct async_req *req; + void (*trigger)(struct async_req *req); +}; + +struct async_req_queue { + struct async_queue_entry *queue; +}; + +struct async_req_queue *async_req_queue_init(TALLOC_CTX *mem_ctx) +{ + return TALLOC_ZERO_P(mem_ctx, struct async_req_queue); +} + +static int async_queue_entry_destructor(struct async_queue_entry *e) +{ + struct async_req_queue *queue = e->queue; + + DLIST_REMOVE(queue->queue, e); + + if (queue->queue != NULL) { + queue->queue->trigger(queue->queue->req); + } + + return 0; +} + +static void async_req_immediate_trigger(struct event_context *ev, + struct timed_event *te, + const struct timeval *now, + void *priv) +{ + struct async_queue_entry *e = talloc_get_type_abort( + priv, struct async_queue_entry); + + TALLOC_FREE(te); + e->trigger(e->req); +} + +bool async_req_enqueue(struct async_req_queue *queue, struct event_context *ev, + struct async_req *req, + void (*trigger)(struct async_req *req)) +{ + struct async_queue_entry *e; + bool busy; + + busy = (queue->queue != NULL); + + e = talloc(req, struct async_queue_entry); + if (e == NULL) { + return false; + } + + e->req = req; + e->trigger = trigger; + e->queue = queue; + + DLIST_ADD_END(queue->queue, e, struct async_queue_entry *); + talloc_set_destructor(e, async_queue_entry_destructor); + + if (!busy) { + struct timed_event *te; + + te = event_add_timed(ev, e, timeval_zero(), + "async_req_immediate_trigger", + async_req_immediate_trigger, + e); + if (te == NULL) { + TALLOC_FREE(e); + return false; + } + } + + return true; +} diff --git a/source3/lib/async_sock.c b/source3/lib/async_sock.c index 225cc7b195..bb89a1353a 100644 --- a/source3/lib/async_sock.c +++ b/source3/lib/async_sock.c @@ -106,7 +106,7 @@ static struct async_req *async_syscall_new(TALLOC_CTX *mem_ctx, struct async_req *result; struct async_syscall_state *state; - result = async_req_new(mem_ctx, ev); + result = async_req_new(mem_ctx); if (result == NULL) { return NULL; } @@ -209,7 +209,7 @@ size_t async_syscall_result_size_t(struct async_req *req, int *perrno) * @retval The return value from the asynchronously called syscall */ -ssize_t async_syscall_result_int(struct async_req *req, int *perrno) +int async_syscall_result_int(struct async_req *req, int *perrno) { struct async_syscall_state *state = talloc_get_type_abort( req->private_data, struct async_syscall_state); @@ -236,7 +236,10 @@ static void async_send_callback(struct event_context *ev, req->private_data, struct async_syscall_state); struct param_send *p = &state->param.param_send; - SMB_ASSERT(state->syscall_type == ASYNC_SYSCALL_SEND); + if (state->syscall_type != ASYNC_SYSCALL_SEND) { + async_req_error(req, NT_STATUS_INTERNAL_ERROR); + return; + } state->result.result_ssize_t = send(p->fd, p->buffer, p->length, p->flags); @@ -300,7 +303,10 @@ static void async_sendall_callback(struct event_context *ev, req->private_data, struct async_syscall_state); struct param_sendall *p = &state->param.param_sendall; - SMB_ASSERT(state->syscall_type == ASYNC_SYSCALL_SENDALL); + if (state->syscall_type != ASYNC_SYSCALL_SENDALL) { + async_req_error(req, NT_STATUS_INTERNAL_ERROR); + return; + } state->result.result_ssize_t = send(p->fd, (char *)p->buffer + p->sent, p->length - p->sent, p->flags); @@ -317,7 +323,10 @@ static void async_sendall_callback(struct event_context *ev, } p->sent += state->result.result_ssize_t; - SMB_ASSERT(p->sent <= p->length); + if (p->sent > p->length) { + async_req_error(req, NT_STATUS_INTERNAL_ERROR); + return; + } if (p->sent == p->length) { TALLOC_FREE(state->fde); @@ -385,7 +394,10 @@ static void async_recv_callback(struct event_context *ev, req->private_data, struct async_syscall_state); struct param_recv *p = &state->param.param_recv; - SMB_ASSERT(state->syscall_type == ASYNC_SYSCALL_RECV); + if (state->syscall_type != ASYNC_SYSCALL_RECV) { + async_req_error(req, NT_STATUS_INTERNAL_ERROR); + return; + } state->result.result_ssize_t = recv(p->fd, p->buffer, p->length, p->flags); @@ -450,7 +462,10 @@ static void async_recvall_callback(struct event_context *ev, req->private_data, struct async_syscall_state); struct param_recvall *p = &state->param.param_recvall; - SMB_ASSERT(state->syscall_type == ASYNC_SYSCALL_RECVALL); + if (state->syscall_type != ASYNC_SYSCALL_RECVALL) { + async_req_error(req, NT_STATUS_INTERNAL_ERROR); + return; + } state->result.result_ssize_t = recv(p->fd, (char *)p->buffer + p->received, @@ -468,7 +483,10 @@ static void async_recvall_callback(struct event_context *ev, } p->received += state->result.result_ssize_t; - SMB_ASSERT(p->received <= p->length); + if (p->received > p->length) { + async_req_error(req, NT_STATUS_INTERNAL_ERROR); + return; + } if (p->received == p->length) { TALLOC_FREE(state->fde); @@ -517,60 +535,16 @@ NTSTATUS recvall_recv(struct async_req *req) return async_req_simple_recv(req); } -/** - * fde event handler for connect(2) - * @param[in] ev The event context that sent us here - * @param[in] fde The file descriptor event associated with the connect - * @param[in] flags Indicate read/writeability of the socket - * @param[in] priv private data, "struct async_req *" in this case - */ - -static void async_connect_callback(struct event_context *ev, - struct fd_event *fde, uint16_t flags, - void *priv) -{ - struct async_req *req = talloc_get_type_abort( - priv, struct async_req); - struct async_syscall_state *state = talloc_get_type_abort( - req->private_data, struct async_syscall_state); - struct param_connect *p = &state->param.param_connect; - - SMB_ASSERT(state->syscall_type == ASYNC_SYSCALL_CONNECT); - - TALLOC_FREE(state->fde); - - /* - * Stevens, Network Programming says that if there's a - * successful connect, the socket is only writable. Upon an - * error, it's both readable and writable. - */ - if ((flags & (EVENT_FD_READ|EVENT_FD_WRITE)) - == (EVENT_FD_READ|EVENT_FD_WRITE)) { - int sockerr; - socklen_t err_len = sizeof(sockerr); - - if (getsockopt(p->fd, SOL_SOCKET, SO_ERROR, - (void *)&sockerr, &err_len) == 0) { - errno = sockerr; - } - - state->sys_errno = errno; - - DEBUG(10, ("connect returned %s\n", strerror(errno))); - - sys_fcntl_long(p->fd, F_SETFL, p->old_sockflags); - - async_req_error(req, map_nt_error_from_unix(state->sys_errno)); - return; - } - - sys_fcntl_long(p->fd, F_SETFL, p->old_sockflags); - - state->result.result_int = 0; - state->sys_errno = 0; +struct async_connect_state { + int fd; + int result; + int sys_errno; + long old_sockflags; +}; - async_req_done(req); -} +static void async_connect_connected(struct event_context *ev, + struct fd_event *fde, uint16_t flags, + void *priv); /** * @brief async version of connect(2) @@ -585,47 +559,46 @@ static void async_connect_callback(struct event_context *ev, * connect in an async state. This will be reset when the request is finished. */ -struct async_req *async_connect(TALLOC_CTX *mem_ctx, struct event_context *ev, - int fd, const struct sockaddr *address, - socklen_t address_len) +struct async_req *async_connect_send(TALLOC_CTX *mem_ctx, + struct event_context *ev, + int fd, const struct sockaddr *address, + socklen_t address_len) { struct async_req *result; - struct async_syscall_state *state; - struct param_connect *p; + struct async_connect_state *state; + struct fd_event *fde; + NTSTATUS status; - result = async_syscall_new(mem_ctx, ev, ASYNC_SYSCALL_CONNECT, &state); + result = async_req_new(mem_ctx); if (result == NULL) { return NULL; } - p = &state->param.param_connect; + state = talloc(result, struct async_connect_state); + if (state == NULL) { + goto fail; + } + result->private_data = state; /** * We have to set the socket to nonblocking for async connect(2). Keep * the old sockflags around. */ - p->old_sockflags = sys_fcntl_long(fd, F_GETFL, 0); + state->fd = fd; + state->sys_errno = 0; - if (p->old_sockflags == -1) { - if (async_post_status(result, map_nt_error_from_unix(errno))) { - return result; - } - TALLOC_FREE(result); - return NULL; + state->old_sockflags = sys_fcntl_long(fd, F_GETFL, 0); + if (state->old_sockflags == -1) { + goto post_errno; } - set_blocking(fd, true); + set_blocking(fd, false); - state->result.result_int = connect(fd, address, address_len); - - if (state->result.result_int == 0) { + state->result = connect(fd, address, address_len); + if (state->result == 0) { state->sys_errno = 0; - if (async_post_status(result, NT_STATUS_OK)) { - return result; - } - sys_fcntl_long(fd, F_SETFL, p->old_sockflags); - TALLOC_FREE(result); - return NULL; + status = NT_STATUS_OK; + goto post_status; } /** @@ -640,31 +613,93 @@ struct async_req *async_connect(TALLOC_CTX *mem_ctx, struct event_context *ev, errno == EISCONN || #endif errno == EAGAIN || errno == EINTR)) { + goto post_errno; + } - state->sys_errno = errno; - - if (async_post_status(result, map_nt_error_from_unix(errno))) { - return result; - } - sys_fcntl_long(fd, F_SETFL, p->old_sockflags); - TALLOC_FREE(result); - return NULL; + fde = event_add_fd(ev, state, fd, EVENT_FD_READ | EVENT_FD_WRITE, + async_connect_connected, result); + if (fde == NULL) { + status = NT_STATUS_NO_MEMORY; + goto post_status; } + return result; - state->fde = event_add_fd(ev, state, fd, - EVENT_FD_READ | EVENT_FD_WRITE, - async_connect_callback, result); - if (state->fde == NULL) { - sys_fcntl_long(fd, F_SETFL, p->old_sockflags); - TALLOC_FREE(result); - return NULL; + post_errno: + state->sys_errno = errno; + status = map_nt_error_from_unix(state->sys_errno); + post_status: + sys_fcntl_long(fd, F_SETFL, state->old_sockflags); + if (!async_post_status(result, ev, status)) { + goto fail; } - result->private_data = state; + return result; + fail: + TALLOC_FREE(result); + return NULL; +} + +/** + * fde event handler for connect(2) + * @param[in] ev The event context that sent us here + * @param[in] fde The file descriptor event associated with the connect + * @param[in] flags Indicate read/writeability of the socket + * @param[in] priv private data, "struct async_req *" in this case + */ - state->param.param_connect.fd = fd; - state->param.param_connect.address = address; - state->param.param_connect.address_len = address_len; +static void async_connect_connected(struct event_context *ev, + struct fd_event *fde, uint16_t flags, + void *priv) +{ + struct async_req *req = talloc_get_type_abort( + priv, struct async_req); + struct async_connect_state *state = talloc_get_type_abort( + req->private_data, struct async_connect_state); - return result; + TALLOC_FREE(fde); + + /* + * Stevens, Network Programming says that if there's a + * successful connect, the socket is only writable. Upon an + * error, it's both readable and writable. + */ + if ((flags & (EVENT_FD_READ|EVENT_FD_WRITE)) + == (EVENT_FD_READ|EVENT_FD_WRITE)) { + int sockerr; + socklen_t err_len = sizeof(sockerr); + + if (getsockopt(state->fd, SOL_SOCKET, SO_ERROR, + (void *)&sockerr, &err_len) == 0) { + errno = sockerr; + } + + state->sys_errno = errno; + + DEBUG(10, ("connect returned %s\n", strerror(errno))); + + sys_fcntl_long(state->fd, F_SETFL, state->old_sockflags); + async_req_error(req, map_nt_error_from_unix(state->sys_errno)); + return; + } + + state->sys_errno = 0; + async_req_done(req); } +NTSTATUS async_connect_recv(struct async_req *req, int *perrno) +{ + struct async_connect_state *state = talloc_get_type_abort( + req->private_data, struct async_connect_state); + NTSTATUS status; + + sys_fcntl_long(state->fd, F_SETFL, state->old_sockflags); + + *perrno = state->sys_errno; + + if (async_req_is_error(req, &status)) { + return status; + } + if (state->sys_errno == 0) { + return NT_STATUS_OK; + } + return map_nt_error_from_unix(state->sys_errno); +} diff --git a/source3/lib/ctdbd_conn.c b/source3/lib/ctdbd_conn.c index 8d97606b85..75a513312e 100644 --- a/source3/lib/ctdbd_conn.c +++ b/source3/lib/ctdbd_conn.c @@ -155,17 +155,17 @@ static NTSTATUS ctdbd_connect(TALLOC_CTX *mem_ctx, * Do we have a complete ctdb packet in the queue? */ -static bool ctdb_req_complete(const DATA_BLOB *data, +static bool ctdb_req_complete(const uint8_t *buf, size_t available, size_t *length, void *private_data) { uint32 msglen; - if (data->length < sizeof(msglen)) { + if (available < sizeof(msglen)) { return False; } - msglen = *((uint32 *)data->data); + msglen = *((uint32 *)buf); DEBUG(10, ("msglen = %d\n", msglen)); @@ -176,12 +176,12 @@ static bool ctdb_req_complete(const DATA_BLOB *data, cluster_fatal("ctdbd protocol error\n"); } - if (data->length >= msglen) { - *length = msglen; - return True; + if (available < msglen) { + return false; } - return False; + *length = msglen; + return true; } /* @@ -220,16 +220,13 @@ struct req_pull_state { * Pull a ctdb request out of the incoming packet queue */ -static NTSTATUS ctdb_req_pull(const DATA_BLOB *data, +static NTSTATUS ctdb_req_pull(uint8_t *buf, size_t length, void *private_data) { struct req_pull_state *state = (struct req_pull_state *)private_data; - state->req = data_blob_talloc(state->mem_ctx, data->data, - data->length); - if (state->req.data == NULL) { - return NT_STATUS_NO_MEMORY; - } + state->req.data = talloc_move(state->mem_ctx, &buf); + state->req.length = length; return NT_STATUS_OK; } @@ -497,7 +494,7 @@ NTSTATUS ctdbd_messaging_connection(TALLOC_CTX *mem_ctx, /* * Packet handler to receive and handle a ctdb message */ -static NTSTATUS ctdb_handle_message(const DATA_BLOB *data, +static NTSTATUS ctdb_handle_message(uint8_t *buf, size_t length, void *private_data) { struct ctdbd_connection *conn = talloc_get_type_abort( @@ -505,11 +502,12 @@ static NTSTATUS ctdb_handle_message(const DATA_BLOB *data, struct ctdb_req_message *msg; struct messaging_rec *msg_rec; - msg = (struct ctdb_req_message *)data->data; + msg = (struct ctdb_req_message *)buf; if (msg->hdr.operation != CTDB_REQ_MESSAGE) { DEBUG(0, ("Received async msg of type %u, discarding\n", msg->hdr.operation)); + TALLOC_FREE(buf); return NT_STATUS_INVALID_PARAMETER; } @@ -519,6 +517,7 @@ static NTSTATUS ctdb_handle_message(const DATA_BLOB *data, DEBUG(10, ("received CTDB_SRVID_RELEASE_IP\n")); conn->release_ip_handler((const char *)msg->data, conn->release_ip_priv); + TALLOC_FREE(buf); return NT_STATUS_OK; } @@ -540,6 +539,8 @@ static NTSTATUS ctdb_handle_message(const DATA_BLOB *data, */ message_send_all(conn->msg_ctx, MSG_SMB_UNLOCK, NULL, 0, NULL); + TALLOC_FREE(buf); + return NT_STATUS_OK; } @@ -548,17 +549,20 @@ static NTSTATUS ctdb_handle_message(const DATA_BLOB *data, if (msg->srvid != sys_getpid() && msg->srvid != MSG_SRVID_SAMBA) { DEBUG(0,("Got unexpected message with srvid=%llu\n", (unsigned long long)msg->srvid)); + TALLOC_FREE(buf); return NT_STATUS_OK; } - if (!(msg_rec = ctdb_pull_messaging_rec(NULL, data->length, msg))) { + if (!(msg_rec = ctdb_pull_messaging_rec(NULL, length, msg))) { DEBUG(10, ("ctdb_pull_messaging_rec failed\n")); + TALLOC_FREE(buf); return NT_STATUS_NO_MEMORY; } messaging_dispatch_rec(conn->msg_ctx, msg_rec); TALLOC_FREE(msg_rec); + TALLOC_FREE(buf); return NT_STATUS_OK; } @@ -1025,7 +1029,7 @@ struct ctdbd_traverse_state { * Handle a traverse record coming in on the ctdbd connection */ -static NTSTATUS ctdb_traverse_handler(const DATA_BLOB *blob, +static NTSTATUS ctdb_traverse_handler(uint8_t *buf, size_t length, void *private_data) { struct ctdbd_traverse_state *state = @@ -1035,11 +1039,11 @@ static NTSTATUS ctdb_traverse_handler(const DATA_BLOB *blob, struct ctdb_rec_data *d; TDB_DATA key, data; - m = (struct ctdb_req_message *)blob->data; + m = (struct ctdb_req_message *)buf; - if (blob->length < sizeof(*m) || m->hdr.length != blob->length) { - DEBUG(0, ("Got invalid message of length %d\n", - (int)blob->length)); + if (length < sizeof(*m) || m->hdr.length != length) { + DEBUG(0, ("Got invalid message of length %d\n", (int)length)); + TALLOC_FREE(buf); return NT_STATUS_UNEXPECTED_IO_ERROR; } @@ -1047,6 +1051,7 @@ static NTSTATUS ctdb_traverse_handler(const DATA_BLOB *blob, if (m->datalen < sizeof(uint32_t) || m->datalen != d->length) { DEBUG(0, ("Got invalid traverse data of length %d\n", (int)m->datalen)); + TALLOC_FREE(buf); return NT_STATUS_UNEXPECTED_IO_ERROR; } @@ -1063,6 +1068,7 @@ static NTSTATUS ctdb_traverse_handler(const DATA_BLOB *blob, if (data.dsize < sizeof(struct ctdb_ltdb_header)) { DEBUG(0, ("Got invalid ltdb header length %d\n", (int)data.dsize)); + TALLOC_FREE(buf); return NT_STATUS_UNEXPECTED_IO_ERROR; } data.dsize -= sizeof(struct ctdb_ltdb_header); @@ -1072,6 +1078,7 @@ static NTSTATUS ctdb_traverse_handler(const DATA_BLOB *blob, state->fn(key, data, state->private_data); } + TALLOC_FREE(buf); return NT_STATUS_OK; } diff --git a/source3/lib/ldb/include/ldb.h b/source3/lib/ldb/include/ldb.h index 0a745742d9..3891c1c6a3 100644 --- a/source3/lib/ldb/include/ldb.h +++ b/source3/lib/ldb/include/ldb.h @@ -991,7 +991,7 @@ int ldb_search(struct ldb_context *ldb, const struct ldb_dn *base, enum ldb_scope scope, const char *expression, - const char * const *attrs, struct ldb_result **res); + const char * const *attrs, struct ldb_result **_res); /* * a useful search function where you can easily define the expression and diff --git a/source3/lib/ldb/tools/ldbadd.c b/source3/lib/ldb/tools/ldbadd.c index 4dde2a1ef5..155395e065 100644 --- a/source3/lib/ldb/tools/ldbadd.c +++ b/source3/lib/ldb/tools/ldbadd.c @@ -35,8 +35,6 @@ #include "ldb/include/includes.h" #include "ldb/tools/cmdline.h" -static int failures; - static void usage(void) { printf("Usage: ldbadd <options> <ldif...>\n"); @@ -53,7 +51,8 @@ static void usage(void) /* add records from an opened file */ -static int process_file(struct ldb_context *ldb, FILE *f, int *count) +static int process_file(struct ldb_context *ldb, FILE *f, int *count, + int *failures) { struct ldb_ldif *ldif; int ret = LDB_SUCCESS; @@ -71,7 +70,7 @@ static int process_file(struct ldb_context *ldb, FILE *f, int *count) if (ret != LDB_SUCCESS) { fprintf(stderr, "ERR: \"%s\" on DN %s\n", ldb_errstring(ldb), ldb_dn_linearize(ldb, ldif->msg->dn)); - failures++; + (*failures)++; } else { (*count)++; } @@ -86,7 +85,7 @@ static int process_file(struct ldb_context *ldb, FILE *f, int *count) int main(int argc, const char **argv) { struct ldb_context *ldb; - int i, ret=0, count=0; + int i, ret=0, count=0, failures=0; struct ldb_cmdline *options; ldb_global_init(); @@ -96,7 +95,7 @@ int main(int argc, const char **argv) options = ldb_cmdline_process(ldb, argc, argv, usage); if (options->argc == 0) { - ret = process_file(ldb, stdin, &count); + ret = process_file(ldb, stdin, &count, &failures); } else { for (i=0;i<options->argc;i++) { const char *fname = options->argv[i]; @@ -106,7 +105,7 @@ int main(int argc, const char **argv) perror(fname); exit(1); } - ret = process_file(ldb, f, &count); + ret = process_file(ldb, f, &count, &failures); fclose(f); } } diff --git a/source3/lib/ldb/tools/ldbmodify.c b/source3/lib/ldb/tools/ldbmodify.c index 368b4cf996..f12387a8f6 100644 --- a/source3/lib/ldb/tools/ldbmodify.c +++ b/source3/lib/ldb/tools/ldbmodify.c @@ -35,8 +35,6 @@ #include "ldb/include/includes.h" #include "ldb/tools/cmdline.h" -static int failures; - static void usage(void) { printf("Usage: ldbmodify <options> <ldif...>\n"); @@ -52,7 +50,8 @@ static void usage(void) /* process modifies for one file */ -static int process_file(struct ldb_context *ldb, FILE *f, int *count) +static int process_file(struct ldb_context *ldb, FILE *f, int *count, + int *failures) { struct ldb_ldif *ldif; int ret = LDB_SUCCESS; @@ -73,7 +72,7 @@ static int process_file(struct ldb_context *ldb, FILE *f, int *count) if (ret != LDB_SUCCESS) { fprintf(stderr, "ERR: \"%s\" on DN %s\n", ldb_errstring(ldb), ldb_dn_linearize(ldb, ldif->msg->dn)); - failures++; + (*failures)++; } else { (*count)++; } @@ -87,6 +86,7 @@ int main(int argc, const char **argv) { struct ldb_context *ldb; int count=0; + int failures=0; int i, ret=LDB_SUCCESS; struct ldb_cmdline *options; @@ -97,7 +97,7 @@ int main(int argc, const char **argv) options = ldb_cmdline_process(ldb, argc, argv, usage); if (options->argc == 0) { - ret = process_file(ldb, stdin, &count); + ret = process_file(ldb, stdin, &count, &failures); } else { for (i=0;i<options->argc;i++) { const char *fname = options->argv[i]; @@ -107,7 +107,7 @@ int main(int argc, const char **argv) perror(fname); exit(1); } - ret = process_file(ldb, f, &count); + ret = process_file(ldb, f, &count, &failures); } } diff --git a/source3/lib/packet.c b/source3/lib/packet.c index e4cab6ba87..ef28bf9f62 100644 --- a/source3/lib/packet.c +++ b/source3/lib/packet.c @@ -120,33 +120,43 @@ NTSTATUS packet_fd_read_sync(struct packet_context *ctx) } bool packet_handler(struct packet_context *ctx, - bool (*full_req)(const DATA_BLOB *data, + bool (*full_req)(const uint8_t *buf, + size_t available, size_t *length, - void *private_data), - NTSTATUS (*callback)(const DATA_BLOB *data, - void *private_data), - void *private_data, - NTSTATUS *status) + void *priv), + NTSTATUS (*callback)(uint8_t *buf, size_t length, + void *priv), + void *priv, NTSTATUS *status) { size_t length; - DATA_BLOB data; + uint8_t *buf; - if (!full_req(&ctx->in, &length, private_data)) { + if (!full_req(ctx->in.data, ctx->in.length, &length, priv)) { return False; } - SMB_ASSERT(length <= ctx->in.length); - - data = data_blob(ctx->in.data, length); - - memmove(ctx->in.data, ctx->in.data + length, - ctx->in.length - length); - ctx->in.length -= length; + if (length > ctx->in.length) { + *status = NT_STATUS_INTERNAL_ERROR; + return true; + } - *status = callback(&data, private_data); + if (length == ctx->in.length) { + buf = ctx->in.data; + ctx->in.data = NULL; + ctx->in.length = 0; + } else { + buf = (uint8_t *)TALLOC_MEMDUP(ctx, ctx->in.data, length); + if (buf == NULL) { + *status = NT_STATUS_NO_MEMORY; + return true; + } - data_blob_free(&data); + memmove(ctx->in.data, ctx->in.data + length, + ctx->in.length - length); + ctx->in.length -= length; + } + *status = callback(buf, length, priv); return True; } diff --git a/source3/lib/util_sock.c b/source3/lib/util_sock.c index d23758ad6a..e913b35d60 100644 --- a/source3/lib/util_sock.c +++ b/source3/lib/util_sock.c @@ -707,10 +707,6 @@ ssize_t write_data_iov(int fd, const struct iovec *orig_iov, int iovcnt) Write data to a fd. ****************************************************************************/ -/**************************************************************************** - Write data to a fd. -****************************************************************************/ - ssize_t write_data(int fd, const char *buffer, size_t N) { ssize_t ret; @@ -948,102 +944,319 @@ int open_socket_in(int type, return( res ); } +struct open_socket_out_state { + int fd; + struct event_context *ev; + struct sockaddr_storage ss; + socklen_t salen; + uint16_t port; + int wait_nsec; +}; + +static void open_socket_out_connected(struct async_req *subreq); + +static int open_socket_out_state_destructor(struct open_socket_out_state *s) +{ + if (s->fd != -1) { + close(s->fd); + } + return 0; +} + /**************************************************************************** Create an outgoing socket. timeout is in milliseconds. **************************************************************************/ -int open_socket_out(int type, - const struct sockaddr_storage *pss, - uint16_t port, - int timeout) +struct async_req *open_socket_out_send(TALLOC_CTX *mem_ctx, + struct event_context *ev, + const struct sockaddr_storage *pss, + uint16_t port, + int timeout) { char addr[INET6_ADDRSTRLEN]; - struct sockaddr_storage sock_out = *pss; - int res,ret; - int connect_loop = 10; - int increment = 10; + struct async_req *result, *subreq; + struct open_socket_out_state *state; + NTSTATUS status; - /* create a socket to write to */ - res = socket(pss->ss_family, type, 0); - if (res == -1) { - DEBUG(0,("socket error (%s)\n", strerror(errno))); - return -1; + result = async_req_new(mem_ctx); + if (result == NULL) { + return NULL; } + state = talloc(result, struct open_socket_out_state); + if (state == NULL) { + goto fail; + } + result->private_data = state; + + state->ev = ev; + state->ss = *pss; + state->port = port; + state->wait_nsec = 10000; + state->salen = -1; - if (type != SOCK_STREAM) { - return res; + state->fd = socket(state->ss.ss_family, SOCK_STREAM, 0); + if (state->fd == -1) { + status = map_nt_error_from_unix(errno); + goto post_status; + } + talloc_set_destructor(state, open_socket_out_state_destructor); + + if (!async_req_set_timeout(result, ev, timeval_set(0, timeout*1000))) { + goto fail; } #if defined(HAVE_IPV6) if (pss->ss_family == AF_INET6) { - struct sockaddr_in6 *psa6 = (struct sockaddr_in6 *)&sock_out; + struct sockaddr_in6 *psa6; + psa6 = (struct sockaddr_in6 *)&state->ss; psa6->sin6_port = htons(port); - if (psa6->sin6_scope_id == 0 && - IN6_IS_ADDR_LINKLOCAL(&psa6->sin6_addr)) { - setup_linklocal_scope_id((struct sockaddr *)&sock_out); + if (psa6->sin6_scope_id == 0 + && IN6_IS_ADDR_LINKLOCAL(&psa6->sin6_addr)) { + setup_linklocal_scope_id( + (struct sockaddr *)&(state->ss)); } + state->salen = sizeof(struct sockaddr_in6); } #endif if (pss->ss_family == AF_INET) { - struct sockaddr_in *psa = (struct sockaddr_in *)&sock_out; + struct sockaddr_in *psa; + psa = (struct sockaddr_in *)&state->ss; psa->sin_port = htons(port); + state->salen = sizeof(struct sockaddr_in); } - /* set it non-blocking */ - set_blocking(res,false); + print_sockaddr(addr, sizeof(addr), &state->ss); + DEBUG(3,("Connecting to %s at port %u\n", addr, (unsigned int)port)); - print_sockaddr(addr, sizeof(addr), &sock_out); - DEBUG(3,("Connecting to %s at port %u\n", - addr, - (unsigned int)port)); + subreq = async_connect_send(state, state->ev, state->fd, + (struct sockaddr *)&state->ss, + state->salen); + if ((subreq == NULL) + || !async_req_set_timeout(subreq, state->ev, + timeval_set(0, state->wait_nsec))) { + status = NT_STATUS_NO_MEMORY; + goto post_status; + } + subreq->async.fn = open_socket_out_connected; + subreq->async.priv = result; + return result; - /* and connect it to the destination */ - connect_again: + post_status: + if (!async_post_status(result, ev, status)) { + goto fail; + } + return result; + fail: + TALLOC_FREE(result); + return NULL; +} - ret = sys_connect(res, (struct sockaddr *)&sock_out); +static void open_socket_out_connected(struct async_req *subreq) +{ + struct async_req *req = talloc_get_type_abort( + subreq->async.priv, struct async_req); + struct open_socket_out_state *state = talloc_get_type_abort( + req->private_data, struct open_socket_out_state); + NTSTATUS status; + int sys_errno; - /* Some systems return EAGAIN when they mean EINPROGRESS */ - if (ret < 0 && (errno == EINPROGRESS || errno == EALREADY || - errno == EAGAIN) && (connect_loop < timeout) ) { - smb_msleep(connect_loop); - timeout -= connect_loop; - connect_loop += increment; - if (increment < 250) { - /* After 8 rounds we end up at a max of 255 msec */ - increment *= 1.5; - } - goto connect_again; + status = async_connect_recv(subreq, &sys_errno); + TALLOC_FREE(subreq); + if (NT_STATUS_IS_OK(status)) { + async_req_done(req); + return; } - if (ret < 0 && (errno == EINPROGRESS || errno == EALREADY || - errno == EAGAIN)) { - DEBUG(1,("timeout connecting to %s:%u\n", - addr, - (unsigned int)port)); - close(res); - return -1; + if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT) + || (sys_errno == EINPROGRESS) + || (sys_errno == EALREADY) + || (sys_errno == EAGAIN)) { + + /* + * retry + */ + + if (state->wait_nsec < 250000) { + state->wait_nsec *= 1.5; + } + + subreq = async_connect_send(state, state->ev, state->fd, + (struct sockaddr *)&state->ss, + state->salen); + if (async_req_nomem(subreq, req)) { + return; + } + if (!async_req_set_timeout(subreq, state->ev, + timeval_set(0, state->wait_nsec))) { + async_req_error(req, NT_STATUS_NO_MEMORY); + return; + } + subreq->async.fn = open_socket_out_connected; + subreq->async.priv = req; + return; } #ifdef EISCONN - if (ret < 0 && errno == EISCONN) { - errno = 0; - ret = 0; + if (sys_errno == EISCONN) { + async_req_done(req); + return; } #endif - if (ret < 0) { - DEBUG(2,("error connecting to %s:%d (%s)\n", - addr, - (unsigned int)port, - strerror(errno))); - close(res); - return -1; + /* real error */ + async_req_error(req, map_nt_error_from_unix(sys_errno)); +} + +NTSTATUS open_socket_out_recv(struct async_req *req, int *pfd) +{ + struct open_socket_out_state *state = talloc_get_type_abort( + req->private_data, struct open_socket_out_state); + NTSTATUS status; + + if (async_req_is_error(req, &status)) { + return status; + } + *pfd = state->fd; + state->fd = -1; + return NT_STATUS_OK; +} + +NTSTATUS open_socket_out(const struct sockaddr_storage *pss, uint16_t port, + int timeout, int *pfd) +{ + TALLOC_CTX *frame = talloc_stackframe(); + struct event_context *ev; + struct async_req *req; + NTSTATUS status = NT_STATUS_NO_MEMORY; + + ev = event_context_init(frame); + if (ev == NULL) { + goto fail; } - /* set it blocking again */ - set_blocking(res,true); + req = open_socket_out_send(frame, ev, pss, port, timeout); + if (req == NULL) { + goto fail; + } + while (req->state < ASYNC_REQ_DONE) { + event_loop_once(ev); + } - return res; + status = open_socket_out_recv(req, pfd); + fail: + TALLOC_FREE(frame); + return status; +} + +struct open_socket_out_defer_state { + struct event_context *ev; + struct sockaddr_storage ss; + uint16_t port; + int timeout; + int fd; +}; + +static void open_socket_out_defer_waited(struct async_req *subreq); +static void open_socket_out_defer_connected(struct async_req *subreq); + +struct async_req *open_socket_out_defer_send(TALLOC_CTX *mem_ctx, + struct event_context *ev, + struct timeval wait_time, + const struct sockaddr_storage *pss, + uint16_t port, + int timeout) +{ + struct async_req *result, *subreq; + struct open_socket_out_defer_state *state; + NTSTATUS status; + + result = async_req_new(mem_ctx); + if (result == NULL) { + return NULL; + } + state = talloc(result, struct open_socket_out_defer_state); + if (state == NULL) { + goto fail; + } + result->private_data = state; + + state->ev = ev; + state->ss = *pss; + state->port = port; + state->timeout = timeout; + + subreq = async_wait_send(state, ev, wait_time); + if (subreq == NULL) { + status = NT_STATUS_NO_MEMORY; + goto post_status; + } + subreq->async.fn = open_socket_out_defer_waited; + subreq->async.priv = result; + return result; + + post_status: + if (!async_post_status(result, ev, status)) { + goto fail; + } + return result; + fail: + TALLOC_FREE(result); + return NULL; +} + +static void open_socket_out_defer_waited(struct async_req *subreq) +{ + struct async_req *req = talloc_get_type_abort( + subreq->async.priv, struct async_req); + struct open_socket_out_defer_state *state = talloc_get_type_abort( + req->private_data, struct open_socket_out_defer_state); + NTSTATUS status; + + status = async_wait_recv(subreq); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + async_req_error(req, status); + return; + } + + subreq = open_socket_out_send(state, state->ev, &state->ss, + state->port, state->timeout); + if (async_req_nomem(subreq, req)) { + return; + } + subreq->async.fn = open_socket_out_defer_connected; + subreq->async.priv = req; +} + +static void open_socket_out_defer_connected(struct async_req *subreq) +{ + struct async_req *req = talloc_get_type_abort( + subreq->async.priv, struct async_req); + struct open_socket_out_defer_state *state = talloc_get_type_abort( + req->private_data, struct open_socket_out_defer_state); + NTSTATUS status; + + status = open_socket_out_recv(subreq, &state->fd); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + async_req_error(req, status); + return; + } + async_req_done(req); +} + +NTSTATUS open_socket_out_defer_recv(struct async_req *req, int *pfd) +{ + struct open_socket_out_defer_state *state = talloc_get_type_abort( + req->private_data, struct open_socket_out_defer_state); + NTSTATUS status; + + if (async_req_is_error(req, &status)) { + return status; + } + *pfd = state->fd; + state->fd = -1; + return NT_STATUS_OK; } /******************************************************************* diff --git a/source3/lib/wb_reqtrans.c b/source3/lib/wb_reqtrans.c new file mode 100644 index 0000000000..1f5f181aa1 --- /dev/null +++ b/source3/lib/wb_reqtrans.c @@ -0,0 +1,542 @@ +/* + Unix SMB/CIFS implementation. + + Async transfer of winbindd_request and _response structs + + Copyright (C) Volker Lendecke 2008 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "winbindd/winbindd.h" + +#undef DBGC_CLASS +#define DBGC_CLASS DBGC_WINBIND + +struct req_read_state { + struct winbindd_request *wb_req; + struct event_context *ev; + size_t max_extra_data; + int fd; +}; + +static void wb_req_read_len(struct async_req *subreq); +static void wb_req_read_main(struct async_req *subreq); +static void wb_req_read_extra(struct async_req *subreq); + +struct async_req *wb_req_read_send(TALLOC_CTX *mem_ctx, + struct event_context *ev, + int fd, size_t max_extra_data) +{ + struct async_req *result, *subreq; + struct req_read_state *state; + + result = async_req_new(mem_ctx); + if (result == NULL) { + return NULL; + } + + state = talloc(result, struct req_read_state); + if (state == NULL) { + goto nomem; + } + result->private_data = state; + + state->fd = fd; + state->ev = ev; + state->max_extra_data = max_extra_data; + state->wb_req = talloc(state, struct winbindd_request); + if (state->wb_req == NULL) { + goto nomem; + } + + subreq = recvall_send(state, ev, state->fd, &(state->wb_req->length), + sizeof(state->wb_req->length), 0); + if (subreq == NULL) { + goto nomem; + } + + subreq->async.fn = wb_req_read_len; + subreq->async.priv = result; + return result; + + nomem: + TALLOC_FREE(result); + return NULL; +} + +static void wb_req_read_len(struct async_req *subreq) +{ + struct async_req *req = talloc_get_type_abort( + subreq->async.priv, struct async_req); + struct req_read_state *state = talloc_get_type_abort( + req->private_data, struct req_read_state); + NTSTATUS status; + + status = recvall_recv(subreq); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + async_req_error(req, status); + return; + } + + if (state->wb_req->length != sizeof(struct winbindd_request)) { + DEBUG(0, ("wb_req_read_len: Invalid request size received: " + "%d (expected %d)\n", (int)state->wb_req->length, + (int)sizeof(struct winbindd_request))); + async_req_error(req, NT_STATUS_INVALID_BUFFER_SIZE); + return; + } + + subreq = recvall_send( + req, state->ev, state->fd, (uint32 *)(state->wb_req)+1, + sizeof(struct winbindd_request) - sizeof(uint32), 0); + if (async_req_nomem(subreq, req)) { + return; + } + + subreq->async.fn = wb_req_read_main; + subreq->async.priv = req; +} + +static void wb_req_read_main(struct async_req *subreq) +{ + struct async_req *req = talloc_get_type_abort( + subreq->async.priv, struct async_req); + struct req_read_state *state = talloc_get_type_abort( + req->private_data, struct req_read_state); + NTSTATUS status; + + status = recvall_recv(subreq); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + async_req_error(req, status); + return; + } + + if ((state->max_extra_data != 0) + && (state->wb_req->extra_len > state->max_extra_data)) { + DEBUG(3, ("Got request with %d bytes extra data on " + "unprivileged socket\n", + (int)state->wb_req->extra_len)); + async_req_error(req, NT_STATUS_INVALID_BUFFER_SIZE); + return; + } + + if (state->wb_req->extra_len == 0) { + async_req_done(req); + return; + } + + state->wb_req->extra_data.data = TALLOC_ARRAY( + state->wb_req, char, state->wb_req->extra_len + 1); + if (async_req_nomem(state->wb_req->extra_data.data, req)) { + return; + } + + state->wb_req->extra_data.data[state->wb_req->extra_len] = 0; + + subreq = recvall_send( + req, state->ev, state->fd, state->wb_req->extra_data.data, + state->wb_req->extra_len, 0); + if (async_req_nomem(subreq, req)) { + return; + } + + subreq->async.fn = wb_req_read_extra; + subreq->async.priv = req; +} + +static void wb_req_read_extra(struct async_req *subreq) +{ + struct async_req *req = talloc_get_type_abort( + subreq->async.priv, struct async_req); + NTSTATUS status; + + status = recvall_recv(subreq); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + async_req_error(req, status); + return; + } + async_req_done(req); +} + + +NTSTATUS wb_req_read_recv(struct async_req *req, TALLOC_CTX *mem_ctx, + struct winbindd_request **preq) +{ + struct req_read_state *state = talloc_get_type_abort( + req->private_data, struct req_read_state); + NTSTATUS status; + + if (async_req_is_error(req, &status)) { + return status; + } + *preq = talloc_move(mem_ctx, &state->wb_req); + return NT_STATUS_OK; +} + +struct req_write_state { + struct winbindd_request *wb_req; + struct event_context *ev; + int fd; +}; + +static void wb_req_write_main(struct async_req *subreq); +static void wb_req_write_extra(struct async_req *subreq); + +struct async_req *wb_req_write_send(TALLOC_CTX *mem_ctx, + struct event_context *ev, int fd, + struct winbindd_request *wb_req) +{ + struct async_req *result, *subreq; + struct req_write_state *state; + + result = async_req_new(mem_ctx); + if (result == NULL) { + return NULL; + } + + state = talloc(result, struct req_write_state); + if (state == NULL) { + goto nomem; + } + result->private_data = state; + + state->fd = fd; + state->ev = ev; + state->wb_req = wb_req; + + subreq = sendall_send(state, state->ev, state->fd, state->wb_req, + sizeof(struct winbindd_request), 0); + if (subreq == NULL) { + goto nomem; + } + + subreq->async.fn = wb_req_write_main; + subreq->async.priv = result; + return result; + + nomem: + TALLOC_FREE(result); + return NULL; +} + +static void wb_req_write_main(struct async_req *subreq) +{ + struct async_req *req = talloc_get_type_abort( + subreq->async.priv, struct async_req); + struct req_write_state *state = talloc_get_type_abort( + req->private_data, struct req_write_state); + NTSTATUS status; + + status = sendall_recv(subreq); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + async_req_error(req, status); + return; + } + + if (state->wb_req->extra_len == 0) { + async_req_done(req); + return; + } + + subreq = sendall_send(state, state->ev, state->fd, + state->wb_req->extra_data.data, + state->wb_req->extra_len, 0); + if (async_req_nomem(subreq, req)) { + return; + } + + subreq->async.fn = wb_req_write_extra; + subreq->async.priv = req; +} + +static void wb_req_write_extra(struct async_req *subreq) +{ + struct async_req *req = talloc_get_type_abort( + subreq->async.priv, struct async_req); + NTSTATUS status; + + status = sendall_recv(subreq); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + async_req_error(req, status); + return; + } + + async_req_done(req); +} + +NTSTATUS wb_req_write_recv(struct async_req *req) +{ + return async_req_simple_recv(req); +} + +struct resp_read_state { + struct winbindd_response *wb_resp; + struct event_context *ev; + size_t max_extra_data; + int fd; +}; + +static void wb_resp_read_len(struct async_req *subreq); +static void wb_resp_read_main(struct async_req *subreq); +static void wb_resp_read_extra(struct async_req *subreq); + +struct async_req *wb_resp_read_send(TALLOC_CTX *mem_ctx, + struct event_context *ev, int fd) +{ + struct async_req *result, *subreq; + struct resp_read_state *state; + + result = async_req_new(mem_ctx); + if (result == NULL) { + return NULL; + } + + state = talloc(result, struct resp_read_state); + if (state == NULL) { + goto nomem; + } + result->private_data = state; + + state->fd = fd; + state->ev = ev; + state->wb_resp = talloc(state, struct winbindd_response); + if (state->wb_resp == NULL) { + goto nomem; + } + + subreq = recvall_send(state, ev, state->fd, &(state->wb_resp->length), + sizeof(state->wb_resp->length), 0); + if (subreq == NULL) { + goto nomem; + } + + subreq->async.fn = wb_resp_read_len; + subreq->async.priv = result; + return result; + + nomem: + TALLOC_FREE(result); + return NULL; +} + +static void wb_resp_read_len(struct async_req *subreq) +{ + struct async_req *req = talloc_get_type_abort( + subreq->async.priv, struct async_req); + struct resp_read_state *state = talloc_get_type_abort( + req->private_data, struct resp_read_state); + NTSTATUS status; + + status = recvall_recv(subreq); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + async_req_error(req, status); + return; + } + + if (state->wb_resp->length < sizeof(struct winbindd_response)) { + DEBUG(0, ("wb_resp_read_len: Invalid response size received: " + "%d (expected at least%d)\n", + (int)state->wb_resp->length, + (int)sizeof(struct winbindd_response))); + async_req_error(req, NT_STATUS_INVALID_BUFFER_SIZE); + return; + } + + subreq = recvall_send( + req, state->ev, state->fd, (uint32 *)(state->wb_resp)+1, + sizeof(struct winbindd_response) - sizeof(uint32), 0); + if (async_req_nomem(subreq, req)) { + return; + } + + subreq->async.fn = wb_resp_read_main; + subreq->async.priv = req; +} + +static void wb_resp_read_main(struct async_req *subreq) +{ + struct async_req *req = talloc_get_type_abort( + subreq->async.priv, struct async_req); + struct resp_read_state *state = talloc_get_type_abort( + req->private_data, struct resp_read_state); + NTSTATUS status; + size_t extra_len; + + status = recvall_recv(subreq); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + async_req_error(req, status); + return; + } + + extra_len = state->wb_resp->length - sizeof(struct winbindd_response); + if (extra_len == 0) { + async_req_done(req); + return; + } + + state->wb_resp->extra_data.data = TALLOC_ARRAY( + state->wb_resp, char, extra_len+1); + if (async_req_nomem(state->wb_resp->extra_data.data, req)) { + return; + } + ((char *)state->wb_resp->extra_data.data)[extra_len] = 0; + + subreq = recvall_send( + req, state->ev, state->fd, state->wb_resp->extra_data.data, + extra_len, 0); + if (async_req_nomem(subreq, req)) { + return; + } + + subreq->async.fn = wb_resp_read_extra; + subreq->async.priv = req; +} + +static void wb_resp_read_extra(struct async_req *subreq) +{ + struct async_req *req = talloc_get_type_abort( + subreq->async.priv, struct async_req); + NTSTATUS status; + + status = recvall_recv(subreq); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + async_req_error(req, status); + return; + } + async_req_done(req); +} + + +NTSTATUS wb_resp_read_recv(struct async_req *req, TALLOC_CTX *mem_ctx, + struct winbindd_response **presp) +{ + struct resp_read_state *state = talloc_get_type_abort( + req->private_data, struct resp_read_state); + NTSTATUS status; + + if (async_req_is_error(req, &status)) { + return status; + } + *presp = talloc_move(mem_ctx, &state->wb_resp); + return NT_STATUS_OK; +} + +struct resp_write_state { + struct winbindd_response *wb_resp; + struct event_context *ev; + int fd; +}; + +static void wb_resp_write_main(struct async_req *subreq); +static void wb_resp_write_extra(struct async_req *subreq); + +struct async_req *wb_resp_write_send(TALLOC_CTX *mem_ctx, + struct event_context *ev, int fd, + struct winbindd_response *wb_resp) +{ + struct async_req *result, *subreq; + struct resp_write_state *state; + + result = async_req_new(mem_ctx); + if (result == NULL) { + return NULL; + } + + state = talloc(result, struct resp_write_state); + if (state == NULL) { + goto nomem; + } + result->private_data = state; + + state->fd = fd; + state->ev = ev; + state->wb_resp = wb_resp; + + subreq = sendall_send(state, state->ev, state->fd, state->wb_resp, + sizeof(struct winbindd_response), 0); + if (subreq == NULL) { + goto nomem; + } + + subreq->async.fn = wb_resp_write_main; + subreq->async.priv = result; + return result; + + nomem: + TALLOC_FREE(result); + return NULL; +} + +static void wb_resp_write_main(struct async_req *subreq) +{ + struct async_req *req = talloc_get_type_abort( + subreq->async.priv, struct async_req); + struct resp_write_state *state = talloc_get_type_abort( + req->private_data, struct resp_write_state); + NTSTATUS status; + + status = sendall_recv(subreq); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + async_req_error(req, status); + return; + } + + if (state->wb_resp->length == sizeof(struct winbindd_response)) { + async_req_done(req); + return; + } + + subreq = sendall_send( + state, state->ev, state->fd, + state->wb_resp->extra_data.data, + state->wb_resp->length - sizeof(struct winbindd_response), 0); + if (async_req_nomem(subreq, req)) { + return; + } + + subreq->async.fn = wb_resp_write_extra; + subreq->async.priv = req; +} + +static void wb_resp_write_extra(struct async_req *subreq) +{ + struct async_req *req = talloc_get_type_abort( + subreq->async.priv, struct async_req); + NTSTATUS status; + + status = sendall_recv(subreq); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + async_req_error(req, status); + return; + } + + async_req_done(req); +} + +NTSTATUS wb_resp_write_recv(struct async_req *req) +{ + return async_req_simple_recv(req); +} diff --git a/source3/lib/wbclient.c b/source3/lib/wbclient.c new file mode 100644 index 0000000000..d58c934c07 --- /dev/null +++ b/source3/lib/wbclient.c @@ -0,0 +1,774 @@ +/* + Unix SMB/CIFS implementation. + Infrastructure for async winbind requests + Copyright (C) Volker Lendecke 2008 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. +*/ + +#include "includes.h" +#include "winbindd/winbindd.h" +#include "winbindd/winbindd_proto.h" + +static int make_nonstd_fd(int fd) +{ + int i; + int sys_errno = 0; + int fds[3]; + int num_fds = 0; + + if (fd == -1) { + return -1; + } + while (fd < 3) { + fds[num_fds++] = fd; + fd = dup(fd); + if (fd == -1) { + sys_errno = errno; + break; + } + } + for (i=0; i<num_fds; i++) { + close(fds[i]); + } + if (fd == -1) { + errno = sys_errno; + } + return fd; +} + +/**************************************************************************** + Set a fd into blocking/nonblocking mode. Uses POSIX O_NONBLOCK if available, + else + if SYSV use O_NDELAY + if BSD use FNDELAY + Set close on exec also. +****************************************************************************/ + +static int make_safe_fd(int fd) +{ + int result, flags; + int new_fd = make_nonstd_fd(fd); + + if (new_fd == -1) { + goto fail; + } + + /* Socket should be nonblocking. */ + +#ifdef O_NONBLOCK +#define FLAG_TO_SET O_NONBLOCK +#else +#ifdef SYSV +#define FLAG_TO_SET O_NDELAY +#else /* BSD */ +#define FLAG_TO_SET FNDELAY +#endif +#endif + + if ((flags = fcntl(new_fd, F_GETFL)) == -1) { + goto fail; + } + + flags |= FLAG_TO_SET; + if (fcntl(new_fd, F_SETFL, flags) == -1) { + goto fail; + } + +#undef FLAG_TO_SET + + /* Socket should be closed on exec() */ +#ifdef FD_CLOEXEC + result = flags = fcntl(new_fd, F_GETFD, 0); + if (flags >= 0) { + flags |= FD_CLOEXEC; + result = fcntl( new_fd, F_SETFD, flags ); + } + if (result < 0) { + goto fail; + } +#endif + return new_fd; + + fail: + if (new_fd != -1) { + int sys_errno = errno; + close(new_fd); + errno = sys_errno; + } + return -1; +} + +static bool winbind_closed_fd(int fd) +{ + struct timeval tv; + fd_set r_fds; + + if (fd == -1) { + return true; + } + + FD_ZERO(&r_fds); + FD_SET(fd, &r_fds); + ZERO_STRUCT(tv); + + if ((select(fd+1, &r_fds, NULL, NULL, &tv) == -1) + || FD_ISSET(fd, &r_fds)) { + return true; + } + + return false; +} + +struct wb_context { + struct async_req_queue *queue; + int fd; + bool is_priv; +}; + +struct wb_context *wb_context_init(TALLOC_CTX *mem_ctx) +{ + struct wb_context *result; + + result = talloc(mem_ctx, struct wb_context); + if (result == NULL) { + return NULL; + } + result->queue = async_req_queue_init(result); + if (result->queue == NULL) { + TALLOC_FREE(result); + return NULL; + } + result->fd = -1; + return result; +} + +static struct async_req *wb_connect_send(TALLOC_CTX *mem_ctx, + struct event_context *ev, + struct wb_context *wb_ctx, + const char *dir) +{ + struct async_req *req; + struct sockaddr_un sunaddr; + struct stat st; + char *path = NULL; + NTSTATUS status; + + if (wb_ctx->fd != -1) { + close(wb_ctx->fd); + wb_ctx->fd = -1; + } + + /* Check permissions on unix socket directory */ + + if (lstat(dir, &st) == -1) { + status = NT_STATUS_OBJECT_NAME_NOT_FOUND; + goto post_status; + } + + if (!S_ISDIR(st.st_mode) || + (st.st_uid != 0 && st.st_uid != geteuid())) { + status = NT_STATUS_OBJECT_NAME_NOT_FOUND; + goto post_status; + } + + /* Connect to socket */ + + path = talloc_asprintf(talloc_tos(), "%s/%s", dir, + WINBINDD_SOCKET_NAME); + if (path == NULL) { + goto nomem; + } + + sunaddr.sun_family = AF_UNIX; + strlcpy(sunaddr.sun_path, path, sizeof(sunaddr.sun_path)); + TALLOC_FREE(path); + + /* If socket file doesn't exist, don't bother trying to connect + with retry. This is an attempt to make the system usable when + the winbindd daemon is not running. */ + + if ((lstat(sunaddr.sun_path, &st) == -1) + || !S_ISSOCK(st.st_mode) + || (st.st_uid != 0 && st.st_uid != geteuid())) { + status = NT_STATUS_OBJECT_NAME_NOT_FOUND; + goto post_status; + } + + wb_ctx->fd = make_safe_fd(socket(AF_UNIX, SOCK_STREAM, 0)); + if (wb_ctx->fd == -1) { + status = map_nt_error_from_unix(errno); + goto post_status; + } + + req = async_connect_send(mem_ctx, ev, wb_ctx->fd, + (struct sockaddr *)&sunaddr, + sizeof(sunaddr)); + if (req == NULL) { + goto nomem; + } + if (!async_req_set_timeout(req, ev, timeval_set(30, 0))) { + TALLOC_FREE(req); + goto nomem; + } + + return req; + + nomem: + status = NT_STATUS_NO_MEMORY; + post_status: + req = async_req_new(mem_ctx); + if (req == NULL) { + return NULL; + } + if (async_post_status(req, ev, status)) { + return req; + } + TALLOC_FREE(req); + return NULL; +} + +static NTSTATUS wb_connect_recv(struct async_req *req) +{ + int dummy; + + return async_connect_recv(req, &dummy); +} + +static struct winbindd_request *winbindd_request_copy( + TALLOC_CTX *mem_ctx, + const struct winbindd_request *req) +{ + struct winbindd_request *result; + + result = (struct winbindd_request *)TALLOC_MEMDUP( + mem_ctx, req, sizeof(struct winbindd_request)); + if (result == NULL) { + return NULL; + } + + if (result->extra_len == 0) { + return result; + } + + result->extra_data.data = (char *)TALLOC_MEMDUP( + result, result->extra_data.data, result->extra_len); + if (result->extra_data.data == NULL) { + TALLOC_FREE(result); + return NULL; + } + return result; +} + +struct wb_int_trans_state { + struct event_context *ev; + int fd; + struct winbindd_request *wb_req; + struct winbindd_response *wb_resp; +}; + +static void wb_int_trans_write_done(struct async_req *subreq); +static void wb_int_trans_read_done(struct async_req *subreq); + +static struct async_req *wb_int_trans_send(TALLOC_CTX *mem_ctx, + struct event_context *ev, int fd, + struct winbindd_request *wb_req) +{ + struct async_req *result; + struct async_req *subreq; + struct wb_int_trans_state *state; + + result = async_req_new(mem_ctx); + if (result == NULL) { + return NULL; + } + state = talloc(result, struct wb_int_trans_state); + if (state == NULL) { + goto fail; + } + result->private_data = state; + + if (winbind_closed_fd(fd)) { + if (!async_post_status(result, ev, + NT_STATUS_PIPE_DISCONNECTED)) { + goto fail; + } + return result; + } + + state->ev = ev; + state->fd = fd; + state->wb_req = wb_req; + + state->wb_req->length = sizeof(struct winbindd_request); + state->wb_req->pid = getpid(); + + subreq = wb_req_write_send(state, state->ev, state->fd, state->wb_req); + if (subreq == NULL) { + goto fail; + } + subreq->async.fn = wb_int_trans_write_done; + subreq->async.priv = result; + + return result; + + fail: + TALLOC_FREE(result); + return NULL; +} + +static void wb_int_trans_write_done(struct async_req *subreq) +{ + struct async_req *req = talloc_get_type_abort( + subreq->async.priv, struct async_req); + struct wb_int_trans_state *state = talloc_get_type_abort( + req->private_data, struct wb_int_trans_state); + NTSTATUS status; + + status = wb_req_write_recv(subreq); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + async_req_error(req, status); + return; + } + + subreq = wb_resp_read_send(state, state->ev, state->fd); + if (subreq == NULL) { + async_req_error(req, NT_STATUS_NO_MEMORY); + } + subreq->async.fn = wb_int_trans_read_done; + subreq->async.priv = req; +} + +static void wb_int_trans_read_done(struct async_req *subreq) +{ + struct async_req *req = talloc_get_type_abort( + subreq->async.priv, struct async_req); + struct wb_int_trans_state *state = talloc_get_type_abort( + req->private_data, struct wb_int_trans_state); + NTSTATUS status; + + status = wb_resp_read_recv(subreq, state, &state->wb_resp); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + async_req_error(req, status); + return; + } + + async_req_done(req); +} + +static NTSTATUS wb_int_trans_recv(struct async_req *req, + TALLOC_CTX *mem_ctx, + struct winbindd_response **presponse) +{ + struct wb_int_trans_state *state = talloc_get_type_abort( + req->private_data, struct wb_int_trans_state); + NTSTATUS status; + + if (async_req_is_error(req, &status)) { + return status; + } + + *presponse = talloc_move(mem_ctx, &state->wb_resp); + return NT_STATUS_OK; +} + +static const char *winbindd_socket_dir(void) +{ +#ifdef SOCKET_WRAPPER + const char *env_dir; + + env_dir = getenv(WINBINDD_SOCKET_DIR_ENVVAR); + if (env_dir) { + return env_dir; + } +#endif + + return WINBINDD_SOCKET_DIR; +} + +struct wb_open_pipe_state { + struct wb_context *wb_ctx; + struct event_context *ev; + bool need_priv; + struct winbindd_request wb_req; +}; + +static void wb_open_pipe_connect_nonpriv_done(struct async_req *subreq); +static void wb_open_pipe_ping_done(struct async_req *subreq); +static void wb_open_pipe_getpriv_done(struct async_req *subreq); +static void wb_open_pipe_connect_priv_done(struct async_req *subreq); + +static struct async_req *wb_open_pipe_send(TALLOC_CTX *mem_ctx, + struct event_context *ev, + struct wb_context *wb_ctx, + bool need_priv) +{ + struct async_req *result; + struct async_req *subreq; + struct wb_open_pipe_state *state; + + result = async_req_new(mem_ctx); + if (result == NULL) { + return NULL; + } + state = talloc(result, struct wb_open_pipe_state); + if (state == NULL) { + goto fail; + } + result->private_data = state; + + state->wb_ctx = wb_ctx; + state->ev = ev; + state->need_priv = need_priv; + + if (wb_ctx->fd != -1) { + close(wb_ctx->fd); + wb_ctx->fd = -1; + } + + subreq = wb_connect_send(state, ev, wb_ctx, winbindd_socket_dir()); + if (subreq == NULL) { + goto fail; + } + + subreq->async.fn = wb_open_pipe_connect_nonpriv_done; + subreq->async.priv = result; + return result; + + fail: + TALLOC_FREE(result); + return NULL; +} + +static void wb_open_pipe_connect_nonpriv_done(struct async_req *subreq) +{ + struct async_req *req = talloc_get_type_abort( + subreq->async.priv, struct async_req); + struct wb_open_pipe_state *state = talloc_get_type_abort( + req->private_data, struct wb_open_pipe_state); + NTSTATUS status; + + status = wb_connect_recv(subreq); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + state->wb_ctx->is_priv = true; + async_req_error(req, status); + return; + } + + ZERO_STRUCT(state->wb_req); + state->wb_req.cmd = WINBINDD_INTERFACE_VERSION; + + subreq = wb_int_trans_send(state, state->ev, state->wb_ctx->fd, + &state->wb_req); + if (async_req_nomem(subreq, req)) { + return; + } + + subreq->async.fn = wb_open_pipe_ping_done; + subreq->async.priv = req; +} + +static void wb_open_pipe_ping_done(struct async_req *subreq) +{ + struct async_req *req = talloc_get_type_abort( + subreq->async.priv, struct async_req); + struct wb_open_pipe_state *state = talloc_get_type_abort( + req->private_data, struct wb_open_pipe_state); + struct winbindd_response *wb_resp; + NTSTATUS status; + + status = wb_int_trans_recv(subreq, state, &wb_resp); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + async_req_error(req, status); + return; + } + + if (!state->need_priv) { + async_req_done(req); + return; + } + + state->wb_req.cmd = WINBINDD_PRIV_PIPE_DIR; + + subreq = wb_int_trans_send(state, state->ev, state->wb_ctx->fd, + &state->wb_req); + if (async_req_nomem(subreq, req)) { + return; + } + + subreq->async.fn = wb_open_pipe_getpriv_done; + subreq->async.priv = req; +} + +static void wb_open_pipe_getpriv_done(struct async_req *subreq) +{ + struct async_req *req = talloc_get_type_abort( + subreq->async.priv, struct async_req); + struct wb_open_pipe_state *state = talloc_get_type_abort( + req->private_data, struct wb_open_pipe_state); + struct winbindd_response *wb_resp = NULL; + NTSTATUS status; + + status = wb_int_trans_recv(subreq, state, &wb_resp); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + async_req_error(req, status); + return; + } + + close(state->wb_ctx->fd); + state->wb_ctx->fd = -1; + + subreq = wb_connect_send(state, state->ev, state->wb_ctx, + (char *)wb_resp->extra_data.data); + TALLOC_FREE(wb_resp); + if (async_req_nomem(subreq, req)) { + return; + } + + subreq->async.fn = wb_open_pipe_connect_priv_done; + subreq->async.priv = req; +} + +static void wb_open_pipe_connect_priv_done(struct async_req *subreq) +{ + struct async_req *req = talloc_get_type_abort( + subreq->async.priv, struct async_req); + struct wb_open_pipe_state *state = talloc_get_type_abort( + req->private_data, struct wb_open_pipe_state); + NTSTATUS status; + + status = wb_connect_recv(subreq); + TALLOC_FREE(subreq); + if (!NT_STATUS_IS_OK(status)) { + async_req_error(req, status); + return; + } + state->wb_ctx->is_priv = true; + async_req_done(req); +} + +static NTSTATUS wb_open_pipe_recv(struct async_req *req) +{ + return async_req_simple_recv(req); +} + +struct wb_trans_state { + struct wb_trans_state *prev, *next; + struct wb_context *wb_ctx; + struct event_context *ev; + struct winbindd_request *wb_req; + struct winbindd_response *wb_resp; + int num_retries; + bool need_priv; +}; + +static void wb_trans_connect_done(struct async_req *subreq); +static void wb_trans_done(struct async_req *subreq); +static void wb_trans_retry_wait_done(struct async_req *subreq); + +static void wb_trigger_trans(struct async_req *req) +{ + struct wb_trans_state *state = talloc_get_type_abort( + req->private_data, struct wb_trans_state); + struct async_req *subreq; + + if ((state->wb_ctx->fd == -1) + || (state->need_priv && !state->wb_ctx->is_priv)) { + + subreq = wb_open_pipe_send(state, state->ev, state->wb_ctx, + state->need_priv); + if (async_req_nomem(subreq, req)) { + return; + } + subreq->async.fn = wb_trans_connect_done; + subreq->async.priv = req; + return; + } + + subreq = wb_int_trans_send(state, state->ev, state->wb_ctx->fd, + state->wb_req); + if (async_req_nomem(subreq, req)) { + return; + } + subreq->async.fn = wb_trans_done; + subreq->async.priv = req; +} + +struct async_req *wb_trans_send(TALLOC_CTX *mem_ctx, struct event_context *ev, + struct wb_context *wb_ctx, bool need_priv, + const struct winbindd_request *wb_req) +{ + struct async_req *result; + struct wb_trans_state *state; + + result = async_req_new(mem_ctx); + if (result == NULL) { + return NULL; + } + state = talloc(result, struct wb_trans_state); + if (state == NULL) { + goto fail; + } + result->private_data = state; + + state->wb_ctx = wb_ctx; + state->ev = ev; + state->wb_req = winbindd_request_copy(state, wb_req); + if (state->wb_req == NULL) { + goto fail; + } + state->num_retries = 10; + state->need_priv = need_priv; + + if (!async_req_enqueue(wb_ctx->queue, ev, result, wb_trigger_trans)) { + goto fail; + } + return result; + + fail: + TALLOC_FREE(result); + return NULL; +} + +static bool wb_trans_retry(struct async_req *req, + struct wb_trans_state *state, + NTSTATUS status) +{ + struct async_req *subreq; + + if (NT_STATUS_IS_OK(status)) { + return false; + } + + if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND) + || NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) { + /* + * Winbind not around or we can't connect to the pipe. Fail + * immediately. + */ + async_req_error(req, status); + return true; + } + + state->num_retries -= 1; + if (state->num_retries == 0) { + async_req_error(req, status); + return true; + } + + /* + * The transfer as such failed, retry after one second + */ + + if (state->wb_ctx->fd != -1) { + close(state->wb_ctx->fd); + state->wb_ctx->fd = -1; + } + + subreq = async_wait_send(state, state->ev, timeval_set(1, 0)); + if (async_req_nomem(subreq, req)) { + return true; + } + + subreq->async.fn = wb_trans_retry_wait_done; + subreq->async.priv = req; + return true; +} + +static void wb_trans_retry_wait_done(struct async_req *subreq) +{ + struct async_req *req = talloc_get_type_abort( + subreq->async.priv, struct async_req); + struct wb_trans_state *state = talloc_get_type_abort( + req->private_data, struct wb_trans_state); + NTSTATUS status; + + status = async_wait_recv(subreq); + TALLOC_FREE(subreq); + if (!NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) { + async_req_error(req, status); + return; + } + + subreq = wb_open_pipe_send(state, state->ev, state->wb_ctx, + state->need_priv); + if (async_req_nomem(subreq, req)) { + return; + } + subreq->async.fn = wb_trans_connect_done; + subreq->async.priv = req; +} + +static void wb_trans_connect_done(struct async_req *subreq) +{ + struct async_req *req = talloc_get_type_abort( + subreq->async.priv, struct async_req); + struct wb_trans_state *state = talloc_get_type_abort( + req->private_data, struct wb_trans_state); + NTSTATUS status; + + status = wb_open_pipe_recv(subreq); + TALLOC_FREE(subreq); + + if (wb_trans_retry(req, state, status)) { + return; + } + + subreq = wb_int_trans_send(state, state->ev, state->wb_ctx->fd, + state->wb_req); + if (async_req_nomem(subreq, req)) { + return; + } + + subreq->async.fn = wb_trans_done; + subreq->async.priv = req; +} + +static void wb_trans_done(struct async_req *subreq) +{ + struct async_req *req = talloc_get_type_abort( + subreq->async.priv, struct async_req); + struct wb_trans_state *state = talloc_get_type_abort( + req->private_data, struct wb_trans_state); + NTSTATUS status; + + status = wb_int_trans_recv(subreq, state, &state->wb_resp); + TALLOC_FREE(subreq); + + if (wb_trans_retry(req, state, status)) { + return; + } + + async_req_done(req); +} + +NTSTATUS wb_trans_recv(struct async_req *req, TALLOC_CTX *mem_ctx, + struct winbindd_response **presponse) +{ + struct wb_trans_state *state = talloc_get_type_abort( + req->private_data, struct wb_trans_state); + NTSTATUS status; + + if (async_req_is_error(req, &status)) { + return status; + } + + *presponse = talloc_move(mem_ctx, &state->wb_resp); + return NT_STATUS_OK; +} |