summaryrefslogtreecommitdiff
path: root/source4
diff options
context:
space:
mode:
Diffstat (limited to 'source4')
-rw-r--r--source4/configure.in1
-rw-r--r--source4/include/includes.h1
-rw-r--r--source4/lib/socket/config.m44
-rw-r--r--source4/lib/socket/config.mk16
-rw-r--r--source4/lib/socket/socket.c215
-rw-r--r--source4/lib/socket/socket.h93
-rw-r--r--source4/lib/socket/socket_ipv4.c293
-rw-r--r--source4/libcli/libsmb.m42
8 files changed, 624 insertions, 1 deletions
diff --git a/source4/configure.in b/source4/configure.in
index eccdc1be6e..6bd8f9323c 100644
--- a/source4/configure.in
+++ b/source4/configure.in
@@ -14,6 +14,7 @@ SMB_INCLUDE_M4(build/m4/rewrite.m4)
SMB_INCLUDE_M4(lib/popt/config.m4)
SMB_INCLUDE_M4(lib/iconv.m4)
SMB_INCLUDE_M4(lib/basic.m4)
+SMB_INCLUDE_M4(lib/socket/config.m4)
SMB_INCLUDE_M4(lib/tdb/config.m4)
SMB_INCLUDE_M4(lib/ldb/config.m4)
SMB_INCLUDE_M4(lib/cmdline/config.m4)
diff --git a/source4/include/includes.h b/source4/include/includes.h
index 33806ab36f..b033d584f8 100644
--- a/source4/include/includes.h
+++ b/source4/include/includes.h
@@ -632,6 +632,7 @@ extern int errno;
#include "rewrite.h"
#include "smb.h"
#include "ads.h"
+#include "lib/socket/socket.h"
#include "libcli/ldap/ldap.h"
#include "nameserv.h"
#include "secrets.h"
diff --git a/source4/lib/socket/config.m4 b/source4/lib/socket/config.m4
new file mode 100644
index 0000000000..a5d3d0916e
--- /dev/null
+++ b/source4/lib/socket/config.m4
@@ -0,0 +1,4 @@
+
+SMB_MODULE_MK(socket_ipv4,SOCKET,STATIC,lib/socket/config.mk)
+
+SMB_SUBSYSTEM_MK(SOCKET,lib/socket/config.mk)
diff --git a/source4/lib/socket/config.mk b/source4/lib/socket/config.mk
new file mode 100644
index 0000000000..854702a6f8
--- /dev/null
+++ b/source4/lib/socket/config.mk
@@ -0,0 +1,16 @@
+
+################################################
+# Start MODULE socket_ipv4
+[MODULE::socket_ipv4]
+INIT_OBJ_FILES = \
+ lib/socket/socket_ipv4.o
+# End MODULE socket_ipv4
+################################################
+
+################################################
+# Start SUBSYSTEM SOCKET
+[SUBSYSTEM::SOCKET]
+INIT_OBJ_FILES = \
+ lib/socket/socket.o
+# End SUBSYSTEM SOCKET
+################################################
diff --git a/source4/lib/socket/socket.c b/source4/lib/socket/socket.c
new file mode 100644
index 0000000000..fefd7a14b2
--- /dev/null
+++ b/source4/lib/socket/socket.c
@@ -0,0 +1,215 @@
+/*
+ Unix SMB/CIFS implementation.
+ Socket functions
+ Copyright (C) Stefan Metzmacher 2004
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+NTSTATUS socket_create(const char *name, enum socket_type type, struct socket_context **new_sock, uint32_t flags)
+{
+ NTSTATUS status;
+
+ (*new_sock) = talloc_p(NULL, struct socket_context);
+ if (!(*new_sock)) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ (*new_sock)->type = type;
+ (*new_sock)->state = SOCKET_STATE_UNDEFINED;
+ (*new_sock)->flags = flags;
+
+ (*new_sock)->fd = -1;
+
+ (*new_sock)->private_data = NULL;
+ (*new_sock)->ops = socket_getops_byname(name, type);
+ if (!(*new_sock)->ops) {
+ talloc_free((*new_sock));
+ return status;
+ }
+
+ status = (*new_sock)->ops->init((*new_sock));
+ if (!NT_STATUS_IS_OK(status)) {
+ talloc_free((*new_sock));
+ return status;
+ }
+
+ return NT_STATUS_OK;
+}
+
+void socket_destroy(struct socket_context *sock)
+{
+ if (sock->ops->close) {
+ sock->ops->close(sock);
+ }
+ talloc_free(sock);
+}
+
+NTSTATUS socket_connect(struct socket_context *sock,
+ const char *my_address, int my_port,
+ const char *server_address, int server_port,
+ uint32_t flags)
+{
+ if (sock->type != SOCKET_TYPE_STREAM) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (sock->state != SOCKET_STATE_UNDEFINED) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (!sock->ops->connect) {
+ return NT_STATUS_NOT_IMPLEMENTED;
+ }
+
+ return sock->ops->connect(sock, my_address, my_port, server_address, server_port, flags);
+}
+
+NTSTATUS socket_listen(struct socket_context *sock, const char *my_address, int port, int queue_size, uint32_t flags)
+{
+ if (sock->type != SOCKET_TYPE_STREAM) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (sock->state != SOCKET_STATE_UNDEFINED) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (!sock->ops->listen) {
+ return NT_STATUS_NOT_IMPLEMENTED;
+ }
+
+ return sock->ops->listen(sock, my_address, port, queue_size, flags);
+}
+
+NTSTATUS socket_accept(struct socket_context *sock, struct socket_context **new_sock, uint32_t flags)
+{
+ if (sock->type != SOCKET_TYPE_STREAM) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (sock->state != SOCKET_STATE_SERVER_LISTEN) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (!sock->ops->accept) {
+ return NT_STATUS_NOT_IMPLEMENTED;
+ }
+
+ return sock->ops->accept(sock, new_sock, flags);
+}
+
+NTSTATUS socket_recv(struct socket_context *sock, TALLOC_CTX *mem_ctx,
+ DATA_BLOB *blob, size_t wantlen, uint32_t flags)
+{
+ if (sock->type != SOCKET_TYPE_STREAM) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (sock->state != SOCKET_STATE_CLIENT_CONNECTED ||
+ sock->state != SOCKET_STATE_SERVER_CONNECTED) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (!sock->ops->recv) {
+ return NT_STATUS_NOT_IMPLEMENTED;
+ }
+
+ return sock->ops->recv(sock, mem_ctx, blob, wantlen, flags);
+}
+
+NTSTATUS socket_send(struct socket_context *sock, TALLOC_CTX *mem_ctx,
+ const DATA_BLOB *blob, size_t *sendlen, uint32_t flags)
+{
+ if (sock->type != SOCKET_TYPE_STREAM) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (sock->state != SOCKET_STATE_CLIENT_CONNECTED ||
+ sock->state != SOCKET_STATE_SERVER_CONNECTED) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ if (!sock->ops->send) {
+ return NT_STATUS_NOT_IMPLEMENTED;
+ }
+
+ return sock->ops->send(sock, mem_ctx, blob, sendlen, flags);
+}
+
+NTSTATUS socket_set_option(struct socket_context *sock, const char *option, const char *val)
+{
+ if (!sock->ops->set_option) {
+ return NT_STATUS_NOT_IMPLEMENTED;
+ }
+
+ return sock->ops->set_option(sock, option, val);
+}
+
+const char *socket_get_peer_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
+{
+ if (!sock->ops->get_peer_addr) {
+ return NULL;
+ }
+
+ return sock->ops->get_peer_addr(sock, mem_ctx);
+}
+
+int socket_get_peer_port(struct socket_context *sock, TALLOC_CTX *mem_ctx)
+{
+ if (!sock->ops->get_peer_port) {
+ return -1;
+ }
+
+ return sock->ops->get_peer_port(sock, mem_ctx);
+}
+
+const char *socket_get_my_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
+{
+ if (!sock->ops->get_my_addr) {
+ return NULL;
+ }
+
+ return sock->ops->get_my_addr(sock, mem_ctx);
+}
+
+int socket_get_my_port(struct socket_context *sock, TALLOC_CTX *mem_ctx)
+{
+ if (!sock->ops->get_my_port) {
+ return -1;
+ }
+
+ return sock->ops->get_my_port(sock, mem_ctx);
+}
+
+int socket_get_fd(struct socket_context *sock, TALLOC_CTX *mem_ctx)
+{
+ if (!sock->ops->get_fd) {
+ return -1;
+ }
+
+ return sock->ops->get_fd(sock, mem_ctx);
+}
+
+const struct socket_ops *socket_getops_byname(const char *name, enum socket_type type)
+{
+ if (strequal("ip", name) || strequal("ipv4", name)) {
+ return socket_ipv4_ops();
+ }
+
+ return NULL;
+}
diff --git a/source4/lib/socket/socket.h b/source4/lib/socket/socket.h
new file mode 100644
index 0000000000..dfc964b741
--- /dev/null
+++ b/source4/lib/socket/socket.h
@@ -0,0 +1,93 @@
+/*
+ Unix SMB/CIFS implementation.
+ Socket functions
+ Copyright (C) Stefan Metzmacher 2004
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#ifndef _SAMBA_SOCKET_H
+#define _SAMBA_SOCKET_H
+
+struct socket_context;
+
+enum socket_type {
+ SOCKET_TYPE_STREAM
+};
+
+struct socket_ops {
+ const char *name;
+ enum socket_type type;
+
+ NTSTATUS (*init)(struct socket_context *sock);
+
+ /* client ops */
+ NTSTATUS (*connect)(struct socket_context *sock,
+ const char *my_address, int my_port,
+ const char *server_address, int server_port,
+ uint32_t flags);
+
+ /* server ops */
+ NTSTATUS (*listen)(struct socket_context *sock,
+ const char *my_address, int port, int queue_size, uint32_t flags);
+ NTSTATUS (*accept)(struct socket_context *sock,
+ struct socket_context **new_sock, uint32_t flags);
+
+ /* general ops */
+ NTSTATUS (*recv)(struct socket_context *sock, TALLOC_CTX *mem_ctx,
+ DATA_BLOB *blob, size_t wantlen, uint32_t flags);
+ NTSTATUS (*send)(struct socket_context *sock, TALLOC_CTX *mem_ctx,
+ const DATA_BLOB *blob, size_t *sendlen, uint32_t flags);
+
+ void (*close)(struct socket_context *sock);
+
+ NTSTATUS (*set_option)(struct socket_context *sock, const char *option, const char *val);
+
+ const char *(*get_peer_addr)(struct socket_context *sock, TALLOC_CTX *mem_ctx);
+ int (*get_peer_port)(struct socket_context *sock, TALLOC_CTX *mem_ctx);
+ const char *(*get_my_addr)(struct socket_context *sock, TALLOC_CTX *mem_ctx);
+ int (*get_my_port)(struct socket_context *sock, TALLOC_CTX *mem_ctx);
+
+ int (*get_fd)(struct socket_context *sock, TALLOC_CTX *mem_ctx);
+};
+
+enum socket_state {
+ SOCKET_STATE_UNDEFINED,
+
+ SOCKET_STATE_CLIENT_START,
+ SOCKET_STATE_CLIENT_CONNECTED,
+ SOCKET_STATE_CLIENT_STARTTLS,
+ SOCKET_STATE_CLIENT_ERROR,
+
+ SOCKET_STATE_SERVER_LISTEN,
+ SOCKET_STATE_SERVER_CONNECTED,
+ SOCKET_STATE_SERVER_STARTTLS,
+ SOCKET_STATE_SERVER_ERROR
+};
+
+#define SOCKET_OPTION_BLOCK 0x00000001
+
+struct socket_context {
+ enum socket_type type;
+ enum socket_state state;
+ uint32_t flags;
+
+ int fd;
+
+ void *private_data;
+ const struct socket_ops *ops;
+};
+
+#endif /* _SAMBA_SOCKET_H */
diff --git a/source4/lib/socket/socket_ipv4.c b/source4/lib/socket/socket_ipv4.c
new file mode 100644
index 0000000000..90f289a1e0
--- /dev/null
+++ b/source4/lib/socket/socket_ipv4.c
@@ -0,0 +1,293 @@
+/*
+ Unix SMB/CIFS implementation.
+ Socket IPv4 functions
+ Copyright (C) Stefan Metzmacher 2004
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 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, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+static NTSTATUS ipv4_tcp_init(struct socket_context *sock)
+{
+ sock->fd = socket(PF_INET, SOCK_STREAM, 0);
+ if (sock->fd == -1) {
+ /* TODO: we need to map from errno to NTSTATUS here! */
+ return NT_STATUS_FOOBAR;
+ }
+
+ return NT_STATUS_OK;
+}
+
+static void ipv4_tcp_close(struct socket_context *sock)
+{
+ close(sock->fd);
+}
+
+static NTSTATUS ipv4_tcp_connect(struct socket_context *sock,
+ const char *my_address, int my_port,
+ const char *srv_address, int srv_port,
+ uint32_t flags)
+{
+ struct sockaddr_in my_addr;
+ struct sockaddr_in srv_addr;
+ struct in_addr my_ip;
+ struct in_addr srv_ip;
+ int ret;
+
+ ret = inet_aton(my_address, &my_ip);
+ if (ret == 0) {
+ /* not a valid ipv4 address */
+ return NT_STATUS_FOOBAR;
+ }
+
+ ZERO_STRUCT(my_addr);
+#ifdef HAVE_SOCK_SIN_LEN
+ my_addr.sin_len = sizeof(my_addr);
+#endif
+ my_addr.sin_addr = my_ip;
+ my_addr.sin_port = htons(my_port);
+ my_addr.sin_family = PF_INET;
+
+ ret = inet_aton(srv_address, &srv_ip);
+ if (ret == 0) {
+ /* not a valid ipv4 address */
+ return NT_STATUS_FOOBAR;
+ }
+
+ ret = bind(sock->fd, &my_addr, sizeof(my_addr));
+ if (ret == -1) {
+ /* TODO: we need to map from errno to NTSTATUS here! */
+ return NT_STATUS_FOOBAR;
+ }
+
+ ZERO_STRUCT(srv_addr);
+#ifdef HAVE_SOCK_SIN_LEN
+ srv_addr.sin_len = sizeof(srv_addr);
+#endif
+ srv_addr.sin_addr = srv_ip;
+ srv_addr.sin_port = htons(srv_port);
+ srv_addr.sin_family = PF_INET;
+
+ if (!(flags & SOCKET_OPTION_BLOCK)) {
+ ret = set_blocking(sock->fd, False);
+ if (ret == -1) {
+ /* TODO: we need to map from errno to NTSTATUS here! */
+ return NT_STATUS_FOOBAR;
+ }
+ }
+
+
+ ret = connect(sock->fd, &srv_addr, sizeof(srv_addr));
+ if (ret == -1) {
+ /* TODO: we need to map from errno to NTSTATUS here! */
+ return NT_STATUS_FOOBAR;
+ }
+
+ sock->state = SOCKET_STATE_CLIENT_CONNECTED;
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS ipv4_tcp_listen(struct socket_context *sock,
+ const char *my_address, int port,
+ int queue_size, uint32_t flags)
+{
+ struct sockaddr_in my_addr;
+ struct in_addr ip_addr;
+ int ret;
+
+ ZERO_STRUCT(my_addr);
+
+ ret = inet_aton(my_address, &ip_addr);
+ if (ret == 0) {
+ /* not a valid ipv4 address */
+ return NT_STATUS_FOOBAR;
+ }
+
+#ifdef HAVE_SOCK_SIN_LEN
+ my_addr.sin_len = sizeof(my_addr);
+#endif
+ my_addr.sin_addr = ip_addr;
+ my_addr.sin_port = htons(port);
+ my_addr.sin_family = PF_INET;
+
+ ret = bind(sock->fd, &my_addr, sizeof(my_addr));
+ if (ret == -1) {
+ /* TODO: we need to map from errno to NTSTATUS here! */
+ return NT_STATUS_FOOBAR;
+ }
+
+ ret = listen(sock->fd, queue_size);
+ if (ret == -1) {
+ /* TODO: we need to map from errno to NTSTATUS here! */
+ return NT_STATUS_FOOBAR;
+ }
+
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+static NTSTATUS ipv4_tcp_accept(struct socket_context *sock, struct socket_context **new_sock, uint32_t flags)
+{
+ struct sockaddr_in cli_addr;
+ socklen_t cli_addr_len = 0;
+ int new_fd;
+ int ret;
+
+ new_fd = accept(sock->fd, &cli_addr, &cli_addr_len);
+ if (new_fd == -1) {
+ /* TODO: we need to map from errno to NTSTATUS here! */
+ return NT_STATUS_FOOBAR;
+ }
+
+ if (!(flags & SOCKET_OPTION_BLOCK)) {
+ ret = set_blocking(sock->fd, False);
+ if (ret == -1) {
+ /* TODO: we need to map from errno to NTSTATUS here! */
+ return NT_STATUS_FOOBAR;
+ }
+ }
+
+ /* TODO: we could add a 'accept_check' hook here
+ * which get the black/white lists via socket_set_accept_filter()
+ * or something like that
+ * --metze
+ */
+
+ (*new_sock) = talloc_p(NULL, struct socket_context);
+ if (!(*new_sock)) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* copy the socket_context */
+ (*new_sock)->type = sock->type;
+ (*new_sock)->state = SOCKET_STATE_SERVER_CONNECTED;
+ (*new_sock)->flags = flags;
+
+ (*new_sock)->fd = new_fd;
+
+ (*new_sock)->private_data = NULL;
+ (*new_sock)->ops = sock->ops;
+
+ return NT_STATUS_NOT_IMPLEMENTED;
+}
+
+static NTSTATUS ipv4_tcp_recv(struct socket_context *sock, TALLOC_CTX *mem_ctx,
+ DATA_BLOB *blob, size_t wantlen, uint32_t flags)
+{
+ ssize_t gotlen;
+ void *buf;
+ int flgs = 0;
+
+ buf = talloc(mem_ctx, wantlen);
+ if (!buf) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* TODO: we need to map the flags here */
+
+ gotlen = recv(sock->fd, buf, wantlen, flgs);
+ if (gotlen == -1) {
+ talloc_free(buf);
+ /* TODO: we need to map from errno to NTSTATUS here! */
+ return NT_STATUS_FOOBAR;
+ }
+
+ blob->length = gotlen;
+ blob->data = buf;
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS ipv4_tcp_send(struct socket_context *sock, TALLOC_CTX *mem_ctx,
+ const DATA_BLOB *blob, size_t *sendlen, uint32_t flags)
+{
+ ssize_t len;
+ int flgs = 0;
+
+ /* TODO: we need to map the flags here */
+
+ len = send(sock->fd, blob->data, blob->length, flgs);
+ if (len == -1) {
+ /* TODO: we need to map from errno to NTSTATUS here! */
+ return NT_STATUS_FOOBAR;
+ }
+
+ *sendlen = len;
+
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS ipv4_tcp_set_option(struct socket_context *sock, const char *option, const char *val)
+{
+ return NT_STATUS_NOT_SUPPORTED;
+}
+
+static const char *ipv4_tcp_get_peer_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
+{
+ return NULL;
+}
+
+static int ipv4_tcp_get_peer_port(struct socket_context *sock, TALLOC_CTX *mem_ctx)
+{
+ return -1;
+}
+
+static const char *ipv4_tcp_get_my_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
+{
+ return NULL;
+}
+
+static int ipv4_tcp_get_my_port(struct socket_context *sock, TALLOC_CTX *mem_ctx)
+{
+ return -1;
+}
+
+static int ipv4_tcp_get_fd(struct socket_context *sock, TALLOC_CTX *mem_ctx)
+{
+ return sock->fd;
+}
+
+static const struct socket_ops ipv4_tcp_ops = {
+ .name = "ipv4",
+ .type = SOCKET_TYPE_STREAM,
+
+ .init = ipv4_tcp_init,
+ .connect = ipv4_tcp_connect,
+ .listen = ipv4_tcp_listen,
+ .accept = ipv4_tcp_accept,
+ .recv = ipv4_tcp_recv,
+ .send = ipv4_tcp_send,
+ .close = ipv4_tcp_close,
+
+ .set_option = ipv4_tcp_set_option,
+
+ .get_peer_addr = ipv4_tcp_get_peer_addr,
+ .get_peer_port = ipv4_tcp_get_peer_port,
+ .get_my_addr = ipv4_tcp_get_my_addr,
+ .get_my_port = ipv4_tcp_get_my_port,
+
+ .get_fd = ipv4_tcp_get_fd
+};
+
+const struct socket_ops *socket_ipv4_ops(void)
+{
+ return &ipv4_tcp_ops;
+}
+
+NTSTATUS socket_ipv4_init(void)
+{
+ return NT_STATUS_OK;
+}
diff --git a/source4/libcli/libsmb.m4 b/source4/libcli/libsmb.m4
index fe2a5b17ba..9293ea2038 100644
--- a/source4/libcli/libsmb.m4
+++ b/source4/libcli/libsmb.m4
@@ -9,4 +9,4 @@ SMB_SUBSYSTEM(LIBSMB,[],
libcli/climessage.o
libcli/clideltree.o],
[],
- [LIBCLI LIBRPC])
+ [LIBCLI LIBRPC SOCKET])