<programlisting>
<smbconfsection name="[global]"/>
- <smbconfoption name="rpc_daemon:fssd">fork</smbconfoption>
<smbconfoption name="registry shares">yes</smbconfoption>
<smbconfoption name="include">registry</smbconfoption>
<programlisting>
<smbconfsection name="[global]"/>
- <smbconfoption name="rpc_daemon:fssd">fork</smbconfoption>
<smbconfoption name="registry shares">yes</smbconfoption>
<smbconfoption name="include">registry</smbconfoption>
</programlisting>
<programlisting>
<smbconfsection name="[global]"/>
- <smbconfoption name="rpc_daemon:fssd">fork</smbconfoption>
<smbconfoption name="registry shares">yes</smbconfoption>
<smbconfoption name="include">registry</smbconfoption>
</programlisting>
+++ /dev/null
-<samba:parameter name="rpc_daemon:DAEMON"
- context="G"
- type="string"
- xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
-<description>
- <para>
- Defines whether to use the embedded code or start a separate daemon
- for the defined rpc services.
- The rpc_daemon prefix must be followed by the server name, and a value.
- </para>
-
- <para>
- Two possible values are currently supported:
- <programlisting>
- disabled
- fork
- </programlisting>
- </para>
-
- <para>
- The classic method is to run rpc services as internal daemons
- embedded in smbd, therefore the external daemons are
- <emphasis>disabled</emphasis> by default.
- </para>
-
- <para>
- Choosing the <emphasis>fork</emphasis> option will cause samba to fork
- a separate process for each daemon configured this way. Each daemon may
- in turn fork a number of children used to handle requests from multiple
- smbds and direct tcp/ip connections (if the Endpoint Mapper is
- enabled). Communication with smbd happens over named pipes and require
- that said pipes are forward to the external daemon (see <smbconfoption
- name="rpc_server"/>).
- </para>
-
- <para>
- Forked RPC Daemons support dynamically forking children to handle
- connections. The heuristics about how many children to keep around and
- how fast to allow them to fork and also how many clients each child is
- allowed to handle concurrently is defined by parametrical options named
- after the daemon.
- Five options are currently supported:
- <programlisting>
- prefork_min_children
- prefork_max_children
- prefork_spawn_rate
- prefork_max_allowed_clients
- prefork_child_min_life
- </programlisting>
-
- To set one of these options use the following syntax:
- <programlisting>
- daemonname:prefork_min_children = 5
- </programlisting>
- </para>
-
- <para>
- Samba includes separate daemons for spoolss, lsarpc/lsass,
- netlogon, samr, FSRVP and mdssvc(Spotlight). Currently five
- daemons are available and they are called:
- <programlisting>
- epmd
- lsasd
- spoolssd
- fssd
- mdssd
- </programlisting>
- Example:
- <programlisting>
- rpc_daemon:spoolssd = fork
- </programlisting>
- </para>
-</description>
-
-<value type="default">disabled</value>
-</samba:parameter>
+++ /dev/null
-<samba:parameter name="rpc_server:SERVER"
- context="G"
- type="string"
- xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
-<description>
- <para>
- With this option you can define if a rpc service should be
- running internal/embedded in smbd or should be redirected to an
- external daemon like Samba4, the endpoint mapper daemon, the
- spoolss daemon or the new LSA service daemon. The rpc_server
- prefix must be followed by the pipe name, and a value.
- </para>
-
- <para>
- This option can be set for each available rpc service in Samba.
- The following list shows all available pipe names services you
- can modify with this option.
- </para>
-
- <itemizedlist>
- <listitem><para>epmapper - Endpoint Mapper</para></listitem>
- <listitem><para>winreg - Remote Registry Service</para></listitem>
- <listitem><para>srvsvc - Remote Server Services</para></listitem>
- <listitem><para>lsarpc - Local Security Authority</para></listitem>
- <listitem><para>samr - Security Account Management</para></listitem>
- <listitem><para>netlogon - Netlogon Remote Protocol</para></listitem>
- <listitem><para>netdfs - Settings for Distributed File System</para></listitem>
- <listitem><para>dssetup - Active Directory Setup</para></listitem>
- <listitem><para>wkssvc - Workstation Services</para></listitem>
- <listitem><para>spoolss - Network Printing Spooler</para></listitem>
- <listitem><para>svcctl - Service Control</para></listitem>
- <listitem><para>ntsvcs - Plug and Play Services</para></listitem>
- <listitem><para>eventlog - Event Logger</para></listitem>
- <listitem><para>initshutdown - Init Shutdown Service</para></listitem>
- <listitem><para>mdssvc - Spotlight</para></listitem>
- </itemizedlist>
-
- <para>
- Three possible values currently supported are:
- <command moreinfo="none">embedded</command>
- <command moreinfo="none">external</command>
- <command moreinfo="none">disabled</command>
- </para>
-
- <para>
- The classic method is to run every pipe as an internal function
- <emphasis>embedded</emphasis> in smbd. The defaults may vary
- depending on the service.
- </para>
-
- <para>
- Choosing the <emphasis>external</emphasis> option allows one to run
- a separate daemon or even a completely independent (3rd party)
- server capable of interfacing with samba via the MS-RPC
- interface over named pipes.
- </para>
-
- <para>
- Currently in Samba3 we support four daemons, spoolssd, epmd,
- lsasd and mdssd. These daemons can be enabled using the
- <emphasis>rpc_daemon</emphasis> option. For spoolssd you have
- to enable the daemon and proxy the named pipe with:
- </para>
-
- <para>
- Examples:
- <programlisting>
- rpc_daemon:lsasd = fork
- rpc_server:lsarpc = external
- rpc_server:samr = external
- rpc_server:netlogon = external
-
- rpc_server:spoolss = external
- rpc_server:epmapper = disabled
-
- rpc_daemon:mdssd = fork
- rpc_server:mdssvc = external
- </programlisting>
- </para>
-
- <para>
- There is one special option which allows you to enable rpc
- services to listen for ncacn_ip_tcp connections too. Currently
- this is only used for testing and doesn't scale!
-
- <programlisting>
- rpc_server:tcpip = yes
- </programlisting>
- </para>
-
-</description>
-
-<value type="default">embedded</value>
-</samba:parameter>
Samba must be configured and built with Spotlight support.
</para></listitem>
- <listitem><para>
- The <emphasis>mdssvc</emphasis> RPC service must be
- enabled, see below.
- </para></listitem>
-
<listitem><para> Tracker integration must be setup and the
share must be indexed by Tracker.</para></listitem>
</itemizedlist>
url="https://wiki.samba.org/index.php/Spotlight">https://wiki.samba.org/index.php/Spotlight</ulink>.
</para>
- <para>
- The Spotlight RPC service can either be enabled as embedded
- RPC service:
- </para>
-
-<programlisting>
-<smbconfsection name="[Global]"/>
-<smbconfoption name="rpc_server:mdsvc">embedded</smbconfoption>
-</programlisting>
-
- <para>
- Or it can be run in a separate RPC service daemon:
- </para>
-
-<programlisting>
-<smbconfsection name="[Global]"/>
-<smbconfoption name="rpc_server:mdssd">fork</smbconfoption>
-<smbconfoption name="rpc_server:mdsvc">external</smbconfoption>
-</programlisting>
-
</description>
<value type="default">no</value>
</samba:parameter>
my $ip4 = Samba::get_ipv4_addr("FILESERVER");
my $fileserver_options = "
kernel change notify = yes
- rpc_server:mdssvc = embedded
spotlight backend = elasticsearch
elasticsearch:address = $ip4
elasticsearch:port = 8080
server signing = enabled
raw NTLMv2 auth = yes
-rpc_server:default = external
-rpc_server:svcctl = embedded
-rpc_server:srvsvc = embedded
-rpc_server:eventlog = embedded
-rpc_server:ntsvcs = embedded
-rpc_server:winreg = embedded
-rpc_server:spoolss = embedded
-rpc_daemon:spoolssd = embedded
-rpc_server:tcpip = no
# override the new SMB2 only default
client min protocol = CORE
server min protocol = LANMAN1
+++ /dev/null
-/*
- Unix SMB/CIFS implementation.
- Common server globals
-
- Copyright (C) Simo Sorce <idra@samba.org> 2011
-
- 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 3 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, see <http://www.gnu.org/licenses/>.
-*/
-
-#include "includes.h"
-#include "serverid.h"
-#include "messages.h"
-#include "system/time.h"
-#include "system/shmem.h"
-#include "system/filesys.h"
-#include "server_prefork.h"
-#include "../lib/util/samba_util.h"
-#include "../lib/util/tevent_unix.h"
-
-struct prefork_pool {
- int listen_fd_size;
- struct pf_listen_fd *listen_fds;
-
- prefork_main_fn_t *main_fn;
- void *private_data;
-
- int pool_size;
- struct pf_worker_data *pool;
-
- int allowed_clients;
-
- prefork_sigchld_fn_t *sigchld_fn;
- void *sigchld_data;
-};
-
-static bool prefork_setup_sigchld_handler(struct tevent_context *ev_ctx,
- struct prefork_pool *pfp);
-
-static int prefork_pool_destructor(struct prefork_pool *pfp)
-{
- anonymous_shared_free(pfp->pool);
- return 0;
-}
-
-bool prefork_create_pool(TALLOC_CTX *mem_ctx,
- struct tevent_context *ev_ctx,
- struct messaging_context *msg_ctx,
- int listen_fd_size, struct pf_listen_fd *listen_fds,
- int min_children, int max_children,
- prefork_main_fn_t *main_fn, void *private_data,
- struct prefork_pool **pf_pool)
-{
- struct prefork_pool *pfp = NULL;
- pid_t pid;
- time_t now = time(NULL);
- size_t data_size;
- int ret;
- int i;
- bool ok;
-
- pfp = talloc_zero(mem_ctx, struct prefork_pool);
- if (!pfp) {
- DEBUG(1, ("Out of memory!\n"));
- goto fail;
- }
- pfp->listen_fd_size = listen_fd_size;
- pfp->listen_fds = talloc_array(pfp, struct pf_listen_fd,
- listen_fd_size);
- if (!pfp->listen_fds) {
- DEBUG(1, ("Out of memory!\n"));
- goto fail;
- }
- for (i = 0; i < listen_fd_size; i++) {
- pfp->listen_fds[i] = listen_fds[i];
- /* force sockets in non-blocking mode */
- ret = set_blocking(listen_fds[i].fd, false);
- if (ret < 0) {
- DBG_WARNING("Failed to set sockets to non-blocking!\n");
- goto fail;
- }
- }
- pfp->main_fn = main_fn;
- pfp->private_data = private_data;
-
- pfp->pool_size = max_children;
- data_size = sizeof(struct pf_worker_data) * max_children;
-
- pfp->pool = (struct pf_worker_data *)anonymous_shared_allocate(
- data_size);
- if (pfp->pool == NULL) {
- DEBUG(1, ("Failed to mmap memory for prefork pool!\n"));
- goto fail;
- }
- talloc_set_destructor(pfp, prefork_pool_destructor);
-
- for (i = 0; i < min_children; i++) {
-
- pfp->pool[i].allowed_clients = 1;
- pfp->pool[i].started = now;
-
- pid = fork();
- switch (pid) {
- case -1:
- DEBUG(1, ("Failed to prefork child n. %d !\n", i));
- break;
-
- case 0: /* THE CHILD */
-
- pfp->pool[i].status = PF_WORKER_ALIVE;
- ret = pfp->main_fn(ev_ctx, msg_ctx,
- &pfp->pool[i], i + 1,
- pfp->listen_fd_size,
- pfp->listen_fds,
- pfp->private_data);
- exit(ret);
-
- default: /* THE PARENT */
- pfp->pool[i].pid = pid;
- break;
- }
- }
-
- ok = prefork_setup_sigchld_handler(ev_ctx, pfp);
- if (!ok) {
- DEBUG(1, ("Failed to setup SIGCHLD Handler!\n"));
- goto fail;
- }
-
- *pf_pool = pfp;
- return true;
-fail:
- TALLOC_FREE(pfp);
- return false;
-}
-
-/* Provide the new max children number in new_max
- * (must be larger than current max).
- * Returns: 0 if all fine
- * ENOSPC if mremap fails to expand
- * EINVAL if new_max is invalid
- */
-int prefork_expand_pool(struct prefork_pool *pfp, int new_max)
-{
- struct prefork_pool *pool = NULL;
- size_t old_size;
- size_t new_size;
- int ret;
-
- if (new_max <= pfp->pool_size) {
- return EINVAL;
- }
-
- old_size = sizeof(struct pf_worker_data) * pfp->pool_size;
- new_size = sizeof(struct pf_worker_data) * new_max;
-
- pool = (struct prefork_pool *)anonymous_shared_resize(
- &pfp->pool, new_size, false);
- if (pool == NULL) {
- ret = errno;
- DEBUG(3, ("Failed to mremap memory (%d: %s)!\n",
- ret, strerror(ret)));
- return ret;
- }
-
- memset(&pool[pfp->pool_size], 0, new_size - old_size);
-
- pfp->pool_size = new_max;
-
- return 0;
-}
-
-int prefork_add_children(struct tevent_context *ev_ctx,
- struct messaging_context *msg_ctx,
- struct prefork_pool *pfp,
- int num_children)
-{
- pid_t pid;
- time_t now = time(NULL);
- int ret;
- int i, j;
-
- for (i = 0, j = 0; i < pfp->pool_size && j < num_children; i++) {
-
- if (pfp->pool[i].status != PF_WORKER_NONE) {
- continue;
- }
-
- pfp->pool[i].allowed_clients = 1;
- pfp->pool[i].started = now;
-
- pid = fork();
- switch (pid) {
- case -1:
- DEBUG(1, ("Failed to prefork child n. %d !\n", j));
- break;
-
- case 0: /* THE CHILD */
-
- pfp->pool[i].status = PF_WORKER_ALIVE;
- ret = pfp->main_fn(ev_ctx, msg_ctx,
- &pfp->pool[i], i + 1,
- pfp->listen_fd_size,
- pfp->listen_fds,
- pfp->private_data);
-
- pfp->pool[i].status = PF_WORKER_EXITING;
- exit(ret);
-
- default: /* THE PARENT */
- pfp->pool[i].pid = pid;
- j++;
- break;
- }
- }
-
- DEBUG(5, ("Added %d children!\n", j));
-
- return j;
-}
-
-struct prefork_oldest {
- int num;
- time_t started;
-};
-
-/* sort in inverse order */
-static int prefork_sort_oldest(const void *ap, const void *bp)
-{
- const struct prefork_oldest *a = (const struct prefork_oldest *)ap;
- const struct prefork_oldest *b = (const struct prefork_oldest *)bp;
-
- if (a->started == b->started) {
- return 0;
- }
- if (a->started < b->started) {
- return 1;
- }
- return -1;
-}
-
-int prefork_retire_children(struct messaging_context *msg_ctx,
- struct prefork_pool *pfp,
- int num_children, time_t age_limit)
-{
- const DATA_BLOB ping = data_blob_null;
- time_t now = time(NULL);
- struct prefork_oldest *oldest = NULL;
- int i, j;
-
- oldest = talloc_array(pfp, struct prefork_oldest, pfp->pool_size);
- if (!oldest) {
- return -1;
- }
-
- for (i = 0; i < pfp->pool_size; i++) {
- oldest[i].num = i;
- if (pfp->pool[i].status == PF_WORKER_ALIVE ||
- pfp->pool[i].status == PF_WORKER_ACCEPTING) {
- oldest[i].started = pfp->pool[i].started;
- } else {
- oldest[i].started = now;
- }
- }
-
- qsort(oldest, pfp->pool_size,
- sizeof(struct prefork_oldest),
- prefork_sort_oldest);
-
- for (i = 0, j = 0; i < pfp->pool_size && j < num_children; i++) {
- if (((pfp->pool[i].status == PF_WORKER_ALIVE) &&
- (pfp->pool[i].num_clients < 1)) &&
- (pfp->pool[i].started <= age_limit)) {
- /* tell the child it's time to give up */
- DEBUG(5, ("Retiring pid %u!\n", (unsigned int)pfp->pool[i].pid));
- pfp->pool[i].cmds = PF_SRV_MSG_EXIT;
- messaging_send(msg_ctx,
- pid_to_procid(pfp->pool[i].pid),
- MSG_PREFORK_PARENT_EVENT, &ping);
- j++;
- }
- }
-
- return j;
-}
-
-int prefork_count_children(struct prefork_pool *pfp, int *active)
-{
- int i, a, t;
-
- a = 0;
- t = 0;
- for (i = 0; i < pfp->pool_size; i++) {
- if (pfp->pool[i].status == PF_WORKER_NONE) {
- continue;
- }
-
- t++;
-
- if ((pfp->pool[i].status == PF_WORKER_EXITING) ||
- (pfp->pool[i].num_clients <= 0)) {
- continue;
- }
-
- a++;
- }
-
- if (active) {
- *active = a;
- }
- return t;
-}
-
-static void prefork_cleanup_loop(struct prefork_pool *pfp)
-{
- int status;
- pid_t pid;
- int i;
-
- /* TODO: should we use a process group id wait instead of looping ? */
- for (i = 0; i < pfp->pool_size; i++) {
- if (pfp->pool[i].status == PF_WORKER_NONE ||
- pfp->pool[i].pid == 0) {
- continue;
- }
-
- pid = waitpid(pfp->pool[i].pid, &status, WNOHANG);
- if (pid > 0) {
-
- if (pfp->pool[i].status != PF_WORKER_EXITING) {
- DEBUG(3, ("Child (%d) terminated abnormally:"
- " %d\n", (int)pid, status));
- } else {
- DEBUG(10, ("Child (%d) terminated with status:"
- " %d\n", (int)pid, status));
- }
-
- /* reset all fields,
- * this makes status = PF_WORK_NONE */
- memset(&pfp->pool[i], 0,
- sizeof(struct pf_worker_data));
- }
- }
-
-}
-
-int prefork_count_allowed_connections(struct prefork_pool *pfp)
-{
- int c;
- int i;
-
- c = 0;
- for (i = 0; i < pfp->pool_size; i++) {
- if (pfp->pool[i].status == PF_WORKER_NONE ||
- pfp->pool[i].status == PF_WORKER_EXITING) {
- continue;
- }
-
- if (pfp->pool[i].num_clients < 0) {
- continue;
- }
-
- c += pfp->pool[i].allowed_clients - pfp->pool[i].num_clients;
- }
-
- return c;
-}
-
-void prefork_increase_allowed_clients(struct prefork_pool *pfp, int max)
-{
- int i;
-
- for (i = 0; i < pfp->pool_size; i++) {
- if (pfp->pool[i].status == PF_WORKER_NONE ||
- pfp->pool[i].status == PF_WORKER_EXITING) {
- continue;
- }
-
- if (pfp->pool[i].num_clients < 0) {
- continue;
- }
-
- if (pfp->pool[i].allowed_clients < max) {
- pfp->pool[i].allowed_clients++;
- }
- }
-}
-
-void prefork_decrease_allowed_clients(struct prefork_pool *pfp)
-{
- int i;
-
- for (i = 0; i < pfp->pool_size; i++) {
- if (pfp->pool[i].status == PF_WORKER_NONE ||
- pfp->pool[i].status == PF_WORKER_EXITING) {
- continue;
- }
-
- if (pfp->pool[i].num_clients < 0) {
- continue;
- }
-
- if (pfp->pool[i].allowed_clients > 1) {
- pfp->pool[i].allowed_clients--;
- }
- }
-}
-
-void prefork_reset_allowed_clients(struct prefork_pool *pfp)
-{
- int i;
-
- for (i = 0; i < pfp->pool_size; i++) {
- pfp->pool[i].allowed_clients = 1;
- }
-}
-
-void prefork_send_signal_to_all(struct prefork_pool *pfp, int signal_num)
-{
- int i;
-
- for (i = 0; i < pfp->pool_size; i++) {
- if (pfp->pool[i].status == PF_WORKER_NONE) {
- continue;
- }
-
- kill(pfp->pool[i].pid, signal_num);
- }
-}
-
-void prefork_warn_active_children(struct messaging_context *msg_ctx,
- struct prefork_pool *pfp)
-{
- const DATA_BLOB ping = data_blob_null;
- int i;
-
- for (i = 0; i < pfp->pool_size; i++) {
- if (pfp->pool[i].status == PF_WORKER_NONE) {
- continue;
- }
-
- messaging_send(msg_ctx,
- pid_to_procid(pfp->pool[i].pid),
- MSG_PREFORK_PARENT_EVENT, &ping);
- }
-}
-
-static void prefork_sigchld_handler(struct tevent_context *ev_ctx,
- struct tevent_signal *se,
- int signum, int count,
- void *siginfo, void *pvt)
-{
- struct prefork_pool *pfp = talloc_get_type_abort(
- pvt, struct prefork_pool);
-
- /* run the cleanup function to make sure all dead children are
- * properly and timely retired. */
- prefork_cleanup_loop(pfp);
-
- if (pfp->sigchld_fn) {
- pfp->sigchld_fn(ev_ctx, pfp, pfp->sigchld_data);
- }
-}
-
-static bool prefork_setup_sigchld_handler(struct tevent_context *ev_ctx,
- struct prefork_pool *pfp)
-{
- struct tevent_signal *se = NULL;
-
- se = tevent_add_signal(ev_ctx, pfp, SIGCHLD, 0,
- prefork_sigchld_handler, pfp);
- if (!se) {
- DEBUG(0, ("Failed to setup SIGCHLD handler!\n"));
- return false;
- }
-
- return true;
-}
-
-void prefork_set_sigchld_callback(struct prefork_pool *pfp,
- prefork_sigchld_fn_t *sigchld_fn,
- void *private_data)
-{
- pfp->sigchld_fn = sigchld_fn;
- pfp->sigchld_data = private_data;
-}
-
-/* ==== Functions used by children ==== */
-
-struct pf_listen_state {
- struct tevent_context *ev;
- struct pf_worker_data *pf;
-
- int listen_fd_size;
- struct pf_listen_fd *listen_fds;
-
- struct pf_listen_fd accept;
-
- struct tsocket_address *srv_addr;
- struct tsocket_address *cli_addr;
-
- int error;
-};
-
-struct pf_listen_ctx {
- TALLOC_CTX *fde_ctx;
- struct tevent_req *req;
- int listen_fd;
- void *listen_fd_data;
-};
-
-static void prefork_listen_accept_handler(struct tevent_context *ev,
- struct tevent_fd *fde,
- uint16_t flags, void *pvt);
-
-struct tevent_req *prefork_listen_send(TALLOC_CTX *mem_ctx,
- struct tevent_context *ev,
- struct pf_worker_data *pf,
- int listen_fd_size,
- struct pf_listen_fd *listen_fds)
-{
- struct tevent_req *req = NULL;
- struct pf_listen_state *state = NULL;
- struct pf_listen_ctx *ctx = NULL;
- struct tevent_fd *fde = NULL;
- TALLOC_CTX *fde_ctx = NULL;
- int i;
-
- req = tevent_req_create(mem_ctx, &state, struct pf_listen_state);
- if (!req) {
- return NULL;
- }
-
- state->ev = ev;
- state->pf = pf;
- state->listen_fd_size = listen_fd_size;
- state->listen_fds = listen_fds;
- state->accept.fd = -1;
- state->accept.fd_data = NULL;
- state->error = 0;
-
- fde_ctx = talloc_new(state);
- if (tevent_req_nomem(fde_ctx, req)) {
- return tevent_req_post(req, ev);
- }
-
- /* race on accept */
- for (i = 0; i < state->listen_fd_size; i++) {
- ctx = talloc(fde_ctx, struct pf_listen_ctx);
- if (tevent_req_nomem(ctx, req)) {
- return tevent_req_post(req, ev);
- }
- ctx->fde_ctx = fde_ctx;
- ctx->req = req;
- ctx->listen_fd = state->listen_fds[i].fd;
- ctx->listen_fd_data = state->listen_fds[i].fd_data;
-
- fde = tevent_add_fd(state->ev, fde_ctx,
- ctx->listen_fd, TEVENT_FD_READ,
- prefork_listen_accept_handler, ctx);
- if (tevent_req_nomem(fde, req)) {
- return tevent_req_post(req, ev);
- }
- }
-
- pf->status = PF_WORKER_ACCEPTING;
-
- return req;
-}
-
-static void prefork_listen_accept_handler(struct tevent_context *ev,
- struct tevent_fd *fde,
- uint16_t flags, void *pvt)
-{
- struct pf_listen_ctx *ctx = talloc_get_type_abort(
- pvt, struct pf_listen_ctx);
- struct tevent_req *req = ctx->req;
- struct pf_listen_state *state = tevent_req_data(
- ctx->req, struct pf_listen_state);
- struct sockaddr_storage addr = { .ss_family = 0 };
- socklen_t addrlen = sizeof(addr);
- int soerr = 0;
- socklen_t solen = sizeof(soerr);
- int sd = -1;
- int ret;
-
- if ((state->pf->cmds == PF_SRV_MSG_EXIT) &&
- (state->pf->num_clients <= 0)) {
- /* We have been asked to exit, so drop here and the next
- * child will pick it up */
- state->pf->status = PF_WORKER_EXITING;
- state->error = EINTR;
- goto done;
- }
-
- /* before proceeding check that the listening fd is ok */
- ret = getsockopt(ctx->listen_fd, SOL_SOCKET, SO_ERROR, &soerr, &solen);
- if (ret == -1) {
- /* this is a fatal error, we cannot continue listening */
- state->error = EBADF;
- goto done;
- }
- if (soerr != 0) {
- /* this is a fatal error, we cannot continue listening */
- state->error = soerr;
- goto done;
- }
-
- sd = accept(ctx->listen_fd, (struct sockaddr *)&addr, &addrlen);
- if (sd == -1) {
- state->error = errno;
- DEBUG(6, ("Accept failed! (%d, %s)\n",
- state->error, strerror(state->error)));
- goto done;
- }
- smb_set_close_on_exec(sd);
-
- state->accept.fd = sd;
- state->accept.fd_data = ctx->listen_fd_data;
-
- ret = tsocket_address_bsd_from_sockaddr(state,
- (struct sockaddr *)(void *)&addr,
- addrlen, &state->cli_addr);
- if (ret < 0) {
- state->error = errno;
- goto done;
- }
-
- ZERO_STRUCT(addr);
- addrlen = sizeof(addr);
- ret = getsockname(sd, (struct sockaddr *)(void *)&addr, &addrlen);
- if (ret < 0) {
- state->error = errno;
- goto done;
- }
-
- ret = tsocket_address_bsd_from_sockaddr(state,
- (struct sockaddr *)(void *)&addr,
- addrlen, &state->srv_addr);
- if (ret < 0) {
- state->error = errno;
- goto done;
- }
-
-done:
- /* do not track the listen fds anymore */
- talloc_free(ctx->fde_ctx);
- tevent_req_done(req);
-}
-
-int prefork_listen_recv(struct tevent_req *req,
- TALLOC_CTX *mem_ctx, int *fd,
- void **fd_data,
- struct tsocket_address **srv_addr,
- struct tsocket_address **cli_addr)
-{
- struct pf_listen_state *state = tevent_req_data(
- req, struct pf_listen_state);
- int ret = 0;
-
- if (state->error) {
- ret = state->error;
- } else {
- if (!tevent_req_is_unix_error(req, &ret)) {
- ret = 0;
- }
- }
-
- if (ret) {
- if (state->accept.fd != -1) {
- close(state->accept.fd);
- }
- } else {
- *fd = state->accept.fd;
- if (fd_data != NULL) {
- *fd_data = state->accept.fd_data;
- }
- *srv_addr = talloc_move(mem_ctx, &state->srv_addr);
- *cli_addr = talloc_move(mem_ctx, &state->cli_addr);
- state->pf->num_clients++;
- }
- if (state->pf->status == PF_WORKER_ACCEPTING) {
- state->pf->status = PF_WORKER_ALIVE;
- }
-
- tevent_req_received(req);
- return ret;
-}
+++ /dev/null
-/*
- Unix SMB/CIFS implementation.
- Common server globals
-
- Copyright (C) Simo Sorce <idra@samba.org> 2011
-
- 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 3 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, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef _SOURCE3_LIB_SERVER_PREFORK_H_
-#define _SOURCE3_LIB_SERVER_PREFORK_H_
-
-#include "system/network.h"
-#include <tevent.h>
-#include "lib/tsocket/tsocket.h"
-
-struct prefork_pool;
-
-enum pf_worker_status {
- PF_WORKER_NONE = 0,
- PF_WORKER_ALIVE,
- PF_WORKER_ACCEPTING,
- PF_WORKER_EXITING
-};
-
-enum pf_server_cmds {
- PF_SRV_MSG_NONE = 0,
- PF_SRV_MSG_EXIT
-};
-
-/**
- * @brief This structure contains a socket listening for clients and a
- * private pointer with any data associated to that particular
- * socket.
- */
-struct pf_listen_fd {
- /* The socket to listen on */
- int fd;
-
- /* The socket associated data */
- void *fd_data;
-};
-
-/**
-* @brief This structure is shared between the controlling parent and the
-* the child. The parent can only write to the 'cmds' and
-* 'allowed_clients' variables, while a child is running.
-* The child can change 'status', and 'num_clients'.
-* All other variables are initialized by the parent before forking the
-* child.
-*/
-struct pf_worker_data {
- pid_t pid;
- enum pf_worker_status status;
- time_t started;
- time_t last_used;
- int num_clients;
-
- enum pf_server_cmds cmds;
- int allowed_clients;
-};
-
-/**
-* @brief This is the 'main' function called by a child right after the fork.
-* It is daemon specific and should initialize and perform whatever
-* operation the child is meant to do. Returning from this function will
-* cause the termination of the child.
-*
-* @param ev The event context
-* @param msg_ctx The messaging context
-* @param pf The mmaped area used to communicate with parent
-* @param listen_fd_size The number of file descriptors to monitor
-* @param listen_fds The array of file descriptors
-* @param private_data Private data that needs to be passed to the main
-* function from the calling parent.
-*
-* @return Returns the exit status to be reported to the parent via exit()
-*/
-typedef int (prefork_main_fn_t)(struct tevent_context *ev,
- struct messaging_context *msg_ctx,
- struct pf_worker_data *pf,
- int child_id,
- int listen_fd_size,
- struct pf_listen_fd *pf_listen_fds,
- void *private_data);
-
-/**
-* @brief Callback function for parents that also want to be called on sigchld
-*
-* @param ev_ctx The event context
-* @param pool The pool handler
-* @param private_data Data private to the parent
-*/
-typedef void (prefork_sigchld_fn_t)(struct tevent_context *ev_ctx,
- struct prefork_pool *pool,
- void *private_data);
-
-/* ==== Functions used by controlling process ==== */
-
-/**
-* @brief Creates the first pool of preforked processes
-*
-* @param mem_ctx The memory context used to hold the pool structure
-* @param ev_ctx The event context
-* @param msg_ctx The messaging context
-* @param listen_fd_size The number of file descriptors to monitor
-* @param listen_fds The array of file descriptors to monitor
-* @param min_children Minimum number of children that must be available at
-* any given time
-* @param max_children Maximum number of children that can be started. Also
-* determines the initial size of the pool.
-* @param main_fn The children 'main' function to be called after fork
-* @param private_data The children private data.
-* @param pf_pool The allocated pool.
-*
-* @return True if it was successful, False otherwise.
-*
-* NOTE: each listen_fd is forced to non-blocking mode once handed over.
-* You should not touch listen_fds once you hand them to the prefork library.
-*/
-bool prefork_create_pool(TALLOC_CTX *mem_ctx,
- struct tevent_context *ev_ctx,
- struct messaging_context *msg_ctx,
- int listen_fd_size, struct pf_listen_fd *listen_fds,
- int min_children, int max_children,
- prefork_main_fn_t *main_fn, void *private_data,
- struct prefork_pool **pf_pool);
-/**
-* @brief Function used to attempt to expand the size of children.
-*
-* @param pfp The pool structure.
-* @param new_max The new max number of children.
-*
-* @return 0 if operation was successful
-* ENOSPC if the mmap area could not be grown to the requested size
-* EINVAL if the new max is invalid.
-*
-* NOTE: this function can easily fail if the mmap area cannot be enlarged.
-* A well behaving parent MUST NOT error out if this happen.
-*/
-int prefork_expand_pool(struct prefork_pool *pfp, int new_max);
-
-/**
-* @brief Used to prefork a number of new children
-*
-* @param ev_ctx The event context
-* @param msg_ctx The messaging context
-* @param pfp The pool structure
-* @param num_children The number of children to be started
-*
-* @return The number of new children effectively forked.
-*
-* NOTE: This method does not expand the pool, if the max number of children
-* has already been forked it will do nothing.
-*/
-int prefork_add_children(struct tevent_context *ev_ctx,
- struct messaging_context *msg_ctx,
- struct prefork_pool *pfp,
- int num_children);
-/**
-* @brief Commands a number of children to stop and exit
-*
-* @param msg_ctx The messaging context.
-* @param pfp The pool.
-* @param num_children The number of children we need to retire.
-* @param age_limit The minimum age a child has been active to be
-* considered for retirement. (Compared against the
-* 'started' value in the pf_worker_data structure of the
-* children.
-*
-* @return Number of children that were signaled to stop
-*
-* NOTE: Only children that have no attached clients can be stopped.
-* If all the available children are too young or are busy then it
-* is possible that none will be asked to stop.
-*/
-int prefork_retire_children(struct messaging_context *msg_ctx,
- struct prefork_pool *pfp,
- int num_children, time_t age_limit);
-/**
-* @brief Count the number of children
-*
-* @param pfp The pool.
-* @param active Number of children currently active if not NULL
-*
-* @return The total number of children.
-*/
-int prefork_count_children(struct prefork_pool *pfp, int *active);
-
-/**
-* @brief Count the number of actual connections currently allowed
-*
-* @param pfp The pool.
-*
-* @return The number of connections that can still be opened by clients
-* with the current pool of children.
-*/
-int prefork_count_allowed_connections(struct prefork_pool *pfp);
-
-/**
-* @brief Increase the amount of clients each child is allowed to handle
-* simultaneaously. It will allow each child to handle more than
-* one client at a time, up to 'max' (currently set to 100).
-*
-* @param pfp The pool.
-* @param max Max number of allowed connections per child
-*/
-void prefork_increase_allowed_clients(struct prefork_pool *pfp, int max);
-
-/**
-* @brief Decrease the amount of clients each child is allowed to handle.
-* Min is 1.
-*
-* @param pfp The pool.
-*/
-void prefork_decrease_allowed_clients(struct prefork_pool *pfp);
-
-/**
-* @brief Reset the maximum allowed clients per child to 1.
-* Does not reduce the number of clients actually beeing served by
-* any given child, but prevents children from overcommitting from
-* now on.
-*
-* @param pfp The pool.
-*/
-void prefork_reset_allowed_clients(struct prefork_pool *pfp);
-
-/**
-* @brief Send a specific signal to all children.
-* Used to send SIGHUP when a reload of the configuration is needed
-* for example.
-*
-* @param pfp The pool.
-* @param signal_num The signal number to be sent.
-*/
-void prefork_send_signal_to_all(struct prefork_pool *pfp, int signal_num);
-
-/**
-* @brief Send a message to all children that the server changed something
-* in the pool and they may want to take action.
-*
-* @param msg_ctx The messaging context.
-* @param pfp The pool.
-*/
-void prefork_warn_active_children(struct messaging_context *msg_ctx,
- struct prefork_pool *pfp);
-
-/**
-* @brief Sets the SIGCHLD callback
-*
-* @param pfp The pool handler.
-* @param sigchld_fn The callback function (pass NULL to unset).
-* @param private_data Private data for the callback function.
-*/
-void prefork_set_sigchld_callback(struct prefork_pool *pfp,
- prefork_sigchld_fn_t *sigchld_fn,
- void *private_data);
-
-/* ==== Functions used by children ==== */
-
-/**
-* @brief Try to listen and accept on one of the listening sockets.
-* Asynchronously tries to grab the lock and perform an accept.
-* Will automatically update the 'status' of the child and handle
-* all the locking/unlocking/timingout as necessary.
-* Changes behavior depending on whether the child already has other
-* client connections. If not it blocks on the lock call for periods of
-* time. Otherwise it loops on the lock using a timer in order to allow
-* processing of the other clients requests.
-*
-* @param mem_ctx The memory context on whic to allocate the request
-* @param ev The event context
-* @param pf The child/parent shared structure
-* @param listen_fd_size The number of listening file descriptors
-* @param listen_fds The array of listening file descriptors
-*
-* @return The tevent request pointer or NULL on allocation errors.
-*/
-struct tevent_req *prefork_listen_send(TALLOC_CTX *mem_ctx,
- struct tevent_context *ev,
- struct pf_worker_data *pf,
- int listen_fd_size,
- struct pf_listen_fd *listen_fds);
-/**
-* @brief Returns the file descriptor after the new client connection has
-* been accepted.
-*
-* @param req The request
-* @param mem_ctx The memory context for cli_addr and srv_addr
-* @param fd The new file descriptor.
-* @param srv_addr The server address in tsocket_address format
-* @param cli_addr The client address in tsocket_address format
-*
-* @return The error in case the operation failed.
-*/
-int prefork_listen_recv(struct tevent_req *req,
- TALLOC_CTX *mem_ctx, int *fd, void **fd_data,
- struct tsocket_address **srv_addr,
- struct tsocket_address **cli_addr);
-
-#endif /* _SOURCE3_LIB_SERVER_PREFORK_H_ */
+++ /dev/null
-/*
- Unix SMB/Netbios implementation.
- Prefork Helpers
- Copyright (C) Simo Sorce <idra@samba.org> 2011
-
- 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 3 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, see <http://www.gnu.org/licenses/>.
-*/
-
-#include "includes.h"
-#include "lib/server_prefork.h"
-#include "lib/server_prefork_util.h"
-
-void pfh_daemon_config(const char *daemon_name,
- struct pf_daemon_config *cfg,
- const struct pf_daemon_config *default_cfg)
-{
- int min, max, rate, allow, life;
-
- min = lp_parm_int(GLOBAL_SECTION_SNUM,
- daemon_name,
- "prefork_min_children",
- default_cfg->min_children);
- max = lp_parm_int(GLOBAL_SECTION_SNUM,
- daemon_name,
- "prefork_max_children",
- default_cfg->max_children);
- rate = lp_parm_int(GLOBAL_SECTION_SNUM,
- daemon_name,
- "prefork_spawn_rate",
- default_cfg->spawn_rate);
- allow = lp_parm_int(GLOBAL_SECTION_SNUM,
- daemon_name,
- "prefork_max_allowed_clients",
- default_cfg->max_allowed_clients);
- life = lp_parm_int(GLOBAL_SECTION_SNUM,
- daemon_name,
- "prefork_child_min_life",
- default_cfg->child_min_life);
-
- if (max > cfg->max_children && cfg->max_children != 0) {
- cfg->prefork_status |= PFH_NEW_MAX;
- }
-
- cfg->min_children = min;
- cfg->max_children = max;
- cfg->spawn_rate = rate;
- cfg->max_allowed_clients = allow;
- cfg->child_min_life = life;
-}
-
-void pfh_manage_pool(struct tevent_context *ev_ctx,
- struct messaging_context *msg_ctx,
- struct pf_daemon_config *cfg,
- struct prefork_pool *pool)
-{
- time_t now = time(NULL);
- int total, avail;
- int ret, n;
- bool msg = false;
-
- if ((cfg->prefork_status & PFH_NEW_MAX) &&
- !(cfg->prefork_status & PFH_ENOSPC)) {
- ret = prefork_expand_pool(pool, cfg->max_children);
- if (ret == ENOSPC) {
- cfg->prefork_status |= PFH_ENOSPC;
- }
- cfg->prefork_status &= ~PFH_NEW_MAX;
- }
-
- total = prefork_count_children(pool, NULL);
- avail = prefork_count_allowed_connections(pool);
- DEBUG(10, ("(Pre)Stats: children: %d, allowed connections: %d\n",
- total, avail));
-
- if ((total < cfg->max_children) && (avail < cfg->spawn_rate)) {
- n = prefork_add_children(ev_ctx, msg_ctx,
- pool, cfg->spawn_rate);
- if (n < cfg->spawn_rate) {
- DEBUG(10, ("Attempted to add %d children but only "
- "%d were actually added!\n",
- cfg->spawn_rate, n));
- }
- } else if ((avail - cfg->min_children) >= cfg->spawn_rate) {
- /* be a little slower in retiring children, to allow for
- * double spikes of traffic to be handled more gracefully */
- n = (cfg->spawn_rate / 2) + 1;
- if (n > cfg->spawn_rate) {
- n = cfg->spawn_rate;
- }
- if ((total - n) < cfg->min_children) {
- n = total - cfg->min_children;
- }
- if (n >= 0) {
- prefork_retire_children(msg_ctx, pool, n,
- now - cfg->child_min_life);
- }
- }
-
- /* total/avail may have just been changed in the above if/else */
- total = prefork_count_children(pool, NULL);
- avail = prefork_count_allowed_connections(pool);
- if ((total == cfg->max_children) && (avail < cfg->spawn_rate)) {
- n = avail;
- while (avail < cfg->spawn_rate) {
- prefork_increase_allowed_clients(pool,
- cfg->max_allowed_clients);
- avail = prefork_count_allowed_connections(pool);
- /* if avail didn't change do not loop forever */
- if (n == avail) break;
- n = avail;
- }
- msg = true;
- } else if (avail > total + cfg->spawn_rate) {
- n = avail;
- while (avail > total + cfg->spawn_rate) {
- prefork_decrease_allowed_clients(pool);
- avail = prefork_count_allowed_connections(pool);
- /* if avail didn't change do not loop forever */
- if (n == avail) break;
- n = avail;
- }
- }
-
- /* send message to all children when we change maximum allowed
- * connections, so that they can decide to start again to listen to
- * sockets if they were already topping the number of allowed
- * clients. Useful only when we increase allowed clients */
- if (msg) {
- prefork_warn_active_children(msg_ctx, pool);
- }
-
- DEBUG(10, ("Stats: children: %d, allowed connections: %d\n",
- prefork_count_children(pool, NULL),
- prefork_count_allowed_connections(pool)));
-}
-
-void pfh_client_terminated(struct pf_worker_data *pf)
-{
- if (pf->num_clients >= 0) {
- pf->num_clients--;
- } else {
- if (pf->status != PF_WORKER_EXITING) {
- DEBUG(1, ("Invalid num clients, stopping!\n"));
- }
- pf->status = PF_WORKER_EXITING;
- pf->num_clients = -1;
- }
-}
-
-bool pfh_child_allowed_to_accept(struct pf_worker_data *pf)
-{
- if (pf->status == PF_WORKER_EXITING ||
- pf->status == PF_WORKER_ACCEPTING) {
- return false;
- }
-
- return (pf->num_clients < pf->allowed_clients);
-}
+++ /dev/null
-/*
- Unix SMB/CIFS implementation.
- Prefork Helpers.
-
- Copyright (C) Simo Sorce <idra@samba.org> 2011
-
- 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 3 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, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef _SERVER_PREFORK_UTIL_H_
-#define _SERVER_PREFORK_UTIL_H_
-
-struct tevent_context;
-struct messaging_context;
-
-#define PFH_INIT 0x00
-#define PFH_NEW_MAX 0x01
-#define PFH_ENOSPC 0x02
-
-struct pf_daemon_config {
- int prefork_status;
- int min_children;
- int max_children;
- int spawn_rate;
- int max_allowed_clients;
- int child_min_life;
-};
-
-void pfh_daemon_config(const char *daemon_name,
- struct pf_daemon_config *cfg,
- const struct pf_daemon_config *default_cfg);
-
-void pfh_manage_pool(struct tevent_context *ev_ctx,
- struct messaging_context *msg_ctx,
- struct pf_daemon_config *cfg,
- struct prefork_pool *pool);
-
-void pfh_client_terminated(struct pf_worker_data *pf);
-bool pfh_child_allowed_to_accept(struct pf_worker_data *pf);
-
-#endif /* _SERVER_PREFORK_UTIL_H_ */
+++ /dev/null
-/*
- * Endpoint Mapper Functions
- * DCERPC local endpoint mapper client routines
- * Copyright (c) 2010-2011 Andreas Schneider.
- *
- * 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 3 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, see <http://www.gnu.org/licenses/>.
- */
-
-#include "includes.h"
-#include "librpc/rpc/dcerpc.h"
-#include "librpc/rpc/dcerpc_ep.h"
-#include "../librpc/gen_ndr/ndr_epmapper_c.h"
-#include "rpc_client/cli_pipe.h"
-#include "auth.h"
-#include "rpc_server/rpc_ncacn_np.h"
-#include "../lib/tsocket/tsocket.h"
-
-#include "librpc/rpc/dcesrv_core.h"
-#include "rpc_server/rpc_config.h"
-
-#define EPM_MAX_ANNOTATION_SIZE 64
-
-static NTSTATUS ep_register(TALLOC_CTX *mem_ctx,
- struct messaging_context *msg_ctx,
- struct dcesrv_context *dce_ctx,
- const struct dcesrv_interface *iface,
- const struct GUID *object_guid,
- const char *annotation,
- uint32_t replace,
- uint32_t unregister,
- struct dcerpc_binding_handle **pbh)
-{
- struct rpc_pipe_client *cli = NULL;
- struct dcerpc_binding_handle *h;
- struct pipe_auth_data *auth;
- enum rpc_service_mode_e epmd_mode;
- struct epm_entry_t *entries = NULL;
- uint32_t i = 0;
- TALLOC_CTX *tmp_ctx;
- uint32_t result = EPMAPPER_STATUS_OK;
- NTSTATUS status;
- struct dcesrv_endpoint *ep;
- bool found = false;
-
- if (iface == NULL) {
- return NT_STATUS_INVALID_PARAMETER;
- }
-
- if (dce_ctx == NULL || iface == NULL) {
- return NT_STATUS_INVALID_PARAMETER;
- }
-
- /* Check if interface is registered */
- for (ep = dce_ctx->endpoint_list; ep; ep = ep->next) {
- struct dcesrv_if_list *ifl;
- for (ifl = ep->interface_list; ifl; ifl = ifl->next) {
- if (ndr_syntax_id_equal(&ifl->iface->syntax_id,
- &iface->syntax_id)) {
- found = true;
- break;
- }
- }
- if (found) {
- break;
- }
- }
- if (!found) {
- DBG_ERR("Failed to register interface '%s' in the endpoint "
- "mapper as it is not registered in any endpoint\n",
- iface->name);
- return NT_STATUS_INVALID_PARAMETER;
- }
-
- tmp_ctx = talloc_stackframe();
-
- epmd_mode = rpc_epmapper_mode();
-
- if (epmd_mode == RPC_SERVICE_MODE_EMBEDDED) {
- struct tsocket_address *local;
- int rc;
-
- rc = tsocket_address_inet_from_strings(tmp_ctx,
- "ip",
- "127.0.0.1",
- 0,
- &local);
- if (rc < 0) {
- status = NT_STATUS_NO_MEMORY;
- goto done;
- }
-
- status = rpcint_binding_handle(tmp_ctx,
- &ndr_table_epmapper,
- local,
- NULL,
- get_session_info_system(),
- msg_ctx,
- &h);
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(1, ("dcerpc_ep_register: Could not connect to "
- "epmapper (%s)", nt_errstr(status)));
- goto done;
- }
- } else if (epmd_mode == RPC_SERVICE_MODE_EXTERNAL) {
- /* Connect to the endpoint mapper locally */
- status = rpc_pipe_open_ncalrpc(tmp_ctx,
- &ndr_table_epmapper,
- &cli);
- if (!NT_STATUS_IS_OK(status)) {
- goto done;
- }
-
- status = rpccli_ncalrpc_bind_data(cli, &auth);
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(0, ("Failed to initialize anonymous bind.\n"));
- goto done;
- }
-
- status = rpc_pipe_bind(cli, auth);
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(2, ("Failed to bind ncalrpc socket.\n"));
- goto done;
- }
-
- h = cli->binding_handle;
- } else {
- status = NT_STATUS_INVALID_PARAMETER;
- goto done;
- }
-
- for (i = 0, ep = dce_ctx->endpoint_list; ep; i++, ep = ep->next) {
- struct dcerpc_binding *map_binding;
- struct epm_twr_t *map_tower;
- struct dcesrv_if_list *ifl;
-
- for (ifl = ep->interface_list; ifl; ifl = ifl->next) {
- if (!ndr_syntax_id_equal(&ifl->iface->syntax_id,
- &iface->syntax_id)) {
- continue;
- }
- }
-
- /* The interface is registered in this endpoint, add it */
- entries = talloc_realloc(tmp_ctx, entries, struct epm_entry_t,
- i + 1);
- if (entries == NULL) {
- status = NT_STATUS_NO_MEMORY;
- goto done;
- }
-
- map_binding = dcerpc_binding_dup(entries, ep->ep_description);
- if (map_binding == NULL) {
- status = NT_STATUS_NO_MEMORY;
- goto done;
- }
-
- status = dcerpc_binding_set_abstract_syntax(map_binding,
- &iface->syntax_id);
- if (!NT_STATUS_IS_OK(status)) {
- goto done;
- }
-
- map_tower = talloc_zero(entries, struct epm_twr_t);
- if (map_tower == NULL) {
- status = NT_STATUS_NO_MEMORY;
- goto done;
- }
-
- status = dcerpc_binding_build_tower(entries,
- map_binding,
- &map_tower->tower);
- if (!NT_STATUS_IS_OK(status)) {
- goto done;
- }
-
- TALLOC_FREE(map_binding);
-
- entries[i].tower = map_tower;
- if (annotation == NULL) {
- entries[i].annotation = talloc_strdup(entries, "");
- } else {
- entries[i].annotation = talloc_strndup(entries,
- annotation,
- EPM_MAX_ANNOTATION_SIZE);
- }
- if (entries[i].annotation == NULL) {
- status = NT_STATUS_NO_MEMORY;
- goto done;
- }
-
- if (object_guid != NULL) {
- entries[i].object = *object_guid;
- } else {
- ZERO_STRUCT(entries[i].object);
- }
- }
-
- if (unregister) {
- status = dcerpc_epm_Delete(h,
- tmp_ctx,
- i,
- entries,
- &result);
- } else {
- status = dcerpc_epm_Insert(h,
- tmp_ctx,
- i,
- entries,
- replace,
- &result);
- }
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(0, ("dcerpc_ep_register: Could not insert tower (%s)\n",
- nt_errstr(status)));
- goto done;
- }
- if (result != EPMAPPER_STATUS_OK) {
- DEBUG(0, ("dcerpc_ep_register: Could not insert tower (0x%.8x)\n",
- result));
- status = NT_STATUS_UNSUCCESSFUL;
- goto done;
- }
-
- if (pbh != NULL) {
- talloc_steal(h, cli);
- *pbh = talloc_move(mem_ctx, &h);
- }
-
-done:
- talloc_free(tmp_ctx);
-
- return status;
-}
-
-NTSTATUS dcerpc_ep_register(TALLOC_CTX *mem_ctx,
- struct messaging_context *msg_ctx,
- struct dcesrv_context *dce_ctx,
- const struct dcesrv_interface *iface,
- const struct GUID *object_guid,
- const char *annotation,
- struct dcerpc_binding_handle **ph)
-{
- return ep_register(mem_ctx,
- msg_ctx,
- dce_ctx,
- iface,
- object_guid,
- annotation,
- 1,
- 0,
- ph);
-}
-
-NTSTATUS dcerpc_ep_register_noreplace(TALLOC_CTX *mem_ctx,
- struct messaging_context *msg_ctx,
- struct dcesrv_context *dce_ctx,
- const struct dcesrv_interface *iface,
- const struct GUID *object_guid,
- const char *annotation,
- struct dcerpc_binding_handle **ph)
-{
- return ep_register(mem_ctx,
- msg_ctx,
- dce_ctx,
- iface,
- object_guid,
- annotation,
- 0,
- 0,
- ph);
-}
-
-NTSTATUS dcerpc_ep_unregister(struct messaging_context *msg_ctx,
- struct dcesrv_context *dce_ctx,
- const struct dcesrv_interface *iface,
- const struct GUID *object_guid)
-{
- return ep_register(NULL,
- msg_ctx,
- dce_ctx,
- iface,
- object_guid,
- NULL,
- 0,
- 1,
- NULL);
-}
-
-/* vim: set ts=8 sw=8 noet cindent syntax=c.doxygen: */
+++ /dev/null
-/*
- * Endpoint Mapper Functions
- * DCERPC local endpoint mapper client routines
- * Copyright (c) 2010-2011 Andreas Schneider.
- *
- * 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 3 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, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef _DCERPC_EP_H_
-#define _DCERPC_EP_H_
-
-struct dcesrv_context;
-struct dcesrv_interface;
-
-/**
- * @brief Adds server address information in the local endpoint map.
- *
- * @param[in] mem_ctx The memory context to use for the binding handle.
- *
- * @param[in] dce_ctx The dcerpc server context
- *
- * @param[in] iface The interface to register in the endpoint mapper
- *
- * @param[in] object_guid The object GUID that the server offers. The server
- * application constructs this vector.
- *
- * @param[in] annotation Defines a character string comment applied to the
- * element added to the local endpoint map. The string
- * can be up to 64 characters long, including the null
- * terminating character. Strings longer than 64
- * characters are truncated. The application supplies
- * the value NULL or the string "" to indicate an empty
- * annotation string.
- *
- * When replacing elements, the annotation string
- * supplied, including an empty annotation string,
- * replaces any existing annotation string.
- *
- * @param[out] ph A pointer to store the binding handle. The memory
- * context will be the give one. If you free this handle
- * then the connection will be closed.
- *
- * @return An NTSTATUS error code.
- */
-NTSTATUS dcerpc_ep_register(TALLOC_CTX *mem_ctx,
- struct messaging_context *msg_ctx,
- struct dcesrv_context *dce_ctx,
- const struct dcesrv_interface *iface,
- const struct GUID *object_guid,
- const char *annotation,
- struct dcerpc_binding_handle **ph);
-
-NTSTATUS dcerpc_ep_register_noreplace(TALLOC_CTX *mem_ctx,
- struct messaging_context *msg_ctx,
- struct dcesrv_context *dce_ctx,
- const struct dcesrv_interface *iface,
- const struct GUID *object_guid,
- const char *annotation,
- struct dcerpc_binding_handle **ph);
-
-NTSTATUS dcerpc_ep_unregister(struct messaging_context *msg_ctx,
- struct dcesrv_context *dce_ctx,
- const struct dcesrv_interface *iface,
- const struct GUID *object_guid);
-
-#endif /* _DCERPC_EP_H_ */
+++ /dev/null
-/*
- Unix SMB/Netbios implementation.
- SPOOLSS Daemon
- Copyright (C) Simo Sorce <idra@samba.org> 2010-2011
-
- 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 3 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, see <http://www.gnu.org/licenses/>.
-*/
-#include "includes.h"
-#include "locking/share_mode_lock.h"
-#include "smbd/smbd.h"
-
-#include "messages.h"
-#include "include/printing.h"
-#include "printing/nt_printing_migrate_internal.h"
-#include "printing/queue_process.h"
-#include "printing/pcap.h"
-#include "printing/load.h"
-#include "printing/spoolssd.h"
-#include "ntdomain.h"
-#include "librpc/gen_ndr/ndr_winreg_scompat.h"
-#include "librpc/gen_ndr/ndr_spoolss_scompat.h"
-#include "rpc_server/rpc_server.h"
-#include "rpc_server/rpc_service_setup.h"
-#include "rpc_server/rpc_ep_register.h"
-#include "rpc_server/rpc_config.h"
-#include "rpc_server/spoolss/srv_spoolss_nt.h"
-#include "librpc/rpc/dcerpc_ep.h"
-#include "librpc/rpc/dcesrv_core.h"
-#include "lib/server_prefork.h"
-#include "lib/server_prefork_util.h"
-#include "lib/global_contexts.h"
-
-#undef DBGC_CLASS
-#define DBGC_CLASS DBGC_RPC_SRV
-
-#define DAEMON_NAME "spoolssd"
-
-static struct server_id parent_id;
-static struct prefork_pool *spoolss_pool = NULL;
-static int spoolss_child_id = 0;
-
-static const struct pf_daemon_config default_pf_spoolss_cfg = {
- .prefork_status = PFH_INIT,
- .min_children = 5,
- .max_children = 25,
- .spawn_rate = 5,
- .max_allowed_clients = 100,
- .child_min_life = 60 /* 1 minute minimum life time */
-};
-static struct pf_daemon_config pf_spoolss_cfg = { 0 };
-
-static void spoolss_reopen_logs(int child_id)
-{
- const struct loadparm_substitution *lp_sub =
- loadparm_s3_global_substitution();
- char *lfile = lp_logfile(talloc_tos(), lp_sub);
- char *ext;
- int rc;
-
- if (child_id) {
- rc = asprintf(&ext, "%s.%d", DAEMON_NAME, child_id);
- } else {
- rc = asprintf(&ext, "%s", DAEMON_NAME);
- }
-
- if (rc == -1) {
- return;
- }
-
- rc = 0;
- if (lfile == NULL || lfile[0] == '\0') {
- rc = asprintf(&lfile, "%s/log.%s",
- get_dyn_LOGFILEBASE(), ext);
- } else {
- if (strstr(lfile, ext) == NULL) {
- if (child_id) {
- rc = asprintf(&lfile, "%s.%d",
- lp_logfile(talloc_tos(), lp_sub),
- child_id);
- } else {
- rc = asprintf(&lfile, "%s.%s",
- lp_logfile(talloc_tos(), lp_sub),
- ext);
- }
- }
- }
-
- if (rc > 0) {
- lp_set_logfile(lfile);
- SAFE_FREE(lfile);
- }
-
- SAFE_FREE(ext);
-
- reopen_logs();
-}
-
-static void update_conf(struct tevent_context *ev,
- struct messaging_context *msg)
-{
- change_to_root_user();
- lp_load_global(get_dyn_CONFIGFILE());
- load_printers();
-
- spoolss_reopen_logs(spoolss_child_id);
- if (spoolss_child_id == 0) {
- pfh_daemon_config(DAEMON_NAME,
- &pf_spoolss_cfg,
- &default_pf_spoolss_cfg);
- pfh_manage_pool(ev, msg, &pf_spoolss_cfg, spoolss_pool);
- }
-}
-
-static void smb_conf_updated(struct messaging_context *msg,
- void *private_data,
- uint32_t msg_type,
- struct server_id server_id,
- DATA_BLOB *data)
-{
- struct tevent_context *ev_ctx = talloc_get_type_abort(private_data,
- struct tevent_context);
-
- DEBUG(10, ("Got message saying smb.conf was updated. Reloading.\n"));
- update_conf(ev_ctx, msg);
-}
-
-static void spoolss_sig_term_handler(struct tevent_context *ev,
- struct tevent_signal *se,
- int signum,
- int count,
- void *siginfo,
- void *private_data)
-{
- exit_server_cleanly("termination signal");
-}
-
-static void spoolss_setup_sig_term_handler(struct tevent_context *ev_ctx)
-{
- struct tevent_signal *se;
-
- se = tevent_add_signal(ev_ctx,
- ev_ctx,
- SIGTERM, 0,
- spoolss_sig_term_handler,
- NULL);
- if (!se) {
- exit_server("failed to setup SIGTERM handler");
- }
-}
-
-static void spoolss_sig_hup_handler(struct tevent_context *ev,
- struct tevent_signal *se,
- int signum,
- int count,
- void *siginfo,
- void *pvt)
-{
- struct messaging_context *msg_ctx;
-
- msg_ctx = talloc_get_type_abort(pvt, struct messaging_context);
-
- DEBUG(1,("Reloading printers after SIGHUP\n"));
- update_conf(ev, msg_ctx);
-
- /* relay to all children */
- if (spoolss_pool) {
- prefork_send_signal_to_all(spoolss_pool, SIGHUP);
- }
-}
-
-static void spoolss_setup_sig_hup_handler(struct tevent_context *ev_ctx,
- struct messaging_context *msg_ctx)
-{
- struct tevent_signal *se;
-
- se = tevent_add_signal(ev_ctx,
- ev_ctx,
- SIGHUP, 0,
- spoolss_sig_hup_handler,
- msg_ctx);
- if (!se) {
- exit_server("failed to setup SIGHUP handler");
- }
-}
-
-/* Children */
-
-static void spoolss_chld_sig_hup_handler(struct tevent_context *ev,
- struct tevent_signal *se,
- int signum,
- int count,
- void *siginfo,
- void *pvt)
-{
- change_to_root_user();
- DEBUG(1,("Reloading printers after SIGHUP\n"));
- load_printers();
- spoolss_reopen_logs(spoolss_child_id);
-}
-
-static bool spoolss_setup_chld_hup_handler(struct tevent_context *ev_ctx,
- struct messaging_context *msg_ctx,
- struct pf_worker_data *pf)
-{
- struct tevent_signal *se;
-
- se = tevent_add_signal(ev_ctx,
- ev_ctx,
- SIGHUP, 0,
- spoolss_chld_sig_hup_handler,
- msg_ctx);
- if (!se) {
- DEBUG(1, ("failed to setup SIGHUP handler"));
- return false;
- }
-
- return true;
-}
-
-static void parent_ping(struct messaging_context *msg_ctx,
- void *private_data,
- uint32_t msg_type,
- struct server_id server_id,
- DATA_BLOB *data)
-{
-
- /* The fact we received this message is enough to let make the event
- * loop if it was idle. spoolss_children_main will cycle through
- * spoolss_next_client at least once. That function will take whatever
- * action is necessary */
-
- DEBUG(10, ("Got message that the parent changed status.\n"));
- return;
-}
-
-static bool spoolss_child_init(struct tevent_context *ev_ctx,
- int child_id, struct pf_worker_data *pf)
-{
- NTSTATUS status;
- struct messaging_context *msg_ctx = global_messaging_context();
- bool ok;
-
- status = reinit_after_fork(msg_ctx, ev_ctx, true, "spoolssd-child");
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(0,("reinit_after_fork() failed\n"));
- smb_panic("reinit_after_fork() failed");
- }
-
- spoolss_child_id = child_id;
- spoolss_reopen_logs(child_id);
-
- ok = spoolss_setup_chld_hup_handler(ev_ctx, msg_ctx, pf);
- if (!ok) {
- return false;
- }
-
- if (!locking_init()) {
- return false;
- }
-
- messaging_register(msg_ctx, ev_ctx,
- MSG_SMB_CONF_UPDATED, smb_conf_updated);
- messaging_register(msg_ctx, ev_ctx,
- MSG_PREFORK_PARENT_EVENT, parent_ping);
-
- /* As soon as messaging is up check if pcap has been loaded already.
- * If so then we probably missed a message and should load_printers()
- * ourselves. If pcap has not been loaded yet, then ignore, we will get
- * a message as soon as the bq process completes the reload. */
- load_printers();
-
- return true;
-}
-
-struct spoolss_children_data {
- struct tevent_context *ev_ctx;
- struct messaging_context *msg_ctx;
- struct dcesrv_context *dce_ctx;
- struct pf_worker_data *pf;
- int listen_fd_size;
- struct pf_listen_fd *listen_fds;
-};
-
-static void spoolss_next_client(void *pvt);
-
-static int spoolss_children_main(struct tevent_context *ev_ctx,
- struct messaging_context *msg_ctx,
- struct pf_worker_data *pf,
- int child_id,
- int listen_fd_size,
- struct pf_listen_fd *listen_fds,
- void *private_data)
-{
- struct spoolss_children_data *data;
- bool ok;
- int ret = 0;
- struct dcesrv_context *dce_ctx = NULL;
-
- dce_ctx = talloc_get_type_abort(private_data, struct dcesrv_context);
-
- ok = spoolss_child_init(ev_ctx, child_id, pf);
- if (!ok) {
- return 1;
- }
-
- data = talloc(ev_ctx, struct spoolss_children_data);
- if (!data) {
- return 1;
- }
- data->pf = pf;
- data->ev_ctx = ev_ctx;
- data->msg_ctx = msg_ctx;
- data->dce_ctx = dce_ctx;
- data->listen_fd_size = listen_fd_size;
- data->listen_fds = listen_fds;
-
- /* loop until it is time to exit */
- while (pf->status != PF_WORKER_EXITING) {
- /* try to see if it is time to schedule the next client */
- spoolss_next_client(data);
-
- ret = tevent_loop_once(ev_ctx);
- if (ret != 0) {
- DEBUG(0, ("tevent_loop_once() exited with %d: %s\n",
- ret, strerror(errno)));
- pf->status = PF_WORKER_EXITING;
- }
- }
-
- return ret;
-}
-
-static void spoolss_client_terminated(struct dcesrv_connection *conn,
- void *pvt)
-{
- struct spoolss_children_data *data;
-
- data = talloc_get_type_abort(pvt, struct spoolss_children_data);
-
- pfh_client_terminated(data->pf);
-
- spoolss_next_client(pvt);
-}
-
-struct spoolss_new_client {
- struct spoolss_children_data *data;
-};
-
-static void spoolss_handle_client(struct tevent_req *req);
-
-static void spoolss_next_client(void *pvt)
-{
- struct tevent_req *req;
- struct spoolss_children_data *data;
- struct spoolss_new_client *next;
-
- data = talloc_get_type_abort(pvt, struct spoolss_children_data);
-
- if (!pfh_child_allowed_to_accept(data->pf)) {
- /* nothing to do for now we are already listening
- * or we are not allowed to listen further */
- return;
- }
-
- next = talloc_zero(data, struct spoolss_new_client);
- if (!next) {
- DEBUG(1, ("Out of memory!?\n"));
- return;
- }
- next->data = data;
-
- req = prefork_listen_send(next, data->ev_ctx, data->pf,
- data->listen_fd_size,
- data->listen_fds);
- if (!req) {
- DEBUG(1, ("Failed to make listening request!?\n"));
- talloc_free(next);
- return;
- }
- tevent_req_set_callback(req, spoolss_handle_client, next);
-}
-
-static void spoolss_handle_client(struct tevent_req *req)
-{
- struct spoolss_children_data *data;
- struct spoolss_new_client *client;
- const DATA_BLOB ping = data_blob_null;
- int ret;
- int sd;
- struct tsocket_address *srv_addr = NULL;
- struct tsocket_address *cli_addr = NULL;
- void *listen_fd_data = NULL;
- struct dcesrv_endpoint *ep = NULL;
-
- client = tevent_req_callback_data(req, struct spoolss_new_client);
- data = client->data;
-
- ret = prefork_listen_recv(req, data, &sd, &listen_fd_data,
- &srv_addr, &cli_addr);
-
- /* this will free the request too */
- talloc_free(client);
-
- if (ret != 0) {
- DEBUG(6, ("No client connection was available after all!\n"));
- return;
- }
-
- ep = talloc_get_type_abort(listen_fd_data, struct dcesrv_endpoint);
-
- /* Warn parent that our status changed */
- messaging_send(data->msg_ctx, parent_id,
- MSG_PREFORK_CHILD_EVENT, &ping);
-
- DEBUG(2, ("Spoolss preforked child %d got client connection!\n",
- (int)(data->pf->pid)));
-
- dcerpc_ncacn_accept(data->ev_ctx,
- data->msg_ctx,
- data->dce_ctx,
- ep,
- &cli_addr,
- &srv_addr,
- sd,
- spoolss_client_terminated,
- data);
-}
-
-/* ==== Main Process Functions ==== */
-
-extern pid_t background_lpq_updater_pid;
-static char *bq_logfile;
-
-static void check_updater_child(struct tevent_context *ev_ctx,
- struct messaging_context *msg_ctx)
-{
- int status;
- pid_t pid;
-
- if (background_lpq_updater_pid == -1) {
- return;
- }
-
- pid = waitpid(background_lpq_updater_pid, &status, WNOHANG);
- if (pid > 0) {
- DEBUG(2, ("The background queue child died... Restarting!\n"));
- pid = start_background_queue(ev_ctx, msg_ctx, bq_logfile);
- background_lpq_updater_pid = pid;
- }
-}
-
-static void child_ping(struct messaging_context *msg_ctx,
- void *private_data,
- uint32_t msg_type,
- struct server_id server_id,
- DATA_BLOB *data)
-{
- struct tevent_context *ev_ctx;
-
- ev_ctx = talloc_get_type_abort(private_data, struct tevent_context);
-
- DEBUG(10, ("Got message that a child changed status.\n"));
- pfh_manage_pool(ev_ctx, msg_ctx, &pf_spoolss_cfg, spoolss_pool);
-}
-
-static bool spoolssd_schedule_check(struct tevent_context *ev_ctx,
- struct messaging_context *msg_ctx,
- struct timeval current_time);
-static void spoolssd_check_children(struct tevent_context *ev_ctx,
- struct tevent_timer *te,
- struct timeval current_time,
- void *pvt);
-
-static void spoolssd_sigchld_handler(struct tevent_context *ev_ctx,
- struct prefork_pool *pfp,
- void *pvt)
-{
- struct messaging_context *msg_ctx;
-
- msg_ctx = talloc_get_type_abort(pvt, struct messaging_context);
-
- /* run pool management so we can fork/retire or increase
- * the allowed connections per child based on load */
- pfh_manage_pool(ev_ctx, msg_ctx, &pf_spoolss_cfg, spoolss_pool);
-
- /* also check if the updater child is alive and well */
- check_updater_child(ev_ctx, msg_ctx);
-}
-
-static bool spoolssd_setup_children_monitor(struct tevent_context *ev_ctx,
- struct messaging_context *msg_ctx)
-{
- bool ok;
-
- /* add our oun sigchld callback */
- prefork_set_sigchld_callback(spoolss_pool,
- spoolssd_sigchld_handler, msg_ctx);
-
- ok = spoolssd_schedule_check(ev_ctx, msg_ctx,
- tevent_timeval_current());
- return ok;
-}
-
-static bool spoolssd_schedule_check(struct tevent_context *ev_ctx,
- struct messaging_context *msg_ctx,
- struct timeval current_time)
-{
- struct tevent_timer *te;
- struct timeval next_event;
-
- /* check situation again in 10 seconds */
- next_event = tevent_timeval_current_ofs(10, 0);
-
- /* TODO: check when the socket becomes readable, so that children
- * are checked only when there is some activity ? */
- te = tevent_add_timer(ev_ctx, spoolss_pool, next_event,
- spoolssd_check_children, msg_ctx);
- if (!te) {
- DEBUG(2, ("Failed to set up children monitoring!\n"));
- return false;
- }
-
- return true;
-}
-
-static void spoolssd_check_children(struct tevent_context *ev_ctx,
- struct tevent_timer *te,
- struct timeval current_time,
- void *pvt)
-{
- struct messaging_context *msg_ctx;
-
- msg_ctx = talloc_get_type_abort(pvt, struct messaging_context);
-
- pfh_manage_pool(ev_ctx, msg_ctx, &pf_spoolss_cfg, spoolss_pool);
-
- spoolssd_schedule_check(ev_ctx, msg_ctx, current_time);
-}
-
-static void print_queue_forward(struct messaging_context *msg,
- void *private_data,
- uint32_t msg_type,
- struct server_id server_id,
- DATA_BLOB *data)
-{
- send_to_bgqd(msg, msg_type, data->data, data->length);
-}
-
-static char *get_bq_logfile(void)
-{
- const struct loadparm_substitution *lp_sub =
- loadparm_s3_global_substitution();
- char *lfile = lp_logfile(talloc_tos(), lp_sub);
- int rc;
-
- if (lfile == NULL || lfile[0] == '\0') {
- rc = asprintf(&lfile, "%s/log.%s.bq",
- get_dyn_LOGFILEBASE(), DAEMON_NAME);
- } else {
- rc = asprintf(&lfile, "%s.bq", lp_logfile(talloc_tos(), lp_sub));
- }
- if (rc == -1) {
- lfile = NULL;
- }
- return lfile;
-}
-
-static NTSTATUS spoolssd_create_sockets(struct tevent_context *ev_ctx,
- struct messaging_context *msg_ctx,
- struct dcesrv_context *dce_ctx,
- TALLOC_CTX *mem_ctx,
- struct pf_listen_fd **plisten_fds,
- size_t *pnum_listen_fds)
-{
- NTSTATUS status;
- int rc;
- enum rpc_service_mode_e epm_mode = rpc_epmapper_mode();
- size_t i, num_fds;
- struct pf_listen_fd *fds = NULL;
- struct dcesrv_endpoint *e = dce_ctx->endpoint_list;
-
- DBG_INFO("Initializing DCE/RPC connection endpoints\n");
-
- status = dcesrv_create_endpoint_list_pf_listen_fds(
- ev_ctx, msg_ctx, dce_ctx, e, mem_ctx, &num_fds, &fds);
- if (!NT_STATUS_IS_OK(status)) {
- return status;
- }
-
- for (i = 0; i < num_fds; i++) {
- rc = listen(fds[i].fd, pf_spoolss_cfg.max_allowed_clients);
- if (rc == -1) {
- char *ep_string = NULL;
- e = fds[i].fd_data;
-
- ep_string = dcerpc_binding_string(dce_ctx,
- e->ep_description);
- DBG_ERR("Failed to listen on endpoint '%s': %s\n",
- ep_string, strerror(errno));
- status = map_nt_error_from_unix(errno);
- TALLOC_FREE(ep_string);
- goto done;
- }
- }
-
- if (epm_mode != RPC_SERVICE_MODE_DISABLED &&
- (lp_parm_bool(-1, "rpc_server", "register_embedded_np", false))) {
- for (e = dce_ctx->endpoint_list; e; e = e->next) {
- struct dcesrv_if_list *ifl = NULL;
- for (ifl = e->interface_list; ifl; ifl = ifl->next) {
- status = rpc_ep_register(ev_ctx,
- msg_ctx,
- dce_ctx,
- ifl->iface);
- if (!NT_STATUS_IS_OK(status)) {
- DBG_ERR("Failed to register interface"
- " in endpoint mapper: %s\n",
- nt_errstr(status));
- goto done;
- }
- }
- }
- }
-
- *plisten_fds = fds;
- *pnum_listen_fds = num_fds;
-
- status = NT_STATUS_OK;
-done:
- return status;
-}
-
-pid_t start_spoolssd(struct tevent_context *ev_ctx,
- struct messaging_context *msg_ctx,
- struct dcesrv_context *dce_ctx)
-{
- pid_t pid;
- NTSTATUS status;
- struct pf_listen_fd *listen_fds = NULL;
- size_t listen_fds_size = 0;
- int ret;
- bool ok;
- const struct dcesrv_endpoint_server *ep_server = NULL;
- const char *ep_servers[] = { "winreg", "spoolss", NULL };
-
- DEBUG(1, ("Forking SPOOLSS Daemon\n"));
-
- /*
- * Block signals before forking child as it will have to
- * set its own handlers. Child will re-enable SIGHUP as
- * soon as the handlers are set up.
- */
- BlockSignals(true, SIGTERM);
- BlockSignals(true, SIGHUP);
-
- pid = fork();
-
- if (pid == -1) {
- DEBUG(0, ("Failed to fork SPOOLSS [%s]\n",
- strerror(errno)));
- exit(1);
- }
-
- /* parent or error */
- if (pid != 0) {
-
- /* Re-enable SIGHUP before returnig */
- BlockSignals(false, SIGTERM);
- BlockSignals(false, SIGHUP);
- return pid;
- }
-
- status = smbd_reinit_after_fork(msg_ctx, ev_ctx, true,
- "spoolssd-master");
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(0,("reinit_after_fork() failed\n"));
- smb_panic("reinit_after_fork() failed");
- }
-
- /* save the parent process id so the children can use it later */
- parent_id = messaging_server_id(msg_ctx);
-
- spoolss_reopen_logs(0);
- pfh_daemon_config(DAEMON_NAME,
- &pf_spoolss_cfg,
- &default_pf_spoolss_cfg);
-
- spoolss_setup_sig_term_handler(ev_ctx);
- spoolss_setup_sig_hup_handler(ev_ctx, msg_ctx);
-
- BlockSignals(false, SIGTERM);
- BlockSignals(false, SIGHUP);
-
- /* always start the backgroundqueue listner in spoolssd */
- bq_logfile = get_bq_logfile();
- pid = start_background_queue(ev_ctx, msg_ctx, bq_logfile);
- if (pid > 0) {
- background_lpq_updater_pid = pid;
- }
-
- DBG_INFO("Registering DCE/RPC endpoint servers\n");
-
- ep_server = winreg_get_ep_server();
- if (ep_server == NULL) {
- DBG_ERR("Failed to get 'winreg' endpoint server\n");
- exit(1);
- }
-
- status = dcerpc_register_ep_server(ep_server);
- if (!NT_STATUS_IS_OK(status) &&
- !NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
- DBG_ERR("Failed to register 'winreg' endpoint server: %s\n",
- nt_errstr(status));
- exit(1);
- }
-
- ep_server = spoolss_get_ep_server();
- if (ep_server == NULL) {
- DBG_ERR("Failed to get 'spoolss' endpoint server\n");
- exit(1);
- }
-
- status = dcerpc_register_ep_server(ep_server);
- if (!NT_STATUS_IS_OK(status)) {
- DBG_ERR("Failed to register 'spoolss' endpoint server: %s\n",
- nt_errstr(status));
- exit(1);
- }
-
- DBG_INFO("Reinitializing DCE/RPC server context\n");
-
- status = dcesrv_reinit_context(dce_ctx);
- if (!NT_STATUS_IS_OK(status)) {
- DBG_ERR("Failed to reinit DCE/RPC context: %s\n",
- nt_errstr(status));
- exit(1);
- }
-
- DBG_INFO("Initializing DCE/RPC registered endpoint servers\n");
-
- /* Init ep servers */
- status = dcesrv_init_ep_servers(dce_ctx, ep_servers);
- if (!NT_STATUS_IS_OK(status)) {
- DBG_ERR("Failed to init DCE/RPC endpoint server: %s\n",
- nt_errstr(status));
- exit(1);
- }
-
- /* the listening fd must be created before the children are actually
- * forked out. */
- status = spoolssd_create_sockets(ev_ctx,
- msg_ctx,
- dce_ctx,
- dce_ctx,
- &listen_fds,
- &listen_fds_size);
- if (!NT_STATUS_IS_OK(status)) {
- DBG_ERR("Failed to create sockets: %s\n",
- nt_errstr(status));
- exit(1);
- }
-
- /* start children before any more initialization is done */
- ok = prefork_create_pool(ev_ctx, /* mem_ctx */
- ev_ctx, msg_ctx,
- listen_fds_size, listen_fds,
- pf_spoolss_cfg.min_children,
- pf_spoolss_cfg.max_children,
- &spoolss_children_main, dce_ctx,
- &spoolss_pool);
- TALLOC_FREE(listen_fds);
- if (!ok) {
- exit(1);
- }
-
- if (!locking_init()) {
- exit(1);
- }
-
- messaging_register(msg_ctx, ev_ctx,
- MSG_SMB_CONF_UPDATED, smb_conf_updated);
- messaging_register(msg_ctx, NULL, MSG_PRINTER_UPDATE,
- print_queue_forward);
- messaging_register(msg_ctx, ev_ctx,
- MSG_PREFORK_CHILD_EVENT, child_ping);
-
- /*
- * As soon as messaging is up check if pcap has been loaded already.
- * If pcap has not been loaded yet, then ignore, as we will reload on
- * client enumeration anyway.
- */
- load_printers();
-
- ok = spoolssd_setup_children_monitor(ev_ctx, msg_ctx);
- if (!ok) {
- DEBUG(0, ("Failed to setup children monitoring!\n"));
- exit(1);
- }
-
- DEBUG(1, ("SPOOLSS Daemon Started (%u)\n", (unsigned int)getpid()));
-
- pfh_manage_pool(ev_ctx, msg_ctx, &pf_spoolss_cfg, spoolss_pool);
-
- /* loop forever */
- ret = tevent_loop_wait(ev_ctx);
-
- /* should not be reached */
- DEBUG(0,("spoolssd tevent_loop_wait() exited with %d - %s\n",
- ret, (ret == 0) ? "out of events" : strerror(errno)));
- exit(1);
-}
+++ /dev/null
-/*
- Unix SMB/Netbios implementation.
- SPOOLSS Daemon
- Copyright (C) Simo Sorce <idra@samba.org> 2010-2011
-
- 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 3 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, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef _SOURCE3_PRINTING_SPOOLSSD_H_
-#define _SOURCE3_PRINTING_SPOOLSSD_H_
-
-#include "replace.h"
-#include "messages.h"
-
-struct dcesrv_context;
-
-pid_t start_spoolssd(struct tevent_context *ev_ctx,
- struct messaging_context *msg_ctx,
- struct dcesrv_context *dce_ctx);
-
-#endif /* _SOURCE3_PRINTING_SPOOLSSD_H_ */
struct dcesrv_iface_list *iface_list;
};
-struct dcesrv_ep_entry_list {
- struct dcesrv_ep_entry_list *next, *prev;
-
- uint32_t num_ents;
- struct epm_entry_t *entries;
-};
-
struct rpc_eps {
struct dcesrv_ep_iface *e;
uint32_t count;
+++ /dev/null
-/*
- * Unix SMB/CIFS implementation.
- *
- * SMBD RPC service callbacks
- *
- * Copyright (c) 2011 Andreas Schneider <asn@samba.org>
- *
- * 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 3 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, see <http://www.gnu.org/licenses/>.
- */
-
-#include "includes.h"
-
-#include "ntdomain.h"
-#include "messages.h"
-
-#include "librpc/rpc/dcerpc_ep.h"
-
-#include "librpc/rpc/dcesrv_core.h"
-#include "librpc/gen_ndr/ndr_epmapper_scompat.h"
-
-#include "rpc_server/rpc_server.h"
-#include "rpc_server/rpc_service_setup.h"
-#include "rpc_server/rpc_sock_helper.h"
-#include "rpc_server/epmd.h"
-
-#undef DBGC_CLASS
-#define DBGC_CLASS DBGC_RPC_SRV
-
-#define DAEMON_NAME "epmd"
-
-static void epmd_reopen_logs(void)
-{
- const struct loadparm_substitution *lp_sub =
- loadparm_s3_global_substitution();
- char *lfile = lp_logfile(talloc_tos(), lp_sub);
- int rc;
-
- if (lfile == NULL || lfile[0] == '\0') {
- rc = asprintf(&lfile, "%s/log.%s", get_dyn_LOGFILEBASE(), DAEMON_NAME);
- if (rc > 0) {
- lp_set_logfile(lfile);
- SAFE_FREE(lfile);
- }
- } else {
- if (strstr(lfile, DAEMON_NAME) == NULL) {
- rc = asprintf(&lfile, "%s.%s",
- lp_logfile(talloc_tos(), lp_sub), DAEMON_NAME);
- if (rc > 0) {
- lp_set_logfile(lfile);
- SAFE_FREE(lfile);
- }
- }
- }
-
- reopen_logs();
-}
-
-static void epmd_smb_conf_updated(struct messaging_context *msg,
- void *private_data,
- uint32_t msg_type,
- struct server_id server_id,
- DATA_BLOB *data)
-{
- DEBUG(10, ("Got message saying smb.conf was updated. Reloading.\n"));
- change_to_root_user();
- epmd_reopen_logs();
-}
-
-static void epmd_sig_term_handler(struct tevent_context *ev,
- struct tevent_signal *se,
- int signum,
- int count,
- void *siginfo,
- void *private_data)
-{
- exit_server_cleanly("termination signal");
-}
-
-static void epmd_setup_sig_term_handler(struct tevent_context *ev_ctx)
-{
- struct tevent_signal *se;
-
- se = tevent_add_signal(ev_ctx,
- ev_ctx,
- SIGTERM, 0,
- epmd_sig_term_handler,
- NULL);
- if (se == NULL) {
- exit_server("failed to setup SIGTERM handler");
- }
-}
-
-static void epmd_sig_hup_handler(struct tevent_context *ev,
- struct tevent_signal *se,
- int signum,
- int count,
- void *siginfo,
- void *private_data)
-{
- change_to_root_user();
-
- DEBUG(1,("Reloading printers after SIGHUP\n"));
- epmd_reopen_logs();
-}
-
-static void epmd_setup_sig_hup_handler(struct tevent_context *ev_ctx,
- struct messaging_context *msg_ctx)
-{
- struct tevent_signal *se;
-
- se = tevent_add_signal(ev_ctx,
- ev_ctx,
- SIGHUP, 0,
- epmd_sig_hup_handler,
- msg_ctx);
- if (se == NULL) {
- exit_server("failed to setup SIGHUP handler");
- }
-}
-
-void start_epmd(struct tevent_context *ev_ctx,
- struct messaging_context *msg_ctx,
- struct dcesrv_context *dce_ctx)
-{
- NTSTATUS status;
- pid_t pid;
- int rc;
- const struct dcesrv_endpoint_server *ep_server = NULL;
- struct dcesrv_endpoint *e = NULL;
-
- DEBUG(1, ("Forking Endpoint Mapper Daemon\n"));
-
- pid = fork();
-
- if (pid == -1) {
- DEBUG(0, ("Failed to fork Endpoint Mapper [%s], aborting ...\n",
- strerror(errno)));
- exit(1);
- }
-
- if (pid) {
- /* parent */
- return;
- }
-
- status = smbd_reinit_after_fork(msg_ctx, ev_ctx, true, "epmd");
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(0,("reinit_after_fork() failed\n"));
- smb_panic("reinit_after_fork() failed");
- }
-
- epmd_reopen_logs();
-
- epmd_setup_sig_term_handler(ev_ctx);
- epmd_setup_sig_hup_handler(ev_ctx, msg_ctx);
-
- messaging_register(msg_ctx,
- ev_ctx,
- MSG_SMB_CONF_UPDATED,
- epmd_smb_conf_updated);
-
- DBG_INFO("Registering DCE/RPC endpoint servers\n");
-
- /* Register the endpoint server in DCERPC core */
- ep_server = epmapper_get_ep_server();
- if (ep_server == NULL) {
- DBG_ERR("Failed to get 'epmapper' endpoint server\n");
- exit(1);
- }
-
- status = dcerpc_register_ep_server(ep_server);
- if (!NT_STATUS_IS_OK(status)) {
- DBG_ERR("Failed to register 'epmapper' endpoint server: %s\n",
- nt_errstr(status));
- exit(1);
- }
-
- DBG_INFO("Reinitializing DCE/RPC server context\n");
-
- status = dcesrv_reinit_context(dce_ctx);
- if (!NT_STATUS_IS_OK(status)) {
- DBG_ERR("Failed to reinit DCE/RPC context: %s\n",
- nt_errstr(status));
- exit(1);
- }
-
- DBG_INFO("Initializing DCE/RPC registered endpoint servers\n");
-
- status = dcesrv_init_ep_server(dce_ctx, "epmapper");
- if (!NT_STATUS_IS_OK(status)) {
- DBG_ERR("Failed to init DCE/RPC endpoint server: %s\n",
- nt_errstr(status));
- exit(1);
- }
-
- DBG_INFO("Initializing DCE/RPC connection endpoints\n");
-
- for (e = dce_ctx->endpoint_list; e; e = e->next) {
- enum dcerpc_transport_t transport =
- dcerpc_binding_get_transport(e->ep_description);
- dcerpc_ncacn_termination_fn term_fn = NULL;
-
- if (transport == NCACN_HTTP) {
- continue;
- }
-
- status = dcesrv_setup_endpoint_sockets(ev_ctx,
- msg_ctx,
- dce_ctx,
- e,
- term_fn,
- NULL); /* termination_data */
- if (!NT_STATUS_IS_OK(status)) {
- char *ep_string = dcerpc_binding_string(
- dce_ctx, e->ep_description);
- DBG_ERR("Failed to setup endpoint '%s': %s\n",
- ep_string, nt_errstr(status));
- TALLOC_FREE(ep_string);
- exit(1);
- }
- }
-
- DEBUG(1, ("Endpoint Mapper Daemon Started (%u)\n", (unsigned int)getpid()));
-
- /* loop forever */
- rc = tevent_loop_wait(ev_ctx);
-
- /* should not be reached */
- DEBUG(0,("background_queue: tevent_loop_wait() exited with %d - %s\n",
- rc, (rc == 0) ? "out of events" : strerror(errno)));
-
- exit(1);
-}
-
-/* vim: set ts=8 sw=8 noet cindent ft=c.doxygen: */
+++ /dev/null
-/*
- * Unix SMB/CIFS implementation.
- *
- * EPMD header file
- *
- * Copyright (c) 2018 Volker Lendecke <vl@samba.org>
- *
- * 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 3 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, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __RPC_SERVER_EPMD_H__
-#define __RPC_SERVER_EPMD_H__
-
-#include "replace.h"
-#include "messages.h"
-
-struct dcesrv_context;
-
-void start_epmd(struct tevent_context *ev_ctx,
- struct messaging_context *msg_ctx,
- struct dcesrv_context *dce_ctx);
-
-#endif
+++ /dev/null
-/*
- * File Server Shadow-Copy Daemon
- *
- * Copyright (C) David Disseldorp 2012-2015
- *
- * Based on epmd.c:
- * Copyright (c) 2011 Andreas Schneider <asn@samba.org>
- *
- * 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 3 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, see <http://www.gnu.org/licenses/>.
- */
-
-#include "includes.h"
-
-#include "ntdomain.h"
-#include "messages.h"
-
-#include "librpc/rpc/dcerpc_ep.h"
-
-#include "librpc/rpc/dcesrv_core.h"
-#include "librpc/gen_ndr/ndr_fsrvp_scompat.h"
-
-#include "rpc_server/rpc_server.h"
-#include "rpc_server/rpc_service_setup.h"
-#include "rpc_server/rpc_sock_helper.h"
-#include "rpc_server/fssd.h"
-
-#undef DBGC_CLASS
-#define DBGC_CLASS DBGC_RPC_SRV
-
-#define DAEMON_NAME "fssd"
-
-static void fssd_reopen_logs(void)
-{
- const struct loadparm_substitution *lp_sub =
- loadparm_s3_global_substitution();
- char *lfile = lp_logfile(NULL, lp_sub);
- int rc;
-
- if (lfile == NULL || lfile[0] == '\0') {
- rc = asprintf(&lfile, "%s/log.%s", get_dyn_LOGFILEBASE(), DAEMON_NAME);
- if (rc > 0) {
- lp_set_logfile(lfile);
- SAFE_FREE(lfile);
- }
- } else {
- if (strstr(lfile, DAEMON_NAME) == NULL) {
- rc = asprintf(&lfile, "%s.%s", lp_logfile(NULL, lp_sub), DAEMON_NAME);
- if (rc > 0) {
- lp_set_logfile(lfile);
- SAFE_FREE(lfile);
- }
- }
- }
-
- reopen_logs();
-}
-
-static void fssd_smb_conf_updated(struct messaging_context *msg,
- void *private_data,
- uint32_t msg_type,
- struct server_id server_id,
- DATA_BLOB *data)
-{
- DEBUG(10, ("Got message saying smb.conf was updated. Reloading.\n"));
- change_to_root_user();
- fssd_reopen_logs();
-}
-
-static void fssd_sig_term_handler(struct tevent_context *ev,
- struct tevent_signal *se,
- int signum,
- int count,
- void *siginfo,
- void *private_data)
-{
- exit_server_cleanly("termination signal");
-}
-
-static void fssd_setup_sig_term_handler(struct tevent_context *ev_ctx)
-{
- struct tevent_signal *se;
-
- se = tevent_add_signal(ev_ctx,
- ev_ctx,
- SIGTERM, 0,
- fssd_sig_term_handler,
- NULL);
- if (se == NULL) {
- exit_server("failed to setup SIGTERM handler");
- }
-}
-
-static void fssd_sig_hup_handler(struct tevent_context *ev,
- struct tevent_signal *se,
- int signum,
- int count,
- void *siginfo,
- void *private_data)
-{
- change_to_root_user();
-
- DEBUG(1,("reopening logs after SIGHUP\n"));
- fssd_reopen_logs();
-}
-
-static void fssd_setup_sig_hup_handler(struct tevent_context *ev_ctx,
- struct messaging_context *msg_ctx)
-{
- struct tevent_signal *se;
-
- se = tevent_add_signal(ev_ctx,
- ev_ctx,
- SIGHUP, 0,
- fssd_sig_hup_handler,
- msg_ctx);
- if (se == NULL) {
- exit_server("failed to setup SIGHUP handler");
- }
-}
-
-void start_fssd(struct tevent_context *ev_ctx,
- struct messaging_context *msg_ctx,
- struct dcesrv_context *dce_ctx)
-{
- NTSTATUS status;
- pid_t pid;
- int rc;
- const struct dcesrv_endpoint_server *ep_server = NULL;
- struct dcesrv_endpoint *e = NULL;
-
- DEBUG(1, ("Forking File Server Shadow-copy Daemon\n"));
-
- pid = fork();
-
- if (pid == -1) {
- DEBUG(0, ("failed to fork file server shadow-copy daemon [%s], "
- "aborting ...\n", strerror(errno)));
- exit(1);
- }
-
- if (pid) {
- /* parent */
- return;
- }
-
- /* child */
- status = smbd_reinit_after_fork(msg_ctx, ev_ctx, true, NULL);
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(0,("reinit_after_fork() failed\n"));
- smb_panic("reinit_after_fork() failed");
- }
-
- fssd_reopen_logs();
-
- fssd_setup_sig_term_handler(ev_ctx);
- fssd_setup_sig_hup_handler(ev_ctx, msg_ctx);
-
- messaging_register(msg_ctx,
- ev_ctx,
- MSG_SMB_CONF_UPDATED,
- fssd_smb_conf_updated);
-
- DBG_INFO("Registering DCE/RPC endpoint servers\n");
-
- ep_server = FileServerVssAgent_get_ep_server();
- if (ep_server == NULL) {
- DBG_ERR("Failed to get 'FileServerVssAgent' endpoint "
- "server\n");
- exit(1);
- }
-
- status = dcerpc_register_ep_server(ep_server);
- if (!NT_STATUS_IS_OK(status)) {
- DBG_ERR("Failed to register 'FileServerVssAgent' endpoint "
- "server: %s\n", nt_errstr(status));
- exit(1);
- }
-
- DBG_INFO("Reinitializing DCE/RPC server context\n");
-
- status = dcesrv_reinit_context(dce_ctx);
- if (!NT_STATUS_IS_OK(status)) {
- DBG_ERR("Failed to reinit DCE/RPC context: %s\n",
- nt_errstr(status));
- exit(1);
- }
-
- DBG_INFO("Initializing DCE/RPC registered endpoint servers\n");
-
- status = dcesrv_init_ep_server(dce_ctx, "FileServerVssAgent");
- if (!NT_STATUS_IS_OK(status)) {
- DBG_ERR("Failed to init DCE/RPC endpoint server: %s\n",
- nt_errstr(status));
- exit(1);
- }
-
- DBG_INFO("Initializing DCE/RPC connection endpoints\n");
-
- for (e = dce_ctx->endpoint_list; e; e = e->next) {
- status = dcesrv_setup_endpoint_sockets(ev_ctx,
- msg_ctx,
- dce_ctx,
- e,
- NULL, /* termination function */
- NULL); /* termination data */
- if (!NT_STATUS_IS_OK(status)) {
- char *ep_string = dcerpc_binding_string(
- dce_ctx, e->ep_description);
- DBG_ERR("Failed to setup endpoint '%s': %s\n",
- ep_string, nt_errstr(status));
- TALLOC_FREE(ep_string);
- exit(1);
- }
- }
-
- DEBUG(1, ("File Server Shadow-copy Daemon Started (%d)\n",
- (int)getpid()));
-
- /* loop forever */
- rc = tevent_loop_wait(ev_ctx);
-
- /* should not be reached */
- DEBUG(0,("tevent_loop_wait() exited with %d - %s\n",
- rc, (rc == 0) ? "out of events" : strerror(errno)));
-
- exit(1);
-}
+++ /dev/null
-/*
- * Unix SMB/CIFS implementation.
- *
- * FSSD header file
- *
- * Copyright (c) 2018 Volker Lendecke <vl@samba.org>
- *
- * 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 3 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, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __RPC_SERVER_FSSD_H__
-#define __RPC_SERVER_FSSD_H__
-
-#include "replace.h"
-#include "messages.h"
-
-struct dcesrv_context;
-
-void start_fssd(struct tevent_context *ev_ctx,
- struct messaging_context *msg_ctx,
- struct dcesrv_context *dce_ctx);
-
-#endif
+++ /dev/null
-/*
- * Unix SMB/CIFS implementation.
- *
- * LSA service daemon
- *
- * Copyright (c) 2011 Andreas Schneider <asn@samba.org>
- *
- * 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 3 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, see <http://www.gnu.org/licenses/>.
- */
-
-#include "includes.h"
-#include "messages.h"
-#include "ntdomain.h"
-#include "passdb.h"
-
-#include "lib/id_cache.h"
-
-#include "../lib/tsocket/tsocket.h"
-#include "lib/server_prefork.h"
-#include "lib/server_prefork_util.h"
-#include "librpc/rpc/dcerpc_ep.h"
-#include "librpc/rpc/dcesrv_core.h"
-
-#include "rpc_server/rpc_server.h"
-#include "rpc_server/rpc_ep_register.h"
-#include "rpc_server/rpc_sock_helper.h"
-#include "rpc_server/rpc_service_setup.h"
-
-#include "rpc_server/lsasd.h"
-
-#include "librpc/gen_ndr/ndr_lsa_scompat.h"
-#include "librpc/gen_ndr/ndr_samr_scompat.h"
-#include "librpc/gen_ndr/ndr_netlogon_scompat.h"
-#include "lib/global_contexts.h"
-
-#undef DBGC_CLASS
-#define DBGC_CLASS DBGC_RPC_SRV
-
-#define DAEMON_NAME "lsasd"
-
-static struct server_id parent_id;
-static struct prefork_pool *lsasd_pool = NULL;
-static int lsasd_child_id = 0;
-
-static const struct pf_daemon_config default_pf_lsasd_cfg = {
- .prefork_status = PFH_INIT,
- .min_children = 5,
- .max_children = 25,
- .spawn_rate = 5,
- .max_allowed_clients = 100,
- .child_min_life = 60 /* 1 minute minimum life time */
-};
-static struct pf_daemon_config pf_lsasd_cfg = { 0 };
-
-static void lsasd_reopen_logs(int child_id)
-{
- const struct loadparm_substitution *lp_sub =
- loadparm_s3_global_substitution();
- char *lfile = lp_logfile(talloc_tos(), lp_sub);
- char *extension;
- int rc;
-
- if (child_id) {
- rc = asprintf(&extension, "%s.%d", DAEMON_NAME, child_id);
- } else {
- rc = asprintf(&extension, "%s", DAEMON_NAME);
- }
- if (rc == -1) {
- return;
- }
-
- rc = 0;
- if (lfile == NULL || lfile[0] == '\0') {
- rc = asprintf(&lfile, "%s/log.%s",
- get_dyn_LOGFILEBASE(), extension);
- } else {
- if (strstr(lfile, extension) == NULL) {
- if (child_id) {
- rc = asprintf(&lfile, "%s.%d",
- lp_logfile(talloc_tos(), lp_sub),
- child_id);
- } else {
- rc = asprintf(&lfile, "%s.%s",
- lp_logfile(talloc_tos(), lp_sub),
- extension);
- }
- }
- }
-
- if (rc > 0) {
- lp_set_logfile(lfile);
- SAFE_FREE(lfile);
- }
-
- SAFE_FREE(extension);
-
- reopen_logs();
-}
-
-static void lsasd_smb_conf_updated(struct messaging_context *msg,
- void *private_data,
- uint32_t msg_type,
- struct server_id server_id,
- DATA_BLOB *data)
-{
- struct tevent_context *ev_ctx;
-
- DEBUG(10, ("Got message saying smb.conf was updated. Reloading.\n"));
- ev_ctx = talloc_get_type_abort(private_data, struct tevent_context);
-
- change_to_root_user();
- lp_load_global(get_dyn_CONFIGFILE());
-
- lsasd_reopen_logs(lsasd_child_id);
- if (lsasd_child_id == 0) {
- pfh_daemon_config(DAEMON_NAME,
- &pf_lsasd_cfg,
- &default_pf_lsasd_cfg);
- pfh_manage_pool(ev_ctx, msg, &pf_lsasd_cfg, lsasd_pool);
- }
-}
-
-static void lsasd_sig_term_handler(struct tevent_context *ev,
- struct tevent_signal *se,
- int signum,
- int count,
- void *siginfo,
- void *private_data)
-{
- exit_server_cleanly("termination signal");
-}
-
-static void lsasd_setup_sig_term_handler(struct tevent_context *ev_ctx)
-{
- struct tevent_signal *se;
-
- se = tevent_add_signal(ev_ctx,
- ev_ctx,
- SIGTERM, 0,
- lsasd_sig_term_handler,
- NULL);
- if (!se) {
- exit_server("failed to setup SIGTERM handler");
- }
-}
-
-static void lsasd_sig_hup_handler(struct tevent_context *ev,
- struct tevent_signal *se,
- int signum,
- int count,
- void *siginfo,
- void *pvt)
-{
-
- change_to_root_user();
- lp_load_global(get_dyn_CONFIGFILE());
-
- lsasd_reopen_logs(lsasd_child_id);
- pfh_daemon_config(DAEMON_NAME,
- &pf_lsasd_cfg,
- &default_pf_lsasd_cfg);
-
- /* relay to all children */
- prefork_send_signal_to_all(lsasd_pool, SIGHUP);
-}
-
-static void lsasd_setup_sig_hup_handler(struct tevent_context *ev_ctx)
-{
- struct tevent_signal *se;
-
- se = tevent_add_signal(ev_ctx,
- ev_ctx,
- SIGHUP, 0,
- lsasd_sig_hup_handler,
- NULL);
- if (!se) {
- DEBUG(0, ("failed to setup SIGHUP handler\n"));
- exit(1);
- }
-}
-
-/**********************************************************
- * Children
- **********************************************************/
-
-static void lsasd_chld_sig_hup_handler(struct tevent_context *ev,
- struct tevent_signal *se,
- int signum,
- int count,
- void *siginfo,
- void *pvt)
-{
- change_to_root_user();
- lsasd_reopen_logs(lsasd_child_id);
-}
-
-static bool lsasd_setup_chld_hup_handler(struct tevent_context *ev_ctx)
-{
- struct tevent_signal *se;
-
- se = tevent_add_signal(ev_ctx,
- ev_ctx,
- SIGHUP, 0,
- lsasd_chld_sig_hup_handler,
- NULL);
- if (!se) {
- DEBUG(1, ("failed to setup SIGHUP handler"));
- return false;
- }
-
- return true;
-}
-
-static void parent_ping(struct messaging_context *msg_ctx,
- void *private_data,
- uint32_t msg_type,
- struct server_id server_id,
- DATA_BLOB *data)
-{
-
- /* The fact we received this message is enough to let make the event
- * loop if it was idle. lsasd_children_main will cycle through
- * lsasd_next_client at least once. That function will take whatever
- * action is necessary */
-
- DEBUG(10, ("Got message that the parent changed status.\n"));
- return;
-}
-
-static bool lsasd_child_init(struct tevent_context *ev_ctx,
- int child_id,
- struct pf_worker_data *pf)
-{
- NTSTATUS status;
- struct messaging_context *msg_ctx = global_messaging_context();
- bool ok;
-
- status = reinit_after_fork(msg_ctx, ev_ctx,
- true, "lsasd-child");
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(0,("reinit_after_fork() failed\n"));
- smb_panic("reinit_after_fork() failed");
- }
- initialize_password_db(true, ev_ctx);
-
- lsasd_child_id = child_id;
- lsasd_reopen_logs(child_id);
-
- ok = lsasd_setup_chld_hup_handler(ev_ctx);
- if (!ok) {
- return false;
- }
-
- messaging_register(msg_ctx, ev_ctx,
- MSG_SMB_CONF_UPDATED, lsasd_smb_conf_updated);
- messaging_register(msg_ctx, ev_ctx,
- MSG_PREFORK_PARENT_EVENT, parent_ping);
- id_cache_register_msgs(msg_ctx);
-
- return true;
-}
-
-struct lsasd_children_data {
- struct tevent_context *ev_ctx;
- struct messaging_context *msg_ctx;
- struct dcesrv_context *dce_ctx;
- struct pf_worker_data *pf;
- int listen_fd_size;
- struct pf_listen_fd *listen_fds;
-};
-
-static void lsasd_next_client(void *pvt);
-
-static int lsasd_children_main(struct tevent_context *ev_ctx,
- struct messaging_context *msg_ctx,
- struct pf_worker_data *pf,
- int child_id,
- int listen_fd_size,
- struct pf_listen_fd *listen_fds,
- void *private_data)
-{
- struct lsasd_children_data *data;
- bool ok;
- int ret = 0;
- struct dcesrv_context *dce_ctx = NULL;
-
- dce_ctx = talloc_get_type_abort(private_data, struct dcesrv_context);
-
- ok = lsasd_child_init(ev_ctx, child_id, pf);
- if (!ok) {
- return 1;
- }
-
- data = talloc(ev_ctx, struct lsasd_children_data);
- if (!data) {
- return 1;
- }
- data->pf = pf;
- data->ev_ctx = ev_ctx;
- data->msg_ctx = msg_ctx;
- data->dce_ctx = dce_ctx;
- data->listen_fd_size = listen_fd_size;
- data->listen_fds = listen_fds;
-
- /* loop until it is time to exit */
- while (pf->status != PF_WORKER_EXITING) {
- /* try to see if it is time to schedule the next client */
- lsasd_next_client(data);
-
- ret = tevent_loop_once(ev_ctx);
- if (ret != 0) {
- DEBUG(0, ("tevent_loop_once() exited with %d: %s\n",
- ret, strerror(errno)));
- pf->status = PF_WORKER_EXITING;
- }
- }
-
- return ret;
-}
-
-static void lsasd_client_terminated(struct dcesrv_connection *conn, void *pvt)
-{
- struct lsasd_children_data *data;
-
- data = talloc_get_type_abort(pvt, struct lsasd_children_data);
-
- pfh_client_terminated(data->pf);
-
- lsasd_next_client(pvt);
-}
-
-struct lsasd_new_client {
- struct lsasd_children_data *data;
-};
-
-static void lsasd_handle_client(struct tevent_req *req);
-
-static void lsasd_next_client(void *pvt)
-{
- struct tevent_req *req;
- struct lsasd_children_data *data;
- struct lsasd_new_client *next;
-
- data = talloc_get_type_abort(pvt, struct lsasd_children_data);
-
- if (!pfh_child_allowed_to_accept(data->pf)) {
- /* nothing to do for now we are already listening
- * or we are not allowed to listen further */
- return;
- }
-
- next = talloc_zero(data, struct lsasd_new_client);
- if (!next) {
- DEBUG(1, ("Out of memory!?\n"));
- return;
- }
- next->data = data;
-
- req = prefork_listen_send(next,
- data->ev_ctx,
- data->pf,
- data->listen_fd_size,
- data->listen_fds);
- if (!req) {
- DEBUG(1, ("Failed to make listening request!?\n"));
- talloc_free(next);
- return;
- }
- tevent_req_set_callback(req, lsasd_handle_client, next);
-}
-
-static void lsasd_handle_client(struct tevent_req *req)
-{
- struct lsasd_children_data *data;
- struct lsasd_new_client *client;
- const DATA_BLOB ping = data_blob_null;
- int rc;
- int sd;
- TALLOC_CTX *tmp_ctx;
- struct tsocket_address *srv_addr;
- struct tsocket_address *cli_addr;
- void *listen_fd_data = NULL;
- struct dcesrv_endpoint *ep = NULL;
- enum dcerpc_transport_t transport;
- dcerpc_ncacn_termination_fn term_fn = NULL;
- void *term_fn_data = NULL;
-
- client = tevent_req_callback_data(req, struct lsasd_new_client);
- data = client->data;
-
- tmp_ctx = talloc_stackframe();
- if (tmp_ctx == NULL) {
- DEBUG(1, ("Failed to allocate stackframe!\n"));
- return;
- }
-
- rc = prefork_listen_recv(req,
- tmp_ctx,
- &sd,
- &listen_fd_data,
- &srv_addr,
- &cli_addr);
-
- /* this will free the request too */
- talloc_free(client);
-
- if (rc != 0) {
- DEBUG(6, ("No client connection was available after all!\n"));
- goto done;
- }
-
- ep = talloc_get_type_abort(listen_fd_data, struct dcesrv_endpoint);
- transport = dcerpc_binding_get_transport(ep->ep_description);
- if (transport == NCACN_NP) {
- term_fn = lsasd_client_terminated;
- term_fn_data = data;
- }
-
- /* Warn parent that our status changed */
- messaging_send(data->msg_ctx, parent_id,
- MSG_PREFORK_CHILD_EVENT, &ping);
-
- DBG_INFO("LSASD preforked child %d got client connection on '%s'\n",
- (int)(data->pf->pid), dcerpc_binding_string(tmp_ctx,
- ep->ep_description));
-
- dcerpc_ncacn_accept(data->ev_ctx,
- data->msg_ctx,
- data->dce_ctx,
- ep,
- &cli_addr,
- &srv_addr,
- sd,
- term_fn,
- term_fn_data);
-
-done:
- talloc_free(tmp_ctx);
-}
-
-/*
- * MAIN
- */
-
-static void child_ping(struct messaging_context *msg_ctx,
- void *private_data,
- uint32_t msg_type,
- struct server_id server_id,
- DATA_BLOB *data)
-{
- struct tevent_context *ev_ctx;
-
- ev_ctx = talloc_get_type_abort(private_data, struct tevent_context);
-
- DEBUG(10, ("Got message that a child changed status.\n"));
- pfh_manage_pool(ev_ctx, msg_ctx, &pf_lsasd_cfg, lsasd_pool);
-}
-
-static bool lsasd_schedule_check(struct tevent_context *ev_ctx,
- struct messaging_context *msg_ctx,
- struct timeval current_time);
-
-static void lsasd_check_children(struct tevent_context *ev_ctx,
- struct tevent_timer *te,
- struct timeval current_time,
- void *pvt);
-
-static void lsasd_sigchld_handler(struct tevent_context *ev_ctx,
- struct prefork_pool *pfp,
- void *pvt)
-{
- struct messaging_context *msg_ctx;
-
- msg_ctx = talloc_get_type_abort(pvt, struct messaging_context);
-
- /* run pool management so we can fork/retire or increase
- * the allowed connections per child based on load */
- pfh_manage_pool(ev_ctx, msg_ctx, &pf_lsasd_cfg, lsasd_pool);
-}
-
-static bool lsasd_setup_children_monitor(struct tevent_context *ev_ctx,
- struct messaging_context *msg_ctx)
-{
- bool ok;
-
- /* add our oun sigchld callback */
- prefork_set_sigchld_callback(lsasd_pool, lsasd_sigchld_handler, msg_ctx);
-
- ok = lsasd_schedule_check(ev_ctx, msg_ctx, tevent_timeval_current());
-
- return ok;
-}
-
-static bool lsasd_schedule_check(struct tevent_context *ev_ctx,
- struct messaging_context *msg_ctx,
- struct timeval current_time)
-{
- struct tevent_timer *te;
- struct timeval next_event;
-
- /* check situation again in 10 seconds */
- next_event = tevent_timeval_current_ofs(10, 0);
-
- /* TODO: check when the socket becomes readable, so that children
- * are checked only when there is some activity ? */
- te = tevent_add_timer(ev_ctx, lsasd_pool, next_event,
- lsasd_check_children, msg_ctx);
- if (!te) {
- DEBUG(2, ("Failed to set up children monitoring!\n"));
- return false;
- }
-
- return true;
-}
-
-static void lsasd_check_children(struct tevent_context *ev_ctx,
- struct tevent_timer *te,
- struct timeval current_time,
- void *pvt)
-{
- struct messaging_context *msg_ctx;
-
- msg_ctx = talloc_get_type_abort(pvt, struct messaging_context);
-
- pfh_manage_pool(ev_ctx, msg_ctx, &pf_lsasd_cfg, lsasd_pool);
-
- lsasd_schedule_check(ev_ctx, msg_ctx, current_time);
-}
-
-/*
- * start it up
- */
-
-static NTSTATUS lsasd_create_sockets(struct tevent_context *ev_ctx,
- struct messaging_context *msg_ctx,
- struct dcesrv_context *dce_ctx,
- TALLOC_CTX *mem_ctx,
- struct pf_listen_fd **plisten_fds,
- size_t *pnum_listen_fds)
-{
- NTSTATUS status;
- size_t i, num_fds;
- struct pf_listen_fd *fds = NULL;
- int rc;
- struct dcesrv_endpoint *e = dce_ctx->endpoint_list;
-
- DBG_INFO("Initializing DCE/RPC connection endpoints\n");
-
- status = dcesrv_create_endpoint_list_pf_listen_fds(
- ev_ctx, msg_ctx, dce_ctx, e, mem_ctx, &num_fds, &fds);
- if (!NT_STATUS_IS_OK(status)) {
- return status;
- }
-
- for (i = 0; i < num_fds; i++) {
- rc = listen(fds[i].fd, pf_lsasd_cfg.max_allowed_clients);
- if (rc == -1) {
- char *ep_string = NULL;
- e = fds[i].fd_data;
-
- ep_string = dcerpc_binding_string(dce_ctx,
- e->ep_description);
- DBG_ERR("Failed to listen on endpoint '%s': %s\n",
- ep_string, strerror(errno));
- status = map_nt_error_from_unix(errno);
- TALLOC_FREE(ep_string);
- goto done;
- }
- }
-
- for (e = dce_ctx->endpoint_list; e; e = e->next) {
- struct dcesrv_if_list *ifl = NULL;
- for (ifl = e->interface_list; ifl; ifl = ifl->next) {
- status = rpc_ep_register(ev_ctx,
- msg_ctx,
- dce_ctx,
- ifl->iface);
- if (!NT_STATUS_IS_OK(status)) {
- DBG_ERR("Failed to register interface in "
- "endpoint mapper: %s",
- nt_errstr(status));
- goto done;
- }
- }
- }
-
- *plisten_fds = fds;
- *pnum_listen_fds = num_fds;
-
- status = NT_STATUS_OK;
-done:
- return status;
-}
-
-void start_lsasd(struct tevent_context *ev_ctx,
- struct messaging_context *msg_ctx,
- struct dcesrv_context *dce_ctx)
-{
- NTSTATUS status;
- struct pf_listen_fd *listen_fd = NULL;
- size_t listen_fd_size = 0;
- pid_t pid;
- int rc;
- bool ok;
- const struct dcesrv_endpoint_server *ep_server = NULL;
- const char *ep_servers[] = { "lsarpc", "samr", "netlogon", NULL };
-
- DEBUG(1, ("Forking LSA Service Daemon\n"));
-
- /*
- * Block signals before forking child as it will have to
- * set its own handlers. Child will re-enable SIGHUP as
- * soon as the handlers are set up.
- */
- BlockSignals(true, SIGTERM);
- BlockSignals(true, SIGHUP);
-
- pid = fork();
- if (pid == -1) {
- DEBUG(0, ("Failed to fork LSASD [%s], aborting ...\n",
- strerror(errno)));
- exit(1);
- }
-
- /* parent or error */
- if (pid != 0) {
-
- /* Re-enable SIGHUP before returnig */
- BlockSignals(false, SIGTERM);
- BlockSignals(false, SIGHUP);
-
- return;
- }
-
- status = smbd_reinit_after_fork(msg_ctx, ev_ctx, true, "lsasd-master");
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(0,("reinit_after_fork() failed\n"));
- smb_panic("reinit_after_fork() failed");
- }
- initialize_password_db(true, ev_ctx);
-
- /* save the parent process id so the children can use it later */
- parent_id = messaging_server_id(msg_ctx);
-
- lsasd_reopen_logs(0);
- pfh_daemon_config(DAEMON_NAME,
- &pf_lsasd_cfg,
- &default_pf_lsasd_cfg);
-
- lsasd_setup_sig_term_handler(ev_ctx);
- lsasd_setup_sig_hup_handler(ev_ctx);
-
- BlockSignals(false, SIGTERM);
- BlockSignals(false, SIGHUP);
-
- DBG_INFO("Registering DCE/RPC endpoint servers\n");
-
- ep_server = lsarpc_get_ep_server();
- if (ep_server == NULL) {
- DBG_ERR("Failed to get 'lsarpc' endpoint server\n");
- exit(1);
- }
-
- status = dcerpc_register_ep_server(ep_server);
- if (!NT_STATUS_IS_OK(status)) {
- DBG_ERR("Failed to register 'lsarpc' endpoint server: %s\n",
- nt_errstr(status));
- exit(1);
- }
-
- ep_server = samr_get_ep_server();
- if (ep_server == NULL) {
- DBG_ERR("Failed to get 'samr' endpoint server\n");
- exit(1);
- }
-
- status = dcerpc_register_ep_server(ep_server);
- if (!NT_STATUS_IS_OK(status)) {
- DBG_ERR("Failed to register 'samr' endpoint server: %s\n",
- nt_errstr(status));
- exit(1);
- }
-
- ep_server = netlogon_get_ep_server();
- if (ep_server == NULL) {
- DBG_ERR("Failed to get 'netlogon' endpoint server\n");
- exit(1);
- }
-
- status = dcerpc_register_ep_server(ep_server);
- if (!NT_STATUS_IS_OK(status)) {
- DBG_ERR("Failed to register 'netlogon' endpoint server: %s\n",
- nt_errstr(status));
- exit(1);
- }
-
- DBG_INFO("Reinitializing DCE/RPC server context\n");
-
- status = dcesrv_reinit_context(dce_ctx);
- if (!NT_STATUS_IS_OK(status)) {
- DBG_ERR("Failed to reinit DCE/RPC context: %s\n",
- nt_errstr(status));
- exit(1);
- }
-
- DBG_INFO("Initializing DCE/RPC registered endpoint servers\n");
-
- /* Init ep servers */
- status = dcesrv_init_ep_servers(dce_ctx, ep_servers);
- if (!NT_STATUS_IS_OK(status)) {
- DBG_ERR("Failed to init DCE/RPC endpoint server: %s\n",
- nt_errstr(status));
- exit(1);
- }
-
- status = lsasd_create_sockets(ev_ctx,
- msg_ctx,
- dce_ctx,
- dce_ctx,
- &listen_fd,
- &listen_fd_size);
- if (!NT_STATUS_IS_OK(status)) {
- exit(1);
- }
-
- /* start children before any more initialization is done */
- ok = prefork_create_pool(ev_ctx, /* mem_ctx */
- ev_ctx,
- msg_ctx,
- listen_fd_size,
- listen_fd,
- pf_lsasd_cfg.min_children,
- pf_lsasd_cfg.max_children,
- &lsasd_children_main,
- dce_ctx,
- &lsasd_pool);
- TALLOC_FREE(listen_fd);
- if (!ok) {
- exit(1);
- }
-
- messaging_register(msg_ctx,
- ev_ctx,
- MSG_SMB_CONF_UPDATED,
- lsasd_smb_conf_updated);
- messaging_register(msg_ctx, ev_ctx,
- MSG_PREFORK_CHILD_EVENT, child_ping);
-
- ok = lsasd_setup_children_monitor(ev_ctx, msg_ctx);
- if (!ok) {
- DEBUG(0, ("Failed to setup children monitoring!\n"));
- exit(1);
- }
-
- DEBUG(1, ("LSASD Daemon Started (%u)\n", (unsigned int)getpid()));
-
- /* loop forever */
- rc = tevent_loop_wait(ev_ctx);
-
- /* should not be reached */
- DEBUG(0,("lsasd: tevent_loop_wait() exited with %d - %s\n",
- rc, (rc == 0) ? "out of events" : strerror(errno)));
- exit(1);
-}
+++ /dev/null
-/*
- * Unix SMB/CIFS implementation.
- *
- * LSASD header file
- *
- * Copyright (c) 2018 Volker Lendecke <vl@samba.org>
- *
- * 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 3 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, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __RPC_SERVER_LSASD_H__
-#define __RPC_SERVER_LSASD_H__
-
-#include "replace.h"
-#include "messages.h"
-
-struct dcesrv_context;
-
-void start_lsasd(struct tevent_context *ev_ctx,
- struct messaging_context *msg_ctx,
- struct dcesrv_context *dce_ctx);
-
-#endif
+++ /dev/null
-/*
- * Unix SMB/CIFS implementation.
- *
- * mds service daemon
- *
- * Copyright (c) 2014 Ralph Boehme <rb@sernet.de>
- *
- * 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 3 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, see <http://www.gnu.org/licenses/>.
- */
-
-#include "includes.h"
-#include "messages.h"
-#include "ntdomain.h"
-
-#include "lib/id_cache.h"
-
-#include "../lib/tsocket/tsocket.h"
-#include "lib/server_prefork.h"
-#include "lib/server_prefork_util.h"
-#include "librpc/rpc/dcerpc_ep.h"
-#include "librpc/rpc/dcesrv_core.h"
-
-#include "rpc_server/rpc_server.h"
-#include "rpc_server/rpc_service_setup.h"
-#include "rpc_server/rpc_ep_register.h"
-#include "rpc_server/rpc_sock_helper.h"
-#include "rpc_server/rpc_modules.h"
-
-#include "rpc_server/mdssvc/srv_mdssvc_nt.h"
-#include "rpc_server/mdssd.h"
-#include "lib/global_contexts.h"
-
-#undef DBGC_CLASS
-#define DBGC_CLASS DBGC_RPC_SRV
-
-#define DAEMON_NAME "mdssd"
-
-static struct server_id parent_id;
-static struct prefork_pool *mdssd_pool = NULL;
-static int mdssd_child_id = 0;
-
-static const struct pf_daemon_config default_pf_mdssd_cfg = {
- .prefork_status = PFH_INIT,
- .min_children = 5,
- .max_children = 25,
- .spawn_rate = 5,
- .max_allowed_clients = 1000,
- .child_min_life = 60 /* 1 minute minimum life time */
-};
-static struct pf_daemon_config pf_mdssd_cfg = { 0 };
-
-static void mdssd_smb_conf_updated(struct messaging_context *msg,
- void *private_data,
- uint32_t msg_type,
- struct server_id server_id,
- DATA_BLOB *data)
-{
- struct tevent_context *ev_ctx;
-
- DEBUG(10, ("Got message saying smb.conf was updated. Reloading.\n"));
- ev_ctx = talloc_get_type_abort(private_data, struct tevent_context);
-
- change_to_root_user();
- lp_load_global(get_dyn_CONFIGFILE());
-
- reopen_logs();
- if (mdssd_child_id == 0) {
- pfh_daemon_config(DAEMON_NAME,
- &pf_mdssd_cfg,
- &default_pf_mdssd_cfg);
- pfh_manage_pool(ev_ctx, msg, &pf_mdssd_cfg, mdssd_pool);
- }
-}
-
-static void mdssd_sig_term_handler(struct tevent_context *ev,
- struct tevent_signal *se,
- int signum,
- int count,
- void *siginfo,
- void *private_data)
-{
- exit_server_cleanly("termination signal");
-}
-
-static void mdssd_setup_sig_term_handler(struct tevent_context *ev_ctx)
-{
- struct tevent_signal *se;
-
- se = tevent_add_signal(ev_ctx,
- ev_ctx,
- SIGTERM, 0,
- mdssd_sig_term_handler,
- NULL);
- if (!se) {
- exit_server("failed to setup SIGTERM handler");
- }
-}
-
-static void mdssd_sig_hup_handler(struct tevent_context *ev,
- struct tevent_signal *se,
- int signum,
- int count,
- void *siginfo,
- void *pvt)
-{
-
- change_to_root_user();
- lp_load_global(get_dyn_CONFIGFILE());
-
- reopen_logs();
- pfh_daemon_config(DAEMON_NAME,
- &pf_mdssd_cfg,
- &default_pf_mdssd_cfg);
-
- /* relay to all children */
- prefork_send_signal_to_all(mdssd_pool, SIGHUP);
-}
-
-static void mdssd_setup_sig_hup_handler(struct tevent_context *ev_ctx)
-{
- struct tevent_signal *se;
-
- se = tevent_add_signal(ev_ctx,
- ev_ctx,
- SIGHUP, 0,
- mdssd_sig_hup_handler,
- NULL);
- if (!se) {
- DEBUG(0, ("failed to setup SIGHUP handler\n"));
- exit(1);
- }
-}
-
-/**********************************************************
- * Children
- **********************************************************/
-
-static void mdssd_chld_sig_hup_handler(struct tevent_context *ev,
- struct tevent_signal *se,
- int signum,
- int count,
- void *siginfo,
- void *pvt)
-{
- change_to_root_user();
- reopen_logs();
-}
-
-static bool mdssd_setup_chld_hup_handler(struct tevent_context *ev_ctx)
-{
- struct tevent_signal *se;
-
- se = tevent_add_signal(ev_ctx,
- ev_ctx,
- SIGHUP, 0,
- mdssd_chld_sig_hup_handler,
- NULL);
- if (!se) {
- DEBUG(1, ("failed to setup SIGHUP handler"));
- return false;
- }
-
- return true;
-}
-
-static void parent_ping(struct messaging_context *msg_ctx,
- void *private_data,
- uint32_t msg_type,
- struct server_id server_id,
- DATA_BLOB *data)
-{
- /*
- * The fact we received this message is enough to let make the
- * event loop if it was idle. mdssd_children_main will cycle
- * through mdssd_next_client at least once. That function will
- * take whatever action is necessary
- */
- DEBUG(10, ("Got message that the parent changed status.\n"));
- return;
-}
-
-static bool mdssd_child_init(struct tevent_context *ev_ctx,
- int child_id,
- struct pf_worker_data *pf)
-{
- NTSTATUS status;
- struct messaging_context *msg_ctx = global_messaging_context();
- bool ok;
-
- status = reinit_after_fork(msg_ctx, ev_ctx,
- true, "mdssd-child");
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(0,("reinit_after_fork() failed\n"));
- smb_panic("reinit_after_fork() failed");
- }
-
- mdssd_child_id = child_id;
- reopen_logs();
-
- ok = mdssd_setup_chld_hup_handler(ev_ctx);
- if (!ok) {
- return false;
- }
-
- messaging_register(msg_ctx, ev_ctx,
- MSG_SMB_CONF_UPDATED, mdssd_smb_conf_updated);
- messaging_register(msg_ctx, ev_ctx,
- MSG_PREFORK_PARENT_EVENT, parent_ping);
-
- return true;
-}
-
-struct mdssd_children_data {
- struct tevent_context *ev_ctx;
- struct messaging_context *msg_ctx;
- struct dcesrv_context *dce_ctx;
- struct pf_worker_data *pf;
- int listen_fd_size;
- struct pf_listen_fd *listen_fds;
-};
-
-static void mdssd_next_client(void *pvt);
-
-static int mdssd_children_main(struct tevent_context *ev_ctx,
- struct messaging_context *msg_ctx,
- struct pf_worker_data *pf,
- int child_id,
- int listen_fd_size,
- struct pf_listen_fd *listen_fds,
- void *private_data)
-{
- struct mdssd_children_data *data;
- bool ok;
- int ret = 0;
- struct dcesrv_context *dce_ctx = NULL;
-
- dce_ctx = talloc_get_type_abort(private_data, struct dcesrv_context);
-
- ok = mdssd_child_init(ev_ctx, child_id, pf);
- if (!ok) {
- return 1;
- }
-
- data = talloc(ev_ctx, struct mdssd_children_data);
- if (!data) {
- return 1;
- }
- data->pf = pf;
- data->ev_ctx = ev_ctx;
- data->msg_ctx = msg_ctx;
- data->dce_ctx = dce_ctx;
- data->listen_fd_size = listen_fd_size;
- data->listen_fds = listen_fds;
-
- /* loop until it is time to exit */
- while (pf->status != PF_WORKER_EXITING) {
- /* try to see if it is time to schedule the next client */
- mdssd_next_client(data);
-
- ret = tevent_loop_once(ev_ctx);
- if (ret != 0) {
- DEBUG(0, ("tevent_loop_once() exited with %d: %s\n",
- ret, strerror(errno)));
- pf->status = PF_WORKER_EXITING;
- }
- }
-
- return ret;
-}
-
-static void mdssd_client_terminated(struct dcesrv_connection *conn, void *pvt)
-{
- struct mdssd_children_data *data;
-
- data = talloc_get_type_abort(pvt, struct mdssd_children_data);
-
- pfh_client_terminated(data->pf);
-
- mdssd_next_client(pvt);
-}
-
-struct mdssd_new_client {
- struct mdssd_children_data *data;
-};
-
-static void mdssd_handle_client(struct tevent_req *req);
-
-static void mdssd_next_client(void *pvt)
-{
- struct tevent_req *req;
- struct mdssd_children_data *data;
- struct mdssd_new_client *next;
-
- data = talloc_get_type_abort(pvt, struct mdssd_children_data);
-
- if (!pfh_child_allowed_to_accept(data->pf)) {
- /* nothing to do for now we are already listening
- * or we are not allowed to listen further */
- return;
- }
-
- next = talloc_zero(data, struct mdssd_new_client);
- if (!next) {
- DEBUG(1, ("Out of memory!?\n"));
- return;
- }
- next->data = data;
-
- req = prefork_listen_send(next,
- data->ev_ctx,
- data->pf,
- data->listen_fd_size,
- data->listen_fds);
- if (!req) {
- DEBUG(1, ("Failed to make listening request!?\n"));
- talloc_free(next);
- return;
- }
- tevent_req_set_callback(req, mdssd_handle_client, next);
-}
-
-static void mdssd_handle_client(struct tevent_req *req)
-{
- struct mdssd_children_data *data;
- struct mdssd_new_client *client;
- const DATA_BLOB ping = data_blob_null;
- int rc;
- int sd;
- TALLOC_CTX *tmp_ctx;
- struct tsocket_address *srv_addr;
- struct tsocket_address *cli_addr;
- void *listen_fd_data = NULL;
- struct dcesrv_endpoint *ep = NULL;
- enum dcerpc_transport_t transport;
- dcerpc_ncacn_termination_fn term_fn = NULL;
- void *term_fn_data = NULL;
-
- client = tevent_req_callback_data(req, struct mdssd_new_client);
- data = client->data;
-
- tmp_ctx = talloc_stackframe();
- if (tmp_ctx == NULL) {
- DEBUG(1, ("Failed to allocate stackframe!\n"));
- return;
- }
-
- rc = prefork_listen_recv(req,
- tmp_ctx,
- &sd,
- &listen_fd_data,
- &srv_addr,
- &cli_addr);
-
- /* this will free the request too */
- talloc_free(client);
-
- if (rc != 0) {
- DEBUG(6, ("No client connection was available after all!\n"));
- goto done;
- }
-
- ep = talloc_get_type_abort(listen_fd_data, struct dcesrv_endpoint);
- transport = dcerpc_binding_get_transport(ep->ep_description);
- if (transport == NCACN_NP) {
- term_fn = mdssd_client_terminated;
- term_fn_data = data;
- }
-
- /* Warn parent that our status changed */
- messaging_send(data->msg_ctx, parent_id,
- MSG_PREFORK_CHILD_EVENT, &ping);
-
- DBG_INFO("MDSSD preforked child %d got client connection on '%s'\n",
- (int)(data->pf->pid), dcerpc_binding_string(tmp_ctx,
- ep->ep_description));
-
- dcerpc_ncacn_accept(data->ev_ctx,
- data->msg_ctx,
- data->dce_ctx,
- ep,
- &cli_addr,
- &srv_addr,
- sd,
- term_fn,
- term_fn_data);
-
-done:
- talloc_free(tmp_ctx);
-}
-
-/*
- * MAIN
- */
-
-static void child_ping(struct messaging_context *msg_ctx,
- void *private_data,
- uint32_t msg_type,
- struct server_id server_id,
- DATA_BLOB *data)
-{
- struct tevent_context *ev_ctx;
-
- ev_ctx = talloc_get_type_abort(private_data, struct tevent_context);
-
- DEBUG(10, ("Got message that a child changed status.\n"));
- pfh_manage_pool(ev_ctx, msg_ctx, &pf_mdssd_cfg, mdssd_pool);
-}
-
-static bool mdssd_schedule_check(struct tevent_context *ev_ctx,
- struct messaging_context *msg_ctx,
- struct timeval current_time);
-
-static void mdssd_check_children(struct tevent_context *ev_ctx,
- struct tevent_timer *te,
- struct timeval current_time,
- void *pvt);
-
-static void mdssd_sigchld_handler(struct tevent_context *ev_ctx,
- struct prefork_pool *pfp,
- void *pvt)
-{
- struct messaging_context *msg_ctx;
-
- msg_ctx = talloc_get_type_abort(pvt, struct messaging_context);
-
- /* run pool management so we can fork/retire or increase
- * the allowed connections per child based on load */
- pfh_manage_pool(ev_ctx, msg_ctx, &pf_mdssd_cfg, mdssd_pool);
-}
-
-static bool mdssd_setup_children_monitor(struct tevent_context *ev_ctx,
- struct messaging_context *msg_ctx)
-{
- bool ok;
-
- /* add our oun sigchld callback */
- prefork_set_sigchld_callback(mdssd_pool, mdssd_sigchld_handler, msg_ctx);
-
- ok = mdssd_schedule_check(ev_ctx, msg_ctx, tevent_timeval_current());
-
- return ok;
-}
-
-static bool mdssd_schedule_check(struct tevent_context *ev_ctx,
- struct messaging_context *msg_ctx,
- struct timeval current_time)
-{
- struct tevent_timer *te;
- struct timeval next_event;
-
- /* check situation again in 10 seconds */
- next_event = tevent_timeval_current_ofs(10, 0);
-
- /* TODO: check when the socket becomes readable, so that children
- * are checked only when there is some activity ? */
- te = tevent_add_timer(ev_ctx, mdssd_pool, next_event,
- mdssd_check_children, msg_ctx);
- if (!te) {
- DEBUG(2, ("Failed to set up children monitoring!\n"));
- return false;
- }
-
- return true;
-}
-
-static void mdssd_check_children(struct tevent_context *ev_ctx,
- struct tevent_timer *te,
- struct timeval current_time,
- void *pvt)
-{
- struct messaging_context *msg_ctx;
-
- msg_ctx = talloc_get_type_abort(pvt, struct messaging_context);
-
- pfh_manage_pool(ev_ctx, msg_ctx, &pf_mdssd_cfg, mdssd_pool);
-
- mdssd_schedule_check(ev_ctx, msg_ctx, current_time);
-}
-
-/*
- * start it up
- */
-
-static NTSTATUS mdssd_create_sockets(struct tevent_context *ev_ctx,
- struct messaging_context *msg_ctx,
- struct dcesrv_context *dce_ctx,
- TALLOC_CTX *mem_ctx,
- struct pf_listen_fd **plisten_fds,
- size_t *pnum_listen_fds)
-{
- NTSTATUS status;
- size_t i, num_fds;
- struct pf_listen_fd *fds = NULL;
- int rc;
- struct dcesrv_endpoint *e = dce_ctx->endpoint_list;
-
- DBG_INFO("Initializing DCE/RPC connection endpoints\n");
-
- status = dcesrv_create_endpoint_list_pf_listen_fds(
- ev_ctx, msg_ctx, dce_ctx, e, mem_ctx, &num_fds, &fds);
- if (!NT_STATUS_IS_OK(status)) {
- return status;
- }
-
- for (i = 0; i < num_fds; i++) {
- rc = listen(fds[i].fd, pf_mdssd_cfg.max_allowed_clients);
- if (rc == -1) {
- char *ep_string = NULL;
- e = fds[i].fd_data;
-
- ep_string = dcerpc_binding_string(dce_ctx,
- e->ep_description);
- DBG_ERR("Failed to listen on endpoint '%s': %s\n",
- ep_string, strerror(errno));
- status = map_nt_error_from_unix(errno);
- TALLOC_FREE(ep_string);
- goto done;
- }
- }
-
- for (e = dce_ctx->endpoint_list; e; e = e->next) {
- struct dcesrv_if_list *ifl = NULL;
- for (ifl = e->interface_list; ifl; ifl = ifl->next) {
- status = rpc_ep_register(ev_ctx,
- msg_ctx,
- dce_ctx,
- ifl->iface);
- if (!NT_STATUS_IS_OK(status)) {
- DBG_ERR("Failed to register interface in "
- "endpoint mapper: %s",
- nt_errstr(status));
- goto done;
- }
- }
- }
-
- *plisten_fds = fds;
- *pnum_listen_fds = num_fds;
-
- status = NT_STATUS_OK;
-done:
- return status;
-}
-
-void start_mdssd(struct tevent_context *ev_ctx,
- struct messaging_context *msg_ctx,
- struct dcesrv_context *dce_ctx)
-{
- NTSTATUS status;
- struct pf_listen_fd *listen_fd = NULL;
- size_t listen_fd_size = 0;
- pid_t pid;
- int rc;
- bool ok;
-
- DEBUG(1, ("Forking Metadata Service Daemon\n"));
-
- /*
- * Block signals before forking child as it will have to
- * set its own handlers. Child will re-enable SIGHUP as
- * soon as the handlers are set up.
- */
- BlockSignals(true, SIGTERM);
- BlockSignals(true, SIGHUP);
-
- pid = fork();
- if (pid == -1) {
- DEBUG(0, ("Failed to fork mdssd [%s], aborting ...\n",
- strerror(errno)));
- exit(1);
- }
-
- /* parent or error */
- if (pid != 0) {
-
- /* Re-enable SIGHUP before returnig */
- BlockSignals(false, SIGTERM);
- BlockSignals(false, SIGHUP);
-
- return;
- }
-
- status = smbd_reinit_after_fork(msg_ctx, ev_ctx, true, "mdssd-master");
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(0,("reinit_after_fork() failed\n"));
- smb_panic("reinit_after_fork() failed");
- }
-
- reopen_logs();
-
- /* save the parent process id so the children can use it later */
- parent_id = messaging_server_id(msg_ctx);
-
- pfh_daemon_config(DAEMON_NAME,
- &pf_mdssd_cfg,
- &default_pf_mdssd_cfg);
-
- mdssd_setup_sig_term_handler(ev_ctx);
- mdssd_setup_sig_hup_handler(ev_ctx);
-
- BlockSignals(false, SIGTERM);
- BlockSignals(false, SIGHUP);
-
- /* The module setup function will register the endpoint server,
- * necessary to setup the endpoints below. It is not possible to
- * register it here because MDS service is built as a module.
- */
- ok = setup_rpc_module(ev_ctx, msg_ctx, "mdssvc");
- if (!ok) {
- DBG_ERR("Failed to setup DCE/RPC module\n");
- exit(1);
- }
-
- DBG_INFO("Reinitializing DCE/RPC server context\n");
-
- status = dcesrv_reinit_context(dce_ctx);
- if (!NT_STATUS_IS_OK(status)) {
- DBG_ERR("Failed to reinit DCE/RPC context: %s\n",
- nt_errstr(status));
- exit(1);
- }
-
- DBG_INFO("Initializing DCE/RPC registered endpoint servers\n");
-
- /* Init ep servers */
- status = dcesrv_init_ep_server(dce_ctx, "mdssvc");
- if (!NT_STATUS_IS_OK(status)) {
- DBG_ERR("Failed to init DCE/RPC endpoint server: %s\n",
- nt_errstr(status));
- exit(1);
- }
-
- status = mdssd_create_sockets(ev_ctx,
- msg_ctx,
- dce_ctx,
- dce_ctx,
- &listen_fd,
- &listen_fd_size);
- if (!NT_STATUS_IS_OK(status)) {
- exit(1);
- }
-
- /* start children before any more initialization is done */
- ok = prefork_create_pool(ev_ctx, /* mem_ctx */
- ev_ctx,
- msg_ctx,
- listen_fd_size,
- listen_fd,
- pf_mdssd_cfg.min_children,
- pf_mdssd_cfg.max_children,
- &mdssd_children_main,
- dce_ctx,
- &mdssd_pool);
- TALLOC_FREE(listen_fd);
- if (!ok) {
- exit(1);
- }
-
- messaging_register(msg_ctx,
- ev_ctx,
- MSG_SMB_CONF_UPDATED,
- mdssd_smb_conf_updated);
- messaging_register(msg_ctx, ev_ctx,
- MSG_PREFORK_CHILD_EVENT, child_ping);
-
- ok = mdssd_setup_children_monitor(ev_ctx, msg_ctx);
- if (!ok) {
- exit(1);
- }
-
- DEBUG(1, ("mdssd Daemon Started (%u)\n", (unsigned int)getpid()));
-
- /* loop forever */
- rc = tevent_loop_wait(ev_ctx);
-
- /* should not be reached */
- DEBUG(0,("mdssd: tevent_loop_wait() exited with %d - %s\n",
- rc, (rc == 0) ? "out of events" : strerror(errno)));
- exit(1);
-}
+++ /dev/null
-/*
- * Unix SMB/CIFS implementation.
- *
- * MDSSD header file
- *
- * Copyright (c) 2018 Volker Lendecke <vl@samba.org>
- *
- * 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 3 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, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef __RPC_SERVER_MDSSD_H__
-#define __RPC_SERVER_MDSSD_H__
-
-#include "replace.h"
-#include "messages.h"
-
-struct dcesrv_context;
-
-void start_mdssd(struct tevent_context *ev_ctx,
- struct messaging_context *msg_ctx,
- struct dcesrv_context *dce_ctx);
-
-#endif
{
TALLOC_FREE(global_dcesrv_ctx);
}
-
-#if 0
-/* the default is "embedded" so this table
- * lists only services that are not using
- * the default in order to keep enumerating it
- * in rpc_service_mode() as short as possible
- */
-struct rpc_service_defaults {
- const char *name;
- const char *def_mode;
-} rpc_service_defaults[] = {
- { "epmapper", "disabled" },
- /* { "mdssvc", "embedded" }, */
- /* { "spoolss", "embedded" }, */
- /* { "lsarpc", "embedded" }, */
- /* { "samr", "embedded" }, */
- /* { "netlogon", "embedded" }, */
- { "fssagentrpc", "external" },
-
- { NULL, NULL }
-};
-
-enum rpc_service_mode_e rpc_service_mode(const char *name)
-{
- const char *pipe_name = name;
- const char *rpcsrv_type;
- enum rpc_service_mode_e state;
- const char *def;
- enum server_role server_role = lp_server_role();
- int i;
-
- /* Handle pipes with multiple names */
- if (strcmp(pipe_name, "lsass") == 0) {
- pipe_name = "lsarpc";
- } else if (strcmp(pipe_name, "plugplay") == 0) {
- pipe_name = "ntsvcs";
- }
-
- def = lp_parm_const_string(GLOBAL_SECTION_SNUM,
- "rpc_server", "default", NULL);
- if (def == NULL) {
- for (i = 0; rpc_service_defaults[i].name; i++) {
- if (strcasecmp_m(pipe_name, rpc_service_defaults[i].name) == 0) {
- def = rpc_service_defaults[i].def_mode;
- break;
- }
- }
- /* if the default is unspecified then use 'embedded' */
- if (def == NULL) {
- def = "embedded";
- }
- }
-
- /*
- * Only enable the netlogon server by default if we are a
- * classic/NT4 domain controller
- */
- if (strcasecmp_m(name, "netlogon") == 0) {
- switch (server_role) {
- case ROLE_STANDALONE:
- case ROLE_DOMAIN_MEMBER:
- def = "disabled";
- break;
- default:
- break;
- }
- }
-
- rpcsrv_type = lp_parm_const_string(GLOBAL_SECTION_SNUM,
- "rpc_server", pipe_name, def);
-
- if (strcasecmp_m(rpcsrv_type, "embedded") == 0) {
- state = RPC_SERVICE_MODE_EMBEDDED;
- } else if (strcasecmp_m(rpcsrv_type, "external") == 0) {
- state = RPC_SERVICE_MODE_EXTERNAL;
- } else {
- state = RPC_SERVICE_MODE_DISABLED;
- }
-
- return state;
-}
-
-
-/* the default is "embedded" so this table
- * lists only daemons that are not using
- * the default in order to keep enumerating it
- * in rpc_daemon_type() as short as possible
- */
-struct rpc_daemon_defaults {
- const char *name;
- const char *def_type;
-} rpc_daemon_defaults[] = {
- { "epmd", "disabled" },
- /* { "spoolssd", "embedded" }, */
- /* { "lsasd", "embedded" }, */
- { "fssd", "disabled" },
-
- { NULL, NULL }
-};
-
-enum rpc_daemon_type_e rpc_daemon_type(const char *name)
-{
- const char *rpcsrv_type;
- enum rpc_daemon_type_e type;
- const char *def;
- int i;
-
- def = "embedded";
- for (i = 0; rpc_daemon_defaults[i].name; i++) {
- if (strcasecmp_m(name, rpc_daemon_defaults[i].name) == 0) {
- def = rpc_daemon_defaults[i].def_type;
- }
- }
-
- rpcsrv_type = lp_parm_const_string(GLOBAL_SECTION_SNUM,
- "rpc_daemon", name, def);
-
- if (strcasecmp_m(rpcsrv_type, "embedded") == 0) {
- type = RPC_DAEMON_EMBEDDED;
- } else if (strcasecmp_m(rpcsrv_type, "fork") == 0) {
- type = RPC_DAEMON_FORK;
- } else {
- type = RPC_DAEMON_DISABLED;
- }
-
- return type;
-}
-#endif
#ifndef _RPC_CONFIG_H
#define _RPC_CONFIG_H
-#if 0
-enum rpc_service_mode_e {
- RPC_SERVICE_MODE_DISABLED = 0,
- RPC_SERVICE_MODE_EMBEDDED,
- RPC_SERVICE_MODE_EXTERNAL
-};
-
-/**
- * @brief Get the mode in which service pipes are configured.
- *
- * @param name Name of the service
- *
- * @return The actual configured mode.
- */
-enum rpc_service_mode_e rpc_service_mode(const char *name);
-
-#define rpc_epmapper_mode() rpc_service_mode("epmapper")
-#define rpc_spoolss_mode() rpc_service_mode("spoolss")
-#define rpc_lsarpc_mode() rpc_service_mode("lsarpc")
-#define rpc_samr_mode() rpc_service_mode("samr")
-#define rpc_netlogon_mode() rpc_service_mode("netlogon")
-#define rpc_fssagentrpc_mode() rpc_service_mode("fssagentrpc")
-#define rpc_mdssvc_mode() rpc_service_mode("mdssvc")
-
-
-
-enum rpc_daemon_type_e {
- RPC_DAEMON_DISABLED = 0,
- RPC_DAEMON_EMBEDDED,
- RPC_DAEMON_FORK
-};
-
-/**
- * @brief Get the mode in which a server is started.
- *
- * @param name Name of the rpc server
- *
- * @return The actual configured type.
- */
-enum rpc_daemon_type_e rpc_daemon_type(const char *name);
-
-#define rpc_epmapper_daemon() rpc_daemon_type("epmd")
-#define rpc_spoolss_daemon() rpc_daemon_type("spoolssd")
-#define rpc_lsasd_daemon() rpc_daemon_type("lsasd")
-#define rpc_fss_daemon() rpc_daemon_type("fssd")
-#define rpc_mdssd_daemon() rpc_daemon_type("mdssd")
-#endif
-
struct dcesrv_context;
struct dcesrv_context *global_dcesrv_context(void);
void global_dcesrv_context_free(void);
+++ /dev/null
-/*
- * Unix SMB/CIFS implementation.
- *
- * RPC Endpoint Registration
- *
- * Copyright (c) 2011 Andreas Schneider <asn@samba.org>
- *
- * 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 3 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, see <http://www.gnu.org/licenses/>.
- */
-
-#include "includes.h"
-#include "ntdomain.h"
-
-#include "../librpc/gen_ndr/ndr_epmapper_c.h"
-
-#include "librpc/rpc/dcerpc_ep.h"
-#include "librpc/rpc/dcesrv_core.h"
-#include "rpc_server/rpc_ep_register.h"
-
-#undef DBGC_CLASS
-#define DBGC_CLASS DBGC_RPC_SRV
-
-static void rpc_ep_register_loop(struct tevent_req *subreq);
-static NTSTATUS rpc_ep_try_register(TALLOC_CTX *mem_ctx,
- struct tevent_context *ev_ctx,
- struct messaging_context *msg_ctx,
- struct dcesrv_context *dce_ctx,
- const struct dcesrv_interface *iface,
- struct dcerpc_binding_handle **pbh);
-
-struct rpc_ep_register_state {
- struct dcerpc_binding_handle *h;
-
- struct tevent_context *ev_ctx;
- struct messaging_context *msg_ctx;
- struct dcesrv_context *dce_ctx;
-
- const struct dcesrv_interface *iface;
-
- uint32_t wait_time;
-};
-
-NTSTATUS rpc_ep_register(struct tevent_context *ev_ctx,
- struct messaging_context *msg_ctx,
- struct dcesrv_context *dce_ctx,
- const struct dcesrv_interface *iface)
-{
- struct rpc_ep_register_state *state;
- struct tevent_req *req;
-
- /* Allocate under iface to stop the loop if the interface is
- * removed from server */
- state = talloc_zero(iface, struct rpc_ep_register_state);
- if (state == NULL) {
- return NT_STATUS_NO_MEMORY;
- }
-
- state->wait_time = 1;
- state->ev_ctx = ev_ctx;
- state->msg_ctx = msg_ctx;
- state->dce_ctx = dce_ctx;
- state->iface = iface;
-
- req = tevent_wakeup_send(state,
- state->ev_ctx,
- timeval_current_ofs(1, 0));
- if (req == NULL) {
- talloc_free(state);
- return NT_STATUS_NO_MEMORY;
- }
-
- tevent_req_set_callback(req, rpc_ep_register_loop, state);
-
- return NT_STATUS_OK;
-}
-
-#define MONITOR_WAIT_TIME 30
-static void rpc_ep_monitor_loop(struct tevent_req *subreq);
-
-static void rpc_ep_register_loop(struct tevent_req *subreq)
-{
- struct rpc_ep_register_state *state =
- tevent_req_callback_data(subreq, struct rpc_ep_register_state);
- NTSTATUS status;
- bool ok;
-
- ok = tevent_wakeup_recv(subreq);
- TALLOC_FREE(subreq);
- if (!ok) {
- talloc_free(state);
- return;
- }
-
- status = rpc_ep_try_register(state,
- state->ev_ctx,
- state->msg_ctx,
- state->dce_ctx,
- state->iface,
- &state->h);
- if (NT_STATUS_IS_OK(status)) {
- /* endpoint registered, monitor the connnection. */
- subreq = tevent_wakeup_send(state,
- state->ev_ctx,
- timeval_current_ofs(MONITOR_WAIT_TIME, 0));
- if (subreq == NULL) {
- talloc_free(state);
- return;
- }
-
- tevent_req_set_callback(subreq, rpc_ep_monitor_loop, state);
- return;
- }
-
- state->wait_time = state->wait_time * 2;
- if (state->wait_time > 16) {
- DEBUG(0, ("Failed to register endpoint '%s'!\n",
- state->iface->name));
- state->wait_time = 16;
- }
-
- subreq = tevent_wakeup_send(state,
- state->ev_ctx,
- timeval_current_ofs(state->wait_time, 0));
- if (subreq == NULL) {
- talloc_free(state);
- return;
- }
-
- tevent_req_set_callback(subreq, rpc_ep_register_loop, state);
- return;
-}
-
-static NTSTATUS rpc_ep_try_register(TALLOC_CTX *mem_ctx,
- struct tevent_context *ev_ctx,
- struct messaging_context *msg_ctx,
- struct dcesrv_context *dce_ctx,
- const struct dcesrv_interface *iface,
- struct dcerpc_binding_handle **pbh)
-{
- NTSTATUS status;
-
- status = dcerpc_ep_register(mem_ctx,
- msg_ctx,
- dce_ctx,
- iface,
- &iface->syntax_id.uuid,
- iface->name,
- pbh);
- if (!NT_STATUS_IS_OK(status)) {
- return status;
- }
-
- return status;
-}
-
-/*
- * Monitor the connection to the endpoint mapper and if it goes away, try to
- * register the endpoint.
- */
-static void rpc_ep_monitor_loop(struct tevent_req *subreq)
-{
- struct rpc_ep_register_state *state =
- tevent_req_callback_data(subreq, struct rpc_ep_register_state);
- struct policy_handle entry_handle;
- struct dcerpc_binding *map_binding;
- struct epm_twr_p_t towers[10];
- struct epm_twr_t *map_tower;
- uint32_t num_towers = 0;
- struct GUID object;
- NTSTATUS status;
- uint32_t result = EPMAPPER_STATUS_CANT_PERFORM_OP;
- TALLOC_CTX *tmp_ctx;
- bool ok;
-
- ZERO_STRUCT(object);
- ZERO_STRUCT(entry_handle);
-
- tmp_ctx = talloc_stackframe();
- if (tmp_ctx == NULL) {
- talloc_free(state);
- return;
- }
-
- ok = tevent_wakeup_recv(subreq);
- TALLOC_FREE(subreq);
- if (!ok) {
- talloc_free(tmp_ctx);
- talloc_free(state);
- return;
- }
-
- /* Create map tower */
- status = dcerpc_parse_binding(tmp_ctx, "ncacn_np:", &map_binding);
- if (!NT_STATUS_IS_OK(status)) {
- talloc_free(tmp_ctx);
- talloc_free(state);
- return;
- }
-
- status = dcerpc_binding_set_abstract_syntax(map_binding,
- &state->iface->syntax_id);
- if (!NT_STATUS_IS_OK(status)) {
- talloc_free(tmp_ctx);
- talloc_free(state);
- return;
- }
-
- map_tower = talloc_zero(tmp_ctx, struct epm_twr_t);
- if (map_tower == NULL) {
- talloc_free(tmp_ctx);
- talloc_free(state);
- return;
- }
-
- status = dcerpc_binding_build_tower(map_tower, map_binding,
- &map_tower->tower);
- if (!NT_STATUS_IS_OK(status)) {
- talloc_free(tmp_ctx);
- talloc_free(state);
- return;
- }
-
- ok = false;
- status = dcerpc_epm_Map(state->h,
- tmp_ctx,
- &object,
- map_tower,
- &entry_handle,
- 10,
- &num_towers,
- towers,
- &result);
- if (NT_STATUS_IS_OK(status)) {
- ok = true;
- }
- if (result == EPMAPPER_STATUS_OK ||
- result == EPMAPPER_STATUS_NO_MORE_ENTRIES) {
- ok = true;
- }
- if (num_towers == 0) {
- ok = false;
- }
-
- dcerpc_epm_LookupHandleFree(state->h,
- tmp_ctx,
- &entry_handle,
- &result);
- talloc_free(tmp_ctx);
-
- subreq = tevent_wakeup_send(state,
- state->ev_ctx,
- timeval_current_ofs(MONITOR_WAIT_TIME, 0));
- if (subreq == NULL) {
- talloc_free(state);
- return;
- }
-
- if (ok) {
- tevent_req_set_callback(subreq, rpc_ep_monitor_loop, state);
- } else {
- TALLOC_FREE(state->h);
- state->wait_time = 1;
-
- tevent_req_set_callback(subreq, rpc_ep_register_loop, state);
- }
-
- return;
-}
+++ /dev/null
-/*
- * Unix SMB/CIFS implementation.
- *
- * RPC Endpoint Registration
- *
- * Copyright (c) 2011 Andreas Schneider <asn@samba.org>
- *
- * 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 3 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, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef _RPC_EP_REGISTER_H
-#define _RPC_EP_REGISTER_H
-
-struct dcesrv_context;
-struct dcesrv_interface;
-
-/**
- * @brief Register an endpoint at the endpoint mapper.
- *
- * This just sets up a register and monitor loop to try to regsiter the
- * endpoint at the endpoint mapper.
- *
- * @param[in] ev_ctx The event context to setup the loop.
- *
- * @param[in] msg_ctx The messaging context to use for the connnection.
- *
- * @param[in] iface The interface table to register.
- *
- * @param[in] v The binding vector to register.
- *
- * @return NT_STATUS_OK on success or a corresponding error code.
- */
-NTSTATUS rpc_ep_register(struct tevent_context *ev_ctx,
- struct messaging_context *msg_ctx,
- struct dcesrv_context *dce_ctx,
- const struct dcesrv_interface *iface);
-
-#endif /* _RPC_EP_REGISTER_H */
-
-/* vim: set ts=8 sw=8 noet cindent ft=c.doxygen: */
+++ /dev/null
-/*
- * Unix SMB/CIFS implementation.
- *
- * SMBD RPC modules
- *
- * Copyright (c) 2015 Ralph Boehme <slow@samba.org>
- *
- * 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 3 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, see <http://www.gnu.org/licenses/>.
- */
-
-#include "includes.h"
-#include "rpc_server/rpc_modules.h"
-
-#undef DBGC_CLASS
-#define DBGC_CLASS DBGC_RPC_SRV
-
-static struct rpc_module *rpc_modules;
-
-struct rpc_module {
- struct rpc_module *prev, *next;
- char *name;
- struct rpc_module_fns *fns;
-};
-
-static struct rpc_module *find_rpc_module(const char *name)
-{
- struct rpc_module *module = NULL;
-
- for (module = rpc_modules; module != NULL; module = module->next) {
- if (strequal(module->name, name)) {
- return module;
- }
- }
-
- return NULL;
-}
-
-NTSTATUS register_rpc_module(struct rpc_module_fns *fns,
- const char *name)
-{
- struct rpc_module *module = find_rpc_module(name);
-
- if (module != NULL) {
- DBG_ERR("RPC module %s already loaded!\n", name);
- return NT_STATUS_OBJECT_NAME_COLLISION;
- }
-
- module = SMB_XMALLOC_P(struct rpc_module);
- module->name = smb_xstrdup(name);
- module->fns = fns;
-
- DLIST_ADD(rpc_modules, module);
- DBG_NOTICE("Successfully added RPC module '%s'\n", name);
-
- return NT_STATUS_OK;
-}
-
-bool setup_rpc_module(struct tevent_context *ev_ctx,
- struct messaging_context *msg_ctx,
- const char *name)
-{
- bool ok;
- struct rpc_module *module = find_rpc_module(name);
-
- if (module == NULL) {
- return false;
- }
-
- ok = module->fns->setup(ev_ctx, msg_ctx);
- if (!ok) {
- DBG_ERR("calling setup for %s failed\n", name);
- }
-
- return true;
-}
-
-bool setup_rpc_modules(struct tevent_context *ev_ctx,
- struct messaging_context *msg_ctx)
-{
- bool ok;
- struct rpc_module *module = rpc_modules;
-
- for (module = rpc_modules; module; module = module->next) {
- ok = module->fns->setup(ev_ctx, msg_ctx);
- if (!ok) {
- DBG_ERR("calling setup for %s failed\n", module->name);
- }
- }
-
- return true;
-}
+++ /dev/null
-/*
- * Unix SMB/CIFS implementation.
- *
- * SMBD RPC modules
- *
- * Copyright (c) 2015 Ralph Boehme <slow@samba.org>
- *
- * 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 3 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, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef _RPC_MODULES_H
-#define _RPC_MODULES_H
-
-struct rpc_module_fns {
- bool (*setup)(struct tevent_context *ev_ctx,
- struct messaging_context *msg_ctx);
-};
-
-NTSTATUS register_rpc_module(struct rpc_module_fns *fns,
- const char *name);
-
-bool setup_rpc_modules(struct tevent_context *ev_ctx,
- struct messaging_context *msg_ctx);
-
-bool setup_rpc_module(struct tevent_context *ev_ctx,
- struct messaging_context *msg_ctx,
- const char *name);
-#endif
return NULL;
}
-#if 0
-NTSTATUS make_internal_rpc_pipe_socketpair(
- TALLOC_CTX *mem_ctx,
- struct tevent_context *ev_ctx,
- struct messaging_context *msg_ctx,
- struct dcesrv_context *dce_ctx,
- struct dcesrv_endpoint *endpoint,
- const struct tsocket_address *remote_address,
- const struct tsocket_address *local_address,
- const struct auth_session_info *session_info,
- struct npa_state **pnpa)
-{
- TALLOC_CTX *tmp_ctx = talloc_stackframe();
- struct dcerpc_ncacn_conn *ncacn_conn = NULL;
- struct dcesrv_connection *dcesrv_conn = NULL;
- struct npa_state *npa;
- NTSTATUS status;
- int rc;
- enum dcerpc_transport_t transport = dcerpc_binding_get_transport(
- endpoint->ep_description);
- const char *pipe_name = dcerpc_binding_get_string_option(
- endpoint->ep_description, "endpoint");
-
- DEBUG(4, ("Create of internal pipe %s requested\n", pipe_name));
-
- npa = npa_state_init(tmp_ctx);
- if (npa == NULL) {
- status = NT_STATUS_NO_MEMORY;
- goto out;
- }
-
- npa->file_type = FILE_TYPE_MESSAGE_MODE_PIPE;
- npa->device_state = 0xff | 0x0400 | 0x0100;
- npa->allocation_size = 4096;
-
- status = dcerpc_ncacn_conn_init(npa,
- ev_ctx,
- msg_ctx,
- dce_ctx,
- endpoint,
- NULL, /* termination fn */
- NULL, /* termination data */
- &ncacn_conn);
- if (!NT_STATUS_IS_OK(status)) {
- goto out;
- }
-
- npa->private_data = (void*)ncacn_conn;
-
- rc = tstream_npa_socketpair(npa->file_type,
- npa,
- &npa->stream,
- ncacn_conn,
- &ncacn_conn->tstream);
- if (rc == -1) {
- status = map_nt_error_from_unix(errno);
- goto out;
- }
-
- ncacn_conn->remote_client_addr = tsocket_address_copy(remote_address,
- ncacn_conn);
- if (ncacn_conn->remote_client_addr == NULL) {
- status = NT_STATUS_NO_MEMORY;
- goto out;
- }
-
- ncacn_conn->remote_client_name = tsocket_address_inet_addr_string(
- ncacn_conn->remote_client_addr, ncacn_conn);
- if (ncacn_conn->remote_client_name == NULL) {
- status = NT_STATUS_NO_MEMORY;
- goto out;
- }
-
- ncacn_conn->local_server_addr = tsocket_address_copy(local_address,
- ncacn_conn);
- if (ncacn_conn->local_server_addr == NULL) {
- status = NT_STATUS_NO_MEMORY;
- goto out;
- }
-
- ncacn_conn->local_server_name = tsocket_address_inet_addr_string(
- ncacn_conn->local_server_addr, ncacn_conn);
- if (ncacn_conn->local_server_name == NULL) {
- status = NT_STATUS_NO_MEMORY;
- goto out;
- }
-
- ncacn_conn->session_info = copy_session_info(ncacn_conn, session_info);
- if (ncacn_conn->session_info == NULL) {
- status = NT_STATUS_NO_MEMORY;
- goto out;
- }
-
- rc = make_base_pipes_struct(ncacn_conn,
- ncacn_conn->msg_ctx,
- pipe_name,
- transport,
- ncacn_conn->remote_client_addr,
- ncacn_conn->local_server_addr,
- &ncacn_conn->p);
- if (rc != 0) {
- status = map_nt_error_from_unix(rc);
- goto out;
- }
-
- /*
- * This fills in dcesrv_conn->endpoint with the endpoint
- * associated with the socket. From this point on we know
- * which (group of) services we are handling, but not the
- * specific interface.
- */
- status = dcesrv_endpoint_connect(ncacn_conn->dce_ctx,
- ncacn_conn,
- ncacn_conn->endpoint,
- ncacn_conn->session_info,
- ncacn_conn->ev_ctx,
- DCESRV_CALL_STATE_FLAG_MAY_ASYNC,
- &dcesrv_conn);
- if (!NT_STATUS_IS_OK(status)) {
- DBG_ERR("Failed to connect to endpoint: %s\n",
- nt_errstr(status));
- goto out;
- }
-
- dcesrv_conn->transport.private_data = ncacn_conn;
- dcesrv_conn->transport.report_output_data =
- dcesrv_sock_report_output_data;
- dcesrv_conn->transport.terminate_connection =
- dcesrv_transport_terminate_connection;
- dcesrv_conn->send_queue = tevent_queue_create(dcesrv_conn,
- "dcesrv send queue");
- if (dcesrv_conn->send_queue == NULL) {
- status = NT_STATUS_NO_MEMORY;
- DBG_ERR("Failed to create send queue: %s\n",
- nt_errstr(status));
- goto out;
- }
-
- dcesrv_conn->stream = talloc_move(dcesrv_conn, &ncacn_conn->tstream);
- dcesrv_conn->local_address = ncacn_conn->local_server_addr;
- dcesrv_conn->remote_address = ncacn_conn->remote_client_addr;
-
- status = dcesrv_connection_loop_start(dcesrv_conn);
- if (!NT_STATUS_IS_OK(status)) {
- DBG_ERR("Failed to start dcesrv_connection loop: %s\n",
- nt_errstr(status));
- goto out;
- }
-
- *pnpa = talloc_move(mem_ctx, &npa);
- status = NT_STATUS_OK;
-out:
- talloc_free(tmp_ctx);
- return status;
-}
-
-static NTSTATUS make_internal_ncacn_conn(TALLOC_CTX *mem_ctx,
- const struct ndr_interface_table *table,
- const struct tsocket_address *remote_address,
- const struct tsocket_address *local_address,
- const struct auth_session_info *session_info,
- struct messaging_context *msg_ctx,
- struct dcerpc_ncacn_conn **_out)
-{
- struct dcerpc_ncacn_conn *ncacn_conn = NULL;
- const char *pipe_name = NULL;
- NTSTATUS status;
- int ret;
-
- pipe_name = dcerpc_default_transport_endpoint(mem_ctx,
- NCACN_NP,
- table);
-
- DBG_INFO("Create pipe requested %s\n", pipe_name);
-
- ncacn_conn = talloc_zero(mem_ctx, struct dcerpc_ncacn_conn);
- if (ncacn_conn == NULL) {
- return NT_STATUS_NO_MEMORY;
- }
-
- ncacn_conn->msg_ctx = msg_ctx;
-
- if (remote_address != NULL) {
- ncacn_conn->remote_client_addr =
- tsocket_address_copy(remote_address, ncacn_conn);
- if (ncacn_conn->remote_client_addr == NULL) {
- status = NT_STATUS_NO_MEMORY;
- goto fail;
- }
- }
-
- if (local_address != NULL) {
- ncacn_conn->local_server_addr =
- tsocket_address_copy(local_address, ncacn_conn);
- if (ncacn_conn->local_server_addr == NULL) {
- status = NT_STATUS_NO_MEMORY;
- goto fail;
- }
- }
-
- ncacn_conn->session_info = copy_session_info(ncacn_conn, session_info);
- if (ncacn_conn->session_info == NULL) {
- status = NT_STATUS_NO_MEMORY;
- goto fail;
- }
-
- ret = make_base_pipes_struct(ncacn_conn,
- msg_ctx,
- pipe_name,
- NCALRPC,
- ncacn_conn->remote_client_addr,
- ncacn_conn->local_server_addr,
- &ncacn_conn->p);
- if (ret) {
- DBG_ERR("No memory for pipes_struct!\n");
- status = NT_STATUS_NO_MEMORY;
- goto fail;
- }
-
- DEBUG(4,("Created internal pipe %s\n", pipe_name));
-
- *_out = ncacn_conn;
-
- return NT_STATUS_OK;
-
-fail:
- talloc_free(ncacn_conn);
- return status;
-}
-
-static NTSTATUS find_ncalrpc_default_endpoint(struct dcesrv_context *dce_ctx,
- const struct ndr_interface_table *ndr_table,
- struct dcesrv_endpoint **ep)
-{
- TALLOC_CTX *tmp_ctx = NULL;
- struct dcerpc_binding *binding = NULL;
- const char *ep_description = NULL;
- NTSTATUS status;
-
- tmp_ctx = talloc_new(dce_ctx);
- if (tmp_ctx == NULL) {
- return NT_STATUS_NO_MEMORY;
- }
-
- if (rpc_service_mode(ndr_table->name) == RPC_SERVICE_MODE_EXTERNAL) {
- ep_description = talloc_asprintf(tmp_ctx, "ncalrpc:[%s]",
- talloc_strdup_upper(tmp_ctx, ndr_table->name));
- if (ep_description == NULL) {
- status = NT_STATUS_NO_MEMORY;
- goto out;
- }
-
- status = dcerpc_parse_binding(tmp_ctx, ep_description, &binding);
- if (!NT_STATUS_IS_OK(status)) {
- goto out;
- }
-
- status = dcesrv_find_endpoint(dce_ctx, binding, ep);
- if (NT_STATUS_IS_OK(status)) {
- goto out;
- }
- }
-
- /*
- * Some services use a rpcint binding handle in their initialization,
- * before the server is fully initialized. Search the NCALRPC endpoint
- * with and without endpoint
- */
- status = dcerpc_parse_binding(tmp_ctx, "ncalrpc:", &binding);
- if (!NT_STATUS_IS_OK(status)) {
- goto out;
- }
-
- status = dcesrv_find_endpoint(dce_ctx, binding, ep);
- if (NT_STATUS_IS_OK(status)) {
- goto out;
- }
-
- if (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC) {
- ep_description = "ncalrpc:[SMBD]";
- } else {
- ep_description = "ncalrpc:[DEFAULT]";
- }
-
- status = dcerpc_parse_binding(tmp_ctx, ep_description, &binding);
- if (!NT_STATUS_IS_OK(status)) {
- goto out;
- }
-
- status = dcesrv_find_endpoint(dce_ctx, binding, ep);
- if (!NT_STATUS_IS_OK(status)) {
- goto out;
- }
-
-out:
- talloc_free(tmp_ctx);
- return status;
-}
-
-static NTSTATUS make_internal_dcesrv_connection(TALLOC_CTX *mem_ctx,
- const struct ndr_interface_table *ndr_table,
- struct dcerpc_ncacn_conn *ncacn_conn,
- struct dcesrv_connection **_out)
-{
- struct dcesrv_connection *conn = NULL;
- struct dcesrv_connection_context *context = NULL;
- struct dcesrv_endpoint *endpoint = NULL;
- NTSTATUS status;
-
- conn = talloc_zero(mem_ctx, struct dcesrv_connection);
- if (conn == NULL) {
- return NT_STATUS_NO_MEMORY;
- }
- conn->dce_ctx = global_dcesrv_context();
- conn->preferred_transfer = &ndr_transfer_syntax_ndr;
- conn->transport.private_data = ncacn_conn;
-
- status = find_ncalrpc_default_endpoint(conn->dce_ctx, ndr_table, &endpoint);
- if (!NT_STATUS_IS_OK(status)) {
- goto fail;
- }
- conn->endpoint = endpoint;
-
- conn->default_auth_state = talloc_zero(conn, struct dcesrv_auth);
- if (conn->default_auth_state == NULL) {
- status = NT_STATUS_NO_MEMORY;
- goto fail;
- }
- conn->default_auth_state->session_info = ncacn_conn->session_info;
- conn->default_auth_state->auth_finished = true;
-
- context = talloc_zero(conn, struct dcesrv_connection_context);
- if (context == NULL) {
- status = NT_STATUS_NO_MEMORY;
- goto fail;
- }
- context->conn = conn;
- context->context_id = 0;
- context->transfer_syntax = *(conn->preferred_transfer);
- context->iface = find_interface_by_syntax_id(
- conn->endpoint, &ndr_table->syntax_id);
- if (context->iface == NULL) {
- status = NT_STATUS_RPC_INTERFACE_NOT_FOUND;
- goto fail;
- }
-
- DLIST_ADD(conn->contexts, context);
-
- *_out = conn;
-
- return NT_STATUS_OK;
-fail:
- talloc_free(conn);
- return status;
-}
-
-struct rpcint_bh_state {
- struct dcesrv_connection *conn;
-};
-
-static bool rpcint_bh_is_connected(struct dcerpc_binding_handle *h)
-{
- struct rpcint_bh_state *hs = dcerpc_binding_handle_data(h,
- struct rpcint_bh_state);
-
- if (hs->conn == NULL) {
- return false;
- }
-
- return true;
-}
-
-static uint32_t rpcint_bh_set_timeout(struct dcerpc_binding_handle *h,
- uint32_t timeout)
-{
- /* TODO: implement timeouts */
- return UINT32_MAX;
-}
-
-struct rpcint_bh_raw_call_state {
- struct dcesrv_call_state *call;
-};
-
-static struct tevent_req *rpcint_bh_raw_call_send(TALLOC_CTX *mem_ctx,
- struct tevent_context *ev,
- struct dcerpc_binding_handle *h,
- const struct GUID *object,
- uint32_t opnum,
- uint32_t in_flags,
- const uint8_t *in_data,
- size_t in_length)
-{
- struct rpcint_bh_state *hs =
- dcerpc_binding_handle_data(h,
- struct rpcint_bh_state);
- struct tevent_req *req;
- struct rpcint_bh_raw_call_state *state;
- struct dcesrv_context *dce_ctx = global_dcesrv_context();
- bool ok;
- NTSTATUS status;
-
- req = tevent_req_create(mem_ctx, &state,
- struct rpcint_bh_raw_call_state);
- if (req == NULL) {
- return NULL;
- }
-
- ok = rpcint_bh_is_connected(h);
- if (!ok) {
- tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
- return tevent_req_post(req, ev);
- }
-
- state->call = talloc_zero(state, struct dcesrv_call_state);
- if (tevent_req_nomem(state->call, req)) {
- return tevent_req_post(req, ev);
- }
-
- state->call->event_ctx = ev;
- state->call->conn = hs->conn;
- state->call->context = hs->conn->contexts;
- state->call->auth_state = hs->conn->default_auth_state;
-
- if (hs->conn->assoc_group == NULL) {
- ZERO_STRUCT(state->call->pkt);
- state->call->pkt.u.bind.assoc_group_id = 0;
- status = dce_ctx->callbacks->assoc_group.find(
- state->call,
- dce_ctx->callbacks->assoc_group.private_data);
- if (tevent_req_nterror(req, status)) {
- return tevent_req_post(req, ev);
- }
- }
-
- ZERO_STRUCT(state->call->pkt);
- state->call->pkt.u.request.opnum = opnum;
- state->call->pkt.u.request.context_id = 0;
- state->call->pkt.u.request.stub_and_verifier.data = discard_const_p(uint8_t, in_data);
- state->call->pkt.u.request.stub_and_verifier.length = in_length;
-
- /* TODO: allow async */
- status = dcesrv_call_dispatch_local(state->call);
- if (!NT_STATUS_IS_OK(status)) {
- tevent_req_nterror(req, status);
- return tevent_req_post(req, ev);
- }
-
- tevent_req_done(req);
- return tevent_req_post(req, ev);
-}
-
-static NTSTATUS rpcint_bh_raw_call_recv(struct tevent_req *req,
- TALLOC_CTX *mem_ctx,
- uint8_t **out_data,
- size_t *out_length,
- uint32_t *out_flags)
-{
- struct rpcint_bh_raw_call_state *state =
- tevent_req_data(req,
- struct rpcint_bh_raw_call_state);
- struct data_blob_list_item *rep = NULL;
- NTSTATUS status;
-
- if (tevent_req_is_nterror(req, &status)) {
- tevent_req_received(req);
- return status;
- }
-
- rep = state->call->replies;
- DLIST_REMOVE(state->call->replies, rep);
-
- *out_data = talloc_steal(mem_ctx, rep->blob.data);
- *out_length = rep->blob.length;
- *out_flags = 0;
-
- talloc_free(rep);
-
- tevent_req_received(req);
- return NT_STATUS_OK;
-}
-
-struct rpcint_bh_disconnect_state {
- uint8_t _dummy;
-};
-
-static struct tevent_req *rpcint_bh_disconnect_send(TALLOC_CTX *mem_ctx,
- struct tevent_context *ev,
- struct dcerpc_binding_handle *h)
-{
- struct rpcint_bh_state *hs = dcerpc_binding_handle_data(h,
- struct rpcint_bh_state);
- struct tevent_req *req;
- struct rpcint_bh_disconnect_state *state;
- bool ok;
-
- req = tevent_req_create(mem_ctx, &state,
- struct rpcint_bh_disconnect_state);
- if (req == NULL) {
- return NULL;
- }
-
- ok = rpcint_bh_is_connected(h);
- if (!ok) {
- tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
- return tevent_req_post(req, ev);
- }
-
- /*
- * TODO: do a real async disconnect ...
- *
- * For now the caller needs to free dcesrv_connection
- */
- hs->conn = NULL;
-
- tevent_req_done(req);
- return tevent_req_post(req, ev);
-}
-
-static NTSTATUS rpcint_bh_disconnect_recv(struct tevent_req *req)
-{
- NTSTATUS status;
-
- if (tevent_req_is_nterror(req, &status)) {
- tevent_req_received(req);
- return status;
- }
-
- tevent_req_received(req);
- return NT_STATUS_OK;
-}
-
-static bool rpcint_bh_ref_alloc(struct dcerpc_binding_handle *h)
-{
- return true;
-}
-
-static void rpcint_bh_do_ndr_print(struct dcerpc_binding_handle *h,
- int ndr_flags,
- const void *_struct_ptr,
- const struct ndr_interface_call *call)
-{
- void *struct_ptr = discard_const(_struct_ptr);
-
- if (DEBUGLEVEL < 11) {
- return;
- }
-
- if (ndr_flags & NDR_IN) {
- ndr_print_function_debug(call->ndr_print,
- call->name,
- ndr_flags,
- struct_ptr);
- }
- if (ndr_flags & NDR_OUT) {
- ndr_print_function_debug(call->ndr_print,
- call->name,
- ndr_flags,
- struct_ptr);
- }
-}
-
-static const struct dcerpc_binding_handle_ops rpcint_bh_ops = {
- .name = "rpcint",
- .is_connected = rpcint_bh_is_connected,
- .set_timeout = rpcint_bh_set_timeout,
- .raw_call_send = rpcint_bh_raw_call_send,
- .raw_call_recv = rpcint_bh_raw_call_recv,
- .disconnect_send = rpcint_bh_disconnect_send,
- .disconnect_recv = rpcint_bh_disconnect_recv,
-
- .ref_alloc = rpcint_bh_ref_alloc,
- .do_ndr_print = rpcint_bh_do_ndr_print,
-};
-#endif
-
static NTSTATUS rpcint_binding_handle_ex(TALLOC_CTX *mem_ctx,
const struct ndr_syntax_id *abstract_syntax,
const struct ndr_interface_table *ndr_table,
msg_ctx, binding_handle);
}
-#if 0
-/**
- * @internal
- *
- * @brief Create a new RPC client context which uses a local transport.
- *
- * This creates a local transport. It is a shortcut to directly call the server
- * functions and avoid marshalling.
- * NOTE: this function should be used only by rpc_pipe_open_interface()
- *
- * @param[in] mem_ctx The memory context to use.
- *
- * @param[in] ndr_table the ndr_table_<name> structure.
- *
- * @param[in] serversupplied_info The server supplied authentication function.
- *
- * @param[in] remote_address The client address information.
- *
- * @param[in] msg_ctx The messaging context to use.
- *
- * @param[out] presult A pointer to store the connected rpc client pipe.
- *
- * @return NT_STATUS_OK on success, a corresponding NT status if an
- * error occurred.
- */
-NTSTATUS rpc_pipe_open_internal(TALLOC_CTX *mem_ctx,
- const struct ndr_interface_table *ndr_table,
- const struct auth_session_info *session_info,
- const struct tsocket_address *remote_address,
- const struct tsocket_address *local_address,
- struct messaging_context *msg_ctx,
- struct rpc_pipe_client **presult)
-{
- struct rpc_pipe_client *result;
- NTSTATUS status;
-
- result = talloc_zero(mem_ctx, struct rpc_pipe_client);
- if (result == NULL) {
- return NT_STATUS_NO_MEMORY;
- }
-
- result->abstract_syntax = ndr_table->syntax_id;
- result->transfer_syntax = ndr_transfer_syntax_ndr;
-
- if (remote_address == NULL) {
- struct tsocket_address *local;
- int rc;
-
- rc = tsocket_address_inet_from_strings(mem_ctx,
- "ip",
- "127.0.0.1",
- 0,
- &local);
- if (rc < 0) {
- TALLOC_FREE(result);
- return NT_STATUS_NO_MEMORY;
- }
-
- remote_address = local;
- }
-
- result->max_xmit_frag = -1;
-
- status = rpcint_binding_handle(result,
- ndr_table,
- remote_address,
- local_address,
- session_info,
- msg_ctx,
- &result->binding_handle);
- if (!NT_STATUS_IS_OK(status)) {
- TALLOC_FREE(result);
- return status;
- }
-
- *presult = result;
- return NT_STATUS_OK;
-}
-
-/****************************************************************************
- * External pipes functions
- ***************************************************************************/
-
-NTSTATUS make_external_rpc_pipe(TALLOC_CTX *mem_ctx,
- const char *pipe_name,
- const struct tsocket_address *remote_client_address,
- const struct tsocket_address *local_server_address,
- const struct auth_session_info *session_info,
- struct npa_state **pnpa)
-{
- TALLOC_CTX *tmp_ctx = talloc_stackframe();
- struct auth_session_info_transport *session_info_t;
- struct tevent_context *ev_ctx;
- struct tevent_req *subreq;
- const char *socket_np_dir;
- const char *socket_dir;
- struct npa_state *npa;
- int sys_errno;
- NTSTATUS status;
- int rc = -1;
- bool ok;
-
- npa = npa_state_init(tmp_ctx);
- if (npa == NULL) {
- status = NT_STATUS_NO_MEMORY;
- goto out;
- }
-
- socket_dir = lp_parm_const_string(GLOBAL_SECTION_SNUM,
- "external_rpc_pipe",
- "socket_dir",
- lp_ncalrpc_dir());
- if (socket_dir == NULL) {
- DEBUG(0, ("external_rpc_pipe: socket_dir not set\n"));
- status = NT_STATUS_PIPE_NOT_AVAILABLE;
- goto out;
- }
-
- socket_np_dir = talloc_asprintf(tmp_ctx, "%s/np", socket_dir);
- if (socket_np_dir == NULL) {
- DEBUG(0, ("talloc_asprintf failed\n"));
- status = NT_STATUS_NO_MEMORY;
- goto out;
- }
-
- session_info_t = talloc_zero(tmp_ctx,
- struct auth_session_info_transport);
- if (session_info_t == NULL) {
- DEBUG(0, ("talloc failed\n"));
- status = NT_STATUS_NO_MEMORY;
- goto out;
- }
-
- session_info_t->session_info = copy_session_info(session_info_t,
- session_info);
- if (session_info_t->session_info == NULL) {
- DEBUG(0, ("copy_session_info failed\n"));
- status = NT_STATUS_NO_MEMORY;
- goto out;
- }
-
- ev_ctx = samba_tevent_context_init(tmp_ctx);
- if (ev_ctx == NULL) {
- DEBUG(0, ("samba_tevent_context_init failed\n"));
- status = NT_STATUS_NO_MEMORY;
- goto out;
- }
-
- become_root();
- subreq = tstream_npa_connect_send(tmp_ctx,
- ev_ctx,
- socket_np_dir,
- pipe_name,
- NCACN_NP,
- remote_client_address,
- NULL, /* client_name */
- local_server_address,
- NULL, /* server_name */
- session_info_t);
- if (subreq == NULL) {
- unbecome_root();
- DEBUG(0, ("tstream_npa_connect_send to %s for pipe %s and "
- "user %s\\%s failed\n",
- socket_np_dir, pipe_name, session_info_t->session_info->info->domain_name,
- session_info_t->session_info->info->account_name));
- status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
- goto out;
- }
- ok = tevent_req_poll(subreq, ev_ctx);
- unbecome_root();
- if (!ok) {
- DEBUG(0, ("tevent_req_poll to %s for pipe %s and user %s\\%s "
- "failed for tstream_npa_connect: %s\n",
- socket_np_dir,
- pipe_name,
- session_info_t->session_info->info->domain_name,
- session_info_t->session_info->info->account_name,
- strerror(errno)));
- status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
- goto out;
- }
-
- rc = tstream_npa_connect_recv(subreq,
- &sys_errno,
- npa,
- &npa->stream,
- &npa->file_type,
- &npa->device_state,
- &npa->allocation_size);
- talloc_free(subreq);
- if (rc != 0) {
- int l = 1;
-
- if (errno == ENOENT) {
- l = 2;
- }
-
- DEBUG(l, ("tstream_npa_connect_recv to %s for pipe %s and "
- "user %s\\%s failed: %s\n",
- socket_np_dir,
- pipe_name,
- session_info_t->session_info->info->domain_name,
- session_info_t->session_info->info->account_name,
- strerror(sys_errno)));
- status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
- goto out;
- }
-
- *pnpa = talloc_steal(mem_ctx, npa);
- status = NT_STATUS_OK;
-out:
- talloc_free(tmp_ctx);
-
- return status;
-}
-
-static struct np_proxy_state *make_external_rpc_pipe_p(TALLOC_CTX *mem_ctx,
- const char *pipe_name,
- const struct tsocket_address *remote_address,
- const struct tsocket_address *local_address,
- const struct auth_session_info *session_info)
-{
- struct np_proxy_state *result;
- char *socket_np_dir;
- const char *socket_dir;
- struct tevent_context *ev;
- struct tevent_req *subreq;
- struct auth_session_info_transport *session_info_t;
- bool ok;
- int ret;
- int sys_errno;
-
- result = talloc(mem_ctx, struct np_proxy_state);
- if (result == NULL) {
- DEBUG(0, ("talloc failed\n"));
- return NULL;
- }
-
- result->read_queue = tevent_queue_create(result, "np_read");
- if (result->read_queue == NULL) {
- DEBUG(0, ("tevent_queue_create failed\n"));
- goto fail;
- }
-
- result->write_queue = tevent_queue_create(result, "np_write");
- if (result->write_queue == NULL) {
- DEBUG(0, ("tevent_queue_create failed\n"));
- goto fail;
- }
-
- ev = samba_tevent_context_init(talloc_tos());
- if (ev == NULL) {
- DEBUG(0, ("samba_tevent_context_init failed\n"));
- goto fail;
- }
-
- socket_dir = lp_parm_const_string(
- GLOBAL_SECTION_SNUM, "external_rpc_pipe", "socket_dir",
- lp_ncalrpc_dir());
- if (socket_dir == NULL) {
- DEBUG(0, ("external_rpc_pipe:socket_dir not set\n"));
- goto fail;
- }
- socket_np_dir = talloc_asprintf(talloc_tos(), "%s/np", socket_dir);
- if (socket_np_dir == NULL) {
- DEBUG(0, ("talloc_asprintf failed\n"));
- goto fail;
- }
-
- session_info_t = talloc_zero(talloc_tos(), struct auth_session_info_transport);
- if (session_info_t == NULL) {
- DEBUG(0, ("talloc failed\n"));
- goto fail;
- }
-
- session_info_t->session_info = copy_session_info(session_info_t,
- session_info);
- if (session_info_t->session_info == NULL) {
- DEBUG(0, ("copy_session_info failed\n"));
- goto fail;
- }
-
- become_root();
- subreq = tstream_npa_connect_send(talloc_tos(), ev,
- socket_np_dir,
- pipe_name,
- NCACN_NP,
- remote_address,
- NULL, /* client_name */
- local_address,
- NULL, /* server_name */
- session_info_t);
- if (subreq == NULL) {
- unbecome_root();
- DEBUG(0, ("tstream_npa_connect_send to %s for pipe %s and "
- "user %s\\%s failed\n",
- socket_np_dir, pipe_name, session_info_t->session_info->info->domain_name,
- session_info_t->session_info->info->account_name));
- goto fail;
- }
- ok = tevent_req_poll(subreq, ev);
- unbecome_root();
- if (!ok) {
- DEBUG(0, ("tevent_req_poll to %s for pipe %s and user %s\\%s "
- "failed for tstream_npa_connect: %s\n",
- socket_np_dir, pipe_name, session_info_t->session_info->info->domain_name,
- session_info_t->session_info->info->account_name,
- strerror(errno)));
- goto fail;
-
- }
- ret = tstream_npa_connect_recv(subreq, &sys_errno,
- result,
- &result->npipe,
- &result->file_type,
- &result->device_state,
- &result->allocation_size);
- TALLOC_FREE(subreq);
- if (ret != 0) {
- int l = 1;
- if (sys_errno == ENOENT) {
- l = 2;
- }
- DEBUG(l, ("tstream_npa_connect_recv to %s for pipe %s and "
- "user %s\\%s failed: %s\n",
- socket_np_dir, pipe_name, session_info_t->session_info->info->domain_name,
- session_info_t->session_info->info->account_name,
- strerror(sys_errno)));
- goto fail;
- }
-
- return result;
-
- fail:
- TALLOC_FREE(result);
- return NULL;
-}
-
-static NTSTATUS rpc_pipe_open_external(TALLOC_CTX *mem_ctx,
- const char *pipe_name,
- const struct ndr_interface_table *table,
- const struct auth_session_info *session_info,
- const struct tsocket_address *remote_client_address,
- const struct tsocket_address *local_server_address,
- struct rpc_pipe_client **_result)
-{
- struct rpc_pipe_client *result = NULL;
- struct np_proxy_state *proxy_state = NULL;
- struct pipe_auth_data *auth;
- struct tsocket_address *remote_client_addr;
- struct tsocket_address *local_server_addr;
- NTSTATUS status;
- int ret;
-
- if (local_server_address == NULL) {
- /* this is an internal connection, fake up ip addresses */
- ret = tsocket_address_inet_from_strings(talloc_tos(), "ip",
- NULL, 0, &local_server_addr);
- if (ret) {
- return NT_STATUS_NO_MEMORY;
- }
- local_server_address = local_server_addr;
- }
-
- if (remote_client_address == NULL) {
- /* this is an internal connection, fake up ip addresses */
- ret = tsocket_address_inet_from_strings(talloc_tos(), "ip",
- NULL, 0, &remote_client_addr);
- if (ret) {
- return NT_STATUS_NO_MEMORY;
- }
- remote_client_address = remote_client_addr;
- }
-
- proxy_state = make_external_rpc_pipe_p(mem_ctx, pipe_name,
- remote_client_address,
- local_server_address,
- session_info);
- if (!proxy_state) {
- DEBUG(1, ("Unable to make proxy_state for connection to %s.\n", pipe_name));
- return NT_STATUS_UNSUCCESSFUL;
- }
-
- result = talloc_zero(mem_ctx, struct rpc_pipe_client);
- if (result == NULL) {
- status = NT_STATUS_NO_MEMORY;
- goto done;
- }
-
- result->abstract_syntax = table->syntax_id;
- result->transfer_syntax = ndr_transfer_syntax_ndr;
-
- result->desthost = get_myname(result);
- result->srv_name_slash = talloc_asprintf_strupper_m(
- result, "\\\\%s", result->desthost);
- if ((result->desthost == NULL) || (result->srv_name_slash == NULL)) {
- status = NT_STATUS_NO_MEMORY;
- goto done;
- }
-
- result->max_xmit_frag = RPC_MAX_PDU_FRAG_LEN;
-
- status = rpc_transport_tstream_init(result,
- &proxy_state->npipe,
- &result->transport);
- if (!NT_STATUS_IS_OK(status)) {
- goto done;
- }
-
- result->binding_handle = rpccli_bh_create(result, NULL, table);
- if (result->binding_handle == NULL) {
- status = NT_STATUS_NO_MEMORY;
- DEBUG(0, ("Failed to create binding handle.\n"));
- goto done;
- }
-
- result->auth = talloc_zero(result, struct pipe_auth_data);
- if (!result->auth) {
- status = NT_STATUS_NO_MEMORY;
- goto done;
- }
- result->auth->auth_type = DCERPC_AUTH_TYPE_NONE;
- result->auth->auth_level = DCERPC_AUTH_LEVEL_NONE;
- result->auth->auth_context_id = 0;
-
- status = rpccli_anon_bind_data(result, &auth);
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(0, ("Failed to initialize anonymous bind.\n"));
- goto done;
- }
-
- status = rpc_pipe_bind(result, auth);
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(0, ("Failed to bind external pipe.\n"));
- goto done;
- }
-
-done:
- if (!NT_STATUS_IS_OK(status)) {
- TALLOC_FREE(result);
- }
- TALLOC_FREE(proxy_state);
- *_result = result;
- return status;
-}
-#endif
-
/**
* @brief Create a new RPC client context which uses a local dispatch function
* or a remote transport, depending on rpc_server configuration for the
#include "source3/librpc/rpc/dcerpc.h"
-struct dcesrv_ep_entry_list;
struct tsocket_address;
struct pipes_struct;
struct dcesrv_context;
struct auth_session_info *session_info;
struct messaging_context *msg_ctx;
- struct dcesrv_ep_entry_list *ep_entries;
-
struct pipe_auth_data auth;
/*
void *termination_data;
};
-#if 0
-static void dcesrv_ncacn_listener(
- struct tevent_context *ev,
- struct tevent_fd *fde,
- uint16_t flags,
- void *private_data);
-
-int dcesrv_setup_ncacn_listener(
- TALLOC_CTX *mem_ctx,
- struct dcesrv_context *dce_ctx,
- struct tevent_context *ev_ctx,
- struct messaging_context *msg_ctx,
- struct dcesrv_endpoint *e,
- int *fd,
- dcerpc_ncacn_termination_fn term_fn,
- void *termination_data,
- struct dcerpc_ncacn_listen_state **listen_state)
-{
- struct dcerpc_ncacn_listen_state *state = NULL;
- struct tevent_fd *fde = NULL;
- int rc, err = ENOMEM;
-
- state = talloc_zero(mem_ctx, struct dcerpc_ncacn_listen_state);
- if (state == NULL) {
- DBG_ERR("Out of memory\n");
- return ENOMEM;
- }
-
- state->fd = *fd;
- state->ev_ctx = ev_ctx;
- state->msg_ctx = msg_ctx;
- state->dce_ctx = dce_ctx;
- state->endpoint = e;
- state->termination_fn = term_fn;
- state->termination_data = termination_data;
-
- rc = listen(state->fd, SMBD_LISTEN_BACKLOG);
- if (rc < 0) {
- err = errno;
- DBG_ERR("listen(%d) failed: %s\n",
- state->fd,
- strerror(err));
- goto fail;
- }
-
- /* Set server socket to non-blocking for the accept. */
- rc = set_blocking(state->fd, false);
- if (rc < 0) {
- err = errno;
- goto fail;
- }
-
- fde = tevent_add_fd(
- state->ev_ctx,
- state,
- state->fd,
- TEVENT_FD_READ,
- dcesrv_ncacn_listener,
- state);
- if (fde == NULL) {
- err = errno;
- DBG_ERR("tevent_add_fd for %d failed: %s\n",
- state->fd,
- strerror(err));
- goto fail;
- }
- tevent_fd_set_auto_close(fde);
- *fd = -1;
-
- *listen_state = state;
-
- return 0;
-
-fail:
- TALLOC_FREE(state);
- return err;
-}
-
-static void dcesrv_ncacn_listener(
- struct tevent_context *ev,
- struct tevent_fd *fde,
- uint16_t flags,
- void *private_data)
-{
- struct dcerpc_ncacn_listen_state *state = talloc_get_type_abort(
- private_data, struct dcerpc_ncacn_listen_state);
- struct tsocket_address *cli_addr = NULL, *srv_addr = NULL;
- struct samba_sockaddr addr = {
- .sa_socklen = sizeof(struct samba_sockaddr),
- };
- int sd = -1;
- int rc;
-
- sd = accept(state->fd, &addr.u.sa, &addr.sa_socklen);
- if (sd == -1) {
- if (errno != EINTR) {
- DBG_ERR("Failed to accept: %s\n", strerror(errno));
- }
- return;
- }
- smb_set_close_on_exec(sd);
-
- rc = tsocket_address_bsd_from_samba_sockaddr(state, &addr, &cli_addr);
- if (rc < 0) {
- goto fail;
- }
-
- rc = getsockname(sd, &addr.u.sa, &addr.sa_socklen);
- if (rc < 0) {
- goto fail;
- }
-
- rc = tsocket_address_bsd_from_samba_sockaddr(state, &addr, &srv_addr);
- if (rc < 0) {
- goto fail;
- }
-
- dcerpc_ncacn_accept(
- state->ev_ctx,
- state->msg_ctx,
- state->dce_ctx,
- state->endpoint,
- &cli_addr,
- &srv_addr,
- sd,
- state->termination_fn,
- state->termination_data);
- return;
-
-fail:
- TALLOC_FREE(cli_addr);
- TALLOC_FREE(srv_addr);
- if (sd != -1) {
- close(sd);
- }
-}
-
-static int dcesrv_connection_destructor(struct dcesrv_connection *conn)
-{
- struct dcerpc_ncacn_conn *ncacn_conn = talloc_get_type_abort(
- conn->transport.private_data,
- struct dcerpc_ncacn_conn);
-
- if (ncacn_conn->termination_fn != NULL) {
- ncacn_conn->termination_fn(conn, ncacn_conn->termination_data);
- }
-
- return 0;
-}
-#endif
-
NTSTATUS dcerpc_ncacn_conn_init(TALLOC_CTX *mem_ctx,
struct tevent_context *ev_ctx,
struct messaging_context *msg_ctx,
return NT_STATUS_OK;
}
-#if 0
-static void dcesrv_ncacn_np_accept_done(struct tevent_req *subreq);
-static void dcesrv_ncacn_accept_step2(struct dcerpc_ncacn_conn *ncacn_conn);
-#endif
-
static void ncacn_terminate_connection(struct dcerpc_ncacn_conn *conn,
const char *reason);
-#if 0
-void dcerpc_ncacn_accept(struct tevent_context *ev_ctx,
- struct messaging_context *msg_ctx,
- struct dcesrv_context *dce_ctx,
- struct dcesrv_endpoint *e,
- struct tsocket_address **cli_addr,
- struct tsocket_address **srv_addr,
- int s,
- dcerpc_ncacn_termination_fn termination_fn,
- void *termination_data)
-{
- enum dcerpc_transport_t transport =
- dcerpc_binding_get_transport(e->ep_description);
- struct dcerpc_ncacn_conn *ncacn_conn;
- NTSTATUS status;
- int rc;
-
- DBG_DEBUG("dcerpc_ncacn_accept\n");
-
- status = dcerpc_ncacn_conn_init(ev_ctx,
- ev_ctx,
- msg_ctx,
- dce_ctx,
- e,
- termination_fn,
- termination_data,
- &ncacn_conn);
- if (!NT_STATUS_IS_OK(status)) {
- DBG_ERR("Failed to initialize dcerpc_ncacn_connection: %s\n",
- nt_errstr(status));
- close(s);
- return;
- }
-
- ncacn_conn->sock = s;
-
- if ((cli_addr != NULL) && (*cli_addr != NULL)) {
- ncacn_conn->remote_client_addr = talloc_move(
- ncacn_conn, cli_addr);
-
- if (tsocket_address_is_inet(ncacn_conn->remote_client_addr, "ip")) {
- ncacn_conn->remote_client_name =
- tsocket_address_inet_addr_string(ncacn_conn->remote_client_addr,
- ncacn_conn);
- } else {
- ncacn_conn->remote_client_name =
- tsocket_address_unix_path(ncacn_conn->remote_client_addr,
- ncacn_conn);
- }
-
- if (ncacn_conn->remote_client_name == NULL) {
- DBG_ERR("Out of memory obtaining remote socket address as a string!\n");
- ncacn_terminate_connection(ncacn_conn, "No memory");
- close(s);
- return;
- }
- }
-
- if ((srv_addr != NULL) && (*srv_addr != NULL)) {
- ncacn_conn->local_server_addr = talloc_move(
- ncacn_conn, srv_addr);
-
- if (tsocket_address_is_inet(ncacn_conn->local_server_addr, "ip")) {
- ncacn_conn->local_server_name =
- tsocket_address_inet_addr_string(ncacn_conn->local_server_addr,
- ncacn_conn);
- } else {
- ncacn_conn->local_server_name =
- tsocket_address_unix_path(ncacn_conn->local_server_addr,
- ncacn_conn);
- }
- if (ncacn_conn->local_server_name == NULL) {
- DBG_ERR("No memory\n");
- ncacn_terminate_connection(ncacn_conn, "No memory");
- close(s);
- return;
- }
- }
-
- rc = set_blocking(s, false);
- if (rc < 0) {
- DBG_WARNING("Failed to set dcerpc socket to non-blocking\n");
- ncacn_terminate_connection(ncacn_conn, strerror(errno));
- close(s);
- return;
- }
-
- /*
- * As soon as we have tstream_bsd_existing_socket set up it will
- * take care of closing the socket.
- */
- rc = tstream_bsd_existing_socket(ncacn_conn, s, &ncacn_conn->tstream);
- if (rc < 0) {
- DBG_WARNING("Failed to create tstream socket for dcerpc\n");
- ncacn_terminate_connection(ncacn_conn, "No memory");
- close(s);
- return;
- }
-
- if (transport == NCACN_NP) {
- struct tevent_req *subreq = NULL;
- uint64_t allocation_size = 4096;
- uint16_t device_state = 0xff | 0x0400 | 0x0100;
- uint16_t file_type = FILE_TYPE_MESSAGE_MODE_PIPE;
-
- subreq = tstream_npa_accept_existing_send(ncacn_conn,
- ncacn_conn->ev_ctx,
- ncacn_conn->tstream,
- file_type,
- device_state,
- allocation_size);
- if (subreq == NULL) {
- ncacn_terminate_connection(ncacn_conn, "No memory");
- return;
- }
- tevent_req_set_callback(subreq, dcesrv_ncacn_np_accept_done,
- ncacn_conn);
- return;
- }
-
- dcesrv_ncacn_accept_step2(ncacn_conn);
-}
-
-static void dcesrv_ncacn_np_accept_done(struct tevent_req *subreq)
-{
- struct dcerpc_ncacn_conn *ncacn_conn = tevent_req_callback_data(
- subreq, struct dcerpc_ncacn_conn);
- struct auth_session_info_transport *session_info_transport = NULL;
- enum dcerpc_transport_t transport;
- int error;
- int ret;
-
- ret = tstream_npa_accept_existing_recv(subreq, &error, ncacn_conn,
- &ncacn_conn->tstream,
- NULL,
- &transport,
- &ncacn_conn->remote_client_addr,
- &ncacn_conn->remote_client_name,
- &ncacn_conn->local_server_addr,
- &ncacn_conn->local_server_name,
- &session_info_transport);
- ncacn_conn->session_info = talloc_move(ncacn_conn,
- &session_info_transport->session_info);
-
- if (transport != NCACN_NP) {
- ncacn_terminate_connection(
- ncacn_conn,
- "Only allow NCACN_NP transport on named pipes\n");
- return;
- }
-
- if (security_token_is_system(
- ncacn_conn->session_info->security_token)) {
- ncacn_terminate_connection(
- ncacn_conn,
- "No system token via NCACN_NP allowed\n");
- return;
- }
-
- TALLOC_FREE(subreq);
- if (ret != 0) {
- DBG_ERR("Failed to accept named pipe connection: %s\n",
- strerror(error));
- ncacn_terminate_connection(ncacn_conn, strerror(errno));
- return;
- }
-
- dcesrv_ncacn_accept_step2(ncacn_conn);
-}
-
-static void dcesrv_ncacn_accept_step2(struct dcerpc_ncacn_conn *ncacn_conn)
-{
- char *pipe_name = NULL;
- uid_t uid;
- gid_t gid;
- int rc;
- enum dcerpc_transport_t transport = dcerpc_binding_get_transport(
- ncacn_conn->endpoint->ep_description);
- const char *endpoint = dcerpc_binding_get_string_option(
- ncacn_conn->endpoint->ep_description, "endpoint");
- struct dcesrv_connection *dcesrv_conn = NULL;
- NTSTATUS status;
-
- switch (transport) {
- case NCACN_IP_TCP:
- pipe_name = tsocket_address_string(ncacn_conn->remote_client_addr,
- ncacn_conn);
- if (pipe_name == NULL) {
- DBG_ERR("No memory\n");
- ncacn_terminate_connection(ncacn_conn, "No memory");
- return;
- }
-
- break;
- case NCALRPC:
- rc = getpeereid(ncacn_conn->sock, &uid, &gid);
- if (rc < 0) {
- DEBUG(2, ("Failed to get ncalrpc connecting "
- "uid - %s!\n", strerror(errno)));
- } else {
- if (uid == sec_initial_uid()) {
- TALLOC_FREE(ncacn_conn->remote_client_addr);
-
- rc = tsocket_address_unix_from_path(ncacn_conn,
- AS_SYSTEM_MAGIC_PATH_TOKEN,
- &ncacn_conn->remote_client_addr);
- if (rc < 0) {
- DBG_ERR("No memory\n");
- ncacn_terminate_connection(ncacn_conn, "No memory");
- return;
- }
-
- TALLOC_FREE(ncacn_conn->remote_client_name);
- ncacn_conn->remote_client_name
- = tsocket_address_unix_path(ncacn_conn->remote_client_addr,
- ncacn_conn);
- if (ncacn_conn->remote_client_name == NULL) {
- DBG_ERR("No memory\n");
- ncacn_terminate_connection(ncacn_conn, "No memory");
- return;
- }
- }
- }
-
- FALL_THROUGH;
- case NCACN_NP:
- pipe_name = talloc_strdup(ncacn_conn, endpoint);
- if (pipe_name == NULL) {
- DBG_ERR("No memory\n");
- ncacn_terminate_connection(ncacn_conn, "No memory");
- return;
- }
- break;
- default:
- DBG_ERR("unknown dcerpc transport: %u!\n", transport);
- ncacn_terminate_connection(ncacn_conn,
- "Unknown DCE/RPC transport");
- return;
- }
-
- if (ncacn_conn->session_info == NULL) {
- status = make_session_info_anonymous(ncacn_conn,
- &ncacn_conn->session_info);
- if (!NT_STATUS_IS_OK(status)) {
- DBG_ERR("Failed to create anonymous session info: "
- "%s\n", nt_errstr(status));
- ncacn_terminate_connection(ncacn_conn,
- nt_errstr(status));
- return;
- }
- }
-
- rc = make_base_pipes_struct(ncacn_conn,
- ncacn_conn->msg_ctx,
- pipe_name,
- transport,
- ncacn_conn->remote_client_addr,
- ncacn_conn->local_server_addr,
- &ncacn_conn->p);
- if (rc != 0) {
- const char *errstr = strerror(rc);
- DBG_ERR("Failed to create pipe struct: %s\n", errstr);
- ncacn_terminate_connection(ncacn_conn, errstr);
- return;
- }
-
- /*
- * This fills in dcesrv_conn->endpoint with the endpoint
- * associated with the socket. From this point on we know
- * which (group of) services we are handling, but not the
- * specific interface.
- */
- status = dcesrv_endpoint_connect(ncacn_conn->dce_ctx,
- ncacn_conn,
- ncacn_conn->endpoint,
- ncacn_conn->session_info,
- ncacn_conn->ev_ctx,
- DCESRV_CALL_STATE_FLAG_MAY_ASYNC,
- &dcesrv_conn);
- if (!NT_STATUS_IS_OK(status)) {
- DBG_ERR("Failed to connect to endpoint: %s\n",
- nt_errstr(status));
- ncacn_terminate_connection(ncacn_conn, nt_errstr(status));
- return;
- }
- talloc_set_destructor(dcesrv_conn, dcesrv_connection_destructor);
-
- dcesrv_conn->transport.private_data = ncacn_conn;
- dcesrv_conn->transport.report_output_data =
- dcesrv_sock_report_output_data;
- dcesrv_conn->transport.terminate_connection =
- dcesrv_transport_terminate_connection;
- dcesrv_conn->send_queue = tevent_queue_create(dcesrv_conn,
- "dcesrv send queue");
- if (dcesrv_conn->send_queue == NULL) {
- status = NT_STATUS_NO_MEMORY;
- DBG_ERR("Failed to create send queue: %s\n",
- nt_errstr(status));
- ncacn_terminate_connection(ncacn_conn, nt_errstr(status));
- return;
- }
-
- dcesrv_conn->stream = talloc_move(dcesrv_conn, &ncacn_conn->tstream);
- dcesrv_conn->local_address = ncacn_conn->local_server_addr;
- dcesrv_conn->remote_address = ncacn_conn->remote_client_addr;
- status = dcesrv_connection_loop_start(dcesrv_conn);
- if (!NT_STATUS_IS_OK(status)) {
- DBG_ERR("Failed to start dcesrv_connection loop: %s\n",
- nt_errstr(status));
- ncacn_terminate_connection(ncacn_conn, nt_errstr(status));
- }
- DBG_DEBUG("dcerpc_ncacn_accept done\n");
-
- return;
-}
-#endif
-
NTSTATUS dcesrv_auth_gensec_prepare(
TALLOC_CTX *mem_ctx,
struct dcesrv_call_state *call,
+++ /dev/null
-/*
- * Unix SMB/CIFS implementation.
- *
- * SMBD RPC service callbacks
- *
- * Copyright (c) 2011 Andreas Schneider <asn@samba.org>
- *
- * 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 3 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, see <http://www.gnu.org/licenses/>.
- */
-
-#include "includes.h"
-#include "ntdomain.h"
-
-#include "librpc/gen_ndr/ndr_winreg_scompat.h"
-#include "librpc/gen_ndr/ndr_srvsvc_scompat.h"
-#include "librpc/gen_ndr/ndr_lsa_scompat.h"
-#include "librpc/gen_ndr/ndr_samr_scompat.h"
-#include "librpc/gen_ndr/ndr_netlogon_scompat.h"
-#include "librpc/gen_ndr/ndr_dfs_scompat.h"
-#include "librpc/gen_ndr/ndr_echo_scompat.h"
-#include "librpc/gen_ndr/ndr_dssetup_scompat.h"
-#include "librpc/gen_ndr/ndr_wkssvc_scompat.h"
-#include "librpc/gen_ndr/ndr_spoolss_scompat.h"
-#include "librpc/gen_ndr/ndr_svcctl_scompat.h"
-#include "librpc/gen_ndr/ndr_ntsvcs_scompat.h"
-#include "librpc/gen_ndr/ndr_eventlog_scompat.h"
-#include "librpc/gen_ndr/ndr_initshutdown_scompat.h"
-
-#include "printing/nt_printing_migrate_internal.h"
-#include "rpc_server/eventlog/srv_eventlog_reg.h"
-#include "rpc_server/svcctl/srv_svcctl_reg.h"
-#include "rpc_server/spoolss/srv_spoolss_nt.h"
-#include "rpc_server/svcctl/srv_svcctl_nt.h"
-
-#include "lib/server_prefork.h"
-#include "librpc/rpc/dcesrv_core.h"
-#include "librpc/rpc/dcerpc_ep.h"
-#include "rpc_server/rpc_sock_helper.h"
-#include "rpc_server/rpc_service_setup.h"
-#include "rpc_server/rpc_ep_register.h"
-#include "rpc_server/rpc_server.h"
-#include "rpc_server/rpc_config.h"
-#include "rpc_server/rpc_modules.h"
-
-#undef DBGC_CLASS
-#define DBGC_CLASS DBGC_RPC_SRV
-
-static_decl_rpc;
-
-/* Common routine for embedded RPC servers */
-NTSTATUS rpc_setup_embedded(struct tevent_context *ev_ctx,
- struct messaging_context *msg_ctx,
- struct dcesrv_context *dce_ctx,
- const struct dcesrv_interface *iface)
-{
- enum rpc_service_mode_e epm_mode = rpc_epmapper_mode();
- NTSTATUS status;
-
- /* Registration of ncacn_np services is problematic. The
- * ev_ctx passed in here is passed down to all children of the
- * smbd process, and if the end point mapper ever goes away,
- * they will all attempt to re-register. But we want to test
- * the code for now, so it is enabled in on environment in
- * make test */
- if (epm_mode != RPC_SERVICE_MODE_DISABLED &&
- (lp_parm_bool(-1, "rpc_server", "register_embedded_np", false))) {
- status = rpc_ep_register(ev_ctx, msg_ctx, dce_ctx, iface);
- if (!NT_STATUS_IS_OK(status)) {
- return status;
- }
- }
-
- return NT_STATUS_OK;
-}
-
-NTSTATUS dcesrv_create_endpoint_sockets(struct tevent_context *ev_ctx,
- struct messaging_context *msg_ctx,
- struct dcesrv_endpoint *e,
- TALLOC_CTX *mem_ctx,
- size_t *pnum_fds,
- int **pfds)
-{
- struct dcerpc_binding *b = e->ep_description;
- char *binding = NULL;
- int *fds = NULL;
- size_t num_fds;
- NTSTATUS status;
-
- binding = dcerpc_binding_string(mem_ctx, b);
- if (binding == NULL) {
- return NT_STATUS_NO_MEMORY;
- }
- DBG_DEBUG("Creating endpoint '%s'\n", binding);
- TALLOC_FREE(binding);
-
- status = dcesrv_create_binding_sockets(b, mem_ctx, &num_fds, &fds);
-
- /* Build binding string again as the endpoint may have changed by
- * dcesrv_create_<transport>_socket functions */
- binding = dcerpc_binding_string(mem_ctx, b);
- if (binding == NULL) {
- return NT_STATUS_NO_MEMORY;
- }
-
- if (!NT_STATUS_IS_OK(status)) {
- struct dcesrv_if_list *iface = NULL;
- DBG_ERR("Failed to create '%s' sockets for ", binding);
- for (iface = e->interface_list; iface; iface = iface->next) {
- DEBUGADD(DBGLVL_ERR, ("'%s' ", iface->iface->name));
- }
- DEBUGADD(DBGLVL_ERR, (": %s\n", nt_errstr(status)));
- return status;
- } else {
- struct dcesrv_if_list *iface = NULL;
- DBG_INFO("Successfully listening on '%s' for ", binding);
- for (iface = e->interface_list; iface; iface = iface->next) {
- DEBUGADD(DBGLVL_INFO, ("'%s' ", iface->iface->name));
- }
- DEBUGADD(DBGLVL_INFO, ("\n"));
- }
-
- TALLOC_FREE(binding);
-
- *pnum_fds = num_fds;
- *pfds = fds;
-
- return status;
-}
-
-NTSTATUS dcesrv_create_endpoint_list_pf_listen_fds(
- struct tevent_context *ev_ctx,
- struct messaging_context *msg_ctx,
- struct dcesrv_context *dce_ctx,
- struct dcesrv_endpoint *e,
- TALLOC_CTX *mem_ctx,
- size_t *pnum_fds,
- struct pf_listen_fd **pfds)
-{
- struct pf_listen_fd *fds = NULL;
- size_t num_fds = 0;
- NTSTATUS status;
-
- for (; e != NULL; e = e->next) {
- int *ep_fds = NULL;
- struct pf_listen_fd *tmp = NULL;
- size_t i, num_ep_fds;
-
- status = dcesrv_create_endpoint_sockets(
- ev_ctx,
- msg_ctx,
- e,
- mem_ctx,
- &num_ep_fds,
- &ep_fds);
- if (!NT_STATUS_IS_OK(status)) {
- char *ep_string = dcerpc_binding_string(
- dce_ctx, e->ep_description);
- DBG_ERR("Failed to create endpoint '%s': %s\n",
- ep_string, nt_errstr(status));
- TALLOC_FREE(ep_string);
- goto fail;
- }
-
- if (num_fds + num_ep_fds < num_fds) {
- /* overflow */
- status = NT_STATUS_INTEGER_OVERFLOW;
- goto fail;
- }
-
- tmp = talloc_realloc(
- mem_ctx,
- fds,
- struct pf_listen_fd,
- num_fds + num_ep_fds);
- if (tmp == NULL) {
- status = NT_STATUS_NO_MEMORY;
- goto fail;
- }
- fds = tmp;
-
- for (i=0; i<num_ep_fds; i++) {
- fds[num_fds].fd = ep_fds[i];
- fds[num_fds].fd_data = e;
- num_fds += 1;
- }
-
- TALLOC_FREE(ep_fds);
- }
-
- *pnum_fds = num_fds;
- *pfds = fds;
- return NT_STATUS_OK;
-
-fail:
- {
- size_t i;
- for (i=0; i<num_fds; i++) {
- close(fds[i].fd);
- }
- }
-
- TALLOC_FREE(fds);
- return status;
-}
-
-NTSTATUS dcesrv_setup_endpoint_sockets(struct tevent_context *ev_ctx,
- struct messaging_context *msg_ctx,
- struct dcesrv_context *dce_ctx,
- struct dcesrv_endpoint *e,
- dcerpc_ncacn_termination_fn term_fn,
- void *term_data)
-{
- TALLOC_CTX *frame = talloc_stackframe();
- struct dcerpc_binding *b = e->ep_description;
- char *binding = NULL;
- NTSTATUS status = NT_STATUS_NO_MEMORY;
- struct dcesrv_if_list *iface = NULL;
- int *fds = NULL;
- size_t i, num_fds = 0;
- struct dcerpc_ncacn_listen_state **listen_states = NULL;
-
- binding = dcerpc_binding_string(frame, b);
- if (binding == NULL) {
- goto fail;
- }
-
- DBG_DEBUG("Setting up endpoint '%s'\n", binding);
- TALLOC_FREE(binding);
-
- status = dcesrv_create_binding_sockets(b, frame, &num_fds, &fds);
-
- /* Build binding string again as the endpoint may have changed by
- * dcesrv_create_<transport>_socket functions */
- binding = dcerpc_binding_string(frame, b);
- if (binding == NULL) {
- status = NT_STATUS_NO_MEMORY;
- goto fail;
- }
-
- if (!NT_STATUS_IS_OK(status)) {
- DBG_ERR("Failed to setup '%s' sockets for ", binding);
- for (iface = e->interface_list; iface; iface = iface->next) {
- DEBUGADD(DBGLVL_ERR, ("'%s' ", iface->iface->name));
- }
- DEBUGADD(DBGLVL_ERR, (": %s\n", nt_errstr(status)));
- goto fail;
- }
-
- listen_states = talloc_array(
- frame, struct dcerpc_ncacn_listen_state *, num_fds);
- if (listen_states == NULL) {
- status = NT_STATUS_NO_MEMORY;
- goto fail;
- }
-
- for (i=0; i<num_fds; i++) {
- int ret = dcesrv_setup_ncacn_listener(
- listen_states,
- dce_ctx,
- ev_ctx,
- msg_ctx,
- e,
- &fds[i],
- term_fn,
- term_data,
- &listen_states[i]);
- if (ret != 0) {
- DBG_ERR("dcesrv_setup_ncacn_listener failed for "
- "socket %d: %s\n",
- fds[i],
- strerror(ret));
- break;
- }
- }
-
- if (i < num_fds) {
- goto fail;
- }
-
- for (i=0; i<num_fds; i++) {
- /*
- * Make the listener states including the tevent_fd's
- * talloc children of the endpoint. If the endpoint is
- * freed (for example when forked daemons reinit) the
- * dcesrv_context, the tevent_fd listener will be
- * stopped and the socket closed.
- *
- * Do this in a loop separate from the one doing the
- * dcesrv_setup_ncacn_listener() that can't fail
- * anymore.
- */
- talloc_move(e, &listen_states[i]);
- }
-
- DBG_INFO("Successfully listening on '%s' for ", binding);
- for (iface = e->interface_list; iface; iface = iface->next) {
- DEBUGADD(DBGLVL_INFO, ("'%s' ", iface->iface->name));
- }
- DEBUGADD(DBGLVL_INFO, ("\n"));
-
- TALLOC_FREE(frame);
- return NT_STATUS_OK;
-
-fail:
- for (i=0; i<num_fds; i++) {
- if (fds[i] != -1) {
- close(fds[i]);
- }
- }
- TALLOC_FREE(frame);
- return status;
-}
-
-static NTSTATUS dcesrv_init_endpoints(struct tevent_context *ev_ctx,
- struct messaging_context *msg_ctx,
- struct dcesrv_context *dce_ctx)
-{
- struct dcesrv_endpoint *e = NULL;
- NTSTATUS status;
-
- for (e = dce_ctx->endpoint_list; e; e = e->next) {
- enum dcerpc_transport_t transport =
- dcerpc_binding_get_transport(e->ep_description);
-
- if (transport == NCACN_HTTP) {
- /*
- * We don't support ncacn_http yet
- */
- continue;
- }
-
- status = dcesrv_setup_endpoint_sockets(ev_ctx,
- msg_ctx,
- dce_ctx,
- e,
- NULL,
- NULL);
- if (!NT_STATUS_IS_OK(status)) {
- return status;
- }
-
- /* Register only NCACN_NP for embedded services */
- if (transport == NCACN_NP) {
- struct dcesrv_if_list *ifl = NULL;
- for (ifl = e->interface_list; ifl; ifl = ifl->next) {
- status = rpc_setup_embedded(ev_ctx,
- msg_ctx,
- dce_ctx,
- ifl->iface);
- if (!NT_STATUS_IS_OK(status)) {
- DBG_ERR("Failed to register embedded "
- "interface in endpoint mapper "
- ": %s", nt_errstr(status));
- return status;
- }
- }
- }
- }
-
- return NT_STATUS_OK;
-}
-
-static NTSTATUS rpc_setup_winreg(struct tevent_context *ev_ctx,
- struct messaging_context *msg_ctx)
-{
- NTSTATUS status;
- enum rpc_service_mode_e service_mode;
- const struct dcesrv_endpoint_server *ep_server = NULL;
-
- /* Register the endpoint server in DCERPC core */
- ep_server = winreg_get_ep_server();
- if (ep_server == NULL) {
- DBG_ERR("Failed to get 'winreg' endpoint server\n");
- return NT_STATUS_UNSUCCESSFUL;
- }
-
- service_mode = rpc_service_mode(ep_server->name);
- if (service_mode != RPC_SERVICE_MODE_EMBEDDED) {
- return NT_STATUS_OK;
- }
-
- status = dcerpc_register_ep_server(ep_server);
- if (!NT_STATUS_IS_OK(status)) {
- DBG_ERR("Failed to register '%s' endpoint server: "
- "%s\n", ep_server->name, nt_errstr(status));
- return status;
- }
-
- return NT_STATUS_OK;
-}
-
-static NTSTATUS rpc_setup_srvsvc(struct tevent_context *ev_ctx,
- struct messaging_context *msg_ctx)
-{
- NTSTATUS status;
- enum rpc_service_mode_e service_mode;
- const struct dcesrv_endpoint_server *ep_server = NULL;
-
- /* Register the endpoint server in DCERPC core */
- ep_server = srvsvc_get_ep_server();
- if (ep_server == NULL) {
- DBG_ERR("Failed to get 'srvsvc' endpoint server\n");
- return NT_STATUS_UNSUCCESSFUL;
- }
-
- service_mode = rpc_service_mode(ep_server->name);
- if (service_mode != RPC_SERVICE_MODE_EMBEDDED) {
- return NT_STATUS_OK;
- }
-
- status = dcerpc_register_ep_server(ep_server);
- if (!NT_STATUS_IS_OK(status)) {
- DBG_ERR("Failed to register '%s' endpoint server: "
- "%s\n", ep_server->name, nt_errstr(status));
- return status;
- }
-
- return NT_STATUS_OK;
-}
-
-static NTSTATUS rpc_setup_lsarpc(struct tevent_context *ev_ctx,
- struct messaging_context *msg_ctx)
-{
- enum rpc_daemon_type_e lsasd_type = rpc_lsasd_daemon();
- NTSTATUS status;
- enum rpc_service_mode_e service_mode;
- const struct dcesrv_endpoint_server *ep_server = NULL;
-
- /* Register the endpoint server in DCERPC core */
- ep_server = lsarpc_get_ep_server();
- if (ep_server == NULL) {
- DBG_ERR("Failed to get 'lsarpc' endpoint server\n");
- return NT_STATUS_UNSUCCESSFUL;
- }
-
- service_mode = rpc_service_mode(ep_server->name);
- if (service_mode != RPC_SERVICE_MODE_EMBEDDED ||
- lsasd_type != RPC_DAEMON_EMBEDDED) {
- return NT_STATUS_OK;
- }
-
- status = dcerpc_register_ep_server(ep_server);
- if (!NT_STATUS_IS_OK(status)) {
- DBG_ERR("Failed to register '%s' endpoint server: "
- "%s\n", ep_server->name, nt_errstr(status));
- return status;
- }
-
- return NT_STATUS_OK;
-}
-
-static NTSTATUS rpc_setup_samr(struct tevent_context *ev_ctx,
- struct messaging_context *msg_ctx)
-{
- enum rpc_daemon_type_e lsasd_type = rpc_lsasd_daemon();
- NTSTATUS status;
- enum rpc_service_mode_e service_mode;
- const struct dcesrv_endpoint_server *ep_server = NULL;
-
- /* Register the endpoint server in DCERPC core */
- ep_server = samr_get_ep_server();
- if (ep_server == NULL) {
- DBG_ERR("Failed to get 'samr' endpoint server\n");
- return NT_STATUS_UNSUCCESSFUL;
- }
-
- service_mode = rpc_service_mode(ep_server->name);
- if (service_mode != RPC_SERVICE_MODE_EMBEDDED ||
- lsasd_type != RPC_DAEMON_EMBEDDED) {
- return NT_STATUS_OK;
- }
-
- status = dcerpc_register_ep_server(ep_server);
- if (!NT_STATUS_IS_OK(status)) {
- DBG_ERR("Failed to register '%s' endpoint server: "
- "%s\n", ep_server->name, nt_errstr(status));
- return status;
- }
-
- return NT_STATUS_OK;
-}
-
-static NTSTATUS rpc_setup_netlogon(struct tevent_context *ev_ctx,
- struct messaging_context *msg_ctx)
-{
- enum rpc_daemon_type_e lsasd_type = rpc_lsasd_daemon();
- NTSTATUS status;
- enum rpc_service_mode_e service_mode;
- const struct dcesrv_endpoint_server *ep_server = NULL;
-
- /* Register the endpoint server in DCERPC core */
- ep_server = netlogon_get_ep_server();
- if (ep_server == NULL) {
- DBG_ERR("Failed to get 'netlogon' endpoint server\n");
- return NT_STATUS_UNSUCCESSFUL;
- }
-
- service_mode = rpc_service_mode(ep_server->name);
- if (service_mode != RPC_SERVICE_MODE_EMBEDDED ||
- lsasd_type != RPC_DAEMON_EMBEDDED) {
- return NT_STATUS_OK;
- }
-
- status = dcerpc_register_ep_server(ep_server);
- if (!NT_STATUS_IS_OK(status)) {
- DBG_ERR("Failed to register '%s' endpoint server: "
- "%s\n", ep_server->name, nt_errstr(status));
- return status;
- }
-
- return NT_STATUS_OK;
-}
-
-static NTSTATUS rpc_setup_netdfs(struct tevent_context *ev_ctx,
- struct messaging_context *msg_ctx)
-{
- NTSTATUS status;
- enum rpc_service_mode_e service_mode;
- const struct dcesrv_endpoint_server *ep_server = NULL;
-
- /* Register the endpoint server in DCERPC core */
- ep_server = netdfs_get_ep_server();
- if (ep_server == NULL) {
- DBG_ERR("Failed to get 'netdfs' endpoint server\n");
- return NT_STATUS_UNSUCCESSFUL;
- }
-
- service_mode = rpc_service_mode(ep_server->name);
- if (service_mode != RPC_SERVICE_MODE_EMBEDDED) {
- return NT_STATUS_OK;
- }
-
- status = dcerpc_register_ep_server(ep_server);
- if (!NT_STATUS_IS_OK(status)) {
- DBG_ERR("Failed to register '%s' endpoint server: "
- "%s\n", ep_server->name, nt_errstr(status));
- return status;
- }
-
- return NT_STATUS_OK;
-}
-
-#ifdef DEVELOPER
-static NTSTATUS rpc_setup_rpcecho(struct tevent_context *ev_ctx,
- struct messaging_context *msg_ctx)
-{
- NTSTATUS status;
- enum rpc_service_mode_e service_mode;
- const struct dcesrv_endpoint_server *ep_server = NULL;
-
- /* Register the endpoint server in DCERPC core */
- ep_server = rpcecho_get_ep_server();
- if (ep_server == NULL) {
- DBG_ERR("Failed to get 'rpcecho' endpoint server\n");
- return NT_STATUS_UNSUCCESSFUL;
- }
-
- service_mode = rpc_service_mode(ep_server->name);
- if (service_mode != RPC_SERVICE_MODE_EMBEDDED) {
- return NT_STATUS_OK;
- }
-
- status = dcerpc_register_ep_server(ep_server);
- if (!NT_STATUS_IS_OK(status)) {
- DBG_ERR("Failed to register '%s' endpoint server: "
- "%s\n", ep_server->name, nt_errstr(status));
- return status;
- }
-
- return NT_STATUS_OK;
-}
-#endif
-
-static NTSTATUS rpc_setup_dssetup(struct tevent_context *ev_ctx,
- struct messaging_context *msg_ctx)
-{
- NTSTATUS status;
- enum rpc_service_mode_e service_mode;
- const struct dcesrv_endpoint_server *ep_server = NULL;
-
- /* Register the endpoint server in DCERPC core */
- ep_server = dssetup_get_ep_server();
- if (ep_server == NULL) {
- DBG_ERR("Failed to get 'dssetup' endpoint server\n");
- return NT_STATUS_UNSUCCESSFUL;
- }
-
- service_mode = rpc_service_mode(ep_server->name);
- if (service_mode != RPC_SERVICE_MODE_EMBEDDED) {
- return NT_STATUS_OK;
- }
-
- status = dcerpc_register_ep_server(ep_server);
- if (!NT_STATUS_IS_OK(status)) {
- DBG_ERR("Failed to register '%s' endpoint server: "
- "%s\n", ep_server->name, nt_errstr(status));
- return status;
- }
-
- return NT_STATUS_OK;
-}
-
-static NTSTATUS rpc_setup_wkssvc(struct tevent_context *ev_ctx,
- struct messaging_context *msg_ctx)
-{
- NTSTATUS status;
- enum rpc_service_mode_e service_mode;
- const struct dcesrv_endpoint_server *ep_server = NULL;
-
- /* Register the endpoint server in DCERPC core */
- ep_server = wkssvc_get_ep_server();
- if (ep_server == NULL) {
- DBG_ERR("Failed to get 'wkssvc' endpoint server\n");
- return NT_STATUS_UNSUCCESSFUL;
- }
-
- service_mode = rpc_service_mode(ep_server->name);
- if (service_mode != RPC_SERVICE_MODE_EMBEDDED) {
- return NT_STATUS_OK;
- }
-
- status = dcerpc_register_ep_server(ep_server);
- if (!NT_STATUS_IS_OK(status)) {
- DBG_ERR("Failed to register '%s' endpoint server: "
- "%s\n", ep_server->name, nt_errstr(status));
- return status;
- }
-
- return NT_STATUS_OK;
-}
-
-static NTSTATUS rpc_setup_spoolss(struct tevent_context *ev_ctx,
- struct messaging_context *msg_ctx)
-{
- enum rpc_daemon_type_e spoolss_type = rpc_spoolss_daemon();
- NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
- enum rpc_service_mode_e service_mode;
- const struct dcesrv_endpoint_server *ep_server = NULL;
-
- if (lp__disable_spoolss()) {
- return NT_STATUS_OK;
- }
-
- /* Register the endpoint server in DCERPC core */
- ep_server = spoolss_get_ep_server();
- if (ep_server == NULL) {
- DBG_ERR("Failed to get 'spoolss' endpoint server\n");
- return NT_STATUS_UNSUCCESSFUL;
- }
-
- service_mode = rpc_service_mode(ep_server->name);
- if (service_mode != RPC_SERVICE_MODE_EMBEDDED ||
- spoolss_type != RPC_DAEMON_EMBEDDED) {
- return NT_STATUS_OK;
- }
-
- status = dcerpc_register_ep_server(ep_server);
- if (!NT_STATUS_IS_OK(status)) {
- DBG_ERR("Failed to register '%s' endpoint server"
- ": %s\n", ep_server->name, nt_errstr(status));
- return status;
- }
-
- return NT_STATUS_OK;
-}
-
-static NTSTATUS rpc_setup_svcctl(struct tevent_context *ev_ctx,
- struct messaging_context *msg_ctx)
-{
- NTSTATUS status;
- enum rpc_service_mode_e service_mode;
- const struct dcesrv_endpoint_server *ep_server = NULL;
-
- /* Register the endpoint server in DCERPC core */
- ep_server = svcctl_get_ep_server();
- if (ep_server == NULL) {
- DBG_ERR("Failed to get 'svcctl' endpoint server\n");
- return NT_STATUS_UNSUCCESSFUL;
- }
-
- service_mode = rpc_service_mode(ep_server->name);
- if (service_mode != RPC_SERVICE_MODE_EMBEDDED) {
- return NT_STATUS_OK;
- }
-
- status = dcerpc_register_ep_server(ep_server);
- if (!NT_STATUS_IS_OK(status)) {
- DBG_ERR("Failed to register '%s' endpoint server"
- ": %s\n", ep_server->name, nt_errstr(status));
- return status;
- }
-
- return NT_STATUS_OK;
-}
-
-static NTSTATUS rpc_setup_ntsvcs(struct tevent_context *ev_ctx,
- struct messaging_context *msg_ctx)
-{
- NTSTATUS status;
- enum rpc_service_mode_e service_mode;
- const struct dcesrv_endpoint_server *ep_server = NULL;
-
- /* Register the endpoint server in DCERPC core */
- ep_server = ntsvcs_get_ep_server();
- if (ep_server == NULL) {
- DBG_ERR("Failed to get 'ntsvcs' endpoint server\n");
- return NT_STATUS_UNSUCCESSFUL;
- }
-
- service_mode = rpc_service_mode(ep_server->name);
- if (service_mode != RPC_SERVICE_MODE_EMBEDDED) {
- return NT_STATUS_OK;
- }
-
- status = dcerpc_register_ep_server(ep_server);
- if (!NT_STATUS_IS_OK(status)) {
- DBG_ERR("Failed to register '%s' endpoint server"
- ": %s\n", ep_server->name, nt_errstr(status));
- return status;
- }
-
- return NT_STATUS_OK;
-}
-
-static NTSTATUS rpc_setup_eventlog(struct tevent_context *ev_ctx,
- struct messaging_context *msg_ctx)
-{
- NTSTATUS status;
- enum rpc_service_mode_e service_mode;
- const struct dcesrv_endpoint_server *ep_server = NULL;
-
- /* Register the endpoint server in DCERPC core */
- ep_server = eventlog_get_ep_server();
- if (ep_server == NULL) {
- DBG_ERR("Failed to get 'eventlog' endpoint server\n");
- return NT_STATUS_UNSUCCESSFUL;
- }
-
- service_mode = rpc_service_mode(ep_server->name);
- if (service_mode != RPC_SERVICE_MODE_EMBEDDED) {
- return NT_STATUS_OK;
- }
-
- status = dcerpc_register_ep_server(ep_server);
- if (!NT_STATUS_IS_OK(status)) {
- DBG_ERR("Failed to register '%s' endpoint server"
- ": %s\n", ep_server->name, nt_errstr(status));
- return status;
- }
-
- return NT_STATUS_OK;
-}
-
-static NTSTATUS rpc_setup_initshutdown(struct tevent_context *ev_ctx,
- struct messaging_context *msg_ctx)
-{
- NTSTATUS status;
- enum rpc_service_mode_e service_mode;
- const struct dcesrv_endpoint_server *ep_server = NULL;
-
- /* Register the endpoint server in DCERPC core */
- ep_server = initshutdown_get_ep_server();
- if (ep_server == NULL) {
- DBG_ERR("Failed to get 'initshutdown' endpoint server\n");
- return NT_STATUS_UNSUCCESSFUL;
- }
-
- service_mode = rpc_service_mode(ep_server->name);
- if (service_mode != RPC_SERVICE_MODE_EMBEDDED) {
- return NT_STATUS_OK;
- }
-
- status = dcerpc_register_ep_server(ep_server);
- if (!NT_STATUS_IS_OK(status)) {
- DBG_ERR("Failed to register '%s' endpoint "
- "server: %s\n", ep_server->name, nt_errstr(status));
- return status;
- }
-
- return NT_STATUS_OK;
-}
-
-NTSTATUS dcesrv_init(TALLOC_CTX *mem_ctx,
- struct tevent_context *ev_ctx,
- struct messaging_context *msg_ctx,
- struct dcesrv_context *dce_ctx)
-{
- TALLOC_CTX *tmp_ctx;
- bool ok;
- init_module_fn *mod_init_fns = NULL;
- NTSTATUS status;
-
- tmp_ctx = talloc_stackframe();
- if (tmp_ctx == NULL) {
- return NT_STATUS_NO_MEMORY;
- }
-
- DBG_INFO("Registering DCE/RPC endpoint servers\n");
-
- status = rpc_setup_winreg(ev_ctx, msg_ctx);
- if (!NT_STATUS_IS_OK(status)) {
- goto done;
- }
-
- status = rpc_setup_srvsvc(ev_ctx, msg_ctx);
- if (!NT_STATUS_IS_OK(status)) {
- goto done;
- }
-
- status = rpc_setup_lsarpc(ev_ctx, msg_ctx);
- if (!NT_STATUS_IS_OK(status)) {
- goto done;
- }
-
- status = rpc_setup_samr(ev_ctx, msg_ctx);
- if (!NT_STATUS_IS_OK(status)) {
- goto done;
- }
-
- status = rpc_setup_netlogon(ev_ctx, msg_ctx);
- if (!NT_STATUS_IS_OK(status)) {
- goto done;
- }
-
- status = rpc_setup_netdfs(ev_ctx, msg_ctx);
- if (!NT_STATUS_IS_OK(status)) {
- goto done;
- }
-
-#ifdef DEVELOPER
- status = rpc_setup_rpcecho(ev_ctx, msg_ctx);
- if (!NT_STATUS_IS_OK(status)) {
- goto done;
- }
-#endif
-
- status = rpc_setup_dssetup(ev_ctx, msg_ctx);
- if (!NT_STATUS_IS_OK(status)) {
- goto done;
- }
-
- status = rpc_setup_wkssvc(ev_ctx, msg_ctx);
- if (!NT_STATUS_IS_OK(status)) {
- goto done;
- }
-
- status = rpc_setup_spoolss(ev_ctx, msg_ctx);
- if (!NT_STATUS_IS_OK(status)) {
- goto done;
- }
-
- status = rpc_setup_svcctl(ev_ctx, msg_ctx);
- if (!NT_STATUS_IS_OK(status)) {
- goto done;
- }
-
- status = rpc_setup_ntsvcs(ev_ctx, msg_ctx);
- if (!NT_STATUS_IS_OK(status)) {
- goto done;
- }
-
- status = rpc_setup_eventlog(ev_ctx, msg_ctx);
- if (!NT_STATUS_IS_OK(status)) {
- goto done;
- }
-
- status = rpc_setup_initshutdown(ev_ctx, msg_ctx);
- if (!NT_STATUS_IS_OK(status)) {
- goto done;
- }
-
- DBG_INFO("Initializing DCE/RPC modules\n");
-
- /* Initialize static subsystems */
- static_init_rpc(NULL);
-
- /* Initialize shared modules */
- mod_init_fns = load_samba_modules(tmp_ctx, "rpc");
- if ((mod_init_fns == NULL) && (errno != ENOENT)) {
- /*
- * ENOENT means the directory doesn't exist which can happen if
- * all modules are static. So ENOENT is ok, everything else is
- * not ok.
- */
- DBG_ERR("Loading shared DCE/RPC modules failed [%s]\n",
- strerror(errno));
- status = NT_STATUS_UNSUCCESSFUL;
- goto done;
- }
-
- ok = run_init_functions(NULL, mod_init_fns);
- if (!ok) {
- DBG_ERR("Initializing shared DCE/RPC modules failed\n");
- status = NT_STATUS_UNSUCCESSFUL;
- goto done;
- }
-
- /* The RPC module setup function has to register the endpoint server */
- ok = setup_rpc_modules(ev_ctx, msg_ctx);
- if (!ok) {
- DBG_ERR("Shared DCE/RPC modules setup failed\n");
- status = NT_STATUS_UNSUCCESSFUL;
- goto done;
- }
-
- DBG_INFO("Initializing DCE/RPC registered endpoint servers\n");
-
- status = dcesrv_init_registered_ep_servers(dce_ctx);
- if (!NT_STATUS_IS_OK(status)) {
- DBG_ERR("Failed to init DCE/RPC endpoint servers: %s\n",
- nt_errstr(status));
- goto done;
- }
-
- DBG_INFO("Initializing DCE/RPC connection endpoints\n");
-
- status = dcesrv_init_endpoints(ev_ctx, msg_ctx, dce_ctx);
- if (!NT_STATUS_IS_OK(status)) {
- DBG_ERR("Failed to init DCE/RPC endpoints: %s\n",
- nt_errstr(status));
- goto done;
- }
-
- status = NT_STATUS_OK;
-done:
- talloc_free(tmp_ctx);
- return status;
-}
-
-/* vim: set ts=8 sw=8 noet cindent ft=c.doxygen: */
+++ /dev/null
-/*
- * Unix SMB/CIFS implementation.
- *
- * SMBD RPC service callbacks
- *
- * Copyright (c) 2011 Andreas Schneider <asn@samba.org>
- *
- * 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 3 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, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef _RPC_EP_SETUP_H
-#define _RPC_EP_SETUP_H
-
-#include "rpc_server/rpc_server.h"
-
-struct pf_listen_fd;
-
-NTSTATUS dcesrv_init(TALLOC_CTX *mem_ctx,
- struct tevent_context *ev_ctx,
- struct messaging_context *msg_ctx,
- struct dcesrv_context *dce_ctx);
-
-NTSTATUS dcesrv_setup_endpoint_sockets(struct tevent_context *ev_ctx,
- struct messaging_context *msg_ctx,
- struct dcesrv_context *dce_ctx,
- struct dcesrv_endpoint *e,
- dcerpc_ncacn_termination_fn term_fn,
- void *term_data);
-
-NTSTATUS dcesrv_create_endpoint_sockets(struct tevent_context *ev_ctx,
- struct messaging_context *msg_ctx,
- struct dcesrv_endpoint *e,
- TALLOC_CTX *mem_ctx,
- size_t *pnum_fds,
- int **pfds);
-NTSTATUS dcesrv_create_endpoint_list_pf_listen_fds(
- struct tevent_context *ev_ctx,
- struct messaging_context *msg_ctx,
- struct dcesrv_context *dce_ctx,
- struct dcesrv_endpoint *e,
- TALLOC_CTX *mem_ctx,
- size_t *pnum_fds,
- struct pf_listen_fd **pfds);
-
-NTSTATUS rpc_setup_embedded(struct tevent_context *ev_ctx,
- struct messaging_context *msg_ctx,
- struct dcesrv_context *dce_ctx,
- const struct dcesrv_interface *iface);
-
-#endif /* _RPC_EP_SETUP_H */
-
-/* vim: set ts=8 sw=8 noet cindent ft=c.doxygen: */
#include "../lib/tsocket/tsocket.h"
#include "librpc/rpc/dcesrv_core.h"
#include "rpc_server/rpc_sock_helper.h"
-#include "lib/server_prefork.h"
#include "librpc/ndr/ndr_table.h"
#undef DBGC_CLASS
+++ /dev/null
-/*
- * Unix SMB/CIFS implementation.
- * RPC Pipe client / server routines
- * Almost completely rewritten by (C) Jeremy Allison 2005 - 2010
- *
- * 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 3 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, see <http://www.gnu.org/licenses/>.
- */
-
-/* this module apparently provides an implementation of DCE/RPC over a
- * named pipe (IPC$ connection using SMBtrans). details of DCE/RPC
- * documentation are available (in on-line form) from the X-Open group.
- *
- * this module should provide a level of abstraction between SMB
- * and DCE/RPC, while minimising the amount of mallocs, unnecessary
- * data copies, and network traffic.
- *
- */
-
-#include "includes.h"
-#include "rpc_server.h"
-#include "rpc_server/srv_pipe.h"
-
-#undef DBGC_CLASS
-#define DBGC_CLASS DBGC_RPC_SRV
-
-/**
- * Is a named pipe known?
- * @param[in] dce_ctx The rpc server context
- * @param[in] pipename Just the filename
- * @param[out] endpoint The DCERPC endpoint serving the pipe name
- * @result NT error code
- */
-NTSTATUS is_known_pipename(struct dcesrv_context *dce_ctx,
- const char *pipename,
- struct dcesrv_endpoint **ep)
-{
- NTSTATUS status;
-
- if (strchr(pipename, '/')) {
- DBG_WARNING("Refusing open on pipe %s\n", pipename);
- return NT_STATUS_OBJECT_NAME_NOT_FOUND;
- }
-
- if (lp_disable_spoolss() && strequal(pipename, "spoolss")) {
- DBG_DEBUG("refusing spoolss access\n");
- return NT_STATUS_OBJECT_NAME_NOT_FOUND;
- }
-
- status = dcesrv_endpoint_by_ncacn_np_name(dce_ctx, pipename, ep);
- if (NT_STATUS_IS_OK(status)) {
- return NT_STATUS_OK;
- }
-
- status = smb_probe_module("rpc", pipename);
- if (!NT_STATUS_IS_OK(status)) {
- DBG_DEBUG("Unknown pipe '%s'\n", pipename);
- return NT_STATUS_OBJECT_NAME_NOT_FOUND;
- }
- DBG_DEBUG("'%s' loaded dynamically\n", pipename);
-
- /*
- * Scan the list again for the interface id
- */
- status = dcesrv_endpoint_by_ncacn_np_name(dce_ctx, pipename, ep);
- if (NT_STATUS_IS_OK(status)) {
- return NT_STATUS_OK;
- }
-
- DBG_DEBUG("pipe %s did not register itself!\n", pipename);
-
- return NT_STATUS_OBJECT_NAME_NOT_FOUND;
-}
+++ /dev/null
-/*
- * Unix SMB/CIFS implementation.
- * RPC Pipe client / server routines
- * Almost completely rewritten by (C) Jeremy Allison 2005 - 2010
- *
- * 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 3 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, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef _RPC_SERVER_SRV_PIPE_H_
-#define _RPC_SERVER_SRV_PIPE_H_
-
-struct dcesrv_context;
-struct dcesrv_endpoint;
-
-/* The following definitions come from rpc_server/srv_pipe.c */
-
-NTSTATUS is_known_pipename(struct dcesrv_context *dce_ctx,
- const char *pipename,
- struct dcesrv_endpoint **ep);
-
-#endif /* _RPC_SERVER_SRV_PIPE_H_ */
lib/gencache.c
lib/util_event.c
lib/global_contexts.c
- lib/server_prefork.c
- lib/server_prefork_util.c
lib/ldap_escape.c
lib/system_smbd.c
lib/audit.c