diff options
author | Andrew Tridgell <tridge@samba.org> | 2005-01-30 00:54:57 +0000 |
---|---|---|
committer | Gerald (Jerry) Carter <jerry@samba.org> | 2007-10-10 13:09:22 -0500 |
commit | 55d4d36993293fee914a009f1d8f05810e347f2b (patch) | |
tree | 587a9bafd1c8df901aad8766acb0fe9ef4c3d8c0 | |
parent | 5540449f1cd9d9a6efab59f2bf47be4e1487ffc2 (diff) | |
download | samba-55d4d36993293fee914a009f1d8f05810e347f2b.tar.gz samba-55d4d36993293fee914a009f1d8f05810e347f2b.tar.bz2 samba-55d4d36993293fee914a009f1d8f05810e347f2b.zip |
r5102: This is a major simplification of the logic for controlling top level
servers in smbd. The old code still contained a fairly bit of legacy
from the time when smbd was only handling SMB connection. The new code
gets rid of all of the smb_server specific code in smbd/, and creates
a much simpler infrastructures for new server code.
Major changes include:
- simplified the process model code a lot.
- got rid of the top level server and service structures
completely. The top level context is now the event_context. This
got rid of service.h and server.h completely (they were the most
confusing parts of the old code)
- added service_stream.[ch] for the helper functions that are
specific to stream type services (services that handle streams, and
use a logically separate process per connection)
- got rid of the builtin idle_handler code in the service logic, as
none of the servers were using it, and it can easily be handled by
a server in future by adding its own timed_event to the event
context.
- fixed some major memory leaks in the rpc server code.
- added registration of servers, rather than hard coding our list of
possible servers. This allows for servers as modules in the future.
- temporarily disabled the winbind code until I add the helper
functions for that type of server
- added error checking on service startup. If a configured server
fails to startup then smbd doesn't startup.
- cleaned up the command line handling in smbd, removing unused options
(This used to be commit cf6a46c3cbde7b1eb1b86bd3882b953a2de3a42e)
36 files changed, 633 insertions, 1558 deletions
diff --git a/source4/build/smb_build/main.pm b/source4/build/smb_build/main.pm index 55009d14e5..3911820edb 100644 --- a/source4/build/smb_build/main.pm +++ b/source4/build/smb_build/main.pm @@ -54,8 +54,7 @@ sub smb_build_main($) "client/config.mk", "libcli/libsmb.mk", "libcli/config.mk", - "libcli/security/config.mk", - "winbind/config.mk", + "libcli/security/config.mk" ); $| = 1; diff --git a/source4/include/includes.h b/source4/include/includes.h index 70e06e2a58..ce24525158 100644 --- a/source4/include/includes.h +++ b/source4/include/includes.h @@ -139,8 +139,6 @@ extern int errno; #include "lib/dcom/common/dcom.h" #include "librpc/gen_ndr/ndr_dcom.h" #include "smb_interfaces.h" -#include "smbd/server.h" -#include "smbd/service.h" #include "ntvfs/ntvfs.h" #include "cli_context.h" #include "nsswitch/winbind_client.h" diff --git a/source4/include/structs.h b/source4/include/structs.h index 29a6589a86..cf59296f32 100644 --- a/source4/include/structs.h +++ b/source4/include/structs.h @@ -151,3 +151,8 @@ struct nbt_name_socket; struct nbt_name_query; struct nbt_name_status; + +struct messaging_context; +struct stream_connection; +struct model_ops; +struct stream_server_ops; diff --git a/source4/ldap_server/ldap_server.c b/source4/ldap_server/ldap_server.c index d5b4aaae43..96305b1b2a 100644 --- a/source4/ldap_server/ldap_server.c +++ b/source4/ldap_server/ldap_server.c @@ -25,107 +25,14 @@ #include "dlinklist.h" #include "asn_1.h" #include "ldap_server/ldap_server.h" +#include "smbd/service_stream.h" /* close the socket and shutdown a server_context */ static void ldapsrv_terminate_connection(struct ldapsrv_connection *ldap_conn, const char *reason) { - server_terminate_connection(ldap_conn->connection, reason); -} - -static const struct server_stream_ops *ldapsrv_get_stream_ops(void); - -/* - add a socket address to the list of events, one event per port -*/ -static void add_socket(struct server_service *service, - struct ipv4_addr *ifip) -{ - struct server_stream_socket *stream_socket; - uint16_t port = 389; - char *ip_str = talloc_strdup(service, sys_inet_ntoa(*ifip)); - - stream_socket = service_setup_stream_socket(service, ldapsrv_get_stream_ops(), "ipv4", ip_str, &port); - - port = 3268; - stream_socket = service_setup_stream_socket(service, ldapsrv_get_stream_ops(), "ipv4", ip_str, &port); - - talloc_free(ip_str); -} - -/**************************************************************************** - Open the socket communication. -****************************************************************************/ -static void ldapsrv_init(struct server_service *service) -{ - struct ldapsrv_service *ldap_service; - struct ldapsrv_partition *rootDSE_part; - struct ldapsrv_partition *part; - - DEBUG(10,("ldapsrv_init\n")); - - ldap_service = talloc(service, struct ldapsrv_service); - if (!ldap_service) { - DEBUG(0,("talloc(service, struct ldapsrv_service) failed\n")); - return; - } - ZERO_STRUCTP(ldap_service); - - rootDSE_part = talloc(ldap_service, struct ldapsrv_partition); - if (!rootDSE_part) { - DEBUG(0,("talloc(ldap_service, struct ldapsrv_partition) failed\n")); - return; - } - rootDSE_part->base_dn = ""; /* RootDSE */ - rootDSE_part->ops = ldapsrv_get_rootdse_partition_ops(); - - ldap_service->rootDSE = rootDSE_part; - DLIST_ADD_END(ldap_service->partitions, rootDSE_part, struct ldapsrv_partition *); - - part = talloc(ldap_service, struct ldapsrv_partition); - if (!ldap_service) { - DEBUG(0,("talloc(ldap_service, struct ldapsrv_partition) failed\n")); - return; - } - part->base_dn = "*"; /* default partition */ - if (lp_parm_bool(-1, "ldapsrv", "hacked", False)) { - part->ops = ldapsrv_get_hldb_partition_ops(); - } else { - part->ops = ldapsrv_get_sldb_partition_ops(); - } - - ldap_service->default_partition = part; - DLIST_ADD_END(ldap_service->partitions, part, struct ldapsrv_partition *); - - service->service.private_data = ldap_service; - - if (lp_interfaces() && lp_bind_interfaces_only()) { - int num_interfaces = iface_count(); - int i; - - /* We have been given an interfaces line, and been - told to only bind to those interfaces. Create a - socket per interface and bind to only these. - */ - for(i = 0; i < num_interfaces; i++) { - struct ipv4_addr *ifip = iface_n_ip(i); - - if (ifip == NULL) { - DEBUG(0,("ldapsrv_init: interface %d has NULL " - "IP address !\n", i)); - continue; - } - - add_socket(service, ifip); - } - } else { - struct ipv4_addr ifip; - - /* Just bind to lp_socket_address() (usually 0.0.0.0) */ - ifip = interpret_addr2(lp_socket_address()); - add_socket(service, &ifip); - } + stream_terminate_connection(ldap_conn->connection, reason); } /* This rw-buf api is made to avoid memcpy. For now do that like mad... The @@ -421,10 +328,10 @@ NTSTATUS ldapsrv_flush_responses(struct ldapsrv_connection *conn) /* called when a LDAP socket becomes readable */ -static void ldapsrv_recv(struct server_connection *conn, struct timeval t, +static void ldapsrv_recv(struct stream_connection *conn, struct timeval t, uint16_t flags) { - struct ldapsrv_connection *ldap_conn = conn->connection.private_data; + struct ldapsrv_connection *ldap_conn = talloc_get_type(conn->private, struct ldapsrv_connection); uint8_t *buf; size_t buf_length, msg_length; DATA_BLOB blob; @@ -517,10 +424,10 @@ static void ldapsrv_recv(struct server_connection *conn, struct timeval t, /* called when a LDAP socket becomes writable */ -static void ldapsrv_send(struct server_connection *conn, struct timeval t, +static void ldapsrv_send(struct stream_connection *conn, struct timeval t, uint16_t flags) { - struct ldapsrv_connection *ldap_conn = conn->connection.private_data; + struct ldapsrv_connection *ldap_conn = talloc_get_type(conn->private, struct ldapsrv_connection); DEBUG(10,("ldapsrv_send\n")); @@ -540,52 +447,108 @@ static void ldapsrv_send(struct server_connection *conn, struct timeval t, initialise a server_context from a open socket and register a event handler for reading from that socket */ -static void ldapsrv_accept(struct server_connection *conn) +static void ldapsrv_accept(struct stream_connection *conn) { struct ldapsrv_connection *ldap_conn; DEBUG(10, ("ldapsrv_accept\n")); - ldap_conn = talloc(conn, struct ldapsrv_connection); + ldap_conn = talloc_zero(conn, struct ldapsrv_connection); if (ldap_conn == NULL) return; - ZERO_STRUCTP(ldap_conn); ldap_conn->connection = conn; - ldap_conn->service = talloc_reference(ldap_conn, conn->stream_socket->service->service.private_data); - - conn->connection.private_data = ldap_conn; - - return; + ldap_conn->service = talloc_get_type(conn->private, struct ldapsrv_service); + conn->private = ldap_conn; } -static const struct server_stream_ops ldap_stream_ops = { +static const struct stream_server_ops ldap_stream_ops = { .name = "ldap", - .socket_init = NULL, .accept_connection = ldapsrv_accept, .recv_handler = ldapsrv_recv, .send_handler = ldapsrv_send, - .idle_handler = NULL, - .close_connection = NULL }; -static const struct server_stream_ops *ldapsrv_get_stream_ops(void) +/* + add a socket address to the list of events, one event per port +*/ +static NTSTATUS add_socket(struct event_context *event_context, const struct model_ops *model_ops, + const char *address, struct ldapsrv_service *ldap_service) { - return &ldap_stream_ops; + uint16_t port = 389; + NTSTATUS status; + + status = stream_setup_socket(event_context, model_ops, &ldap_stream_ops, + "ipv4", address, &port, ldap_service); + NT_STATUS_NOT_OK_RETURN(status); + + port = 3268; + + return stream_setup_socket(event_context, model_ops, &ldap_stream_ops, + "ipv4", address, &port, ldap_service); } -static const struct server_service_ops ldap_server_ops = { - .name = "ldap", - .service_init = ldapsrv_init -}; +/* + open the ldap server sockets +*/ +static NTSTATUS ldapsrv_init(struct event_context *event_context, const struct model_ops *model_ops) +{ + struct ldapsrv_service *ldap_service; + struct ldapsrv_partition *rootDSE_part; + struct ldapsrv_partition *part; + NTSTATUS status; -const struct server_service_ops *ldapsrv_get_ops(void) -{ - return &ldap_server_ops; + DEBUG(10,("ldapsrv_init\n")); + + ldap_service = talloc_zero(event_context, struct ldapsrv_service); + NT_STATUS_HAVE_NO_MEMORY(ldap_service); + + rootDSE_part = talloc(ldap_service, struct ldapsrv_partition); + NT_STATUS_HAVE_NO_MEMORY(rootDSE_part); + + rootDSE_part->base_dn = ""; /* RootDSE */ + rootDSE_part->ops = ldapsrv_get_rootdse_partition_ops(); + + ldap_service->rootDSE = rootDSE_part; + DLIST_ADD_END(ldap_service->partitions, rootDSE_part, struct ldapsrv_partition *); + + part = talloc(ldap_service, struct ldapsrv_partition); + NT_STATUS_HAVE_NO_MEMORY(part); + + part->base_dn = "*"; /* default partition */ + if (lp_parm_bool(-1, "ldapsrv", "hacked", False)) { + part->ops = ldapsrv_get_hldb_partition_ops(); + } else { + part->ops = ldapsrv_get_sldb_partition_ops(); + } + + ldap_service->default_partition = part; + DLIST_ADD_END(ldap_service->partitions, part, struct ldapsrv_partition *); + + if (lp_interfaces() && lp_bind_interfaces_only()) { + int num_interfaces = iface_count(); + int i; + + /* We have been given an interfaces line, and been + told to only bind to those interfaces. Create a + socket per interface and bind to only these. + */ + for(i = 0; i < num_interfaces; i++) { + const char *address = sys_inet_ntoa(*iface_n_ip(i)); + status = add_socket(event_context, model_ops, address, ldap_service); + NT_STATUS_NOT_OK_RETURN(status); + } + } else { + status = add_socket(event_context, model_ops, lp_socket_address(), ldap_service); + NT_STATUS_NOT_OK_RETURN(status); + } + + return NT_STATUS_OK; } + NTSTATUS server_service_ldap_init(void) { - return NT_STATUS_OK; + return register_server_service("ldap", ldapsrv_init); } diff --git a/source4/ldap_server/ldap_server.h b/source4/ldap_server/ldap_server.h index 6d4824bc9d..39052a7671 100644 --- a/source4/ldap_server/ldap_server.h +++ b/source4/ldap_server/ldap_server.h @@ -57,7 +57,7 @@ struct ldapsrv_call { struct ldapsrv_service; struct ldapsrv_connection { - struct server_connection *connection; + struct stream_connection *connection; struct gensec_security *gensec; struct auth_session_info *session_info; diff --git a/source4/lib/messaging/messaging.c b/source4/lib/messaging/messaging.c index e2e8161111..09d30027b0 100644 --- a/source4/lib/messaging/messaging.c +++ b/source4/lib/messaging/messaging.c @@ -33,7 +33,7 @@ #define MESSAGING_BACKOFF 250000 struct messaging_context { - servid_t server_id; + uint32_t server_id; struct socket_context *sock; char *path; struct dispatch_fn *dispatch; @@ -51,7 +51,7 @@ struct dispatch_fn { uint32_t msg_type; void *private; void (*fn)(struct messaging_context *msg, void *private, - uint32_t msg_type, servid_t server_id, DATA_BLOB *data); + uint32_t msg_type, uint32_t server_id, DATA_BLOB *data); }; /* an individual message */ @@ -64,8 +64,8 @@ struct messaging_rec { struct { uint32_t version; uint32_t msg_type; - servid_t from; - servid_t to; + uint32_t from; + uint32_t to; uint32_t length; } header; @@ -78,7 +78,7 @@ struct messaging_rec { A useful function for testing the message system. */ static void ping_message(struct messaging_context *msg, void *private, - uint32_t msg_type, servid_t src, DATA_BLOB *data) + uint32_t msg_type, uint32_t src, DATA_BLOB *data) { DEBUG(1,("INFO: Received PING message from server %u [%.*s]\n", (uint_t)src, data->length, data->data?(const char *)data->data:"")); @@ -88,7 +88,7 @@ static void ping_message(struct messaging_context *msg, void *private, /* return the path to a messaging socket */ -static char *messaging_path(TALLOC_CTX *mem_ctx, servid_t server_id) +static char *messaging_path(TALLOC_CTX *mem_ctx, uint32_t server_id) { char *name = talloc_asprintf(mem_ctx, "messaging/msg.%u", (unsigned)server_id); char *ret; @@ -228,7 +228,7 @@ static void messaging_listen_handler(struct event_context *ev, struct fd_event * */ void messaging_register(struct messaging_context *msg, void *private, uint32_t msg_type, - void (*fn)(struct messaging_context *, void *, uint32_t, servid_t, DATA_BLOB *)) + void (*fn)(struct messaging_context *, void *, uint32_t, uint32_t, DATA_BLOB *)) { struct dispatch_fn *d; @@ -365,7 +365,7 @@ static void messaging_backoff_handler(struct event_context *ev, struct timed_eve /* Send a message to a particular server */ -NTSTATUS messaging_send(struct messaging_context *msg, servid_t server, uint32_t msg_type, DATA_BLOB *data) +NTSTATUS messaging_send(struct messaging_context *msg, uint32_t server, uint32_t msg_type, DATA_BLOB *data) { struct messaging_rec *rec; NTSTATUS status; @@ -429,7 +429,7 @@ NTSTATUS messaging_send(struct messaging_context *msg, servid_t server, uint32_t /* Send a message to a particular server, with the message containing a single pointer */ -NTSTATUS messaging_send_ptr(struct messaging_context *msg, servid_t server, +NTSTATUS messaging_send_ptr(struct messaging_context *msg, uint32_t server, uint32_t msg_type, void *ptr) { DATA_BLOB blob; @@ -454,7 +454,7 @@ static int messaging_destructor(void *ptr) /* create the listening socket and setup the dispatcher */ -struct messaging_context *messaging_init(TALLOC_CTX *mem_ctx, servid_t server_id, struct event_context *ev) +struct messaging_context *messaging_init(TALLOC_CTX *mem_ctx, uint32_t server_id, struct event_context *ev) { struct messaging_context *msg; NTSTATUS status; @@ -496,7 +496,7 @@ struct messaging_context *messaging_init(TALLOC_CTX *mem_ctx, servid_t server_id fde.flags = EVENT_FD_READ; fde.handler = messaging_listen_handler; - msg->event.ev = talloc_reference(msg,ev); + msg->event.ev = talloc_reference(msg, ev); msg->event.fde = event_add_fd(ev, &fde, msg); talloc_set_destructor(msg, messaging_destructor); diff --git a/source4/ntvfs/cifs/vfs_cifs.c b/source4/ntvfs/cifs/vfs_cifs.c index 7ac687dd46..13b11d8ba2 100644 --- a/source4/ntvfs/cifs/vfs_cifs.c +++ b/source4/ntvfs/cifs/vfs_cifs.c @@ -30,6 +30,7 @@ #include "libcli/raw/libcliraw.h" #include "libcli/composite/composite.h" #include "smb_server/smb_server.h" +#include "smbd/service_stream.h" /* this is stored in ntvfs_private */ struct cvfs_private { @@ -49,22 +50,6 @@ struct async_info { #define SETUP_PID private->tree->session->pid = SVAL(req->in.hdr, HDR_PID) /* - an idle function to cope with messages from the smbd client while - waiting for a reply from the server - this function won't be needed once all of the cifs backend - and the core of smbd is converted to use async calls -*/ -static void idle_func(struct smbcli_transport *transport, void *p_private) -{ - struct cvfs_private *private = p_private; - int fd = socket_get_fd(private->tcon->smb_conn->connection->socket); - - if (socket_pending(fd)) { - smbd_process_async(private->tcon->smb_conn); - } -} - -/* a handler for oplock break events from the server - these need to be passed along to the client */ @@ -158,7 +143,6 @@ static NTSTATUS cvfs_connect(struct ntvfs_module_context *ntvfs, /* we need to receive oplock break requests from the server */ smbcli_oplock_handler(private->transport, oplock_handler, private); - smbcli_transport_idle_handler(private->transport, idle_func, 50000, private); private->transport->socket->event.fde->handler = cifs_socket_handler; private->transport->socket->event.fde->private = private; diff --git a/source4/ntvfs/common/brlock.c b/source4/ntvfs/common/brlock.c index f51e3d0694..d521dc80d3 100644 --- a/source4/ntvfs/common/brlock.c +++ b/source4/ntvfs/common/brlock.c @@ -41,7 +41,7 @@ lock is the same as another lock */ struct lock_context { - servid_t server; + uint32_t server; uint16_t smbpid; uint16_t tid; }; @@ -60,7 +60,7 @@ struct lock_struct { struct brl_context { struct tdb_wrap *w; - servid_t server; + uint32_t server; uint16_t tid; struct messaging_context *messaging_ctx; struct lock_struct last_lock; @@ -72,7 +72,7 @@ struct brl_context { talloc_free(). We need the messaging_ctx to allow for pending lock notifications. */ -struct brl_context *brl_init(TALLOC_CTX *mem_ctx, servid_t server, uint16_t tid, +struct brl_context *brl_init(TALLOC_CTX *mem_ctx, uint32_t server, uint16_t tid, struct messaging_context *messaging_ctx) { char *path; diff --git a/source4/ntvfs/common/opendb.c b/source4/ntvfs/common/opendb.c index 0aa257073d..3c206528dd 100644 --- a/source4/ntvfs/common/opendb.c +++ b/source4/ntvfs/common/opendb.c @@ -44,7 +44,7 @@ struct odb_context { struct tdb_wrap *w; - servid_t server; + uint32_t server; struct messaging_context *messaging_ctx; }; @@ -53,7 +53,7 @@ struct odb_context { following form */ struct odb_entry { - servid_t server; + uint32_t server; void *file_handle; uint32_t stream_id; uint32_t share_access; @@ -78,7 +78,7 @@ struct odb_lock { talloc_free(). We need the messaging_ctx to allow for pending open notifications. */ -struct odb_context *odb_init(TALLOC_CTX *mem_ctx, servid_t server, +struct odb_context *odb_init(TALLOC_CTX *mem_ctx, uint32_t server, struct messaging_context *messaging_ctx) { char *path; diff --git a/source4/ntvfs/ipc/vfs_ipc.c b/source4/ntvfs/ipc/vfs_ipc.c index 402d1ead64..04a1a06db3 100644 --- a/source4/ntvfs/ipc/vfs_ipc.c +++ b/source4/ntvfs/ipc/vfs_ipc.c @@ -180,7 +180,7 @@ static NTSTATUS ipc_open_generic(struct ntvfs_module_context *ntvfs, struct dcerpc_binding ep_description; struct ipc_private *private = ntvfs->private_data; int fnum; - struct server_connection *srv_conn; + struct stream_connection *srv_conn = req->smb_conn->connection; if (!req->session || !req->session->session_info) { return NT_STATUS_ACCESS_DENIED; @@ -211,11 +211,6 @@ static NTSTATUS ipc_open_generic(struct ntvfs_module_context *ntvfs, ep_description.transport = NCACN_NP; ep_description.endpoint = p->pipe_name; - /* TOTO: pass in full server_connection in here */ - srv_conn = talloc_zero(p, struct server_connection); - NT_STATUS_HAVE_NO_MEMORY(srv_conn); - srv_conn->event.ctx = talloc_reference(srv_conn, req->smb_conn->connection->event.ctx); - /* The session info is refcount-increased in the * dcesrv_endpoint_search_connect() function */ diff --git a/source4/ntvfs/posix/pvfs_wait.c b/source4/ntvfs/posix/pvfs_wait.c index c8d696f0fc..276b1d4e9a 100644 --- a/source4/ntvfs/posix/pvfs_wait.c +++ b/source4/ntvfs/posix/pvfs_wait.c @@ -24,6 +24,7 @@ #include "events.h" #include "dlinklist.h" #include "vfs_posix.h" +#include "smbd/service_stream.h" /* the context for a single wait instance */ struct pvfs_wait { @@ -56,7 +57,7 @@ NTSTATUS pvfs_async_setup(struct ntvfs_module_context *ntvfs, receive a completion message for a wait */ static void pvfs_wait_dispatch(struct messaging_context *msg, void *private, uint32_t msg_type, - servid_t src, DATA_BLOB *data) + uint32_t src, DATA_BLOB *data) { struct pvfs_wait *pwait = private; struct smbsrv_request *req; @@ -133,7 +134,7 @@ static int pvfs_wait_destructor(void *ptr) pwait->private = private; pwait->handler = fn; - pwait->msg_ctx = pvfs->tcon->smb_conn->connection->messaging.ctx; + pwait->msg_ctx = pvfs->tcon->smb_conn->connection->msg_ctx; pwait->ev = req->tcon->smb_conn->connection->event.ctx; pwait->msg_type = msg_type; pwait->req = talloc_reference(pwait, req); diff --git a/source4/ntvfs/posix/vfs_posix.c b/source4/ntvfs/posix/vfs_posix.c index 314f9736a3..0ed878c1f0 100644 --- a/source4/ntvfs/posix/vfs_posix.c +++ b/source4/ntvfs/posix/vfs_posix.c @@ -27,6 +27,7 @@ #include "includes.h" #include "vfs_posix.h" #include "librpc/gen_ndr/ndr_security.h" +#include "smbd/service_stream.h" /* @@ -130,16 +131,16 @@ static NTSTATUS pvfs_connect(struct ntvfs_module_context *ntvfs, ntvfs->private_data = pvfs; pvfs->brl_context = brl_init(pvfs, - pvfs->tcon->smb_conn->connection->connection.id, + pvfs->tcon->smb_conn->connection->server_id, pvfs->tcon->service, - pvfs->tcon->smb_conn->connection->messaging.ctx); + pvfs->tcon->smb_conn->connection->msg_ctx); if (pvfs->brl_context == NULL) { return NT_STATUS_INTERNAL_DB_CORRUPTION; } pvfs->odb_context = odb_init(pvfs, - pvfs->tcon->smb_conn->connection->connection.id, - pvfs->tcon->smb_conn->connection->messaging.ctx); + pvfs->tcon->smb_conn->connection->server_id, + pvfs->tcon->smb_conn->connection->msg_ctx); if (pvfs->odb_context == NULL) { return NT_STATUS_INTERNAL_DB_CORRUPTION; } diff --git a/source4/passdb/secrets.c b/source4/passdb/secrets.c index 7045cf6af7..14e5642ae2 100644 --- a/source4/passdb/secrets.c +++ b/source4/passdb/secrets.c @@ -64,7 +64,7 @@ BOOL secrets_init(void) pstrcpy(fname, lp_private_dir()); pstrcat(fname,"/secrets.tdb"); - tdb = tdb_wrap_open(NULL, fname, 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600); + tdb = tdb_wrap_open(talloc_autofree_context(), fname, 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600); if (!tdb) { DEBUG(0,("Failed to open %s\n", fname)); diff --git a/source4/rpc_server/dcerpc_server.c b/source4/rpc_server/dcerpc_server.c index 575c073e46..c21ab3d883 100644 --- a/source4/rpc_server/dcerpc_server.c +++ b/source4/rpc_server/dcerpc_server.c @@ -28,6 +28,7 @@ #include "dlinklist.h" #include "rpc_server/dcerpc_server.h" #include "events.h" +#include "smbd/service_stream.h" /* see if two endpoints match @@ -299,7 +300,7 @@ static int dcesrv_endpoint_destructor(void *ptr) NTSTATUS dcesrv_endpoint_connect(struct dcesrv_context *dce_ctx, TALLOC_CTX *mem_ctx, const struct dcesrv_endpoint *ep, - struct server_connection *srv_conn, + struct stream_connection *srv_conn, struct dcesrv_connection **_p) { struct dcesrv_connection *p; @@ -333,7 +334,7 @@ NTSTATUS dcesrv_endpoint_search_connect(struct dcesrv_context *dce_ctx, TALLOC_CTX *mem_ctx, const struct dcerpc_binding *ep_description, struct auth_session_info *session_info, - struct server_connection *srv_conn, + struct stream_connection *srv_conn, struct dcesrv_connection **dce_conn_p) { NTSTATUS status; @@ -1204,7 +1205,7 @@ static NTSTATUS dcesrv_init_context(TALLOC_CTX *mem_ctx, const char **endpoint_s } /* - initialise the dcerpc server context + initialise the dcerpc server context for ncacn_np based services */ NTSTATUS dcesrv_init_ipc_context(TALLOC_CTX *mem_ctx, struct dcesrv_context **_dce_ctx) { @@ -1218,45 +1219,6 @@ NTSTATUS dcesrv_init_ipc_context(TALLOC_CTX *mem_ctx, struct dcesrv_context **_d return NT_STATUS_OK; } -static void dcesrv_init(struct server_service *service) -{ - NTSTATUS status; - struct dcesrv_context *dce_ctx; - - DEBUG(1,("dcesrv_init\n")); - - status = dcesrv_init_context(service, - lp_dcerpc_endpoint_servers(), - DCESRV_CALL_STATE_FLAG_MAY_ASYNC, - &dce_ctx); - if (!NT_STATUS_IS_OK(status)) { - return; - } - - service->service.private_data = dce_ctx; - - dcesrv_sock_init(service); - - return; -} - -static void dcesrv_accept(struct server_connection *srv_conn) -{ - dcesrv_sock_accept(srv_conn); -} - -static void dcesrv_recv(struct server_connection *srv_conn, - struct timeval t, uint16_t flags) -{ - dcesrv_sock_recv(srv_conn, t, flags); -} - -static void dcesrv_send(struct server_connection *srv_conn, - struct timeval t, uint16_t flags) -{ - dcesrv_sock_send(srv_conn, t, flags); -} - /* the list of currently registered DCERPC endpoint servers. */ static struct ep_server { @@ -1338,32 +1300,25 @@ const struct dcesrv_critical_sizes *dcerpc_module_version(void) return &critical_sizes; } -static const struct server_stream_ops dcesrv_stream_ops = { - .name = "rpc", - .socket_init = NULL, - .accept_connection = dcesrv_accept, - .recv_handler = dcesrv_recv, - .send_handler = dcesrv_send, - .idle_handler = NULL, - .close_connection = NULL -}; - -const struct server_stream_ops *dcesrv_get_stream_ops(void) +/* + initialise the dcerpc server context for socket based services +*/ +static NTSTATUS dcesrv_init(struct event_context *event_context, const struct model_ops *model_ops) { - return &dcesrv_stream_ops; -} + NTSTATUS status; + struct dcesrv_context *dce_ctx; -static const struct server_service_ops dcesrv_ops = { - .name = "rpc", - .service_init = dcesrv_init, -}; + status = dcesrv_init_context(event_context, + lp_dcerpc_endpoint_servers(), + DCESRV_CALL_STATE_FLAG_MAY_ASYNC, + &dce_ctx); + NT_STATUS_NOT_OK_RETURN(status); -const struct server_service_ops *dcesrv_get_ops(void) -{ - return &dcesrv_ops; + return dcesrv_sock_init(dce_ctx, event_context, model_ops); } + NTSTATUS server_service_rpc_init(void) { - return NT_STATUS_OK; + return register_server_service("rpc", dcesrv_init); } diff --git a/source4/rpc_server/dcerpc_server.h b/source4/rpc_server/dcerpc_server.h index 2738cee040..317ebdd2ec 100644 --- a/source4/rpc_server/dcerpc_server.h +++ b/source4/rpc_server/dcerpc_server.h @@ -174,7 +174,7 @@ struct dcesrv_connection { /* the current authentication state */ struct dcesrv_auth auth_state; - struct server_connection *srv_conn; + struct stream_connection *srv_conn; /* the transport level session key */ DATA_BLOB transport_session_key; diff --git a/source4/rpc_server/dcerpc_sock.c b/source4/rpc_server/dcerpc_sock.c index 222f513bb9..ef5e7c269a 100644 --- a/source4/rpc_server/dcerpc_sock.c +++ b/source4/rpc_server/dcerpc_sock.c @@ -25,6 +25,7 @@ #include "includes.h" #include "events.h" #include "rpc_server/dcerpc_server.h" +#include "smbd/service_stream.h" struct dcesrv_socket_context { const struct dcesrv_endpoint *endpoint; @@ -50,42 +51,129 @@ static ssize_t dcerpc_write_fn(void *private, DATA_BLOB *out) static void dcesrv_terminate_connection(struct dcesrv_connection *dce_conn, const char *reason) { - server_terminate_connection(dce_conn->srv_conn, reason); + stream_terminate_connection(dce_conn->srv_conn, reason); } -static void add_socket_rpc_unix(struct server_service *service, struct dcesrv_endpoint *e) + +void dcesrv_sock_accept(struct stream_connection *srv_conn) { - struct dcesrv_context *dce_ctx = service->service.private_data; - struct server_stream_socket *stream_socket; - struct dcesrv_socket_context *dcesrv_sock; - uint16_t port = 1; + NTSTATUS status; + struct dcesrv_socket_context *dcesrv_sock = + talloc_get_type(srv_conn->private, struct dcesrv_socket_context); + struct dcesrv_connection *dcesrv_conn = NULL; + + status = dcesrv_endpoint_connect(dcesrv_sock->dcesrv_ctx, + srv_conn, + dcesrv_sock->endpoint, + srv_conn, + &dcesrv_conn); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0,("dcesrv_sock_accept: dcesrv_endpoint_connect failed: %s\n", + nt_errstr(status))); + return; + } + + srv_conn->private = dcesrv_conn; + + return; +} + +void dcesrv_sock_recv(struct stream_connection *conn, struct timeval t, uint16_t flags) +{ + NTSTATUS status; + struct dcesrv_connection *dce_conn = talloc_get_type(conn->private, struct dcesrv_connection); + DATA_BLOB tmp_blob; + size_t nread; + + tmp_blob = data_blob_talloc(conn->socket, NULL, 0x1000); + if (tmp_blob.data == NULL) { + dcesrv_terminate_connection(dce_conn, "out of memory"); + return; + } + + status = socket_recv(conn->socket, tmp_blob.data, tmp_blob.length, &nread, 0); + if (NT_STATUS_IS_ERR(status)) { + dcesrv_terminate_connection(dce_conn, nt_errstr(status)); + return; + } + if (nread == 0) { + talloc_free(tmp_blob.data); + return; + } + + tmp_blob.length = nread; + + status = dcesrv_input(dce_conn, &tmp_blob); + talloc_free(tmp_blob.data); - stream_socket = service_setup_stream_socket(service, dcesrv_get_stream_ops(), "unix", e->ep_description.endpoint, &port); - if (!stream_socket) { - DEBUG(0,("service_setup_stream_socket(path=%s) failed\n",e->ep_description.endpoint)); + if (!NT_STATUS_IS_OK(status)) { + dcesrv_terminate_connection(dce_conn, nt_errstr(status)); return; } - dcesrv_sock = talloc(stream_socket, struct dcesrv_socket_context); - if (!dcesrv_sock) { - DEBUG(0,("talloc(stream_socket, struct dcesrv_socket_context) failed\n")); + if (dce_conn->call_list && dce_conn->call_list->replies) { + conn->event.fde->flags |= EVENT_FD_WRITE; + } +} + +void dcesrv_sock_send(struct stream_connection *conn, struct timeval t, uint16_t flags) +{ + struct dcesrv_connection *dce_conn = talloc_get_type(conn->private, struct dcesrv_connection); + NTSTATUS status; + + status = dcesrv_output(dce_conn, conn->socket, dcerpc_write_fn); + if (!NT_STATUS_IS_OK(status)) { + dcesrv_terminate_connection(dce_conn, "eof on socket"); return; } + if (!dce_conn->call_list || !dce_conn->call_list->replies) { + conn->event.fde->flags &= ~EVENT_FD_WRITE; + } +} + + +static const struct stream_server_ops dcesrv_stream_ops = { + .name = "rpc", + .accept_connection = dcesrv_sock_accept, + .recv_handler = dcesrv_sock_recv, + .send_handler = dcesrv_sock_send, +}; + + + +static NTSTATUS add_socket_rpc_unix(struct dcesrv_context *dce_ctx, struct dcesrv_endpoint *e, + struct event_context *event_ctx, const struct model_ops *model_ops) +{ + struct dcesrv_socket_context *dcesrv_sock; + uint16_t port = 1; + NTSTATUS status; + + dcesrv_sock = talloc(dce_ctx, struct dcesrv_socket_context); + NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock); + /* remember the endpoint of this socket */ dcesrv_sock->endpoint = e; - dcesrv_sock->dcesrv_ctx = dce_ctx; + dcesrv_sock->dcesrv_ctx = talloc_reference(dcesrv_sock, dce_ctx); + + status = stream_setup_socket(event_ctx, model_ops, &dcesrv_stream_ops, + "unix", e->ep_description.endpoint, &port, + dcesrv_sock); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0,("service_setup_stream_socket(path=%s) failed - %s\n", + e->ep_description.endpoint, nt_errstr(status))); + } - stream_socket->stream.private_data = dcesrv_sock; + return status; } -static void add_socket_rpc_ncalrpc(struct server_service *service, struct dcesrv_endpoint *e) +static NTSTATUS add_socket_rpc_ncalrpc(struct dcesrv_context *dce_ctx, struct dcesrv_endpoint *e, + struct event_context *event_ctx, const struct model_ops *model_ops) { - struct dcesrv_context *dce_ctx = service->service.private_data; - struct server_stream_socket *stream_socket; struct dcesrv_socket_context *dcesrv_sock; uint16_t port = 1; char *full_path; + NTSTATUS status; if (!e->ep_description.endpoint) { /* No identifier specified: use DEFAULT. @@ -96,101 +184,88 @@ static void add_socket_rpc_ncalrpc(struct server_service *service, struct dcesrv full_path = talloc_asprintf(dce_ctx, "%s/%s", lp_ncalrpc_dir(), e->ep_description.endpoint); - stream_socket = service_setup_stream_socket(service, dcesrv_get_stream_ops(), "unix", full_path, &port); - if (!stream_socket) { - DEBUG(0,("service_setup_stream_socket(identifier=%s,path=%s) failed\n",e->ep_description.endpoint, full_path)); - return; - } - - dcesrv_sock = talloc(stream_socket, struct dcesrv_socket_context); - if (!dcesrv_sock) { - DEBUG(0,("talloc(stream_socket, struct dcesrv_socket_context) failed\n")); - return; - } + dcesrv_sock = talloc(dce_ctx, struct dcesrv_socket_context); + NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock); /* remember the endpoint of this socket */ dcesrv_sock->endpoint = e; dcesrv_sock->dcesrv_ctx = dce_ctx; - stream_socket->stream.private_data = dcesrv_sock; - - return; + status = stream_setup_socket(event_ctx, model_ops, &dcesrv_stream_ops, + "unix", full_path, &port, dcesrv_sock); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0,("service_setup_stream_socket(identifier=%s,path=%s) failed - %s\n", + e->ep_description.endpoint, full_path, nt_errstr(status))); + } + return status; } /* add a socket address to the list of events, one event per dcerpc endpoint */ -static void add_socket_rpc_tcp_iface(struct server_service *service, - struct dcesrv_endpoint *e, - struct ipv4_addr *ifip) +static NTSTATUS add_socket_rpc_tcp_iface(struct dcesrv_context *dce_ctx, struct dcesrv_endpoint *e, + struct event_context *event_ctx, const struct model_ops *model_ops, + const char *address) { - struct dcesrv_context *dce_ctx = service->service.private_data; - struct server_stream_socket *stream_socket; struct dcesrv_socket_context *dcesrv_sock; uint16_t port = 0; - char *ip_str = talloc_strdup(service, sys_inet_ntoa(*ifip)); + NTSTATUS status; - if (e->ep_description.endpoint) + if (e->ep_description.endpoint) { port = atoi(e->ep_description.endpoint); - - stream_socket = service_setup_stream_socket(service, dcesrv_get_stream_ops(), "ipv4", ip_str, &port); - if (!stream_socket) { - DEBUG(0,("service_setup_stream_socket(address=%s,port=%u) failed\n", ip_str, port)); - return; - } - - if (e->ep_description.endpoint == NULL) { - e->ep_description.endpoint = talloc_asprintf(dce_ctx, "%d", port); } - dcesrv_sock = talloc(stream_socket, struct dcesrv_socket_context); - if (!dcesrv_sock) { - DEBUG(0,("talloc(stream_socket, struct dcesrv_socket_context) failed\n")); - return; - } + dcesrv_sock = talloc(dce_ctx, struct dcesrv_socket_context); + NT_STATUS_HAVE_NO_MEMORY(dcesrv_sock); /* remember the endpoint of this socket */ dcesrv_sock->endpoint = e; dcesrv_sock->dcesrv_ctx = dce_ctx; - stream_socket->stream.private_data = dcesrv_sock; + status = stream_setup_socket(event_ctx, model_ops, &dcesrv_stream_ops, + "ipv4", address, &port, dcesrv_sock); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0,("service_setup_stream_socket(address=%s,port=%u) failed - %s\n", + address, port, nt_errstr(status))); + } - talloc_free(ip_str); + if (e->ep_description.endpoint == NULL) { + e->ep_description.endpoint = talloc_asprintf(dce_ctx, "%d", port); + } - return; + return status; } -static void add_socket_rpc_tcp(struct server_service *service, struct dcesrv_endpoint *e) +static NTSTATUS add_socket_rpc_tcp(struct dcesrv_context *dce_ctx, struct dcesrv_endpoint *e, + struct event_context *event_ctx, const struct model_ops *model_ops) { + NTSTATUS status; + /* Add TCP/IP sockets */ if (lp_interfaces() && lp_bind_interfaces_only()) { int num_interfaces = iface_count(); int i; for(i = 0; i < num_interfaces; i++) { - struct ipv4_addr *ifip = iface_n_ip(i); - if (ifip == NULL) { - continue; - } - add_socket_rpc_tcp_iface(service, e, ifip); + const char *address = sys_inet_ntoa(*iface_n_ip(i)); + status = add_socket_rpc_tcp_iface(dce_ctx, e, event_ctx, model_ops, address); + NT_STATUS_NOT_OK_RETURN(status); } } else { - struct ipv4_addr ifip; - ifip = interpret_addr2(lp_socket_address()); - add_socket_rpc_tcp_iface(service, e, &ifip); + status = add_socket_rpc_tcp_iface(dce_ctx, e, event_ctx, model_ops, lp_socket_address()); + NT_STATUS_NOT_OK_RETURN(status); } - return; + return NT_STATUS_OK; } /**************************************************************************** Open the listening sockets for RPC over NCACN_IP_TCP/NCALRPC/NCACN_UNIX_STREAM ****************************************************************************/ -void dcesrv_sock_init(struct server_service *service) +NTSTATUS dcesrv_sock_init(struct dcesrv_context *dce_ctx, + struct event_context *event_ctx, const struct model_ops *model_ops) { - struct dcesrv_context *dce_ctx = service->service.private_data; struct dcesrv_endpoint *e; - - DEBUG(1,("dcesrv_sock_init\n")); + NTSTATUS status; /* Make sure the directory for NCALRPC exists */ if (!directory_exist(lp_ncalrpc_dir(), NULL)) { @@ -200,15 +275,18 @@ void dcesrv_sock_init(struct server_service *service) for (e=dce_ctx->endpoint_list;e;e=e->next) { switch (e->ep_description.transport) { case NCACN_UNIX_STREAM: - add_socket_rpc_unix(service, e); + status = add_socket_rpc_unix(dce_ctx, e, event_ctx, model_ops); + NT_STATUS_NOT_OK_RETURN(status); break; case NCALRPC: - add_socket_rpc_ncalrpc(service, e); + status = add_socket_rpc_ncalrpc(dce_ctx, e, event_ctx, model_ops); + NT_STATUS_NOT_OK_RETURN(status); break; case NCACN_IP_TCP: - add_socket_rpc_tcp(service, e); + status = add_socket_rpc_tcp(dce_ctx, e, event_ctx, model_ops); + NT_STATUS_NOT_OK_RETURN(status); break; default: @@ -216,89 +294,6 @@ void dcesrv_sock_init(struct server_service *service) } } - return; + return NT_STATUS_OK; } -void dcesrv_sock_accept(struct server_connection *srv_conn) -{ - NTSTATUS status; - struct dcesrv_socket_context *dcesrv_sock = srv_conn->stream_socket->stream.private_data; - struct dcesrv_connection *dcesrv_conn = NULL; - - DEBUG(5,("dcesrv_sock_accept\n")); - - status = dcesrv_endpoint_connect(dcesrv_sock->dcesrv_ctx, - dcesrv_sock, - dcesrv_sock->endpoint, - srv_conn, - &dcesrv_conn); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0,("dcesrv_sock_accept: dcesrv_endpoint_connect failed: %s\n", - nt_errstr(status))); - return; - } - - srv_conn->connection.private_data = dcesrv_conn; - - return; -} - -void dcesrv_sock_recv(struct server_connection *conn, struct timeval t, uint16_t flags) -{ - NTSTATUS status; - struct dcesrv_connection *dce_conn = conn->connection.private_data; - DATA_BLOB tmp_blob; - size_t nread; - - tmp_blob = data_blob_talloc(conn->socket, NULL, 0x1000); - if (tmp_blob.data == NULL) { - dcesrv_terminate_connection(dce_conn, "out of memory"); - return; - } - - status = socket_recv(conn->socket, tmp_blob.data, tmp_blob.length, &nread, 0); - if (NT_STATUS_IS_ERR(status)) { - dcesrv_terminate_connection(dce_conn, nt_errstr(status)); - return; - } - if (nread == 0) { - talloc_free(tmp_blob.data); - return; - } - - tmp_blob.length = nread; - - status = dcesrv_input(dce_conn, &tmp_blob); - talloc_free(tmp_blob.data); - - if (!NT_STATUS_IS_OK(status)) { - dcesrv_terminate_connection(dce_conn, nt_errstr(status)); - return; - } - - if (dce_conn->call_list && dce_conn->call_list->replies) { - conn->event.fde->flags |= EVENT_FD_WRITE; - } - - return; -} - -void dcesrv_sock_send(struct server_connection *conn, struct timeval t, uint16_t flags) -{ - struct dcesrv_connection *dce_conn = conn->connection.private_data; - NTSTATUS status; - - DEBUG(10,("dcesrv_sock_send\n")); - - status = dcesrv_output(dce_conn, conn->socket, dcerpc_write_fn); - if (!NT_STATUS_IS_OK(status)) { - dcesrv_terminate_connection(dce_conn, "eof on socket"); - return; - } - - if (!dce_conn->call_list || !dce_conn->call_list->replies) { - conn->event.fde->flags &= ~EVENT_FD_WRITE; - } - - return; -} diff --git a/source4/rpc_server/epmapper/rpc_epmapper.c b/source4/rpc_server/epmapper/rpc_epmapper.c index 797dcc624e..eb9598b6be 100644 --- a/source4/rpc_server/epmapper/rpc_epmapper.c +++ b/source4/rpc_server/epmapper/rpc_epmapper.c @@ -217,10 +217,11 @@ static error_status_t epm_Map(struct dcesrv_call_state *dce_call, TALLOC_CTX *me transport = dcerpc_transport_by_tower(&r->in.map_tower->tower); if (transport == -1) { - DEBUG(1, ("Client requested unknown transport with levels: ")); + DEBUG(2, ("Client requested unknown transport with levels: ")); for (i = 2; i < r->in.map_tower->tower.num_floors; i++) { - DEBUG(1, ("%d, ", r->in.map_tower->tower.floors[i].lhs.protocol)); + DEBUG(2, ("%d, ", r->in.map_tower->tower.floors[i].lhs.protocol)); } + DEBUG(2, ("\n")); goto failed; } diff --git a/source4/smb_server/conn.c b/source4/smb_server/conn.c index 427add0aa2..45c5376e25 100644 --- a/source4/smb_server/conn.c +++ b/source4/smb_server/conn.c @@ -23,6 +23,7 @@ #include "system/filesys.h" #include "dlinklist.h" #include "smb_server/smb_server.h" +#include "smbd/service_stream.h" /**************************************************************************** diff --git a/source4/smb_server/negprot.c b/source4/smb_server/negprot.c index 4af8fed53b..8223f66dc7 100644 --- a/source4/smb_server/negprot.c +++ b/source4/smb_server/negprot.c @@ -21,6 +21,7 @@ #include "includes.h" #include "auth/auth.h" #include "smb_server/smb_server.h" +#include "smbd/service_stream.h" /* initialise the auth_context for this server and return the cryptkey */ @@ -144,7 +145,7 @@ static void reply_lanman1(struct smbsrv_request *req, uint16_t choice) SSVAL(req->out.vwv, VWV(3), lp_maxmux()); SSVAL(req->out.vwv, VWV(4), 1); SSVAL(req->out.vwv, VWV(5), raw); - SIVAL(req->out.vwv, VWV(6), req->smb_conn->connection->connection.id); + SIVAL(req->out.vwv, VWV(6), req->smb_conn->connection->server_id); srv_push_dos_date(req->smb_conn, req->out.vwv, VWV(8), t); SSVAL(req->out.vwv, VWV(10), req->smb_conn->negotiate.zone_offset/60); SIVAL(req->out.vwv, VWV(11), 0); /* reserved */ @@ -198,7 +199,7 @@ static void reply_lanman2(struct smbsrv_request *req, uint16_t choice) SSVAL(req->out.vwv, VWV(3), lp_maxmux()); SSVAL(req->out.vwv, VWV(4), 1); SSVAL(req->out.vwv, VWV(5), raw); - SIVAL(req->out.vwv, VWV(6), req->smb_conn->connection->connection.id); + SIVAL(req->out.vwv, VWV(6), req->smb_conn->connection->server_id); srv_push_dos_date(req->smb_conn, req->out.vwv, VWV(8), t); SSVAL(req->out.vwv, VWV(10), req->smb_conn->negotiate.zone_offset/60); SIVAL(req->out.vwv, VWV(11), 0); @@ -310,7 +311,7 @@ static void reply_nt1(struct smbsrv_request *req, uint16_t choice) SSVAL(req->out.vwv+1, VWV(2), 1); /* num vcs */ SIVAL(req->out.vwv+1, VWV(3), req->smb_conn->negotiate.max_recv); SIVAL(req->out.vwv+1, VWV(5), 0x10000); /* raw size. full 64k */ - SIVAL(req->out.vwv+1, VWV(7), req->smb_conn->connection->connection.id); /* session key */ + SIVAL(req->out.vwv+1, VWV(7), req->smb_conn->connection->server_id); /* session key */ SIVAL(req->out.vwv+1, VWV(9), capabilities); push_nttime(req->out.vwv+1, VWV(11), nttime); SSVALS(req->out.vwv+1,VWV(15), req->smb_conn->negotiate.zone_offset/60); @@ -443,7 +444,6 @@ void reply_negprot(struct smbsrv_request *req) if(choice != -1) { sub_set_remote_proto(supported_protocols[protocol].short_name); - reload_services(req->smb_conn, True); supported_protocols[protocol].proto_reply_fn(req, choice); DEBUG(3,("Selected protocol %s\n",supported_protocols[protocol].proto_name)); } else { diff --git a/source4/smb_server/request.c b/source4/smb_server/request.c index c2aca04661..26988bf205 100644 --- a/source4/smb_server/request.c +++ b/source4/smb_server/request.c @@ -26,6 +26,7 @@ #include "events.h" #include "dlinklist.h" #include "smb_server/smb_server.h" +#include "smbd/service_stream.h" /* we over allocate the data buffer to prevent too many realloc calls */ diff --git a/source4/smb_server/service.c b/source4/smb_server/service.c index d4386ca77b..180deaf8c5 100644 --- a/source4/smb_server/service.c +++ b/source4/smb_server/service.c @@ -20,6 +20,7 @@ #include "includes.h" #include "smb_server/smb_server.h" +#include "smbd/service_stream.h" diff --git a/source4/smb_server/sesssetup.c b/source4/smb_server/sesssetup.c index eb6c8b9647..dc3a60874a 100644 --- a/source4/smb_server/sesssetup.c +++ b/source4/smb_server/sesssetup.c @@ -25,6 +25,7 @@ #include "version.h" #include "auth/auth.h" #include "smb_server/smb_server.h" +#include "smbd/service_stream.h" /* diff --git a/source4/smb_server/smb_server.c b/source4/smb_server/smb_server.c index 394923635d..1537bf6a47 100644 --- a/source4/smb_server/smb_server.c +++ b/source4/smb_server/smb_server.c @@ -24,6 +24,7 @@ #include "events.h" #include "system/time.h" #include "dlinklist.h" +#include "smbd/service_stream.h" #include "smb_server/smb_server.h" @@ -506,7 +507,7 @@ static void switch_message(int type, struct smbsrv_request *req) session_tag = req->session->vuid; } - DEBUG(3,("switch message %s (task_id %d)\n",smb_fn_name(type), req->smb_conn->connection->connection.id)); + DEBUG(3,("switch message %s (task_id %d)\n",smb_fn_name(type), req->smb_conn->connection->server_id)); /* does this protocol need a valid tree connection? */ if ((flags & AS_USER) && !req->tcon) { @@ -646,69 +647,15 @@ error: */ void smbsrv_terminate_connection(struct smbsrv_connection *smb_conn, const char *reason) { - server_terminate_connection(smb_conn->connection, reason); -} - -static const struct server_stream_ops *smbsrv_stream_ops(void); - -/* - add a socket address to the list of events, one event per port -*/ -static void smb_add_socket(struct server_service *service, - struct ipv4_addr *ifip) -{ - const char **ports = lp_smb_ports(); - int i; - char *ip_str = talloc_strdup(service, sys_inet_ntoa(*ifip)); - - for (i=0;ports[i];i++) { - uint16_t port = atoi(ports[i]); - if (port == 0) continue; - service_setup_stream_socket(service, smbsrv_stream_ops(), "ipv4", ip_str, &port); - } - - talloc_free(ip_str); -} - -/**************************************************************************** - Open the socket communication. -****************************************************************************/ -static void smbsrv_init(struct server_service *service) -{ - DEBUG(1,("smbsrv_init\n")); - - if (lp_interfaces() && lp_bind_interfaces_only()) { - int num_interfaces = iface_count(); - int i; - - /* We have been given an interfaces line, and been - told to only bind to those interfaces. Create a - socket per interface and bind to only these. - */ - for(i = 0; i < num_interfaces; i++) { - struct ipv4_addr *ifip = iface_n_ip(i); - - if (ifip == NULL) { - DEBUG(0,("open_sockets_smbd: interface %d has NULL IP address !\n", i)); - continue; - } - - smb_add_socket(service, ifip); - } - } else { - struct ipv4_addr ifip; - /* Just bind to lp_socket_address() (usually 0.0.0.0) */ - ifip = interpret_addr2(lp_socket_address()); - smb_add_socket(service, &ifip); - } + stream_terminate_connection(smb_conn->connection, reason); } /* called when a SMB socket becomes readable */ -static void smbsrv_recv(struct server_connection *conn, struct timeval t, uint16_t flags) +static void smbsrv_recv(struct stream_connection *conn, struct timeval t, uint16_t flags) { - struct smbsrv_connection *smb_conn = conn->connection.private_data; + struct smbsrv_connection *smb_conn = talloc_get_type(conn->private, struct smbsrv_connection); NTSTATUS status; DEBUG(10,("smbsrv_recv\n")); @@ -727,9 +674,9 @@ static void smbsrv_recv(struct server_connection *conn, struct timeval t, uint16 /* called when a SMB socket becomes writable */ -static void smbsrv_send(struct server_connection *conn, struct timeval t, uint16_t flags) +static void smbsrv_send(struct stream_connection *conn, struct timeval t, uint16_t flags) { - struct smbsrv_connection *smb_conn = conn->connection.private_data; + struct smbsrv_connection *smb_conn = talloc_get_type(conn->private, struct smbsrv_connection); while (smb_conn->pending_send) { struct smbsrv_request *req = smb_conn->pending_send; @@ -767,39 +714,11 @@ static void smbsrv_send(struct server_connection *conn, struct timeval t, uint16 } } -static void smbsrv_close(struct server_connection *conn, const char *reason) -{ - struct smbsrv_connection *smb_conn = conn->connection.private_data; - - DEBUG(5,("smbsrv_close: %s\n",reason)); - - talloc_free(smb_conn); - - return; -} - -/* - process a message from an SMB socket while still processing a - previous message this is used by backends who need to ensure that - new messages from clients are still processed while they are - performing long operations -*/ -void smbd_process_async(struct smbsrv_connection *smb_conn) -{ - NTSTATUS status; - - status = receive_smb_request(smb_conn, timeval_current()); - if (NT_STATUS_IS_ERR(status)) { - smbsrv_terminate_connection(smb_conn, nt_errstr(status)); - } -} - - /* initialise a server_context from a open socket and register a event handler for reading from that socket */ -static void smbsrv_accept(struct server_connection *conn) +static void smbsrv_accept(struct stream_connection *conn) { struct smbsrv_connection *smb_conn; @@ -825,37 +744,71 @@ static void smbsrv_accept(struct server_connection *conn) smb_conn->connection = conn; - conn->connection.private_data = smb_conn; - - return; + conn->private = smb_conn; } -static const struct server_stream_ops smb_stream_ops = { + +static const struct stream_server_ops smb_stream_ops = { .name = "smb", - .socket_init = NULL, .accept_connection = smbsrv_accept, .recv_handler = smbsrv_recv, .send_handler = smbsrv_send, - .idle_handler = NULL, - .close_connection = smbsrv_close }; -static const struct server_stream_ops *smbsrv_stream_ops(void) +/* + setup a listening socket on all the SMB ports for a particular address +*/ +static NTSTATUS smb_add_socket(struct event_context *event_context, + const struct model_ops *model_ops, + const char *address) { - return &smb_stream_ops; + const char **ports = lp_smb_ports(); + int i; + NTSTATUS status; + + for (i=0;ports[i];i++) { + uint16_t port = atoi(ports[i]); + if (port == 0) continue; + status = stream_setup_socket(event_context, model_ops, &smb_stream_ops, + "ipv4", address, &port, NULL); + NT_STATUS_NOT_OK_RETURN(status); + } + + return NT_STATUS_OK; } -static const struct server_service_ops smb_server_ops = { - .name = "smb", - .service_init = smbsrv_init, -}; +/* + called on startup of the smb server service It's job is to start + listening on all configured SMB server sockets +*/ +static NTSTATUS smbsrv_init(struct event_context *event_context, const struct model_ops *model_ops) +{ + NTSTATUS status; -const struct server_service_ops *smbsrv_get_ops(void) -{ - return &smb_server_ops; + if (lp_interfaces() && lp_bind_interfaces_only()) { + int num_interfaces = iface_count(); + int i; + + /* We have been given an interfaces line, and been + told to only bind to those interfaces. Create a + socket per interface and bind to only these. + */ + for(i = 0; i < num_interfaces; i++) { + const char *address = sys_inet_ntoa(*iface_n_ip(i)); + status = smb_add_socket(event_context, model_ops, address); + NT_STATUS_NOT_OK_RETURN(status); + } + } else { + /* Just bind to lp_socket_address() (usually 0.0.0.0) */ + status = smb_add_socket(event_context, model_ops, lp_socket_address()); + NT_STATUS_NOT_OK_RETURN(status); + } + + return NT_STATUS_OK; } +/* called at smbd startup - register ourselves as a server service */ NTSTATUS server_service_smb_init(void) { - return NT_STATUS_OK; + return register_server_service("smb", smbsrv_init); } diff --git a/source4/smb_server/smb_server.h b/source4/smb_server/smb_server.h index 2b1ca87cb9..02070f2b13 100644 --- a/source4/smb_server/smb_server.h +++ b/source4/smb_server/smb_server.h @@ -232,7 +232,7 @@ struct smbsrv_connection { struct smb_signing_context signing; - struct server_connection *connection; + struct stream_connection *connection; /* this holds a partially received request */ struct smbsrv_request *partial_req; diff --git a/source4/smbd/config.mk b/source4/smbd/config.mk index cd2fb4ab72..07847b7fc8 100644 --- a/source4/smbd/config.mk +++ b/source4/smbd/config.mk @@ -44,7 +44,8 @@ REQUIRED_SUBSYSTEMS = \ # Start SUBSYSTEM SERVICE [SUBSYSTEM::SERVER_SERVICE] INIT_OBJ_FILES = \ - smbd/service.o + smbd/service.o \ + smbd/service_stream.o REQUIRED_SUBSYSTEMS = \ MESSAGING # End SUBSYSTEM SERVER @@ -54,8 +55,7 @@ REQUIRED_SUBSYSTEMS = \ # Start BINARY smbd [BINARY::smbd] OBJ_FILES = \ - smbd/server.o \ - smbd/rewrite.o + smbd/server.o REQUIRED_SUBSYSTEMS = \ PROCESS_MODEL \ SERVER_SERVICE \ diff --git a/source4/smbd/process_model.c b/source4/smbd/process_model.c index f2abfd0a49..16a0075d2d 100644 --- a/source4/smbd/process_model.c +++ b/source4/smbd/process_model.c @@ -22,12 +22,11 @@ #include "includes.h" #include "events.h" #include "smb_server/smb_server.h" -#include "smbd/process_model.h" /* setup the events for the chosen process model */ -const struct model_ops *process_model_startup(struct server_context *srv_ctx, const char *model) +const struct model_ops *process_model_startup(struct event_context *ev, const char *model) { const struct model_ops *ops; @@ -37,7 +36,7 @@ const struct model_ops *process_model_startup(struct server_context *srv_ctx, co exit(-1); } - ops->model_init(srv_ctx); + ops->model_init(ev); return ops; } @@ -107,7 +106,6 @@ const struct process_model_critical_sizes *process_model_version(void) static const struct process_model_critical_sizes critical_sizes = { PROCESS_MODEL_VERSION, sizeof(struct model_ops), - sizeof(struct smbsrv_connection), sizeof(struct event_context), sizeof(struct fd_event) }; diff --git a/source4/smbd/process_model.h b/source4/smbd/process_model.h index fb9bdfd44b..943538d7b2 100644 --- a/source4/smbd/process_model.h +++ b/source4/smbd/process_model.h @@ -1,7 +1,9 @@ /* Unix SMB/CIFS implementation. - process model manager - main loop - Copyright (C) Andrew Tridgell 1992-2003 + + process model manager - structures + + Copyright (C) Andrew Tridgell 1992-2005 Copyright (C) James J Myers 2003 <myersjj@samba.org> Copyright (C) Stefan (metze) Metzmacher 2004-2005 @@ -20,9 +22,6 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#ifndef SAMBA_PROCESS_MODEL_H -#define SAMBA_PROCESS_MODEL_H - /* modules can use the following to determine if the interface has changed * please increment the version number after each interface change * with a comment and maybe update struct process_model_critical_sizes. @@ -37,32 +36,22 @@ struct model_ops { const char *name; /* called at startup when the model is selected */ - void (*model_init)(struct server_context *srv_ctx); - /* called at th eend of the main server process */ - void (*model_exit)(struct server_context *srv_ctx, const char *reason); - + void (*model_init)(struct event_context *); /* function to accept new connection */ - void (*accept_connection)(struct event_context *, struct fd_event *, - struct timeval t, uint16_t); - /* function to terminate a connection */ - void (*terminate_connection)(struct server_connection *srv_conn, - const char *reason); - + void (*accept_connection)(struct event_context *, struct socket_context *, + void (*)(struct event_context *, struct socket_context *, + uint32_t , void *), + void *); - /* function to create a new task event_context */ - void (*create_task)(struct server_task *task); - /* function to exit this task */ - void (*terminate_task)(struct server_task *task, const char *reason); + /* function to terminate a connection */ + void (*terminate_connection)(struct event_context *, const char *reason); }; /* this structure is used by modules to determine the size of some critical types */ struct process_model_critical_sizes { int interface_version; int sizeof_model_ops; - int sizeof_server_context; int sizeof_event_context; int sizeof_fd_event; }; - -#endif /* SAMBA_PROCESS_MODEL_H */ diff --git a/source4/smbd/process_single.c b/source4/smbd/process_single.c index 6a00ad237f..d6217d8712 100644 --- a/source4/smbd/process_single.c +++ b/source4/smbd/process_single.c @@ -1,6 +1,8 @@ /* Unix SMB/CIFS implementation. + process model: process (1 process handles all client connections) + Copyright (C) Andrew Tridgell 2003 Copyright (C) James J Myers 2003 <myersjj@samba.org> Copyright (C) Stefan (metze) Metzmacher 2004 @@ -24,121 +26,57 @@ #include "events.h" #include "dlinklist.h" #include "smb_server/smb_server.h" -#include "process_model.h" /* called when the process model is selected */ -static void single_model_init(struct server_context *server) -{ -} - -static void single_model_exit(struct server_context *server, const char *reason) +static void single_model_init(struct event_context *ev) { - DEBUG(1,("single_exit_server: reason[%s]\n",reason)); - talloc_free(server); - exit(0); } /* - called when a listening socket becomes readable + called when a listening socket becomes readable. */ -static void single_accept_connection(struct event_context *ev, struct fd_event *srv_fde, - struct timeval t, uint16_t flags) +static void single_accept_connection(struct event_context *ev, + struct socket_context *sock, + void (*new_conn)(struct event_context *, struct socket_context *, + uint32_t , void *), + void *private) { NTSTATUS status; - struct socket_context *sock; - struct server_stream_socket *stream_socket = srv_fde->private; - struct server_connection *conn; + struct socket_context *sock2; /* accept an incoming connection. */ - status = socket_accept(stream_socket->socket, &sock); + status = socket_accept(sock, &sock2); if (!NT_STATUS_IS_OK(status)) { - DEBUG(0,("accept_connection_single: accept: %s\n", - nt_errstr(status))); - return; - } - - conn = server_setup_connection(ev, stream_socket, sock, t, socket_get_fd(sock)); - if (!conn) { - DEBUG(10,("server_setup_connection failed\n")); + DEBUG(0,("accept_connection_single: accept: %s\n", nt_errstr(status))); return; } - talloc_steal(conn, sock); + talloc_steal(private, sock); - /* return to event handling */ - return; + new_conn(ev, sock2, socket_get_fd(sock), private); } - -/* called when a SMB connection goes down */ -static void single_terminate_connection(struct server_connection *conn, const char *reason) +/* called when a connection goes down */ +static void single_terminate_connection(struct event_context *ev, const char *reason) { - DEBUG(2,("single_terminate_connection: reason[%s]\n",reason)); - - if (conn) { - talloc_free(conn); - } -} - -/* - called to create a new event context for a new task -*/ -static void single_create_task(struct server_task *task) -{ - task->task.id = (uint32_t)task; - task->event.ctx = task->service->server->event.ctx; - - /* setup to receive internal messages on this connection */ - task->messaging.ctx = messaging_init(task, task->task.id, task->event.ctx); - if (!task->messaging.ctx) { - server_terminate_task(task, "messaging_init() failed"); - return; - } - - task->task.ops->task_init(task); - return; -} - -/* - called to exit from a server_task -*/ -static void single_terminate_task(struct server_task *task, const char *reason) -{ - DEBUG(1,("single_exit_server: reason[%s]\n",reason)); - talloc_free(task); - return; } static const struct model_ops single_ops = { .name = "single", - .model_init = single_model_init, - .model_exit = single_model_exit, - .accept_connection = single_accept_connection, .terminate_connection = single_terminate_connection, - - .create_task = single_create_task, - .terminate_task = single_terminate_task }; /* - initialise the single process model, registering ourselves with the process model subsystem + initialise the single process model, registering ourselves with the + process model subsystem */ NTSTATUS process_model_single_init(void) { - NTSTATUS ret; - - /* register ourselves with the PROCESS_MODEL subsystem. */ - ret = register_process_model(&single_ops); - if (!NT_STATUS_IS_OK(ret)) { - DEBUG(0,("Failed to register process_model 'single'!\n")); - return ret; - } - - return ret; + return register_process_model(&single_ops); } diff --git a/source4/smbd/process_standard.c b/source4/smbd/process_standard.c index b0f7cf1a11..ee73cfadcf 100644 --- a/source4/smbd/process_standard.c +++ b/source4/smbd/process_standard.c @@ -1,7 +1,9 @@ /* Unix SMB/CIFS implementation. + process model: standard (1 process per client connection) - Copyright (C) Andrew Tridgell 1992-2003 + + Copyright (C) Andrew Tridgell 1992-2005 Copyright (C) James J Myers 2003 <myersjj@samba.org> Copyright (C) Stefan (metze) Metzmacher 2004 @@ -24,37 +26,31 @@ #include "events.h" #include "dlinklist.h" #include "smb_server/smb_server.h" -#include "process_model.h" /* called when the process model is selected */ -static void standard_model_init(struct server_context *server) +static void standard_model_init(struct event_context *ev) { signal(SIGCHLD, SIG_IGN); } -static void standard_model_exit(struct server_context *server, const char *reason) -{ - DEBUG(1,("standard_model_exit: reason[%s]\n",reason)); - talloc_free(server); - exit(0); -} - /* - called when a listening socket becomes readable + called when a listening socket becomes readable. */ -static void standard_accept_connection(struct event_context *ev, struct fd_event *srv_fde, - struct timeval t, uint16_t flags) +static void standard_accept_connection(struct event_context *ev, + struct socket_context *sock, + void (*new_conn)(struct event_context *, struct socket_context *, + uint32_t , void *), + void *private) { NTSTATUS status; - struct socket_context *sock; - struct server_stream_socket *stream_socket = srv_fde->private; - struct server_connection *conn; + struct socket_context *sock2; pid_t pid; + struct event_context *ev2; /* accept an incoming connection. */ - status = socket_accept(stream_socket->socket, &sock); + status = socket_accept(sock, &sock2); if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("standard_accept_connection: accept: %s\n", nt_errstr(status))); @@ -65,20 +61,28 @@ static void standard_accept_connection(struct event_context *ev, struct fd_event if (pid != 0) { /* parent or error code ... */ - - socket_destroy(sock); + talloc_free(sock2); /* go back to the event loop */ return; } - /* Child code ... */ + /* This is now the child code. We need a completely new event_context to work with */ + ev2 = event_context_init(NULL); - /* close all the listening sockets */ - event_remove_fd_all_handler(ev, server_accept_handler); + /* the service has given us a private pointer that + encapsulates the context it needs for this new connection - + everything else will be freed */ + talloc_steal(ev2, private); + talloc_steal(private, sock2); + + /* this will free all the listening sockets and all state that + is not associated with this new connection */ + talloc_free(sock); + talloc_free(ev); /* we don't care if the dup fails, as its only a select() speed optimisation */ - socket_dup(sock); + socket_dup(sock2); /* tdb needs special fork handling */ if (tdb_reopen_all() == -1) { @@ -86,31 +90,26 @@ static void standard_accept_connection(struct event_context *ev, struct fd_event } /* Ensure that the forked children do not expose identical random streams */ - set_need_random_reseed(); - conn = server_setup_connection(ev, stream_socket, sock, t, getpid()); - if (!conn) { - DEBUG(0,("server_setup_connection(ev, server_socket, sock, t) failed\n")); - exit(1); - return; - } + /* setup this new connection */ + new_conn(ev2, sock2, getpid(), private); - talloc_steal(conn, sock); + /* we can't return to the top level here, as that event context is gone, + so we now process events in the new event context until there are no + more to process */ + event_loop_wait(ev2); - /* return to the event loop */ + talloc_free(ev2); + exit(0); } -/* called when a SMB connection goes down */ -static void standard_terminate_connection(struct server_connection *conn, const char *reason) +/* called when a connection goes down */ +static void standard_terminate_connection(struct event_context *ev, const char *reason) { DEBUG(2,("standard_terminate_connection: reason[%s]\n",reason)); - if (conn) { - talloc_free(conn->stream_socket->service->server); - } - /* this init_iconv() has the effect of freeing the iconv context memory, which makes leak checking easier */ init_iconv(); @@ -118,87 +117,18 @@ static void standard_terminate_connection(struct server_connection *conn, const /* the secrets db should really hang off the connection structure */ secrets_shutdown(); - /* terminate this process */ - exit(0); -} - -/* - called to create a new event context for a new task -*/ -static void standard_create_task(struct server_task *task) -{ - pid_t pid; - - pid = fork(); - - if (pid != 0) { - /* parent or error code ... */ - talloc_free(task); - /* go back to the event loop */ - return; - } - - /* Child code ... */ - - /* close all the listening sockets */ - event_remove_fd_all_handler(task->service->server->event.ctx, server_accept_handler); - - /* tdb needs special fork handling */ - if (tdb_reopen_all() == -1) { - DEBUG(0,("standard_accept_connection: tdb_reopen_all failed.\n")); - } - - /* Ensure that the forked children do not expose identical random streams */ - - set_need_random_reseed(); - - task->task.id = (uint32)getpid(); - task->event.ctx = task->service->server->event.ctx; - - /* setup to receive internal messages on this connection */ - task->messaging.ctx = messaging_init(task, task->task.id, task->event.ctx); - if (!task->messaging.ctx) { - server_terminate_task(task, "messaging_init() failed"); - return; - } - - task->task.ops->task_init(task); - - server_terminate_task(task, "exit"); - return; -} - -/* - called to destroy a new event context for a new task -*/ -static void standard_terminate_task(struct server_task *task, const char *reason) -{ - DEBUG(2,("standard_terminate_task: reason[%s]\n",reason)); - - talloc_free(task); - - /* this init_iconv() has the effect of freeing the iconv context memory, - which makes leak checking easier */ - init_iconv(); - - /* the secrets db should really hang off the connection structure */ - secrets_shutdown(); + talloc_free(ev); /* terminate this process */ exit(0); } + static const struct model_ops standard_ops = { .name = "standard", - .model_init = standard_model_init, - .model_exit = standard_model_exit, - .accept_connection = standard_accept_connection, .terminate_connection = standard_terminate_connection, - - .create_task = standard_create_task, - .terminate_task = standard_terminate_task }; /* @@ -206,14 +136,5 @@ static const struct model_ops standard_ops = { */ NTSTATUS process_model_standard_init(void) { - NTSTATUS ret; - - /* register ourselves with the PROCESS_MODEL subsystem. */ - ret = register_process_model(&standard_ops); - if (!NT_STATUS_IS_OK(ret)) { - DEBUG(0,("Failed to register process_model 'standard'!\n")); - return ret; - } - - return ret; + return register_process_model(&standard_ops); } diff --git a/source4/smbd/process_thread.c b/source4/smbd/process_thread.c index 8d65292cfd..6b62ca413e 100644 --- a/source4/smbd/process_thread.c +++ b/source4/smbd/process_thread.c @@ -1,7 +1,9 @@ /* Unix SMB/CIFS implementation. + thread model: standard (1 thread per client connection) - Copyright (C) Andrew Tridgell 2003 + + Copyright (C) Andrew Tridgell 2003-2005 Copyright (C) James J Myers 2003 <myersjj@samba.org> Copyright (C) Stefan (metze) Metzmacher 2004 @@ -30,89 +32,85 @@ #include "events.h" #include "dlinklist.h" #include "smb_server/smb_server.h" -#include "process_model.h" + +struct new_conn_state { + struct event_context *ev; + struct socket_context *sock; + void (*new_conn)(struct event_context *, struct socket_context *, uint32_t , void *); + void *private; +}; static void *thread_connection_fn(void *thread_parm) { - struct server_connection *conn = thread_parm; + struct new_conn_state *new_conn = talloc_get_type(thread_parm, struct new_conn_state); - conn->connection.id = pthread_self(); + new_conn->new_conn(new_conn->ev, new_conn->sock, pthread_self(), new_conn->private); - /* wait for action */ - event_loop_wait(conn->event.ctx); + /* run this connection from here */ + event_loop_wait(new_conn->ev); + + talloc_free(new_conn); -#if 0 - pthread_cleanup_pop(1); /* will invoke terminate_mt_connection() */ -#endif return NULL; } /* called when a listening socket becomes readable */ -static void thread_accept_connection(struct event_context *ev, struct fd_event *srv_fde, - struct timeval t, uint16_t flags) +static void thread_accept_connection(struct event_context *ev, + struct socket_context *sock, + void (*new_conn)(struct event_context *, struct socket_context *, + uint32_t , void *), + void *private) { NTSTATUS status; - struct socket_context *sock; int rc; pthread_t thread_id; pthread_attr_t thread_attr; - struct server_stream_socket *stream_socket = srv_fde->private; - struct server_connection *conn; + struct new_conn_state *state; + struct event_context *ev2; - /* accept an incoming connection. */ - status = socket_accept(stream_socket->socket, &sock); - if (!NT_STATUS_IS_OK(status)) { - return; - } + ev2 = event_context_init(ev); + if (ev2 == NULL) return; - /* create new detached thread for this connection. The new - thread gets a new event_context with a single fd_event for - receiving from the new socket. We set that thread running - with the main event loop, then return. When we return the - main event_context is continued. - */ - - ev = event_context_init(stream_socket); - if (!ev) { - socket_destroy(sock); + state = talloc(ev2, struct new_conn_state); + if (state == NULL) { + talloc_free(ev2); return; } - conn = server_setup_connection(ev, stream_socket, sock, t, -1); - if (!conn) { - event_context_destroy(ev); - socket_destroy(sock); + state->new_conn = new_conn; + state->private = private; + state->ev = ev2; + + /* accept an incoming connection. */ + status = socket_accept(sock, &state->sock); + if (!NT_STATUS_IS_OK(status)) { + talloc_free(ev2); return; } - talloc_steal(conn, ev); - talloc_steal(conn, sock); + talloc_steal(state, state->sock); pthread_attr_init(&thread_attr); pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED); - rc = pthread_create(&thread_id, &thread_attr, thread_connection_fn, conn); + rc = pthread_create(&thread_id, &thread_attr, thread_connection_fn, state); pthread_attr_destroy(&thread_attr); if (rc == 0) { DEBUG(4,("accept_connection_thread: created thread_id=%lu for fd=%d\n", (unsigned long int)thread_id, socket_get_fd(sock))); } else { DEBUG(0,("accept_connection_thread: thread create failed for fd=%d, rc=%d\n", socket_get_fd(sock), rc)); - event_context_destroy(ev); - socket_destroy(sock); - return; + talloc_free(ev2); } } /* called when a SMB connection goes down */ -static void thread_terminate_connection(struct server_connection *conn, const char *reason) +static void thread_terminate_connection(struct event_context *event_ctx, const char *reason) { DEBUG(10,("thread_terminate_connection: reason[%s]\n",reason)); - if (conn) { - talloc_free(conn); - } + talloc_free(event_ctx); /* terminate this thread */ pthread_exit(NULL); /* thread cleanup routine will do actual cleanup */ @@ -342,6 +340,7 @@ static void thread_log_task_id(int fd) write(fd, s, strlen(s)); free(s); } + /**************************************************************************** catch serious errors ****************************************************************************/ @@ -406,7 +405,7 @@ static void thread_fault_handler(int sig) /* called when the process model is selected */ -static void thread_model_init(struct server_context *server) +static void thread_model_init(struct event_context *event_context) { struct mutex_ops m_ops; struct debug_ops d_ops; @@ -438,89 +437,12 @@ static void thread_model_init(struct server_context *server) register_debug_handlers("thread", &d_ops); } -static void thread_model_exit(struct server_context *server, const char *reason) -{ - DEBUG(1,("thread_model_exit: reason[%s]\n",reason)); - talloc_free(server); - exit(0); -} - -static void *thread_task_fn(void *thread_parm) -{ - struct server_task *task = thread_parm; - - task->task.id = pthread_self(); - - task->event.ctx = event_context_init(task); - if (!task->event.ctx) { - server_terminate_task(task, "event_context_init() failed"); - return NULL; - } - - task->messaging.ctx = messaging_init(task, task->task.id, task->event.ctx); - if (!task->messaging.ctx) { - server_terminate_task(task, "messaging_init() failed"); - return NULL; - } - - task->task.ops->task_init(task); - - /* wait for action */ - event_loop_wait(task->event.ctx); - - server_terminate_task(task, "exit"); -#if 0 - pthread_cleanup_pop(1); /* will invoke terminate_mt_connection() */ -#endif - return NULL; -} -/* - called to create a new event context for a new task -*/ -static void thread_create_task(struct server_task *task) -{ - int rc; - pthread_t thread_id; - pthread_attr_t thread_attr; - - pthread_attr_init(&thread_attr); - pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED); - rc = pthread_create(&thread_id, &thread_attr, thread_task_fn, task); - pthread_attr_destroy(&thread_attr); - if (rc == 0) { - DEBUG(4,("thread_create_task: created thread_id=%lu for task='%s'\n", - (unsigned long int)thread_id, task->task.ops->name)); - } else { - DEBUG(0,("thread_create_task: thread create failed for task='%s', rc=%d\n", task->task.ops->name, rc)); - return; - } - return; -} - -/* - called to destroy a new event context for a new task -*/ -static void thread_terminate_task(struct server_task *task, const char *reason) -{ - DEBUG(2,("thread_terminate_task: reason[%s]\n",reason)); - - talloc_free(task); - - /* terminate this thread */ - pthread_exit(NULL); /* thread cleanup routine will do actual cleanup */ -} static const struct model_ops thread_ops = { .name = "thread", - .model_init = thread_model_init, - .model_exit = thread_model_exit, - .accept_connection = thread_accept_connection, .terminate_connection = thread_terminate_connection, - - .create_task = thread_create_task, - .terminate_task = thread_terminate_task }; /* diff --git a/source4/smbd/rewrite.c b/source4/smbd/rewrite.c deleted file mode 100644 index 7128a0ad0d..0000000000 --- a/source4/smbd/rewrite.c +++ /dev/null @@ -1,70 +0,0 @@ -#include "includes.h" -#include "dynconfig.h" - - -/* - * initialize an smb process. Guaranteed to be called only once per - * smbd instance (so it can assume it is starting from scratch, and - * delete temporary files etc) - */ -void smbd_process_init(void) -{ - /* possibly reload the services file. */ - reload_services(NULL, True); - - if (*lp_rootdir()) { - if (sys_chroot(lp_rootdir()) == 0) - DEBUG(2,("Changed root to %s\n", lp_rootdir())); - } - - service_cleanup_tmp_files(); -} - -void init_subsystems(void) -{ - /* Do *not* remove this, until you have removed - * passdb/secrets.c, and proved that Samba still builds... */ - - /* Setup the SECRETS subsystem */ - if (!secrets_init()) { - exit(1); - } - - smbd_init_subsystems; -} - -/**************************************************************************** - Reload the services file. -**************************************************************************/ -BOOL reload_services(struct smbsrv_connection *smb, BOOL test) -{ - BOOL ret; - - if (lp_loaded()) { - pstring fname; - pstrcpy(fname,lp_configfile()); - if (file_exist(fname, NULL) && - !strcsequal(fname, dyn_CONFIGFILE)) { - pstrcpy(dyn_CONFIGFILE, fname); - test = False; - } - } - - reopen_logs(); - - if (test && !lp_file_list_changed()) - return(True); - - ret = lp_load(dyn_CONFIGFILE, False, False, True); - - /* perhaps the config filename is now set */ - if (!test) - reload_services(smb, True); - - reopen_logs(); - - load_interfaces(); - - return(ret); -} - diff --git a/source4/smbd/server.c b/source4/smbd/server.c index 3c4c40fe1c..57f835970e 100644 --- a/source4/smbd/server.c +++ b/source4/smbd/server.c @@ -1,7 +1,9 @@ /* Unix SMB/CIFS implementation. + Main SMB server routines - Copyright (C) Andrew Tridgell 1992-1998 + + Copyright (C) Andrew Tridgell 1992-2005 Copyright (C) Martin Pool 2002 Copyright (C) Jelmer Vernooij 2002 Copyright (C) James J Myers 2003 <myersjj@samba.org> @@ -23,56 +25,56 @@ #include "includes.h" #include "version.h" +#include "dynconfig.h" #include "lib/cmdline/popt_common.h" +#include "system/dir.h" -/**************************************************************************** - main server. -****************************************************************************/ -static int binary_smbd_main(int argc,const char *argv[]) + +/* + cleanup temporary files. This is the new alternative to + TDB_CLEAR_IF_FIRST. Unfortunately TDB_CLEAR_IF_FIRST is not + efficient on unix systems due to the lack of scaling of the byte + range locking system. So instead of putting the burden on tdb to + cleanup tmp files, this function deletes them. +*/ +static void cleanup_tmp_files(void) { - BOOL is_daemon = False; - BOOL interactive = False; - BOOL Fork = True; - BOOL log_stdout = False; - int opt; - poptContext pc; - struct server_context *server; - const char *model = "standard"; - struct poptOption long_options[] = { - POPT_AUTOHELP - POPT_COMMON_SAMBA - {"daemon", 'D', POPT_ARG_VAL, &is_daemon, True, "Become a daemon (default)" , NULL }, - {"interactive", 'i', POPT_ARG_VAL, &interactive, True, "Run interactive (not a daemon)", NULL}, - {"foreground", 'F', POPT_ARG_VAL, &Fork, True, "Run daemon in foreground (for daemontools & etc)" , NULL }, - {"log-stdout", 'S', POPT_ARG_VAL, &log_stdout, True, "Log to stdout", NULL }, - {"port", 'p', POPT_ARG_STRING, NULL, 0, "Listen on the specified ports", "PORTS"}, - {"model", 'M', POPT_ARG_STRING, &model, True, "Select process model", "MODEL"}, - POPT_COMMON_VERSION - POPT_TABLEEND - }; - - pc = poptGetContext("smbd", argc, argv, long_options, 0); - - while((opt = poptGetNextOpt(pc)) != -1) { - switch (opt) { - case 'p': - lp_set_cmdline("smb ports", poptGetOptArg(pc)); - break; - } - } - poptFreeContext(pc); + char *path; + DIR *dir; + struct dirent *de; + TALLOC_CTX *mem_ctx = talloc_new(NULL); + + path = smbd_tmp_path(mem_ctx, NULL); - if (interactive) { - Fork = False; - log_stdout = True; + dir = opendir(path); + if (!dir) { + talloc_free(mem_ctx); + return; } - if (log_stdout && Fork) { - DEBUG(0,("ERROR: Can't log to stdout (-S) unless daemon is in foreground (-F) or interactive (-i)\n")); - exit(1); + for (de=readdir(dir);de;de=readdir(dir)) { + char *fname = talloc_asprintf(mem_ctx, "%s/%s", path, de->d_name); + int ret = unlink(fname); + if (ret == -1 && + errno != ENOENT && + errno != EISDIR && + errno != EISDIR) { + DEBUG(0,("Unabled to delete '%s' - %s\n", + fname, strerror(errno))); + smb_panic("unable to cleanup tmp files"); + } + talloc_free(fname); } - setup_logging(argv[0], log_stdout?DEBUG_STDOUT:DEBUG_FILE); + closedir(dir); + + talloc_free(mem_ctx); +} +/* + setup signal masks +*/ +static void setup_signals(void) +{ fault_setup(NULL); /* we are never interested in SIGPIPE */ @@ -93,6 +95,39 @@ static int binary_smbd_main(int argc,const char *argv[]) BlockSignals(False, SIGHUP); BlockSignals(False, SIGUSR1); BlockSignals(False, SIGTERM); +} + + +/* + main server. +*/ +static int binary_smbd_main(int argc, const char *argv[]) +{ + BOOL interactive = False; + int opt; + poptContext pc; + struct event_context *event_ctx; + NTSTATUS status; + const char *model = "standard"; + struct poptOption long_options[] = { + POPT_AUTOHELP + POPT_COMMON_SAMBA + {"interactive", 'i', POPT_ARG_VAL, &interactive, True, + "Run interactive (not a daemon)", NULL}, + {"model", 'M', POPT_ARG_STRING, &model, True, + "Select process model", "MODEL"}, + POPT_COMMON_VERSION + POPT_TABLEEND + }; + + pc = poptGetContext("smbd", argc, argv, long_options, 0); + + while((opt = poptGetNextOpt(pc)) != -1) /* noop */ ; + + poptFreeContext(pc); + + setup_logging(argv[0], interactive?DEBUG_STDOUT:DEBUG_FILE); + setup_signals(); /* we want total control over the permissions on created files, so set our umask to 0 */ @@ -108,49 +143,51 @@ static int binary_smbd_main(int argc,const char *argv[]) exit(1); } - if (!reload_services(NULL, False)) - return(-1); - - if (!is_daemon && !is_a_socket(0)) { - if (!interactive) - DEBUG(0,("standard input is not a socket, assuming -D option\n")); + lp_load(dyn_CONFIGFILE, False, False, True); - /* - * Setting is_daemon here prevents us from eventually calling - * the open_sockets_inetd() - */ - - is_daemon = True; - } + reopen_logs(); + load_interfaces(); - if (is_daemon && !interactive) { + if (!interactive) { DEBUG(3,("Becoming a daemon.\n")); - become_daemon(Fork); + become_daemon(True); } + cleanup_tmp_files(); + if (!directory_exist(lp_lockdir(), NULL)) { mkdir(lp_lockdir(), 0755); } - if (is_daemon) { - pidfile_create("smbd"); + pidfile_create("smbd"); + + /* Do *not* remove this, until you have removed + * passdb/secrets.c, and proved that Samba still builds... */ + /* Setup the SECRETS subsystem */ + if (!secrets_init()) { + exit(1); } - init_subsystems(); + smbd_init_subsystems; - smbd_process_init(); + /* the event context is the top level structure in smbd. Everything else + should hang off that */ + event_ctx = event_context_init(NULL); DEBUG(0,("Using %s process model\n", model)); - server = server_service_startup(model, lp_server_services()); - if (!server) { - DEBUG(0,("Starting Services failed.\n")); + status = server_service_startup(event_ctx, model, lp_server_services()); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0,("Starting Services failed - %s\n", nt_errstr(status))); return 1; } - /* wait for events */ - event_loop_wait(server->event.ctx); + /* wait for events - this is where smbd sits for most of its + life */ + event_loop_wait(event_ctx); - server_service_shutdown(server, "exit"); + /* as everything hangs off this event context, freeing it + should initiate a clean shutdown of all services */ + talloc_free(event_ctx); return 0; } diff --git a/source4/smbd/server.h b/source4/smbd/server.h deleted file mode 100644 index 6021df12c5..0000000000 --- a/source4/smbd/server.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - Unix SMB/CIFS implementation. - - Copyright (C) Stefan (metze) 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 _SERVER_H -#define _SERVER_H - -struct server_service; -struct event_context; - -struct server_context { - struct { - struct event_context *ctx; - } event; - - struct { - const struct model_ops *ops; - } model; - - struct server_service *service_list; -}; - -/* size of listen() backlog in smbd */ -#define SERVER_LISTEN_BACKLOG 10 - -/* the range of ports to try for dcerpc over tcp endpoints */ -#define SERVER_TCP_LOW_PORT 1024 -#define SERVER_TCP_HIGH_PORT 1300 - -/* the default idle time of a service */ -#define SERVER_DEFAULT_IDLE_TIME 300 - -#endif /* _SERVER_H */ diff --git a/source4/smbd/service.c b/source4/smbd/service.c index 2d532b638d..ab377dc29b 100644 --- a/source4/smbd/service.c +++ b/source4/smbd/service.c @@ -3,7 +3,7 @@ SERVER SERVICE code - Copyright (C) Andrew Tridgell 2003 + Copyright (C) Andrew Tridgell 2003-2005 Copyright (C) Stefan (metze) Metzmacher 2004 This program is free software; you can redistribute it and/or modify @@ -22,377 +22,77 @@ */ #include "includes.h" -#include "events.h" -#include "system/dir.h" #include "dlinklist.h" #include "process_model.h" -struct server_context *server_service_startup(const char *model, const char **server_services) -{ - int i; - struct server_context *server; - - if (!server_services) { - DEBUG(0,("server_service_startup: no endpoint servers configured\n")); - return NULL; - } - - server = talloc_zero(NULL, struct server_context); - if (!server) { - return NULL; - } - - server->model.ops = process_model_startup(server, model); - if (!server->model.ops) { - DEBUG(0,("process_model_startup('%s') failed\n", model)); - return NULL; - } - - server->event.ctx = event_context_init(server); - if (!server->event.ctx) { - DEBUG(0,("event_context_init() failed\n")); - return NULL; - } - - for (i=0;server_services[i];i++) { - const struct server_service_ops *service_ops; - struct server_service *service; - - service_ops = server_service_byname(server_services[i]); - if (!service_ops) { - DEBUG(0,("process_model_startup: failed to find server service = '%s'\n", server_services[i])); - return NULL; - } - - service = talloc_zero(server, struct server_service); - if (!service) { - return NULL; - } - - service->service.ops = service_ops; - service->server = server; - - /* TODO: service_init() should return a result */ - service->service.ops->service_init(service); - - DLIST_ADD(server->service_list, service); - } - - return server; -} - -void server_service_shutdown(struct server_context *server, const char *reason) -{ - server->model.ops->model_exit(server, reason); -} - /* - setup a listen stream socket - if you pass *port == 0, then a port > 1024 is used - */ -struct server_stream_socket *service_setup_stream_socket(struct server_service *service, - const struct server_stream_ops *stream_ops, - const char *family, - const char *sock_addr, - uint16_t *port) -{ - NTSTATUS status; - struct server_stream_socket *stream_socket; - struct socket_context *sock; - struct fd_event fde; - int i; - - status = socket_create(family, SOCKET_TYPE_STREAM, &sock, 0); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0,("Failed to open socket on %s:%u - %s\n", - sock_addr, *port, nt_errstr(status))); - return NULL; - } - - /* ready to listen */ - status = socket_set_option(sock, "SO_KEEPALIVE SO_REUSEADDR=1", NULL); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0,("socket_set_option(socket_ctx, SO_KEEPALIVE, NULL): %s\n", - nt_errstr(status))); - socket_destroy(sock); - return NULL; - } - status = socket_set_option(sock, lp_socket_options(), NULL); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0,("socket_set_option(socket_ctx, lp_socket_options(), NULL): %s\n", - nt_errstr(status))); - socket_destroy(sock); - return NULL; - } - - /* TODO: set socket ACL's here when they're implemented */ - - if (*port == 0) { - for (i=SERVER_TCP_LOW_PORT;i<= SERVER_TCP_HIGH_PORT;i++) { - status = socket_listen(sock, sock_addr, i, SERVER_LISTEN_BACKLOG, 0); - if (NT_STATUS_IS_OK(status)) { - *port = i; - break; - } - } - } else { - status = socket_listen(sock, sock_addr, *port, SERVER_LISTEN_BACKLOG, 0); - } - - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0,("Failed to listen on %s:%u - %s\n", - sock_addr, *port, nt_errstr(status))); - socket_destroy(sock); - return NULL; - } - - stream_socket = talloc_zero(service, struct server_stream_socket); - if (!stream_socket) { - DEBUG(0,("talloc(mem_ctx, struct server_stream_socket) failed\n")); - socket_destroy(sock); - return NULL; - } - - /* we are only interested in read events on the listen socket */ - fde.fd = socket_get_fd(sock); - fde.flags = EVENT_FD_READ; - fde.private = stream_socket; - fde.handler = server_accept_handler; - - stream_socket->stream.ops = stream_ops; - stream_socket->service = service; - stream_socket->socket = sock; - stream_socket->event.ctx = service->server->event.ctx; - stream_socket->event.fde = event_add_fd(stream_socket->event.ctx, - &fde, stream_socket); - if (!stream_socket->event.fde) { - socket_destroy(sock); - return NULL; - } - - talloc_steal(stream_socket, sock); - - if (stream_socket->stream.ops->socket_init) { - stream_socket->stream.ops->socket_init(stream_socket); - } - - return stream_socket; -} - -/* - destructor that handles necessary event context changes - */ -static int server_connection_destructor(void *ptr) -{ - struct server_connection *conn = ptr; - - if (conn->stream_socket && - conn->stream_socket->stream.ops->close_connection) { - /* don't remove this! the stream service needs to free it's data - * before we destroy the server_connection - */ - conn->stream_socket->stream.ops->close_connection(conn, "shutdown"); - } - - return 0; -} - -struct server_connection *server_setup_connection(struct event_context *ev, - struct server_stream_socket *stream_socket, - struct socket_context *sock, - struct timeval t, - servid_t server_id) -{ - struct fd_event fde; - struct timed_event idle; - struct server_connection *srv_conn; - - srv_conn = talloc(stream_socket, struct server_connection); - if (!srv_conn) { - DEBUG(0,("talloc(mem_ctx, struct server_connection) failed\n")); - return NULL; - } - - ZERO_STRUCTP(srv_conn); - - fde.private = srv_conn; - fde.fd = socket_get_fd(sock); - fde.flags = EVENT_FD_READ; - fde.handler = server_io_handler; - - idle.private = srv_conn; - idle.next_event = timeval_add(&t, SERVER_DEFAULT_IDLE_TIME, 0); - idle.handler = server_idle_handler; - - srv_conn->event.ctx = ev; - srv_conn->event.fde = &fde; - srv_conn->event.idle = &idle; - srv_conn->event.idle_time = timeval_set(SERVER_DEFAULT_IDLE_TIME, 0); - - srv_conn->stream_socket = stream_socket; - srv_conn->socket = sock; - srv_conn->connection.id = server_id; - - /* create a server context and add it to out event - handling */ - stream_socket->stream.ops->accept_connection(srv_conn); - - /* accpect_connection() of the service may changed idle.next_event */ - srv_conn->event.fde = event_add_fd(ev, &fde, srv_conn); - srv_conn->event.idle = event_add_timed(ev, &idle, srv_conn); - - talloc_set_destructor(srv_conn, server_connection_destructor); - - if (!socket_check_access(sock, "smbd", lp_hostsallow(-1), lp_hostsdeny(-1))) { - server_terminate_connection(srv_conn, "denied by access rules"); - return NULL; - } - - /* setup to receive internal messages on this connection */ - srv_conn->messaging.ctx = messaging_init(srv_conn, srv_conn->connection.id, ev); - if (!srv_conn->messaging.ctx) { - server_terminate_connection(srv_conn, "messaging_init() failed"); - return NULL; - } - - return srv_conn; -} + a linked list of registered servers +*/ +static struct registered_server { + struct registered_server *next, *prev; + const char *service_name; + NTSTATUS (*service_init)(struct event_context *, const struct model_ops *); +} *registered_servers; /* - close the socket and shutdown a server_context + register a server service. */ -void server_terminate_connection(struct server_connection *srv_conn, const char *reason) -{ - DEBUG(2,("server_terminate_connection\n")); - srv_conn->stream_socket->service->server->model.ops->terminate_connection(srv_conn, reason); -} - -void server_accept_handler(struct event_context *ev, struct fd_event *fde, - struct timeval t, uint16_t flags) +NTSTATUS register_server_service(const char *name, + NTSTATUS (*service_init)(struct event_context *, const struct model_ops *)) { - struct server_stream_socket *stream_socket = talloc_get_type(fde->private, - struct server_stream_socket); - - stream_socket->service->server->model.ops->accept_connection(ev, fde, t, flags); + struct registered_server *srv; + srv = talloc(talloc_autofree_context(), struct registered_server); + NT_STATUS_HAVE_NO_MEMORY(srv); + srv->service_name = name; + srv->service_init = service_init; + DLIST_ADD_END(registered_servers, srv, struct registered_server *); + return NT_STATUS_OK; } -void server_io_handler(struct event_context *ev, struct fd_event *fde, - struct timeval t, uint16_t flags) -{ - struct server_connection *conn = talloc_get_type(fde->private, - struct server_connection); - - conn->event.idle->next_event = timeval_sum(&t, &conn->event.idle_time); - - if (flags & EVENT_FD_WRITE) { - conn->stream_socket->stream.ops->send_handler(conn, t, flags); - return; - } - - if (flags & EVENT_FD_READ) { - conn->stream_socket->stream.ops->recv_handler(conn, t, flags); - } - -} - -void server_idle_handler(struct event_context *ev, struct timed_event *idle, - struct timeval t) -{ - struct server_connection *conn = talloc_get_type(idle->private, - struct server_connection); - - /* Not all services provide an idle handler */ - if (conn->stream_socket->stream.ops->idle_handler) { - conn->event.idle->next_event = timeval_sum(&t, &conn->event.idle_time); - conn->stream_socket->stream.ops->idle_handler(conn, t); - } -} - -void server_terminate_task(struct server_task *task, const char *reason) -{ - task->service->server->model.ops->terminate_task(task, reason); - return; -} - -void server_run_task(struct server_service *service, const struct server_task_ops *ops) -{ - struct server_task *task; - - task = talloc_zero(service, struct server_task); - if (!task) { - return; - } - task->service = service; - task->task.ops = ops; - - service->server->model.ops->create_task(task); - return; -} /* - return the operations structure for a named backend of the specified type + initialise a server service */ -const struct server_service_ops *server_service_byname(const char *name) +static NTSTATUS server_service_init(const char *name, + struct event_context *event_ctx, + const struct model_ops *model_ops) { - if (strcmp("smb",name)==0) { - return smbsrv_get_ops(); - } - if (strcmp("rpc",name)==0) { - return dcesrv_get_ops(); - } - if (strcmp("ldap",name)==0) { - return ldapsrv_get_ops(); - } - if (strcmp("winbind",name)==0) { - return winbind_get_ops(); - } - if (strcmp("winbind_task",name)==0) { - return winbind_task_get_ops(); + struct registered_server *srv; + for (srv=registered_servers; srv; srv=srv->next) { + if (strcasecmp(name, srv->service_name) == 0) { + return srv->service_init(event_ctx, model_ops); + } } - return NULL; + return NT_STATUS_INVALID_SYSTEM_SERVICE; } -NTSTATUS register_server_service_ops(const void *_ops) -{ - return NT_STATUS_NOT_IMPLEMENTED; -} /* - cleanup temporary files. This is the new alternative to - TDB_CLEAR_IF_FIRST. Unfortunately TDB_CLEAR_IF_FIRST is not - efficient on unix systems due to the lack of scaling of the byte - range locking system. So instead of putting the burden on tdb to - cleanup tmp files, this function deletes them. + startup all of our server services */ -void service_cleanup_tmp_files(void) +NTSTATUS server_service_startup(struct event_context *event_ctx, + const char *model, const char **server_services) { - char *path; - DIR *dir; - struct dirent *de; - TALLOC_CTX *mem_ctx = talloc_init("service_cleanup_tmp_files"); + int i; + const struct model_ops *model_ops; - path = smbd_tmp_path(mem_ctx, NULL); + if (!server_services) { + DEBUG(0,("server_service_startup: no endpoint servers configured\n")); + return NT_STATUS_INVALID_PARAMETER; + } - dir = opendir(path); - if (!dir) { - talloc_free(mem_ctx); - return; + model_ops = process_model_startup(event_ctx, model); + if (!model_ops) { + DEBUG(0,("process_model_startup('%s') failed\n", model)); + return NT_STATUS_INTERNAL_ERROR; } - for (de=readdir(dir);de;de=readdir(dir)) { - char *fname = talloc_asprintf(mem_ctx, "%s/%s", path, de->d_name); - int ret = unlink(fname); - if (ret == -1 && - errno != ENOENT && - errno != EISDIR && - errno != EISDIR) { - DEBUG(0,("Unabled to delete '%s' - %s\n", - fname, strerror(errno))); - smb_panic("unable to cleanup tmp files"); - } - talloc_free(fname); + for (i=0;server_services[i];i++) { + NTSTATUS status; + + status = server_service_init(server_services[i], event_ctx, model_ops); + NT_STATUS_NOT_OK_RETURN(status); } - closedir(dir); - talloc_free(mem_ctx); + return NT_STATUS_OK; } diff --git a/source4/smbd/service.h b/source4/smbd/service.h deleted file mode 100644 index d5335b1cef..0000000000 --- a/source4/smbd/service.h +++ /dev/null @@ -1,165 +0,0 @@ -/* - Unix SMB/CIFS implementation. - - SERVER SERVICE code - - Copyright (C) Stefan (metze) 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 _SERVER_SERVICE_H -#define _SERVER_SERVICE_H - -struct event_context; -struct model_ops; -struct server_context; - -struct server_connection; -struct server_service; - -/* modules can use the following to determine if the interface has changed - * please increment the version number after each interface change - * with a comment and maybe update struct process_model_critical_sizes. - */ -/* version 1 - initial version - metze */ -#define SERVER_SERVICE_VERSION 1 - -struct server_service_ops { - /* the name of the server_service */ - const char *name; - - /* called at startup when the server_service is selected */ - void (*service_init)(struct server_service *service); -}; - -struct server_stream_socket; - -struct server_stream_ops { - /* the name of the server_service */ - const char *name; - - /* called at startup when the server_service is selected */ - void (*socket_init)(struct server_stream_socket *socket); - - /* function to accept new connection */ - void (*accept_connection)(struct server_connection *); - - void (*recv_handler)(struct server_connection *, struct timeval, uint16_t); - - void (*send_handler)(struct server_connection *, struct timeval, uint16_t); - - /* function to be called when the server is idle */ - void (*idle_handler)(struct server_connection *, struct timeval); - - /* function to close a connection */ - void (*close_connection)(struct server_connection *, const char *reason); -}; - -struct socket_context; - -struct server_stream_socket { - struct server_stream_socket *next,*prev; - struct { - const struct server_stream_ops *ops; - void *private_data; - } stream; - - struct { - struct event_context *ctx; - struct fd_event *fde; - } event; - - struct socket_context *socket; - - struct server_service *service; -}; - -struct server_service { - struct server_service *next,*prev; - struct { - const struct server_service_ops *ops; - void *private_data; - } service; - - struct server_context *server; -}; - -/* the concept of whether two operations are on the same server - connection or different connections is an important one in SMB, especially - for locking and share modes. We will use a servid_t to distinguish different - connections - - this means that (for example) a unique open file is distinguished by the triple - of - servid_t server; - uint16 tid; - uint16 fnum; -*/ -typedef uint32_t servid_t; - -struct server_connection { - struct server_connection *next,*prev; - struct { - void *private_data; - servid_t id; - } connection; - - struct { - struct event_context *ctx; - struct fd_event *fde; - struct timed_event *idle; - struct timeval idle_time; - } event; - - struct socket_context *socket; - - struct server_stream_socket *stream_socket; - - struct { - struct messaging_context *ctx; - } messaging; -}; - -struct server_task; - -struct server_task_ops { - /* the name of the server_task */ - const char *name; - - /* called at startup when the server_task is selected */ - void (*task_init)(struct server_task *task); -}; - -struct server_task { - struct server_task *next,*prev; - struct { - const struct server_task_ops *ops; - void *private_data; - servid_t id; - } task; - - struct { - struct event_context *ctx; - } event; - - struct { - struct messaging_context *ctx; - } messaging; - - struct server_service *service; -}; - -#endif /* _SERVER_SERVICE_H */ diff --git a/source4/torture/local/messaging.c b/source4/torture/local/messaging.c index 9c6f55a6c4..bef2604006 100644 --- a/source4/torture/local/messaging.c +++ b/source4/torture/local/messaging.c @@ -25,7 +25,7 @@ enum {MY_PING=1000, MY_PONG, MY_EXIT}; static void ping_message(struct messaging_context *msg, void *private, - uint32_t msg_type, servid_t src, DATA_BLOB *data) + uint32_t msg_type, uint32_t src, DATA_BLOB *data) { NTSTATUS status; status = messaging_send(msg, src, MY_PONG, data); @@ -35,14 +35,14 @@ static void ping_message(struct messaging_context *msg, void *private, } static void pong_message(struct messaging_context *msg, void *private, - uint32_t msg_type, servid_t src, DATA_BLOB *data) + uint32_t msg_type, uint32_t src, DATA_BLOB *data) { int *count = private; (*count)++; } static void exit_message(struct messaging_context *msg, void *private, - uint32_t msg_type, servid_t src, DATA_BLOB *data) + uint32_t msg_type, uint32_t src, DATA_BLOB *data) { talloc_free(private); exit(0); |