diff options
author | Stefan Metzmacher <metze@samba.org> | 2004-07-13 21:04:56 +0000 |
---|---|---|
committer | Gerald (Jerry) Carter <jerry@samba.org> | 2007-10-10 12:57:35 -0500 |
commit | 45a85bdd353418828df8017a9d7eb7c14f6f0cd3 (patch) | |
tree | 14ec6ac1262f9a0a1974b6725a7f26afddb38f61 /source4 | |
parent | 9b4ac4d81ecf9786d2a3f96914af4a2895046676 (diff) | |
download | samba-45a85bdd353418828df8017a9d7eb7c14f6f0cd3.tar.gz samba-45a85bdd353418828df8017a9d7eb7c14f6f0cd3.tar.bz2 samba-45a85bdd353418828df8017a9d7eb7c14f6f0cd3.zip |
r1486: commit the start of the generic server infastructure
the idea is to have services as modules (smb, dcerpc, swat, ...)
the process_model don't know about the service it self anymore.
TODO:
- the smbsrv should use the smbsrv_send function
- the service subsystem init should be done like for other modules
- we need to have a generic socket subsystem, which handle stream, datagram,
and virtuell other sockets( e.g. for the ntvfs_ipc module to connect to the dcerpc server
, or for smb or dcerpc or whatever to connect to a server wide auth service)
- and other fixes...
NOTE: process model pthread seems to be broken( but also before this patch!)
metze
(This used to be commit bbe5e00715ca4013ff0dbc345aa97adc6b5c2458)
Diffstat (limited to 'source4')
27 files changed, 1076 insertions, 549 deletions
diff --git a/source4/auth/auth.c b/source4/auth/auth.c index 703df21d45..32913f9996 100644 --- a/source4/auth/auth.c +++ b/source4/auth/auth.c @@ -501,3 +501,8 @@ BOOL auth_init(void) DEBUG(3,("AUTH subsystem version %d initialised\n", AUTH_INTERFACE_VERSION)); return True; } + +NTSTATUS server_service_auth_init(void) +{ + return NT_STATUS_OK; +} diff --git a/source4/include/includes.h b/source4/include/includes.h index 058d547736..9ce2b71982 100644 --- a/source4/include/includes.h +++ b/source4/include/includes.h @@ -668,6 +668,8 @@ extern int errno; #include "librpc/rpc/dcerpc.h" +#include "smbd/server.h" +#include "smbd/service.h" #include "rpc_server/dcerpc_server.h" #include "smb_server/smb_server.h" #include "ntvfs/ntvfs.h" diff --git a/source4/include/local.h b/source4/include/local.h index 3f0f8618aa..67b83c316d 100644 --- a/source4/include/local.h +++ b/source4/include/local.h @@ -224,11 +224,4 @@ /* Max number of simultaneous winbindd socket connections. */ #define WINBINDD_MAX_SIMULTANEOUS_CLIENTS 200 -/* size of listen() backlog in smbd */ -#define SMBD_LISTEN_BACKLOG 10 - -/* the range of ports to try for dcerpc over tcp endpoints */ -#define DCERPC_TCP_LOW_PORT 1024 -#define DCERPC_TCP_HIGH_PORT 1300 - #endif diff --git a/source4/ntvfs/cifs/vfs_cifs.c b/source4/ntvfs/cifs/vfs_cifs.c index 93b9f2630e..b6d3486ad8 100644 --- a/source4/ntvfs/cifs/vfs_cifs.c +++ b/source4/ntvfs/cifs/vfs_cifs.c @@ -51,7 +51,7 @@ struct async_info { static void idle_func(struct cli_transport *transport, void *p_private) { struct cvfs_private *private = p_private; - if (socket_pending(private->tcon->smb_conn->socket.fd)) { + if (socket_pending(private->tcon->smb_conn->connection->socket->fde->fd)) { smbd_process_async(private->tcon->smb_conn); } } @@ -164,7 +164,7 @@ static NTSTATUS cvfs_connect(struct smbsrv_request *req, const char *sharename) fde.private = private; fde.handler = cifs_socket_handler; - event_add_fd(tcon->smb_conn->events, &fde); + event_add_fd(tcon->smb_conn->connection->event.ctx, &fde); /* we need to receive oplock break requests from the server */ cli_oplock_handler(private->transport, oplock_handler, private); @@ -180,7 +180,7 @@ static NTSTATUS cvfs_disconnect(struct smbsrv_tcon *tcon) { struct cvfs_private *private = tcon->ntvfs_private; - event_remove_fd_all(tcon->smb_conn->events, private->transport->socket->fd); + event_remove_fd_all(tcon->smb_conn->connection->event.ctx, private->transport->socket->fd); smb_tree_disconnect(private->tree); cli_tree_close(private->tree); diff --git a/source4/param/loadparm.c b/source4/param/loadparm.c index 5493b2617c..293df3bb1f 100644 --- a/source4/param/loadparm.c +++ b/source4/param/loadparm.c @@ -137,6 +137,7 @@ typedef struct char *szWINSHook; char *szWINSPartners; char **dcerpc_ep_servers; + char **server_services; char *szWinbindUID; char *szWinbindGID; char *szNonUnixAccountRange; @@ -568,6 +569,7 @@ static struct parm_struct parm_table[] = { {"bind interfaces only", P_BOOL, P_GLOBAL, &Globals.bBindInterfacesOnly, NULL, NULL, FLAG_ADVANCED | FLAG_WIZARD | FLAG_DEVELOPER}, {"ntvfs handler", P_STRING, P_LOCAL, &sDefault.ntvfs_handler, NULL, NULL, FLAG_ADVANCED}, {"dcerpc endpoint servers", P_LIST, P_GLOBAL, &Globals.dcerpc_ep_servers, NULL, NULL, FLAG_ADVANCED}, + {"server services", P_LIST, P_GLOBAL, &Globals.server_services, NULL, NULL, FLAG_ADVANCED}, {"Security Options", P_SEP, P_SEPARATOR}, @@ -959,6 +961,8 @@ static void init_globals(void) Globals.dcerpc_ep_servers = str_list_make("epmapper srvsvc wkssvc rpcecho samr netlogon lsarpc spoolss", NULL); + Globals.server_services = str_list_make("smb rpc", NULL); + Globals.AuthMethods = str_list_make("guest sam_ignoredomain", NULL); string_set(&Globals.szSMBPasswdFile, dyn_SMB_PASSWD_FILE); @@ -1218,6 +1222,7 @@ FN_GLOBAL_STRING(lp_printcapname, &Globals.szPrintcapname) FN_GLOBAL_STRING(lp_lockdir, &Globals.szLockDir) FN_GLOBAL_STRING(lp_piddir, &Globals.szPidDir) FN_GLOBAL_LIST(lp_dcerpc_endpoint_servers, &Globals.dcerpc_ep_servers) +FN_GLOBAL_LIST(lp_server_services, &Globals.server_services) FN_GLOBAL_STRING(lp_rootdir, &Globals.szRootdir) FN_GLOBAL_STRING(lp_defaultservice, &Globals.szDefaultService) FN_GLOBAL_STRING(lp_hosts_equiv, &Globals.szHostsEquiv) diff --git a/source4/rpc_server/dcerpc_server.c b/source4/rpc_server/dcerpc_server.c index e5c4c120a5..34756349c6 100644 --- a/source4/rpc_server/dcerpc_server.c +++ b/source4/rpc_server/dcerpc_server.c @@ -271,6 +271,7 @@ NTSTATUS dcesrv_endpoint_connect(struct dcesrv_context *dce_ctx, (*p)->auth_state.auth_info = NULL; (*p)->auth_state.gensec_security = NULL; (*p)->auth_state.session_info = NULL; + (*p)->srv_conn = NULL; return NT_STATUS_OK; } @@ -1016,6 +1017,87 @@ NTSTATUS dcesrv_init_context(struct dcesrv_context *dce_ctx) return NT_STATUS_OK; } +static void dcesrv_init(struct server_service *service, const struct model_ops *model_ops) +{ + TALLOC_CTX *mem_ctx; + struct dcesrv_context *dce_ctx; + int i; + const char **endpoint_servers = lp_dcerpc_endpoint_servers(); + + DEBUG(0,("dcesrv_init\n")); + + + if (!endpoint_servers) { + DEBUG(0,("dcesrv_init_context: no endpoint servers configured\n")); + return; + } + + mem_ctx = talloc_init("struct dcesrv_context"); + + dce_ctx = talloc_p(mem_ctx, struct dcesrv_context); + if (!dce_ctx) { + DEBUG(0,("talloc_p(mem_ctx, struct dcesrv_context) failed\n")); + return; + } + + ZERO_STRUCTP(dce_ctx); + dce_ctx->mem_ctx = mem_ctx; + dce_ctx->endpoint_list = NULL; + + for (i=0;endpoint_servers[i];i++) { + NTSTATUS ret; + const struct dcesrv_endpoint_server *ep_server; + + ep_server = dcesrv_ep_server_byname(endpoint_servers[i]); + if (!ep_server) { + DEBUG(0,("dcesrv_init_context: failed to find endpoint server = '%s'\n", endpoint_servers[i])); + return; + } + + ret = ep_server->init_server(dce_ctx, ep_server); + if (!NT_STATUS_IS_OK(ret)) { + DEBUG(0,("dcesrv_init_context: failed to init endpoint server = '%s'\n", endpoint_servers[i])); + return; + } + } + + dcesrv_tcp_init(service, model_ops, dce_ctx); + + return; +} + +static void dcesrv_accept(struct server_connection *srv_conn) +{ + dcesrv_tcp_accept(srv_conn); +} + +static void dcesrv_recv(struct server_connection *srv_conn, time_t t, uint16_t flags) +{ + dcesrv_tcp_recv(srv_conn, t, flags); +} + +static void dcesrv_send(struct server_connection *srv_conn, time_t t, uint16_t flags) +{ + dcesrv_tcp_send(srv_conn, t, flags); +} + +static void dcesrv_idle(struct server_connection *srv_conn, time_t t) +{ + dcesrv_tcp_idle(srv_conn, t); +} + +static void dcesrv_close(struct server_connection *srv_conn, const char *reason) +{ + dcesrv_tcp_close(srv_conn, reason); + return; +} + +static void dcesrv_exit(struct server_service *service, const char *reason) +{ + dcesrv_tcp_exit(service, reason); + return; +} + /* the list of currently registered DCERPC endpoint servers. */ static struct { @@ -1101,7 +1183,7 @@ const struct dcesrv_critical_sizes *dcerpc_module_version(void) /* initialise the DCERPC subsystem */ -BOOL dcesrv_init(void) +BOOL subsystem_dcerpc_init(void) { NTSTATUS status; @@ -1116,3 +1198,24 @@ BOOL dcesrv_init(void) DEBUG(3,("DCERPC subsystem version %d initialised\n", DCERPC_MODULE_VERSION)); return True; } + +static const struct server_service_ops dcesrv_ops = { + .name = "rpc", + .service_init = dcesrv_init, + .accept_connection = dcesrv_accept, + .recv_handler = dcesrv_recv, + .send_handler = dcesrv_send, + .idle_handler = dcesrv_idle, + .close_connection = dcesrv_close, + .service_exit = dcesrv_exit, +}; + +const struct server_service_ops *dcesrv_get_ops(void) +{ + return &dcesrv_ops; +} + +NTSTATUS server_service_rpc_init(void) +{ + return NT_STATUS_OK; +} diff --git a/source4/rpc_server/dcerpc_server.h b/source4/rpc_server/dcerpc_server.h index b1754dd4a3..15da3e38bb 100644 --- a/source4/rpc_server/dcerpc_server.h +++ b/source4/rpc_server/dcerpc_server.h @@ -39,7 +39,7 @@ struct dcesrv_ep_description { enum endpoint_type type; union { const char *smb_pipe; - uint32_t tcp_port; + uint16_t tcp_port; } info; }; @@ -132,6 +132,8 @@ struct dcesrv_connection { /* the current authentication state */ struct dcesrv_auth auth_state; + + struct server_connection *srv_conn; }; diff --git a/source4/rpc_server/dcerpc_tcp.c b/source4/rpc_server/dcerpc_tcp.c index 83a9140dd1..c506cf16cf 100644 --- a/source4/rpc_server/dcerpc_tcp.c +++ b/source4/rpc_server/dcerpc_tcp.c @@ -23,39 +23,12 @@ #include "includes.h" -struct rpc_server_context { - struct dcesrv_ep_description *ep_description; +struct dcesrv_socket_context { const struct dcesrv_endpoint *endpoint; - const struct model_ops *model_ops; - struct dcesrv_connection *dce_conn; - struct dcesrv_context dcesrv_context; - int socket_fd; - struct event_context *events; + struct dcesrv_context *dcesrv_ctx; }; /* - a callback from the process model termination routine -*/ -void rpc_server_terminate(void *rr) -{ - struct rpc_server_context *r = rr; - - dcesrv_endpoint_disconnect(r->dce_conn); - close(r->socket_fd); - event_remove_fd_all(r->events, r->socket_fd); - free(r); -} - -/* - called when a rpc session needs to be shutdown -*/ -static void terminate_rpc_session(struct rpc_server_context *r, const char *reason) -{ - r->model_ops->terminate_rpc_connection(r, reason); -} - - -/* write_fn callback for dcesrv_output() */ static ssize_t dcerpc_write_fn(void *private, const void *buf, size_t count) @@ -69,45 +42,128 @@ static ssize_t dcerpc_write_fn(void *private, const void *buf, size_t count) return ret; } +void dcesrv_terminate_connection(struct dcesrv_connection *dce_conn, const char *reason) +{ + server_terminate_connection(dce_conn->srv_conn, reason); +} + /* - called when a RPC socket becomes writable + add a socket address to the list of events, one event per dcerpc endpoint */ -static void dcerpc_write_handler(struct event_context *ev, struct fd_event *fde, - time_t t, uint16_t flags) +static void add_socket_rpc(struct server_service *service, + const struct model_ops *model_ops, + struct socket_context *socket_ctx, + struct dcesrv_context *dce_ctx, + struct in_addr *ifip) { - struct rpc_server_context *r = fde->private; - NTSTATUS status; + struct dcesrv_endpoint *e; - status = dcesrv_output(r->dce_conn, fde, dcerpc_write_fn); - if (NT_STATUS_IS_ERR(status)) { - /* TODO: destroy fd_event? */ + for (e=dce_ctx->endpoint_list;e;e=e->next) { + if (e->ep_description.type == ENDPOINT_TCP) { + struct server_socket *sock; + struct dcesrv_socket_context *dcesrv_sock; + + sock = service_setup_socket(service,model_ops,socket_ctx,ifip, &e->ep_description.info.tcp_port); + if (!sock) { + DEBUG(0,("service_setup_socket(port=%u) failed\n",e->ep_description.info.tcp_port)); + continue; + } + + dcesrv_sock = talloc_p(sock->mem_ctx, struct dcesrv_socket_context); + if (!dcesrv_sock) { + DEBUG(0,("talloc_p(sock->mem_ctx, struct dcesrv_socket_context) failed\n")); + continue; + } + + /* remeber the enpoint of this socket */ + dcesrv_sock->endpoint = e; + dcesrv_sock->dcesrv_ctx = dce_ctx; + + sock->private_data = dcesrv_sock; + } } +} - if (!r->dce_conn->call_list || !r->dce_conn->call_list->replies) { - fde->flags &= ~EVENT_FD_WRITE; +/**************************************************************************** + Open the listening sockets for RPC over TCP +****************************************************************************/ +void dcesrv_tcp_init(struct server_service *service, const struct model_ops *model_ops, struct dcesrv_context *dce_ctx) +{ + DEBUG(1,("dcesrv_tcp_init\n")); + + if (lp_interfaces() && lp_bind_interfaces_only()) { + int num_interfaces = iface_count(); + int i; + for(i = 0; i < num_interfaces; i++) { + struct in_addr *ifip = iface_n_ip(i); + if (ifip == NULL) { + continue; + } + add_socket_rpc(service, model_ops, NULL, dce_ctx, ifip); + } + } else { + struct in_addr *ifip; + TALLOC_CTX *mem_ctx = talloc_init("open_sockets_smbd"); + if (!mem_ctx) { + smb_panic("No memory"); + } + + ifip = interpret_addr2(mem_ctx, lp_socket_address()); + add_socket_rpc(service, model_ops, NULL, dce_ctx, ifip); + talloc_destroy(mem_ctx); } + + return; } -/* - called when a RPC socket becomes readable -*/ -static void dcerpc_read_handler(struct event_context *ev, struct fd_event *fde, - time_t t, uint16_t flags) +void dcesrv_tcp_accept(struct server_connection *conn) +{ + NTSTATUS status; + struct dcesrv_socket_context *dcesrv_sock = conn->server_socket->private_data; + struct dcesrv_connection *dcesrv_conn = NULL; + + DEBUG(5,("dcesrv_tcp_accept\n")); + + + + status = dcesrv_endpoint_connect(dcesrv_sock->dcesrv_ctx, dcesrv_sock->endpoint, &dcesrv_conn); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(0,("dcesrv_tcp_accept: dcesrv_endpoint_connect failed: %s\n", + nt_errstr(status))); + return; + } + + dcesrv_conn->srv_conn = conn; + + conn->private_data = dcesrv_conn; + + /* TODO: this should to the generic code + * but the smb server can't handle it yet + * --metze + */ + set_blocking(conn->socket->fde->fd, False); + + return; +} + +void dcesrv_tcp_recv(struct server_connection *conn, time_t t, uint16_t flags) { - struct rpc_server_context *r = fde->private; + struct dcesrv_connection *dce_conn = conn->private_data; DATA_BLOB blob; ssize_t ret; + DEBUG(10,("dcesrv_tcp_recv\n")); + blob = data_blob(NULL, 0x4000); if (!blob.data) { - terminate_rpc_session(r, "out of memory"); + dcesrv_terminate_connection(dce_conn, "eof on socket"); return; } - ret = read(fde->fd, blob.data, blob.length); + ret = read(conn->socket->fde->fd, blob.data, blob.length); if (ret == 0 || (ret == -1 && errno != EINTR)) { data_blob_free(&blob); - terminate_rpc_session(r, "eof on socket"); + dcesrv_terminate_connection(dce_conn, "eof on socket"); return; } if (ret == -1) { @@ -117,197 +173,61 @@ static void dcerpc_read_handler(struct event_context *ev, struct fd_event *fde, blob.length = ret; - dcesrv_input(r->dce_conn, &blob); + dcesrv_input(dce_conn, &blob); data_blob_free(&blob); - if (r->dce_conn->call_list && r->dce_conn->call_list->replies) { - fde->flags |= EVENT_FD_WRITE; + if (dce_conn->call_list && dce_conn->call_list->replies) { + conn->socket->fde->flags |= EVENT_FD_WRITE; } -} - - - -/* - called when a RPC socket becomes readable -*/ -static void dcerpc_io_handler(struct event_context *ev, struct fd_event *fde, - time_t t, uint16_t flags) -{ - if (flags & EVENT_FD_WRITE) { - dcerpc_write_handler(ev, fde, t, flags); - } - - if (flags & EVENT_FD_READ) { - dcerpc_read_handler(ev, fde, t, flags); - } + return; } - -/* - initialise a server_context from a open socket and register a event handler - for reading from that socket -*/ -void init_rpc_session(struct event_context *ev, void *private, int fd) + +void dcesrv_tcp_send(struct server_connection *conn, time_t t, uint16_t flags) { - struct fd_event fde; - struct rpc_server_context *r = private; + struct dcesrv_connection *dce_conn = conn->private_data; NTSTATUS status; - r = memdup(r, sizeof(struct rpc_server_context)); - - r->events = ev; - r->socket_fd = fd; + DEBUG(10,("dcesrv_tcp_send\n")); - set_socket_options(fd,"SO_KEEPALIVE"); - set_socket_options(fd, lp_socket_options()); - - status = dcesrv_endpoint_connect(&r->dcesrv_context, r->endpoint, &r->dce_conn); - if (!NT_STATUS_IS_OK(status)) { - close(fd); - free(r); - DEBUG(0,("init_rpc_session: connection to endpoint failed: %s\n", - nt_errstr(status))); - return; + status = dcesrv_output(dce_conn, conn->socket->fde, dcerpc_write_fn); + if (NT_STATUS_IS_ERR(status)) { + /* TODO: destroy fd_event? */ } - r->dce_conn->dce_ctx = &r->dcesrv_context; - - set_blocking(fd, False); - - /* setup a event handler for this socket. We are initially - only interested in reading from the socket */ - fde.fd = fd; - fde.handler = dcerpc_io_handler; - fde.private = r; - fde.flags = EVENT_FD_READ; + if (!dce_conn->call_list || !dce_conn->call_list->replies) { + conn->socket->fde->flags &= ~EVENT_FD_WRITE; + } - event_add_fd(ev, &fde); + return; } - -/* - setup a single rpc listener - */ -static void setup_listen_rpc(struct event_context *events, - const struct model_ops *model_ops, - struct in_addr *ifip, uint32_t *port, - struct rpc_server_context *r, - const struct dcesrv_endpoint *endpoint) +void dcesrv_tcp_idle(struct server_connection *conn, time_t t) { - struct fd_event fde; - int i; - - if (*port == 0) { - fde.fd = -1; - for (i=DCERPC_TCP_LOW_PORT;i<= DCERPC_TCP_HIGH_PORT;i++) { - fde.fd = open_socket_in(SOCK_STREAM, i, 0, ifip->s_addr, True); - if (fde.fd != -1) break; - } - if (fde.fd != -1) { - *port = i; - } - } else { - fde.fd = open_socket_in(SOCK_STREAM, *port, 0, ifip->s_addr, True); - } + DEBUG(10,("dcesrv_tcp_idle\n")); + conn->event.idle->next_event = t + 5; - if (fde.fd == -1) { - DEBUG(0,("Failed to open socket on %s:%u - %s\n", - inet_ntoa(*ifip), *port, strerror(errno))); - return; - } - - /* each listening socket has separate state, so must use a different context */ - r = memdup(r, sizeof(struct rpc_server_context)); - if (!r) { - smb_panic("out of memory"); - } - - r->ep_description = malloc(sizeof(struct dcesrv_ep_description)); - if (!r->ep_description) { - smb_panic("out of memory"); - } - r->ep_description->type = ENDPOINT_TCP; - r->ep_description->info.tcp_port = *port; - - r->endpoint = endpoint; - - /* ready to listen */ - set_socket_options(fde.fd, "SO_KEEPALIVE"); - set_socket_options(fde.fd, lp_socket_options()); - - if (listen(fde.fd, SMBD_LISTEN_BACKLOG) == -1) { - DEBUG(0,("Failed to listen on %s:%d - %s\n", - inet_ntoa(*ifip), *port, strerror(errno))); - close(fde.fd); - return; - } - - /* we are only interested in read events on the listen socket */ - fde.flags = EVENT_FD_READ; - fde.private = r; - fde.handler = model_ops->accept_rpc_connection; - - event_add_fd(events, &fde); + return; } -/* - add a socket address to the list of events, one event per dcerpc endpoint -*/ -static void add_socket_rpc(struct event_context *events, - const struct model_ops *model_ops, - struct in_addr *ifip) +void dcesrv_tcp_close(struct server_connection *conn, const char *reason) { - struct dcesrv_endpoint *e; - struct rpc_server_context *r; + struct dcesrv_connection *dce_conn = conn->private_data; - r = malloc(sizeof(struct rpc_server_context)); - if (!r) { - smb_panic("out of memory"); - } + DEBUG(5,("dcesrv_tcp_close: %s\n",reason)); - r->dcesrv_context.endpoint_list = NULL; - dcesrv_init_context(&r->dcesrv_context); - r->ep_description = NULL; - r->model_ops = model_ops; - r->dce_conn = NULL; - r->socket_fd = -1; - r->events = NULL; - - for (e=r->dcesrv_context.endpoint_list;e;e=e->next) { - if (e->ep_description.type == ENDPOINT_TCP) { - setup_listen_rpc(events, model_ops, ifip, - &e->ep_description.info.tcp_port, - r, e); - } - } + close(conn->event.fde->fd); + event_remove_fd_all(conn->event.ctx, conn->socket->fde->fd); + event_remove_timed(conn->event.ctx, conn->event.idle); - free(r); + talloc_destroy(dce_conn->mem_ctx); + + return; } -/**************************************************************************** - Open the listening sockets for RPC over TCP -****************************************************************************/ -void open_sockets_rpc(struct event_context *events, - const struct model_ops *model_ops) +void dcesrv_tcp_exit(struct server_service *service, const char *reason) { - if (lp_interfaces() && lp_bind_interfaces_only()) { - int num_interfaces = iface_count(); - int i; - for(i = 0; i < num_interfaces; i++) { - struct in_addr *ifip = iface_n_ip(i); - if (ifip == NULL) { - continue; - } - add_socket_rpc(events, model_ops, ifip); - } - } else { - TALLOC_CTX *mem_ctx = talloc_init("open_sockets_smbd"); - struct in_addr *ifip = interpret_addr2(mem_ctx, lp_socket_address()); - if (!mem_ctx) { - smb_panic("No memory"); - } - add_socket_rpc(events, model_ops, ifip); - talloc_destroy(mem_ctx); - } + DEBUG(1,("dcesrv_tcp_exit: %s\n",reason)); + return; } diff --git a/source4/smb_server/connection.c b/source4/smb_server/connection.c index 77f2395d9e..4cb4f2168a 100644 --- a/source4/smb_server/connection.c +++ b/source4/smb_server/connection.c @@ -166,7 +166,7 @@ BOOL claim_connection(struct smbsrv_tcon *tcon, const char *name,int max_connect crec.bcast_msg_flags = msg_flags; StrnCpy(crec.machine,sub_get_remote_machine(),sizeof(crec.machine)-1); - StrnCpy(crec.addr,tcon?tcon->smb_conn->socket.client_addr:"NONE",sizeof(crec.addr)-1); + StrnCpy(crec.addr,tcon?tcon->smb_conn->connection->socket->client_addr:"NONE",sizeof(crec.addr)-1); dbuf.dptr = (char *)&crec; dbuf.dsize = sizeof(crec); diff --git a/source4/smb_server/negprot.c b/source4/smb_server/negprot.c index f239e6ae81..c9c775e62f 100644 --- a/source4/smb_server/negprot.c +++ b/source4/smb_server/negprot.c @@ -342,7 +342,7 @@ static void reply_nt1(struct smbsrv_request *req, uint16_t choice) memcpy(req->out.ptr, blob.data, blob.length); DEBUG(3,("using SPNEGO\n")); #else - exit_server(req->smb_conn, "no SPNEGO please"); + smbsrv_terminate_connection(req->smb_conn, "no SPNEGO please"); #endif } @@ -450,7 +450,7 @@ void reply_negprot(struct smbsrv_request *req) int arch = ARCH_ALL; if (req->smb_conn->negotiate.done_negprot) { - exit_server(req->smb_conn, "multiple negprot's are not permitted"); + smbsrv_terminate_connection(req->smb_conn, "multiple negprot's are not permitted"); } req->smb_conn->negotiate.done_negprot = True; diff --git a/source4/smb_server/reply.c b/source4/smb_server/reply.c index 1c3ffd58bd..bc79892204 100644 --- a/source4/smb_server/reply.c +++ b/source4/smb_server/reply.c @@ -2300,7 +2300,7 @@ void reply_special(struct smbsrv_request *req) switch (msg_type) { case 0x81: /* session request */ if (req->smb_conn->negotiate.done_nbt_session) { - exit_server(req->smb_conn, "multiple session request not permitted"); + smbsrv_terminate_connection(req->smb_conn, "multiple session request not permitted"); } SCVAL(buf,0,0x82); diff --git a/source4/smb_server/request.c b/source4/smb_server/request.c index 3bfe6a4e73..f4cdba79cc 100644 --- a/source4/smb_server/request.c +++ b/source4/smb_server/request.c @@ -54,12 +54,12 @@ struct smbsrv_request *init_smb_request(struct smbsrv_connection *smb_conn) structure itself is also allocated inside this context, so we need to allocate it before we construct the request */ - mem_ctx = talloc_init("request_context[%d]", smb_conn->socket.pkt_count); + mem_ctx = talloc_init("request_context[%d]", smb_conn->connection->socket->pkt_count); if (!mem_ctx) { return NULL; } - smb_conn->socket.pkt_count++; + smb_conn->connection->socket->pkt_count++; req = talloc(mem_ctx, sizeof(*req)); if (!req) { @@ -91,7 +91,7 @@ static void req_setup_chain_reply(struct smbsrv_request *req, uint_t wct, uint_t req->out.buffer = talloc_realloc(req->mem_ctx, req->out.buffer, req->out.allocated); if (!req->out.buffer) { - exit_server(req->smb_conn, "allocation failed"); + smbsrv_terminate_connection(req->smb_conn, "allocation failed"); } req->out.hdr = req->out.buffer + NBT_HDR_SIZE; @@ -125,7 +125,7 @@ void req_setup_reply(struct smbsrv_request *req, uint_t wct, uint_t buflen) req->out.buffer = talloc(req->mem_ctx, req->out.allocated); if (!req->out.buffer) { - exit_server(req->smb_conn, "allocation failed"); + smbsrv_terminate_connection(req->smb_conn, "allocation failed"); } req->out.hdr = req->out.buffer + NBT_HDR_SIZE; @@ -262,7 +262,7 @@ void req_send_reply_nosign(struct smbsrv_request *req) _smb_setlen(req->out.buffer, req->out.size - NBT_HDR_SIZE); } - if (write_data(req->smb_conn->socket.fd, req->out.buffer, req->out.size) != req->out.size) { + if (write_data(req->smb_conn->connection->socket->fde->fd, req->out.buffer, req->out.size) != req->out.size) { smb_panic("failed to send reply\n"); } diff --git a/source4/smb_server/service.c b/source4/smb_server/service.c index 44aae340b2..0a06e2edfa 100644 --- a/source4/smb_server/service.c +++ b/source4/smb_server/service.c @@ -259,7 +259,7 @@ close a cnum void close_cnum(struct smbsrv_tcon *tcon) { DEBUG(3,("%s closed connection to service %s\n", - tcon->smb_conn->socket.client_addr, lp_servicename(SNUM(tcon)))); + tcon->smb_conn->connection->socket->client_addr, lp_servicename(SNUM(tcon)))); yield_connection(tcon, lp_servicename(SNUM(tcon))); diff --git a/source4/smb_server/smb_server.c b/source4/smb_server/smb_server.c index 16d1d774c0..351d9ddf4e 100644 --- a/source4/smb_server/smb_server.c +++ b/source4/smb_server/smb_server.c @@ -63,7 +63,7 @@ static struct smbsrv_request *receive_smb_request(struct smbsrv_connection *smb_ char header[4]; struct smbsrv_request *req; - len = read_data(smb_conn->socket.fd, header, 4); + len = read_data(smb_conn->connection->socket->fde->fd, header, 4); if (len != 4) { return NULL; } @@ -81,7 +81,7 @@ static struct smbsrv_request *receive_smb_request(struct smbsrv_connection *smb_ /* fill in the already received header */ memcpy(req->in.buffer, header, 4); - len2 = read_data(smb_conn->socket.fd, req->in.buffer + NBT_HDR_SIZE, len); + len2 = read_data(smb_conn->connection->socket->fde->fd, req->in.buffer + NBT_HDR_SIZE, len); if (len2 != len) { return NULL; } @@ -467,7 +467,7 @@ static void switch_message(int type, struct smbsrv_request *req) if (req->user_ctx) { req->user_ctx->vuid = session_tag; } - DEBUG(3,("switch message %s (task_id %d)\n",smb_fn_name(type), smb_conn->model_ops->get_id(req))); + DEBUG(3,("switch message %s (task_id %d)\n",smb_fn_name(type), smb_conn->connection->service->model_ops->get_id(req))); /* does this protocol need to be run as root? */ if (!(flags & AS_USER)) { @@ -562,19 +562,19 @@ static void construct_reply(struct smbsrv_request *req) if (memcmp(req->in.hdr,"\377SMB",4) != 0) { DEBUG(2,("Non-SMB packet of length %d. Terminating connection\n", req->in.size)); - exit_server(req->smb_conn, "Non-SMB packet"); + smbsrv_terminate_connection(req->smb_conn, "Non-SMB packet"); return; } if (NBT_HDR_SIZE + MIN_SMB_SIZE + 2*req->in.wct > req->in.size) { DEBUG(2,("Invalid SMB word count %d\n", req->in.wct)); - exit_server(req->smb_conn, "Invalid SMB packet"); + smbsrv_terminate_connection(req->smb_conn, "Invalid SMB packet"); return; } if (NBT_HDR_SIZE + MIN_SMB_SIZE + 2*req->in.wct + req->in.data_size > req->in.size) { DEBUG(2,("Invalid SMB buffer length count %d\n", req->in.data_size)); - exit_server(req->smb_conn, "Invalid SMB packet"); + smbsrv_terminate_connection(req->smb_conn, "Invalid SMB packet"); return; } @@ -667,64 +667,26 @@ error: /* close the socket and shutdown a server_context */ -void server_terminate(struct smbsrv_connection *smb_conn) +void smbsrv_terminate_connection(struct smbsrv_connection *smb_conn, const char *reason) { - close(smb_conn->socket.fd); - event_remove_fd_all(smb_conn->events, smb_conn->socket.fd); - - conn_close_all(smb_conn); - - talloc_destroy(smb_conn->mem_ctx); + server_terminate_connection(smb_conn->connection, reason); } /* called on a fatal error that should cause this server to terminate */ -void exit_server(struct smbsrv_connection *smb_conn, const char *reason) -{ - smb_conn->model_ops->terminate_connection(smb_conn, reason); -} - -/* - setup a single listener of any type - */ -static void setup_listen(struct event_context *events, - const struct model_ops *model_ops, - void (*accept_handler)(struct event_context *,struct fd_event *,time_t,uint16_t), - struct in_addr *ifip, uint_t port) +static void smbsrv_exit(struct server_service *service, const char *reason) { - struct fd_event fde; - fde.fd = open_socket_in(SOCK_STREAM, port, 0, ifip->s_addr, True); - if (fde.fd == -1) { - DEBUG(0,("Failed to open socket on %s:%u - %s\n", - inet_ntoa(*ifip), port, strerror(errno))); - return; - } - - /* ready to listen */ - set_socket_options(fde.fd, "SO_KEEPALIVE"); - set_socket_options(fde.fd, lp_socket_options()); - - if (listen(fde.fd, SMBD_LISTEN_BACKLOG) == -1) { - DEBUG(0,("Failed to listen on %s:%d - %s\n", - inet_ntoa(*ifip), port, strerror(errno))); - close(fde.fd); - return; - } - - /* we are only interested in read events on the listen socket */ - fde.flags = EVENT_FD_READ; - fde.private = model_ops; - fde.handler = accept_handler; - - event_add_fd(events, &fde); + DEBUG(1,("smbsrv_exit\n")); + return; } /* add a socket address to the list of events, one event per port */ -static void add_socket(struct event_context *events, - const struct model_ops *model_ops, +static void add_socket(struct server_service *service, + const struct model_ops *model_ops, + struct socket_context *socket_ctx, struct in_addr *ifip) { char *ptr, *tok; @@ -733,18 +695,19 @@ static void add_socket(struct event_context *events, for (tok=strtok_r(lp_smb_ports(), delim, &ptr); tok; tok=strtok_r(NULL, delim, &ptr)) { - uint_t port = atoi(tok); + uint16_t port = atoi(tok); if (port == 0) continue; - setup_listen(events, model_ops, model_ops->accept_connection, ifip, port); + service_setup_socket(service, model_ops, socket_ctx, ifip, &port); } } /**************************************************************************** Open the socket communication. ****************************************************************************/ -void open_sockets_smbd(struct event_context *events, - const struct model_ops *model_ops) -{ +static void smbsrv_init(struct server_service *service, const struct model_ops *model_ops) +{ + DEBUG(1,("smbsrv_init\n")); + if (lp_interfaces() && lp_bind_interfaces_only()) { int num_interfaces = iface_count(); int i; @@ -761,33 +724,37 @@ void open_sockets_smbd(struct event_context *events, continue; } - add_socket(events, model_ops, ifip); + add_socket(service, model_ops, NULL, ifip); } } else { + struct in_addr *ifip; TALLOC_CTX *mem_ctx = talloc_init("open_sockets_smbd"); - - struct in_addr *ifip = interpret_addr2(mem_ctx, lp_socket_address()); - /* Just bind to lp_socket_address() (usually 0.0.0.0) */ + if (!mem_ctx) { smb_panic("No memory"); - } - add_socket(events, model_ops, ifip); + } + + /* Just bind to lp_socket_address() (usually 0.0.0.0) */ + ifip = interpret_addr2(mem_ctx, lp_socket_address()); + add_socket(service, model_ops, NULL, ifip); + talloc_destroy(mem_ctx); - } + } } /* called when a SMB socket becomes readable */ -void smbd_read_handler(struct event_context *ev, struct fd_event *fde, - time_t t, uint16_t flags) +static void smbsrv_recv(struct server_connection *conn, time_t t, uint16_t flags) { struct smbsrv_request *req; - struct smbsrv_connection *smb_conn = fde->private; - + struct smbsrv_connection *smb_conn = conn->private_data; + + DEBUG(10,("smbsrv_recv\n")); + req = receive_smb_request(smb_conn); if (!req) { - smb_conn->model_ops->terminate_connection(smb_conn, "receive error"); + smbsrv_terminate_connection(smb_conn, "receive error"); return; } @@ -795,8 +762,44 @@ void smbd_read_handler(struct event_context *ev, struct fd_event *fde, /* free up temporary memory */ lp_talloc_free(); + return; +} + +/* + called when a SMB socket becomes writable +*/ +static void smbsrv_send(struct server_connection *conn, time_t t, uint16_t flags) +{ + DEBUG(10,("smbsrv_send\n")); + return; +} + +/* + called when connection is idle +*/ +static void smbsrv_idle(struct server_connection *conn, time_t t) +{ + DEBUG(10,("smbsrv_idle: not implemented!\n")); + conn->event.idle->next_event = t + 5; + + return; } +static void smbsrv_close(struct server_connection *conn, const char *reason) +{ + struct smbsrv_connection *smb_conn = conn->private_data; + + DEBUG(5,("smbsrv_close: %s\n",reason)); + + close(conn->event.fde->fd); + event_remove_fd_all(conn->event.ctx, conn->socket->fde->fd); + event_remove_timed(conn->event.ctx, conn->event.idle); + + conn_close_all(smb_conn); + + talloc_destroy(smb_conn->mem_ctx); + return; +} /* process a message from an SMB socket while still processing a @@ -810,7 +813,7 @@ void smbd_process_async(struct smbsrv_connection *smb_conn) req = receive_smb_request(smb_conn); if (!req) { - smb_conn->model_ops->terminate_connection(smb_conn, "receive error"); + smbsrv_terminate_connection(smb_conn, "receive error"); return; } @@ -822,18 +825,15 @@ void smbd_process_async(struct smbsrv_connection *smb_conn) initialise a server_context from a open socket and register a event handler for reading from that socket */ -void init_smbsession(struct event_context *ev, struct model_ops *model_ops, int fd, - void (*read_handler)(struct event_context *, struct fd_event *, time_t, uint16_t)) +void smbsrv_accept(struct server_connection *conn) { struct smbsrv_connection *smb_conn; TALLOC_CTX *mem_ctx; - struct fd_event fde; char *socket_addr; - set_socket_options(fd,"SO_KEEPALIVE"); - set_socket_options(fd, lp_socket_options()); + DEBUG(5,("smbsrv_accept\n")); - mem_ctx = talloc_init("server_context"); + mem_ctx = talloc_init("smbsrv_context"); smb_conn = talloc_p(mem_ctx, struct smbsrv_connection); if (!smb_conn) return; @@ -841,16 +841,14 @@ void init_smbsession(struct event_context *ev, struct model_ops *model_ops, int ZERO_STRUCTP(smb_conn); smb_conn->mem_ctx = mem_ctx; - smb_conn->socket.fd = fd; smb_conn->pid = getpid(); sub_set_context(&smb_conn->substitute); /* set an initial client name based on its IP address. This will be replaced with the netbios name later if it gives us one */ - socket_addr = get_socket_addr(smb_conn->mem_ctx, fd); + socket_addr = get_socket_addr(smb_conn->mem_ctx, conn->socket->fde->fd); sub_set_remote_machine(socket_addr); - smb_conn->socket.client_addr = socket_addr; /* now initialise a few default values associated with this smb socket */ smb_conn->negotiate.max_send = 0xFFFF; @@ -862,21 +860,36 @@ void init_smbsession(struct event_context *ev, struct model_ops *model_ops, int smb_conn->negotiate.zone_offset = get_time_zone(time(NULL)); smb_conn->users.next_vuid = VUID_OFFSET; - - smb_conn->events = ev; - smb_conn->model_ops = model_ops; conn_init(smb_conn); - /* setup a event handler for this socket. We are initially - only interested in reading from the socket */ - fde.fd = fd; - fde.handler = read_handler; - fde.private = smb_conn; - fde.flags = EVENT_FD_READ; + smb_conn->connection = conn; - event_add_fd(ev, &fde); + conn->private_data = smb_conn; /* setup the DCERPC server subsystem */ dcesrv_init_context(&smb_conn->dcesrv); + + return; +} + +static const struct server_service_ops smb_server_ops = { + .name = "smb", + .service_init = smbsrv_init, + .accept_connection = smbsrv_accept, + .recv_handler = smbsrv_recv, + .send_handler = smbsrv_send, + .idle_handler = smbsrv_idle, + .close_connection = smbsrv_close, + .service_exit = smbsrv_exit, +}; + +const struct server_service_ops *smbsrv_get_ops(void) +{ + return &smb_server_ops; +} + +NTSTATUS server_service_smb_init(void) +{ + return NT_STATUS_OK; } diff --git a/source4/smb_server/smb_server.h b/source4/smb_server/smb_server.h index 6dc40aee08..e7b0ecfb02 100644 --- a/source4/smb_server/smb_server.h +++ b/source4/smb_server/smb_server.h @@ -342,10 +342,8 @@ struct smbsrv_connection { struct dcesrv_context dcesrv; - const struct model_ops *model_ops; - - struct event_context *events; - /* the pid of the process handling this session */ pid_t pid; + + struct server_connection *connection; }; diff --git a/source4/smbd/config.m4 b/source4/smbd/config.m4 index dd7a707714..52ccb68aa8 100644 --- a/source4/smbd/config.m4 +++ b/source4/smbd/config.m4 @@ -1,9 +1,10 @@ dnl # server subsystem -SMB_MODULE_MK(server_smb,SERVER,STATIC,smbd/config.mk) -SMB_MODULE_MK(server_rpc,SERVER,STATIC,smbd/config.mk) -SMB_MODULE_MK(server_auth,SERVER,STATIC,smbd/config.mk) +SMB_MODULE_MK(server_service_auth,SERVER_SERVICE,STATIC,smbd/config.mk) +SMB_MODULE_MK(server_service_smb,SERVER_SERVICE,STATIC,smbd/config.mk) +SMB_MODULE_MK(server_service_rpc,SERVER_SERVICE,STATIC,smbd/config.mk) +SMB_SUBSYSTEM_MK(SERVER_SERVICE,smbd/config.mk) SMB_SUBSYSTEM_MK(SERVER,smbd/config.mk) SMB_BINARY_MK(smbd, smbd/config.mk) diff --git a/source4/smbd/config.mk b/source4/smbd/config.mk index cd0d80150b..f002341a26 100644 --- a/source4/smbd/config.mk +++ b/source4/smbd/config.mk @@ -1,39 +1,47 @@ # server subsystem ################################################ -# Start MODULE server_auth -[MODULE::server_auth] +# Start MODULE server_service_auth +[MODULE::server_service_auth] REQUIRED_SUBSYSTEMS = \ AUTH # End MODULE server_auth ################################################ ################################################ -# Start MODULE server_smb -[MODULE::server_smb] +# Start MODULE server_service_smb +[MODULE::server_service_smb] REQUIRED_SUBSYSTEMS = \ SMB # End MODULE server_smb ################################################ ################################################ -# Start MODULE server_rpc -[MODULE::server_rpc] +# Start MODULE server_service_rpc +[MODULE::server_service_rpc] REQUIRED_SUBSYSTEMS = \ DCERPC # End MODULE server_rpc ################################################ ####################### +# Start SUBSYSTEM SERVICE +[SUBSYSTEM::SERVER_SERVICE] +INIT_OBJ_FILES = \ + smbd/service.o +# End SUBSYSTEM SERVER +####################### + +####################### # Start SUBSYSTEM SERVER [SUBSYSTEM::SERVER] INIT_OBJ_FILES = \ smbd/server.o ADD_OBJ_FILES = \ - smbd/build_options.o \ smbd/rewrite.o REQUIRED_SUBSYSTEMS = \ - PROCESS_MODEL + PROCESS_MODEL \ + SERVER_SERVICE # End SUBSYSTEM SERVER ####################### diff --git a/source4/smbd/process_model.c b/source4/smbd/process_model.c index f981b36798..0bdb316317 100644 --- a/source4/smbd/process_model.c +++ b/source4/smbd/process_model.c @@ -24,8 +24,7 @@ /* setup the events for the chosen process model */ -void process_model_startup(struct event_context *events, - const char *model) +const struct model_ops *process_model_startup(const char *model) { const struct model_ops *ops; @@ -37,12 +36,7 @@ void process_model_startup(struct event_context *events, ops->model_startup(); - /* now setup the listening sockets, adding - event handlers to the events structure */ - open_sockets_smbd(events, ops); - - /* setup any sockets we need to listen on for RPC over TCP */ - open_sockets_rpc(events, ops); + return ops; } /* the list of currently registered process models */ diff --git a/source4/smbd/process_model.h b/source4/smbd/process_model.h index c4c3aa68df..376b9a8ef8 100644 --- a/source4/smbd/process_model.h +++ b/source4/smbd/process_model.h @@ -3,6 +3,7 @@ process model manager - main loop Copyright (C) Andrew Tridgell 1992-2003 Copyright (C) James J Myers 2003 <myersjj@samba.org> + 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 @@ -22,6 +23,8 @@ #ifndef SAMBA_PROCESS_MODEL_H #define SAMBA_PROCESS_MODEL_H +struct server_service_connection; + /* 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. @@ -40,19 +43,13 @@ struct model_ops { /* function to accept new connection */ void (*accept_connection)(struct event_context *, struct fd_event *, time_t, uint16_t); - - /* function to accept new rpc over tcp connection */ - void (*accept_rpc_connection)(struct event_context *, struct fd_event *, time_t, uint16_t); - + /* function to terminate a connection */ - void (*terminate_connection)(struct smbsrv_connection *smb, const char *reason); + void (*terminate_connection)(struct server_connection *srv_conn, const char *reason); - /* function to terminate a connection */ - void (*terminate_rpc_connection)(void *r, const char *reason); - /* function to exit server */ - void (*exit_server)(struct smbsrv_connection *smb, const char *reason); - + void (*exit_server)(struct server_context *srv_ctx, const char *reason); + /* returns process or thread id */ int (*get_id)(struct smbsrv_request *req); }; diff --git a/source4/smbd/process_single.c b/source4/smbd/process_single.c index 9c92d8569a..b65418cd01 100644 --- a/source4/smbd/process_single.c +++ b/source4/smbd/process_single.c @@ -3,6 +3,7 @@ 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 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 @@ -21,10 +22,11 @@ #include "includes.h" + /* called when the process model is selected */ -static void model_startup(void) +static void single_start_server(void) { smbd_process_init(); } @@ -32,67 +34,102 @@ static void model_startup(void) /* called when a listening socket becomes readable */ -static void accept_connection(struct event_context *ev, struct fd_event *fde, time_t t, uint16_t flags) +static void single_accept_connection(struct event_context *ev, struct fd_event *srv_fde, time_t t, uint16_t flags) { int accepted_fd; struct sockaddr addr; socklen_t in_addrlen = sizeof(addr); - struct model_ops *model_ops = fde->private; - + struct fd_event fde; + struct timed_event idle; + struct server_socket *server_socket = srv_fde->private; + struct server_connection *conn; + TALLOC_CTX *mem_ctx; + /* accept an incoming connection. */ - accepted_fd = accept(fde->fd,&addr,&in_addrlen); + accepted_fd = accept(srv_fde->fd,&addr,&in_addrlen); if (accepted_fd == -1) { DEBUG(0,("accept_connection_single: accept: %s\n", strerror(errno))); return; } - /* create a smb server context and add it to out event - handling */ - init_smbsession(ev, model_ops, accepted_fd, smbd_read_handler); + mem_ctx = talloc_init("server_service_connection"); + if (!mem_ctx) { + DEBUG(0,("talloc_init(server_service_connection) failed\n")); + return; + } - /* return to event handling */ -} + conn = talloc_p(mem_ctx, struct server_connection); + if (!conn) { + DEBUG(0,("talloc_p(mem_ctx, struct server_service_connection) failed\n")); + talloc_destroy(mem_ctx); + return; + } + ZERO_STRUCTP(conn); + conn->mem_ctx = mem_ctx; -/* - called when a rpc listening socket becomes readable -*/ -static void accept_rpc_connection(struct event_context *ev, struct fd_event *fde, time_t t, uint16_t flags) -{ - int accepted_fd; - struct sockaddr addr; - socklen_t in_addrlen = sizeof(addr); - - /* accept an incoming connection. */ - accepted_fd = accept(fde->fd,&addr,&in_addrlen); - if (accepted_fd == -1) { - DEBUG(0,("accept_connection_single: accept: %s\n", - strerror(errno))); + fde.private = conn; + fde.fd = accepted_fd; + fde.flags = EVENT_FD_READ; + fde.handler = server_io_handler; + + idle.private = conn; + idle.next_event = t + 300; + idle.handler = server_idle_handler; + + conn->event.ctx = ev; + conn->event.fde = &fde; + conn->event.idle = &idle; + conn->event.idle_time = 300; + + conn->server_socket = server_socket; + conn->service = server_socket->service; + + /* TODO: we need a generic socket subsystem */ + conn->socket = talloc_p(conn->mem_ctx, struct socket_context); + if (!conn->socket) { + DEBUG(0,("talloc_p(conn->mem_ctx, struct socket_context) failed\n")); + talloc_destroy(mem_ctx); return; } + conn->socket->private_data = NULL; + conn->socket->ops = NULL; + conn->socket->client_addr = NULL; + conn->socket->pkt_count = 0; + conn->socket->fde = conn->event.fde; - init_rpc_session(ev, fde->private, accepted_fd); -} + /* create a smb server context and add it to out event + handling */ + server_socket->service->ops->accept_connection(conn); -/* called when a SMB connection goes down */ -static void terminate_connection(struct smbsrv_connection *server, const char *reason) -{ - server_terminate(server); + /* accpect_connection() of the service may changed idle.next_event */ + conn->event.fde = event_add_fd(ev,&fde); + conn->event.idle = event_add_timed(ev,&idle); + + conn->socket->fde = conn->event.fde; + + DLIST_ADD(server_socket->connection_list,conn); + + /* return to event handling */ + return; } -/* called when a rpc connection goes down */ -static void terminate_rpc_connection(void *r, const char *reason) + + +/* called when a SMB connection goes down */ +static void single_terminate_connection(struct server_connection *conn, const char *reason) { - rpc_server_terminate(r); + DEBUG(0,("single_terminate_connection: reason[%s]\n",reason)); + conn->service->ops->close_connection(conn,reason); } -static int get_id(struct smbsrv_request *req) +static int single_get_id(struct smbsrv_request *req) { return (int)req->smb_conn->pid; } -static void single_exit_server(struct smbsrv_connection *smb, const char *reason) +static void single_exit_server(struct server_context *srv_ctx, const char *reason) { DEBUG(1,("single_exit_server: reason[%s]\n",reason)); } @@ -111,13 +148,11 @@ NTSTATUS process_model_single_init(void) ops.name = "single"; /* fill in all the operations */ - ops.model_startup = model_startup; - ops.accept_connection = accept_connection; - ops.accept_rpc_connection = accept_rpc_connection; - ops.terminate_connection = terminate_connection; - ops.terminate_rpc_connection = terminate_rpc_connection; - ops.exit_server = single_exit_server; - ops.get_id = get_id; + ops.model_startup = single_start_server; + ops.accept_connection = single_accept_connection; + ops.terminate_connection = single_terminate_connection; + ops.exit_server = single_exit_server; + ops.get_id = single_get_id; /* register ourselves with the PROCESS_MODEL subsystem. */ ret = register_backend("process_model", &ops); diff --git a/source4/smbd/process_standard.c b/source4/smbd/process_standard.c index 2ee486e1d2..cc02e84d57 100644 --- a/source4/smbd/process_standard.c +++ b/source4/smbd/process_standard.c @@ -3,6 +3,7 @@ process model: standard (1 process per client connection) Copyright (C) Andrew Tridgell 1992-2003 Copyright (C) James J Myers 2003 <myersjj@samba.org> + 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 @@ -24,25 +25,31 @@ /* called when the process model is selected */ -static void model_startup(void) +static void standard_model_startup(void) { signal(SIGCHLD, SIG_IGN); + smbd_process_init(); } /* called when a listening socket becomes readable */ -static void accept_connection(struct event_context *ev, struct fd_event *fde, time_t t, uint16_t flags) +static void standard_accept_connection(struct event_context *ev, struct fd_event *srv_fde, time_t t, uint16_t flags) { int accepted_fd; struct sockaddr addr; socklen_t in_addrlen = sizeof(addr); pid_t pid; - struct model_ops *model_ops = fde->private; - - accepted_fd = accept(fde->fd,&addr,&in_addrlen); + struct fd_event fde; + struct timed_event idle; + struct server_socket *server_socket = srv_fde->private; + struct server_connection *conn; + TALLOC_CTX *mem_ctx; + + /* accept an incoming connection. */ + accepted_fd = accept(srv_fde->fd,&addr,&in_addrlen); if (accepted_fd == -1) { - DEBUG(0,("accept_connection_standard: accept: %s\n", + DEBUG(0,("standard_accept_connection: accept: %s\n", strerror(errno))); return; } @@ -60,82 +67,91 @@ static void accept_connection(struct event_context *ev, struct fd_event *fde, ti /* Child code ... */ /* close all the listening sockets */ - event_remove_fd_all_handler(ev, model_ops->accept_connection); - event_remove_fd_all_handler(ev, model_ops->accept_rpc_connection); + event_remove_fd_all_handler(ev, standard_accept_connection); /* tdb needs special fork handling */ if (tdb_reopen_all() == -1) { - DEBUG(0,("accept_connection_standard: tdb_reopen_all failed.\n")); + DEBUG(0,("standard_accept_connection: tdb_reopen_all failed.\n")); } - /* Load DSO's */ - init_modules(); - - /* initialize new process */ - smbd_process_init(); - - init_smbsession(ev, model_ops, accepted_fd, smbd_read_handler); - - /* return to the event loop */ -} - -/* - called when a rpc listening socket becomes readable -*/ -static void accept_rpc_connection(struct event_context *ev, struct fd_event *fde, time_t t, uint16_t flags) -{ - int accepted_fd; - struct sockaddr addr; - socklen_t in_addrlen = sizeof(addr); - pid_t pid; + mem_ctx = talloc_init("server_service_connection"); + if (!mem_ctx) { + DEBUG(0,("talloc_init(server_service_connection) failed\n")); + return; + } - accepted_fd = accept(fde->fd,&addr,&in_addrlen); - if (accepted_fd == -1) { - DEBUG(0,("accept_connection_standard: accept: %s\n", - strerror(errno))); + conn = talloc_p(mem_ctx, struct server_connection); + if (!conn) { + DEBUG(0,("talloc_p(mem_ctx, struct server_service_connection) failed\n")); + talloc_destroy(mem_ctx); return; } - pid = fork(); + ZERO_STRUCTP(conn); + conn->mem_ctx = mem_ctx; - if (pid != 0) { - /* parent or error code ... */ - close(accepted_fd); - /* go back to the event loop */ + fde.private = conn; + fde.fd = accepted_fd; + fde.flags = EVENT_FD_READ; + fde.handler = server_io_handler; + + idle.private = conn; + idle.next_event = t + 300; + idle.handler = server_idle_handler; + + + conn->event.ctx = ev; + conn->event.fde = &fde; + conn->event.idle = &idle; + conn->event.idle_time = 300; + + conn->server_socket = server_socket; + conn->service = server_socket->service; + + /* TODO: we need a generic socket subsystem */ + conn->socket = talloc_p(conn->mem_ctx, struct socket_context); + if (!conn->socket) { + DEBUG(0,("talloc_p(conn->mem_ctx, struct socket_context) failed\n")); + talloc_destroy(mem_ctx); return; } + conn->socket->private_data = NULL; + conn->socket->ops = NULL; + conn->socket->client_addr = NULL; + conn->socket->pkt_count = 0; + conn->socket->fde = conn->event.fde; - /* Child code ... */ + /* create a smb server context and add it to out event + handling */ + server_socket->service->ops->accept_connection(conn); - /* close all the listening sockets */ - event_remove_fd_all_handler(ev, accept_connection); - event_remove_fd_all_handler(ev, accept_rpc_connection); - - init_rpc_session(ev, fde->private, accepted_fd); -} + /* accpect_connection() of the service may changed idle.next_event */ + conn->event.fde = event_add_fd(ev,&fde); + conn->event.idle = event_add_timed(ev,&idle); -/* called when a SMB connection goes down */ -static void terminate_connection(struct smbsrv_connection *server, const char *reason) -{ - server_terminate(server); - /* terminate this process */ - exit(0); + conn->socket->fde = conn->event.fde; + + DLIST_ADD(server_socket->connection_list,conn); + + /* return to the event loop */ } -/* called when a rpc connection goes down */ -static void terminate_rpc_connection(void *r, const char *reason) + +/* called when a SMB connection goes down */ +static void standard_terminate_connection(struct server_connection *conn, const char *reason) { - rpc_server_terminate(r); + DEBUG(0,("single_terminate_connection: reason[%s]\n",reason)); + conn->service->ops->close_connection(conn,reason); /* terminate this process */ exit(0); } -static int get_id(struct smbsrv_request *req) +static int standard_get_id(struct smbsrv_request *req) { return (int)req->smb_conn->pid; } -static void standard_exit_server(struct smbsrv_connection *smb, const char *reason) +static void standard_exit_server(struct server_context *srv_ctx, const char *reason) { DEBUG(1,("standard_exit_server: reason[%s]\n",reason)); } @@ -154,13 +170,11 @@ NTSTATUS process_model_standard_init(void) ops.name = "standard"; /* fill in all the operations */ - ops.model_startup = model_startup; - ops.accept_connection = accept_connection; - ops.accept_rpc_connection = accept_rpc_connection; - ops.terminate_connection = terminate_connection; - ops.terminate_rpc_connection = terminate_rpc_connection; + ops.model_startup = standard_model_startup; + ops.accept_connection = standard_accept_connection; + ops.terminate_connection = standard_terminate_connection; ops.exit_server = standard_exit_server; - ops.get_id = get_id; + ops.get_id = standard_get_id; /* register ourselves with the PROCESS_MODEL subsystem. */ ret = register_backend("process_model", &ops); diff --git a/source4/smbd/process_thread.c b/source4/smbd/process_thread.c index f79f34e389..553e67feeb 100644 --- a/source4/smbd/process_thread.c +++ b/source4/smbd/process_thread.c @@ -3,6 +3,7 @@ thread model: standard (1 thread per client connection) Copyright (C) Andrew Tridgell 2003 Copyright (C) James J Myers 2003 <myersjj@samba.org> + 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 @@ -25,19 +26,19 @@ #include "execinfo.h" #endif -static void *connection_thread(void *thread_parm) +static void *thread_connection_fn(void *thread_parm) { struct event_context *ev = thread_parm; /* wait for action */ event_loop_wait(ev); - + #if 0 pthread_cleanup_pop(1); /* will invoke terminate_mt_connection() */ #endif return NULL; } -static int get_id(struct smbsrv_request *req) +static int thread_get_id(struct smbsrv_request *req) { return (int)pthread_self(); } @@ -45,21 +46,24 @@ static int get_id(struct smbsrv_request *req) /* called when a listening socket becomes readable */ -static void accept_connection(struct event_context *ev, struct fd_event *fde, +static void thread_accept_connection(struct event_context *ev, struct fd_event *srv_fde, time_t t, uint16_t flags) -{ +{ int accepted_fd, rc; struct sockaddr addr; socklen_t in_addrlen = sizeof(addr); pthread_t thread_id; pthread_attr_t thread_attr; - struct model_ops *model_ops = fde->private; - - /* accept an incoming connection */ - accepted_fd = accept(fde->fd,&addr,&in_addrlen); - + struct fd_event fde; + struct timed_event idle; + struct server_socket *server_socket = srv_fde->private; + struct server_connection *conn; + TALLOC_CTX *mem_ctx; + + /* accept an incoming connection. */ + accepted_fd = accept(srv_fde->fd,&addr,&in_addrlen); if (accepted_fd == -1) { - DEBUG(0,("accept_connection_thread: accept: %s\n", + DEBUG(0,("standard_accept_connection: accept: %s\n", strerror(errno))); return; } @@ -70,52 +74,80 @@ static void accept_connection(struct event_context *ev, struct fd_event *fde, with the main event loop, then return. When we return the main event_context is continued. */ + + ev = event_context_init(); - MUTEX_LOCK_BY_ID(MUTEX_SMBD); - init_smbsession(ev, model_ops, accepted_fd, smbd_read_handler); - MUTEX_UNLOCK_BY_ID(MUTEX_SMBD); - - pthread_attr_init(&thread_attr); - pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED); - rc = pthread_create(&thread_id, &thread_attr, &connection_thread, ev); - 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, accepted_fd)); - } else { - DEBUG(0,("accept_connection_thread: thread create failed for fd=%d, rc=%d\n", accepted_fd, rc)); + if (!ev) { + DEBUG(0,("thread_accept_connection: failed to create event_context!\n")); + return; } -} + mem_ctx = talloc_init("server_service_connection"); + if (!mem_ctx) { + DEBUG(0,("talloc_init(server_service_connection) failed\n")); + return; + } -/* - called when a rpc listening socket becomes readable -*/ -static void accept_rpc_connection(struct event_context *ev, struct fd_event *fde, time_t t, uint16_t flags) -{ - int accepted_fd, rc; - struct sockaddr addr; - socklen_t in_addrlen = sizeof(addr); - pthread_t thread_id; - pthread_attr_t thread_attr; - - /* accept an incoming connection */ - accepted_fd = accept(fde->fd,&addr,&in_addrlen); - - if (accepted_fd == -1) { - DEBUG(0,("accept_connection_thread: accept: %s\n", - strerror(errno))); + conn = talloc_p(mem_ctx, struct server_connection); + if (!conn) { + DEBUG(0,("talloc_p(mem_ctx, struct server_service_connection) failed\n")); + talloc_destroy(mem_ctx); return; } - - ev = event_context_init(); + + ZERO_STRUCTP(conn); + conn->mem_ctx = mem_ctx; + + fde.private = conn; + fde.fd = accepted_fd; + fde.flags = EVENT_FD_READ; + fde.handler = server_io_handler; + + idle.private = conn; + idle.next_event = t + 300; + idle.handler = server_idle_handler; + + conn->event.ctx = ev; + conn->event.fde = &fde; + conn->event.idle = &idle; + conn->event.idle_time = 300; + + conn->server_socket = server_socket; + conn->service = server_socket->service; + + /* TODO: we need a generic socket subsystem */ + conn->socket = talloc_p(conn->mem_ctx, struct socket_context); + if (!conn->socket) { + DEBUG(0,("talloc_p(conn->mem_ctx, struct socket_context) failed\n")); + talloc_destroy(mem_ctx); + return; + } + conn->socket->private_data = NULL; + conn->socket->ops = NULL; + conn->socket->client_addr = NULL; + conn->socket->pkt_count = 0; + conn->socket->fde = conn->event.fde; + + /* create a smb server context and add it to out event + handling */ + server_socket->service->ops->accept_connection(conn); + + /* accpect_connection() of the service may changed idle.next_event */ + conn->event.fde = event_add_fd(ev,&fde); + conn->event.idle = event_add_timed(ev,&idle); + + conn->socket->fde = conn->event.fde; + + /* TODO: is this MUTEX_LOCK in the right place here? + * --metze + */ MUTEX_LOCK_BY_ID(MUTEX_SMBD); - init_rpc_session(ev, fde->private, accepted_fd); + DLIST_ADD(server_socket->connection_list,conn); MUTEX_UNLOCK_BY_ID(MUTEX_SMBD); pthread_attr_init(&thread_attr); pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_DETACHED); - rc = pthread_create(&thread_id, &thread_attr, &connection_thread, ev); + rc = pthread_create(&thread_id, &thread_attr, thread_connection_fn, ev); pthread_attr_destroy(&thread_attr); if (rc == 0) { DEBUG(4,("accept_connection_thread: created thread_id=%lu for fd=%d\n", @@ -126,19 +158,10 @@ static void accept_rpc_connection(struct event_context *ev, struct fd_event *fde } /* called when a SMB connection goes down */ -static void terminate_connection(struct smbsrv_connection *server, const char *reason) +static void thread_terminate_connection(struct server_connection *conn, const char *reason) { - server_terminate(server); - - /* terminate this thread */ - pthread_exit(NULL); /* thread cleanup routine will do actual cleanup */ -} - -/* called when a rpc connection goes down */ -static void terminate_rpc_connection(void *r, const char *reason) -{ - rpc_server_terminate(r); - + DEBUG(0,("thread_terminate_connection: reason[%s]\n",reason)); + conn->service->ops->close_connection(conn,reason); /* terminate this thread */ pthread_exit(NULL); /* thread cleanup routine will do actual cleanup */ } @@ -431,7 +454,7 @@ static void thread_fault_handler(int sig) /* called when the process model is selected */ -static void model_startup(void) +static void thread_model_startup(void) { struct mutex_ops m_ops; struct debug_ops d_ops; @@ -465,7 +488,7 @@ static void model_startup(void) register_debug_handlers("thread", &d_ops); } -static void thread_exit_server(struct smbsrv_connection *smb, const char *reason) +static void thread_exit_server(struct server_context *srv_ctx, const char *reason) { DEBUG(1,("thread_exit_server: reason[%s]\n",reason)); } @@ -484,13 +507,11 @@ NTSTATUS process_model_thread_init(void) ops.name = "thread"; /* fill in all the operations */ - ops.model_startup = model_startup; - ops.accept_connection = accept_connection; - ops.accept_rpc_connection = accept_rpc_connection; - ops.terminate_connection = terminate_connection; - ops.terminate_rpc_connection = terminate_rpc_connection; + ops.model_startup = thread_model_startup; + ops.accept_connection = thread_accept_connection; + ops.terminate_connection = thread_terminate_connection; ops.exit_server = thread_exit_server; - ops.get_id = get_id; + ops.get_id = thread_get_id; /* register ourselves with the PROCESS_MODEL subsystem. */ ret = register_backend("process_model", &ops); diff --git a/source4/smbd/rewrite.c b/source4/smbd/rewrite.c index 5bc826bf71..d0a4bad374 100644 --- a/source4/smbd/rewrite.c +++ b/source4/smbd/rewrite.c @@ -79,6 +79,10 @@ void init_subsystems(void) if (!process_model_init()) exit(1); + /* Setup the SERVER_SERVICE subsystem */ + if (!server_service_init()) + exit(1); + /* Setup the AUTH subsystem */ if (!auth_init()) exit(1); @@ -88,7 +92,7 @@ void init_subsystems(void) exit(1); /* Setup the DCERPC subsystem */ - if (!dcesrv_init()) + if (!subsystem_dcerpc_init()) exit(1); } diff --git a/source4/smbd/server.c b/source4/smbd/server.c index 3a579b846a..e748795177 100644 --- a/source4/smbd/server.c +++ b/source4/smbd/server.c @@ -23,10 +23,16 @@ #include "includes.h" +static void exit_server(const char *reason) +{ + DEBUG(3,("Server exit (%s)\n", (reason ? reason : ""))); + exit(0); +} + /**************************************************************************** - main program. + main server. ****************************************************************************/ - int main(int argc,const char *argv[]) +static int binary_smbd_main(int argc,const char *argv[]) { BOOL is_daemon = False; BOOL interactive = False; @@ -34,7 +40,7 @@ BOOL log_stdout = False; int opt; poptContext pc; - struct event_context *events; + struct server_context *srv_ctx; const char *model = "standard"; struct poptOption long_options[] = { POPT_AUTOHELP @@ -42,7 +48,6 @@ {"interactive", 'i', POPT_ARG_VAL, &interactive, True, "Run interactive (not a daemon)"}, {"foreground", 'F', POPT_ARG_VAL, &Fork, False, "Run daemon in foreground (for daemontools & etc)" }, {"log-stdout", 'S', POPT_ARG_VAL, &log_stdout, True, "Log to stdout" }, - {"build-options", 'b', POPT_ARG_NONE, NULL, 'b', "Print build options" }, {"port", 'p', POPT_ARG_STRING, NULL, 0, "Listen on the specified ports"}, {"model", 'M', POPT_ARG_STRING, &model, 0, "select process model"}, POPT_COMMON_SAMBA @@ -53,11 +58,6 @@ while((opt = poptGetNextOpt(pc)) != -1) { switch (opt) { - case 'b': - /* Display output to screen as well as debug */ - build_options(True); - exit(0); - break; case 'p': lp_set_cmdline("smb ports", poptGetOptArg(pc)); break; @@ -65,8 +65,6 @@ } poptFreeContext(pc); - events = event_context_init(); - load_case_tables(); if (interactive) { @@ -110,15 +108,11 @@ DEBUG(0,("smbd version %s started.\n", SAMBA_VERSION_STRING)); DEBUGADD(0,("Copyright Andrew Tridgell and the Samba Team 1992-2004\n")); - /* Output the build options to the debug log */ - build_options(False); - - if (sizeof(uint16_t) < 2 || sizeof(uint32_t) < 4) { + if (sizeof(uint16_t) < 2 || sizeof(uint32_t) < 4 || sizeof(uint64_t) < 8) { DEBUG(0,("ERROR: Samba is not configured correctly for the word size on your machine\n")); exit(1); } - DEBUG(0,("Using %s process model\n", model)); - + if (!reload_services(NULL, False)) return(-1); @@ -149,8 +143,18 @@ init_subsystems(); - process_model_startup(events, model); + DEBUG(0,("Using %s process model\n", model)); + srv_ctx = server_service_startup(model); + if (!srv_ctx) { + DEBUG(0,("Starting Services failed.\n")); + return 1; + } /* wait for events */ - return event_loop_wait(events); + return event_loop_wait(srv_ctx->events); +} + + int main(int argc, const char *argv[]) +{ + return binary_smbd_main(argc, argv); } diff --git a/source4/smbd/server.h b/source4/smbd/server.h new file mode 100644 index 0000000000..c47cf02d8a --- /dev/null +++ b/source4/smbd/server.h @@ -0,0 +1,40 @@ +/* + 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 { + TALLOC_CTX *mem_ctx; + struct server_service *service_list; + struct event_context *events; +}; + +/* 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 + +#endif /* _SERVER_H */ diff --git a/source4/smbd/service.c b/source4/smbd/service.c new file mode 100644 index 0000000000..2b6e0579fa --- /dev/null +++ b/source4/smbd/service.c @@ -0,0 +1,241 @@ +/* + Unix SMB/CIFS implementation. + + SERVER SERVICE code + + Copyright (C) Andrew Tridgell 2003 + 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. +*/ + +#include "includes.h" + +struct server_context *server_service_startup(const char *model) +{ + int i; + const char **server_services = lp_server_services(); + TALLOC_CTX *mem_ctx; + struct server_context *srv_ctx; + const struct model_ops *model_ops; + + if (!server_services) { + DEBUG(0,("process_model_startup: no endpoint servers configured\n")); + return NULL; + } + + model_ops = process_model_startup(model); + if (!model_ops) { + DEBUG(0,("process_model_startup('%s') failed\n", model)); + return NULL; + } + + mem_ctx = talloc_init("server_context"); + if (!mem_ctx) { + DEBUG(0,("talloc_init(server_context) failed\n")); + return NULL; + } + + srv_ctx = talloc_p(mem_ctx, struct server_context); + if (!srv_ctx) { + DEBUG(0,("talloc_p(mem_ctx, struct server_context) failed\n")); + return NULL; + } + + ZERO_STRUCTP(srv_ctx); + srv_ctx->mem_ctx = mem_ctx; + + srv_ctx->events = event_context_init(); + if (!srv_ctx->events) { + DEBUG(0,("event_context_init() failed\n")); + return NULL; + } + + + for (i=0;server_services[i];i++) { + TALLOC_CTX *mem_ctx2; + 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; + } + + mem_ctx2 = talloc_init("server_service"); + + service = talloc_p(mem_ctx2, struct server_service); + if (!service) { + DEBUG(0,("talloc_p(mem_ctx, struct server_service) failed\n")); + return NULL; + } + + ZERO_STRUCTP(service); + service->mem_ctx = mem_ctx2; + service->ops = service_ops; + service->model_ops = model_ops; + service->srv_ctx = srv_ctx; + + /* TODO: service_init() should return a result */ + service->ops->service_init(service, model_ops); + } + + return srv_ctx; +} + +/* + setup a single listener of any type + if you pass *port == 0, then a port < 1024 is used + */ +struct server_socket *service_setup_socket(struct server_service *service, + const struct model_ops *model_ops, + struct socket_context *socket_ctx, + struct in_addr *ifip, uint16_t *port) +{ + TALLOC_CTX *mem_ctx; + struct server_socket *sock; + struct fd_event fde; + int i; + + mem_ctx = talloc_init("struct server_socket"); + + sock = talloc_p(mem_ctx, struct server_socket); + if (!sock) { + DEBUG(0,("talloc_p(mem_ctx, struct server_socket) failed\n")); + return NULL; + } + + if (*port == 0) { + fde.fd = -1; + for (i=SERVER_TCP_LOW_PORT;i<= SERVER_TCP_HIGH_PORT;i++) { + fde.fd = open_socket_in(SOCK_STREAM, i, 0, ifip->s_addr, True); + if (fde.fd != -1) break; + } + if (fde.fd != -1) { + *port = i; + } + } else { + fde.fd = open_socket_in(SOCK_STREAM, *port, 0, ifip->s_addr, True); + } + + if (fde.fd == -1) { + DEBUG(0,("Failed to open socket on %s:%u - %s\n", + inet_ntoa(*ifip), *port, strerror(errno))); + return NULL; + } + + /* ready to listen */ + set_socket_options(fde.fd, "SO_KEEPALIVE"); + set_socket_options(fde.fd, lp_socket_options()); + + if (listen(fde.fd, SERVER_LISTEN_BACKLOG) == -1) { + DEBUG(0,("Failed to listen on %s:%u - %s\n", + inet_ntoa(*ifip), *port, strerror(errno))); + close(fde.fd); + return NULL; + } + + /* we are only interested in read events on the listen socket */ + fde.flags = EVENT_FD_READ; + fde.private = sock; + fde.handler = model_ops->accept_connection; + + ZERO_STRUCTP(sock); + sock->mem_ctx = mem_ctx; + sock->service = service; + sock->socket = socket_ctx; + sock->event.ctx = service->srv_ctx->events; + sock->event.fde = event_add_fd(sock->event.ctx, &fde); + if (!sock->event.fde) { + DEBUG(0,("event_add_fd(sock->event.ctx, &fde) failed\n")); + return NULL; + } + + DLIST_ADD(service->socket_list, sock); + + return sock; +} + +/* + close the socket and shutdown a server_context +*/ +void server_terminate_connection(struct server_connection *srv_conn, const char *reason) +{ + DEBUG(0,("server_terminate_connection\n")); + srv_conn->service->model_ops->terminate_connection(srv_conn, reason); +} + +void server_io_handler(struct event_context *ev, struct fd_event *fde, time_t t, uint16_t flags) +{ + struct server_connection *conn = fde->private; + + if (flags & EVENT_FD_WRITE) { + conn->service->ops->send_handler(conn, t, flags); + conn->event.idle->next_event = t + conn->event.idle_time; + } + + if (flags & EVENT_FD_READ) { + conn->service->ops->recv_handler(conn, t, flags); + conn->event.idle->next_event = t + conn->event.idle_time; + } + +} + +void server_idle_handler(struct event_context *ev, struct timed_event *idle, time_t t) +{ + struct server_connection *conn = idle->private; + + conn->event.idle->next_event = t + conn->event.idle_time; + + conn->service->ops->idle_handler(conn,t); +} +/* + return the operations structure for a named backend of the specified type +*/ +const struct server_service_ops *server_service_byname(const char *name) +{ + if (strcmp("smb",name)==0) { + return smbsrv_get_ops(); + } + if (strcmp("rpc",name)==0) { + return dcesrv_get_ops(); + } + return NULL; +} + +static NTSTATUS register_server_service_ops(const void *_ops) +{ + return NT_STATUS_NOT_IMPLEMENTED; +} + +/* + initialise the SERVER SERVICE subsystem +*/ +BOOL server_service_init(void) +{ + NTSTATUS status; + + status = register_subsystem("service", register_server_service_ops); + if (!NT_STATUS_IS_OK(status)) { + return False; + } + + /* FIXME: Perhaps panic if a basic endpoint server, such as EPMAPER, fails to initialise? */ + static_init_server_service; + + DEBUG(3,("SERVER SERVICE subsystem version %d initialised\n", SERVER_SERVICE_VERSION)); + return True; +} diff --git a/source4/smbd/service.h b/source4/smbd/service.h new file mode 100644 index 0000000000..41ad381f9e --- /dev/null +++ b/source4/smbd/service.h @@ -0,0 +1,127 @@ +/* + 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, const struct model_ops *ops); + + /* function to accept new connection */ + void (*accept_connection)(struct server_connection *); + + /* function to accept new connection */ + void (*recv_handler)(struct server_connection *, time_t, uint16_t); + + /* function to accept new connection */ + void (*send_handler)(struct server_connection *, time_t, uint16_t); + + /* function to accept new connection */ + void (*idle_handler)(struct server_connection *, time_t); + + /* function to close a connection */ + void (*close_connection)(struct server_connection *, const char *reason); + + /* function to exit server */ + void (*service_exit)(struct server_service *srv_ctx, const char *reason); +}; + +struct socket_ops { + int dummy; +}; + +struct socket_context { + void *private_data; + struct socket_ops *ops; + const char *client_addr; + uint_t pkt_count; + struct fd_event *fde; +}; + +struct server_socket { + struct server_socket *next,*prev; + TALLOC_CTX *mem_ctx; + void *private_data; + + struct { + struct event_context *ctx; + struct fd_event *fde; + } event; + + struct socket_context *socket; + + struct server_service *service; + + struct server_connection *connection_list; +}; + +struct server_service { + struct server_service *next,*prev; + TALLOC_CTX *mem_ctx; + void *private_data; + const struct server_service_ops *ops; + + const struct model_ops *model_ops; + + struct server_socket *socket_list; + + struct server_context *srv_ctx; +}; + +struct server_connection { + struct server_connection *next,*prev; + TALLOC_CTX *mem_ctx; + void *private_data; + + struct { + struct event_context *ctx; + struct fd_event *fde; + struct timed_event *idle; + time_t idle_time; + } event; + + struct socket_context *socket; + + struct server_socket *server_socket; + + struct server_service *service; +}; + +#endif /* _SERVER_SERVICE_H */ |