#include "includes.h"
#include "system/filesys.h"
-#include "memcache.h"
+#include "../lib/util/memcache.h"
#include "../lib/async_req/async_sock.h"
#include "../lib/util/select.h"
#include "lib/socket/interfaces.h"
#include "../lib/util/tevent_unix.h"
#include "../lib/util/tevent_ntstatus.h"
#include "../lib/tsocket/tsocket.h"
-
-const char *client_name(int fd)
-{
- return get_peer_name(fd,false);
-}
+#include "lib/util/sys_rw.h"
+#include "lib/util/sys_rw_data.h"
const char *client_addr(int fd, char *addr, size_t addrlen)
{
on socket calls.
****************************************************************************/
-NTSTATUS read_data(int fd, char *buffer, size_t N)
+NTSTATUS read_data_ntstatus(int fd, char *buffer, size_t N)
{
return read_fd_with_timeout(fd, buffer, N, N, 0, NULL);
}
-/****************************************************************************
- Write all data from an iov array
- NB. This can be called with a non-socket fd, don't add dependencies
- on socket calls.
-****************************************************************************/
-
-ssize_t write_data_iov(int fd, const struct iovec *orig_iov, int iovcnt)
-{
- int i;
- size_t to_send;
- ssize_t thistime;
- size_t sent;
- struct iovec *iov_copy, *iov;
-
- to_send = 0;
- for (i=0; i<iovcnt; i++) {
- to_send += orig_iov[i].iov_len;
- }
-
- thistime = sys_writev(fd, orig_iov, iovcnt);
- if ((thistime <= 0) || (thistime == to_send)) {
- return thistime;
- }
- sent = thistime;
-
- /*
- * We could not send everything in one call. Make a copy of iov that
- * we can mess with. We keep a copy of the array start in iov_copy for
- * the TALLOC_FREE, because we're going to modify iov later on,
- * discarding elements.
- */
-
- iov_copy = (struct iovec *)talloc_memdup(
- talloc_tos(), orig_iov, sizeof(struct iovec) * iovcnt);
-
- if (iov_copy == NULL) {
- errno = ENOMEM;
- return -1;
- }
- iov = iov_copy;
-
- while (sent < to_send) {
- /*
- * We have to discard "thistime" bytes from the beginning
- * iov array, "thistime" contains the number of bytes sent
- * via writev last.
- */
- while (thistime > 0) {
- if (thistime < iov[0].iov_len) {
- char *new_base =
- (char *)iov[0].iov_base + thistime;
- iov[0].iov_base = (void *)new_base;
- iov[0].iov_len -= thistime;
- break;
- }
- thistime -= iov[0].iov_len;
- iov += 1;
- iovcnt -= 1;
- }
-
- thistime = sys_writev(fd, iov, iovcnt);
- if (thistime <= 0) {
- break;
- }
- sent += thistime;
- }
-
- TALLOC_FREE(iov_copy);
- return sent;
-}
-
-/****************************************************************************
- Write data to a fd.
- NB. This can be called with a non-socket fd, don't add dependencies
- on socket calls.
-****************************************************************************/
-
-ssize_t write_data(int fd, const char *buffer, size_t N)
-{
- struct iovec iov;
-
- iov.iov_base = discard_const_p(void, buffer);
- iov.iov_len = N;
- return write_data_iov(fd, &iov, 1);
-}
-
/****************************************************************************
Send a keepalive packet (rfc1002).
****************************************************************************/
socklen_t salen;
uint16_t port;
int wait_usec;
+ struct tevent_req *connect_subreq;
};
static void open_socket_out_connected(struct tevent_req *subreq);
-static int open_socket_out_state_destructor(struct open_socket_out_state *s)
+static void open_socket_out_cleanup(struct tevent_req *req,
+ enum tevent_req_state req_state)
{
- if (s->fd != -1) {
- close(s->fd);
+ struct open_socket_out_state *state =
+ tevent_req_data(req, struct open_socket_out_state);
+
+ /*
+ * Make sure that the async_connect_send subreq has a chance to reset
+ * fcntl before the socket goes away.
+ */
+ TALLOC_FREE(state->connect_subreq);
+
+ if (req_state == TEVENT_REQ_DONE) {
+ /*
+ * we keep the socket open for the caller to use
+ */
+ return;
+ }
+
+ if (state->fd != -1) {
+ close(state->fd);
+ state->fd = -1;
}
- return 0;
}
/****************************************************************************
int timeout)
{
char addr[INET6_ADDRSTRLEN];
- struct tevent_req *result, *subreq;
+ struct tevent_req *result;
struct open_socket_out_state *state;
NTSTATUS status;
state->ev = ev;
state->ss = *pss;
state->port = port;
- state->wait_usec = 10000;
+ state->wait_usec = 10000000;
state->salen = -1;
+ timeout *=100;
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);
+
+ tevent_req_set_cleanup_fn(result, open_socket_out_cleanup);
if (!tevent_req_set_endtime(
result, ev, timeval_current_ofs_msec(timeout))) {
print_sockaddr(addr, sizeof(addr), &state->ss);
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)
+ state->connect_subreq = async_connect_send(
+ state, state->ev, state->fd, (struct sockaddr *)&state->ss,
+ state->salen, NULL, NULL, NULL);
+ if ((state->connect_subreq == NULL)
|| !tevent_req_set_endtime(
- subreq, state->ev,
+ state->connect_subreq, state->ev,
timeval_current_ofs(0, state->wait_usec))) {
goto fail;
}
- tevent_req_set_callback(subreq, open_socket_out_connected, result);
+ tevent_req_set_callback(state->connect_subreq,
+ open_socket_out_connected, result);
return result;
post_status:
ret = async_connect_recv(subreq, &sys_errno);
TALLOC_FREE(subreq);
+ state->connect_subreq = NULL;
if (ret == 0) {
tevent_req_done(req);
return;
subreq = async_connect_send(state, state->ev, state->fd,
(struct sockaddr *)&state->ss,
- state->salen);
+ state->salen, NULL, NULL, NULL);
if (tevent_req_nomem(subreq, req)) {
return;
}
if (!tevent_req_set_endtime(
subreq, state->ev,
timeval_current_ofs_usec(state->wait_usec))) {
- tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
return;
}
+ state->connect_subreq = subreq;
tevent_req_set_callback(subreq, open_socket_out_connected, req);
return;
}
NTSTATUS status;
if (tevent_req_is_nterror(req, &status)) {
+ tevent_req_received(req);
return status;
}
*pfd = state->fd;
state->fd = -1;
+ tevent_req_received(req);
return NT_STATUS_OK;
}
data_blob_free(&tmp);
}
-/*******************************************************************
- Return the DNS name of the remote end of a socket.
-******************************************************************/
-
-const char *get_peer_name(int fd, bool force_lookup)
-{
- struct name_addr_pair nc;
- char addr_buf[INET6_ADDRSTRLEN];
- struct sockaddr_storage ss;
- socklen_t length = sizeof(ss);
- const char *p;
- int ret;
- char name_buf[MAX_DNS_NAME_LENGTH];
- char tmp_name[MAX_DNS_NAME_LENGTH];
-
- /* reverse lookups can be *very* expensive, and in many
- situations won't work because many networks don't link dhcp
- with dns. To avoid the delay we avoid the lookup if
- possible */
- if (!lp_hostname_lookups() && (force_lookup == false)) {
- length = sizeof(nc.ss);
- nc.name = get_peer_addr_internal(fd, addr_buf, sizeof(addr_buf),
- (struct sockaddr *)&nc.ss, &length);
- store_nc(&nc);
- lookup_nc(&nc);
- return nc.name ? nc.name : "UNKNOWN";
- }
-
- lookup_nc(&nc);
-
- memset(&ss, '\0', sizeof(ss));
- p = get_peer_addr_internal(fd, addr_buf, sizeof(addr_buf), (struct sockaddr *)&ss, &length);
-
- /* it might be the same as the last one - save some DNS work */
- if (sockaddr_equal((struct sockaddr *)&ss, (struct sockaddr *)&nc.ss)) {
- return nc.name ? nc.name : "UNKNOWN";
- }
-
- /* Not the same. We need to lookup. */
- if (fd == -1) {
- return "UNKNOWN";
- }
-
- /* Look up the remote host name. */
- ret = sys_getnameinfo((struct sockaddr *)&ss,
- length,
- name_buf,
- sizeof(name_buf),
- NULL,
- 0,
- 0);
-
- if (ret) {
- DEBUG(1,("get_peer_name: getnameinfo failed "
- "for %s with error %s\n",
- p,
- gai_strerror(ret)));
- strlcpy(name_buf, p, sizeof(name_buf));
- } else {
- if (!matchname(name_buf, (struct sockaddr *)&ss, length)) {
- DEBUG(0,("Matchname failed on %s %s\n",name_buf,p));
- strlcpy(name_buf,"UNKNOWN",sizeof(name_buf));
- }
- }
-
- strlcpy(tmp_name, name_buf, sizeof(tmp_name));
- alpha_strcpy(name_buf, tmp_name, "_-.", sizeof(name_buf));
- if (strstr(name_buf,"..")) {
- strlcpy(name_buf, "UNKNOWN", sizeof(name_buf));
- }
-
- nc.name = name_buf;
- nc.ss = ss;
-
- store_nc(&nc);
- lookup_nc(&nc);
- return nc.name ? nc.name : "UNKNOWN";
-}
-
/*******************************************************************
Return the IP addr of the remote end of a socket as a string.
******************************************************************/
lookup_nc(&nc);
if (nc.name == NULL) {
- *name = talloc_strdup(mem_ctx, "UNKOWN");
+ *name = talloc_strdup(mem_ctx, "UNKNOWN");
} else {
*name = talloc_strdup(mem_ctx, nc.name);
}
#ifdef HAVE_UNIXSOCKET
struct sockaddr_un sunaddr;
bool ok;
- int sock;
+ int sock = -1;
+ mode_t old_umask;
char *path = NULL;
+ size_t path_len;
+
+ old_umask = umask(0);
ok = directory_create_or_exist_strict(socket_dir,
sec_initial_uid(),
dir_perms);
if (!ok) {
- return -1;
+ goto out_close;
}
/* Create the socket file */
unlink(path);
memset(&sunaddr, 0, sizeof(sunaddr));
sunaddr.sun_family = AF_UNIX;
- strlcpy(sunaddr.sun_path, path, sizeof(sunaddr.sun_path));
+
+ path_len = strlcpy(sunaddr.sun_path, path, sizeof(sunaddr.sun_path));
+ if (path_len > sizeof(sunaddr.sun_path)) {
+ DBG_ERR("Refusing to attempt to create pipe socket "
+ "%s. Path is longer than permitted for a "
+ "unix domain socket. It would truncate to "
+ "%s\n",
+ path,
+ sunaddr.sun_path);
+ goto out_close;
+ }
if (bind(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) == -1) {
DEBUG(0, ("bind failed on pipe socket %s: %s\n", path,
SAFE_FREE(path);
+ umask(old_umask);
return sock;
out_close:
if (sock != -1)
close(sock);
+ umask(old_umask);
return -1;
#else
return false;
}
-struct getaddrinfo_state {
- const char *node;
- const char *service;
- const struct addrinfo *hints;
- struct addrinfo *res;
- int ret;
-};
-
-static void getaddrinfo_do(void *private_data);
-static void getaddrinfo_done(struct tevent_req *subreq);
-
-struct tevent_req *getaddrinfo_send(TALLOC_CTX *mem_ctx,
- struct tevent_context *ev,
- struct fncall_context *ctx,
- const char *node,
- const char *service,
- const struct addrinfo *hints)
-{
- struct tevent_req *req, *subreq;
- struct getaddrinfo_state *state;
-
- req = tevent_req_create(mem_ctx, &state, struct getaddrinfo_state);
- if (req == NULL) {
- return NULL;
- }
-
- state->node = node;
- state->service = service;
- state->hints = hints;
-
- subreq = fncall_send(state, ev, ctx, getaddrinfo_do, state);
- if (tevent_req_nomem(subreq, req)) {
- return tevent_req_post(req, ev);
- }
- tevent_req_set_callback(subreq, getaddrinfo_done, req);
- return req;
-}
-
-static void getaddrinfo_do(void *private_data)
-{
- struct getaddrinfo_state *state =
- (struct getaddrinfo_state *)private_data;
-
- state->ret = getaddrinfo(state->node, state->service, state->hints,
- &state->res);
-}
-
-static void getaddrinfo_done(struct tevent_req *subreq)
-{
- struct tevent_req *req = tevent_req_callback_data(
- subreq, struct tevent_req);
- int ret, err;
-
- ret = fncall_recv(subreq, &err);
- TALLOC_FREE(subreq);
- if (ret == -1) {
- tevent_req_error(req, err);
- return;
- }
- tevent_req_done(req);
-}
-
-int getaddrinfo_recv(struct tevent_req *req, struct addrinfo **res)
-{
- struct getaddrinfo_state *state = tevent_req_data(
- req, struct getaddrinfo_state);
- int err;
-
- if (tevent_req_is_unix_error(req, &err)) {
- switch(err) {
- case ENOMEM:
- return EAI_MEMORY;
- default:
- return EAI_FAIL;
- }
- }
- if (state->ret == 0) {
- *res = state->res;
- }
- return state->ret;
-}
-
int poll_one_fd(int fd, int events, int timeout, int *revents)
{
- struct pollfd *fds;
+ struct pollfd pfd;
int ret;
- int saved_errno;
- fds = talloc_zero_array(talloc_tos(), struct pollfd, 1);
- if (fds == NULL) {
- errno = ENOMEM;
- return -1;
- }
- fds[0].fd = fd;
- fds[0].events = events;
+ pfd.fd = fd;
+ pfd.events = events;
- ret = poll(fds, 1, timeout);
+ ret = poll(&pfd, 1, timeout);
/*
* Assign whatever poll did, even in the ret<=0 case.
*/
- *revents = fds[0].revents;
- saved_errno = errno;
- TALLOC_FREE(fds);
- errno = saved_errno;
+ *revents = pfd.revents;
return ret;
}