#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"
-
-const char *client_name(int fd)
-{
- return get_peer_name(fd,false);
-}
+#include "../lib/tsocket/tsocket.h"
+#include "lib/util/sys_rw.h"
+#include "lib/util/sys_rw_data.h"
const char *client_addr(int fd, char *addr, size_t addrlen)
{
}
#endif
-/****************************************************************************
- Accessor functions to make thread-safe code easier later...
-****************************************************************************/
-
-void set_smb_read_error(enum smb_read_errors *pre,
- enum smb_read_errors newerr)
-{
- if (pre) {
- *pre = newerr;
- }
-}
-
-void cond_set_smb_read_error(enum smb_read_errors *pre,
- enum smb_read_errors newerr)
-{
- if (pre && *pre == SMB_READ_OK) {
- *pre = newerr;
- }
-}
-
/****************************************************************************
Determine if a file descriptor is in fact a socket.
****************************************************************************/
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).
****************************************************************************/
{
unsigned char buf[4];
- buf[0] = SMBkeepalive;
+ buf[0] = NBSSkeepalive;
buf[1] = buf[2] = buf[3] = 0;
return(write_data(client,(char *)buf,4) == 4);
*len = smb_len(inbuf);
msg_type = CVAL(inbuf,0);
- if (msg_type == SMBkeepalive) {
+ if (msg_type == NBSSkeepalive) {
DEBUG(5,("Got keepalive packet\n"));
}
/* now we've got a socket - we need to bind it */
if (bind(res, (struct sockaddr *)&sock, slen) == -1 ) {
- if( DEBUGLVL(dlevel) && (port == SMB_PORT1 ||
- port == SMB_PORT2 || port == NMB_PORT) ) {
+ if( DEBUGLVL(dlevel) && (port == NMB_PORT ||
+ port == NBT_SMB_PORT ||
+ port == TCP_SMB_PORT) ) {
char addr[INET6_ADDRSTRLEN];
print_sockaddr(addr, sizeof(addr),
&sock);
struct open_socket_out_state {
int fd;
- struct event_context *ev;
+ struct tevent_context *ev;
struct sockaddr_storage ss;
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;
}
/****************************************************************************
**************************************************************************/
struct tevent_req *open_socket_out_send(TALLOC_CTX *mem_ctx,
- struct event_context *ev,
+ struct tevent_context *ev,
const struct sockaddr_storage *pss,
uint16_t port,
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;
}
int timeout, int *pfd)
{
TALLOC_CTX *frame = talloc_stackframe();
- struct event_context *ev;
+ struct tevent_context *ev;
struct tevent_req *req;
NTSTATUS status = NT_STATUS_NO_MEMORY;
- ev = event_context_init(frame);
+ ev = samba_tevent_context_init(frame);
if (ev == NULL) {
goto fail;
}
}
struct open_socket_out_defer_state {
- struct event_context *ev;
+ struct tevent_context *ev;
struct sockaddr_storage ss;
uint16_t port;
int timeout;
static void open_socket_out_defer_connected(struct tevent_req *subreq);
struct tevent_req *open_socket_out_defer_send(TALLOC_CTX *mem_ctx,
- struct event_context *ev,
+ struct tevent_context *ev,
struct timeval wait_time,
const struct sockaddr_storage *pss,
uint16_t port,
{
struct sockaddr_storage ss;
int res;
+ socklen_t salen;
if (!interpret_string_addr(&ss, host, 0)) {
DEBUG(10,("open_udp_socket: can't resolve name %s\n",
setup_linklocal_scope_id(
(struct sockaddr *)&ss);
}
- }
+ salen = sizeof(struct sockaddr_in6);
+ } else
#endif
- if (ss.ss_family == AF_INET) {
- struct sockaddr_in *psa;
- psa = (struct sockaddr_in *)&ss;
- psa->sin_port = htons(port);
- }
+ if (ss.ss_family == AF_INET) {
+ struct sockaddr_in *psa;
+ psa = (struct sockaddr_in *)&ss;
+ psa->sin_port = htons(port);
+ salen = sizeof(struct sockaddr_in);
+ } else {
+ DEBUG(1, ("unknown socket family %d", ss.ss_family));
+ close(res);
+ return -1;
+ }
- if (sys_connect(res,(struct sockaddr *)&ss)) {
+ if (connect(res, (struct sockaddr *)&ss, salen)) {
close(res);
return -1;
}
}
/*******************************************************************
- Return the DNS name of the remote end of a socket.
-******************************************************************/
+ Return the IP addr of the remote end of a socket as a string.
+ ******************************************************************/
-const char *get_peer_name(int fd, bool force_lookup)
+const char *get_peer_addr(int fd, char *addr, size_t addr_len)
+{
+ return get_peer_addr_internal(fd, addr, addr_len, NULL, NULL);
+}
+
+int get_remote_hostname(const struct tsocket_address *remote_address,
+ char **name,
+ TALLOC_CTX *mem_ctx)
{
- 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];
+ struct name_addr_pair nc;
+ struct sockaddr_storage ss;
+ ssize_t len;
+ int rc;
+
+ if (!lp_hostname_lookups()) {
+ nc.name = tsocket_address_inet_addr_string(remote_address,
+ mem_ctx);
+ if (nc.name == NULL) {
+ return -1;
+ }
+
+ len = tsocket_address_bsd_sockaddr(remote_address,
+ (struct sockaddr *) &nc.ss,
+ sizeof(struct sockaddr_storage));
+ if (len < 0) {
+ return -1;
+ }
- /* 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";
+
+ if (nc.name == NULL) {
+ *name = talloc_strdup(mem_ctx, "UNKNOWN");
+ } else {
+ *name = talloc_strdup(mem_ctx, nc.name);
+ }
+ return 0;
}
lookup_nc(&nc);
- memset(&ss, '\0', sizeof(ss));
- p = get_peer_addr_internal(fd, addr_buf, sizeof(addr_buf), (struct sockaddr *)&ss, &length);
+ ZERO_STRUCT(ss);
- /* 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";
+ len = tsocket_address_bsd_sockaddr(remote_address,
+ (struct sockaddr *) &ss,
+ sizeof(struct sockaddr_storage));
+ if (len < 0) {
+ return -1;
}
- /* Not the same. We need to lookup. */
- if (fd == -1) {
- return "UNKNOWN";
+ /* it might be the same as the last one - save some DNS work */
+ if (sockaddr_equal((struct sockaddr *)&ss, (struct sockaddr *)&nc.ss)) {
+ if (nc.name == NULL) {
+ *name = talloc_strdup(mem_ctx, "UNKNOWN");
+ } else {
+ *name = talloc_strdup(mem_ctx, nc.name);
+ }
+ return 0;
}
/* 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)));
+ rc = sys_getnameinfo((struct sockaddr *) &ss,
+ len,
+ name_buf,
+ sizeof(name_buf),
+ NULL,
+ 0,
+ 0);
+ if (rc < 0) {
+ char *p;
+
+ p = tsocket_address_inet_addr_string(remote_address, mem_ctx);
+ if (p == NULL) {
+ return -1;
+ }
+
+ DEBUG(1,("getnameinfo failed for %s with error %s\n",
+ p,
+ gai_strerror(rc)));
strlcpy(name_buf, p, sizeof(name_buf));
+
+ TALLOC_FREE(p);
} 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));
+ if (!matchname(name_buf, (struct sockaddr *)&ss, len)) {
+ DEBUG(0,("matchname failed on %s\n", name_buf));
+ strlcpy(name_buf, "UNKNOWN", sizeof(name_buf));
}
}
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.
- ******************************************************************/
+ if (nc.name == NULL) {
+ *name = talloc_strdup(mem_ctx, "UNKNOWN");
+ } else {
+ *name = talloc_strdup(mem_ctx, nc.name);
+ }
-const char *get_peer_addr(int fd, char *addr, size_t addr_len)
-{
- return get_peer_addr_internal(fd, addr, addr_len, NULL, NULL);
+ return 0;
}
/*******************************************************************
{
#ifdef HAVE_UNIXSOCKET
struct sockaddr_un sunaddr;
- struct stat st;
- int sock;
+ bool ok;
+ int sock = -1;
mode_t old_umask;
char *path = NULL;
+ size_t path_len;
old_umask = umask(0);
- /* Create the socket directory or reuse the existing one */
-
- if (lstat(socket_dir, &st) == -1) {
- if (errno == ENOENT) {
- /* Create directory */
- if (mkdir(socket_dir, dir_perms) == -1) {
- DEBUG(0, ("error creating socket directory "
- "%s: %s\n", socket_dir,
- strerror(errno)));
- goto out_umask;
- }
- } else {
- DEBUG(0, ("lstat failed on socket directory %s: %s\n",
- socket_dir, strerror(errno)));
- goto out_umask;
- }
- } else {
- /* Check ownership and permission on existing directory */
- if (!S_ISDIR(st.st_mode)) {
- DEBUG(0, ("socket directory '%s' isn't a directory\n",
- socket_dir));
- goto out_umask;
- }
- if (st.st_uid != sec_initial_uid()) {
- DEBUG(0, ("invalid ownership on directory "
- "'%s'\n", socket_dir));
- umask(old_umask);
- goto out_umask;
- }
- if ((st.st_mode & 0777) != dir_perms) {
- DEBUG(0, ("invalid permissions on directory "
- "'%s': has 0%o should be 0%o\n", socket_dir,
- (st.st_mode & 0777), dir_perms));
- umask(old_umask);
- goto out_umask;
- }
+ ok = directory_create_or_exist_strict(socket_dir,
+ sec_initial_uid(),
+ dir_perms);
+ if (!ok) {
+ goto out_close;
}
/* Create the socket file */
-
sock = socket(AF_UNIX, SOCK_STREAM, 0);
if (sock == -1) {
unlink(path);
memset(&sunaddr, 0, sizeof(sunaddr));
sunaddr.sun_family = AF_UNIX;
- strlcpy(sunaddr.sun_path, path, sizeof(sunaddr.sun_path));
- if (bind(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) == -1) {
- DEBUG(0, ("bind failed on pipe socket %s: %s\n", path,
- strerror(errno)));
+ 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 (listen(sock, 5) == -1) {
- DEBUG(0, ("listen failed on pipe socket %s: %s\n", path,
+ if (bind(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) == -1) {
+ DEBUG(0, ("bind failed on pipe socket %s: %s\n", path,
strerror(errno)));
goto out_close;
}
if (sock != -1)
close(sock);
-out_umask:
umask(old_umask);
return -1;
}
/* Optimize for the common case */
- if (strequal(servername, global_myname())) {
+ if (strequal(servername, lp_netbios_name())) {
return true;
}
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, 2);
- if (fds == NULL) {
- errno = ENOMEM;
- return -1;
- }
- fds[0].fd = fd;
- fds[0].events = events;
+ pfd.fd = fd;
+ pfd.events = events;
- ret = sys_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;
}