1
0
mirror of https://github.com/samba-team/samba.git synced 2025-02-22 05:57:43 +03:00

s3:rpc_server: Delete unused code and doc references

Signed-off-by: Volker Lendecke <vl@samba.org>
Reviewed-by: Samuel Cabrero <scabrero@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
Reviewed-by: Stefan Metzmacher <metze@samba.org>
This commit is contained in:
Volker Lendecke 2021-06-08 09:10:05 +02:00
parent 9e3ee8c40c
commit 730f7dfd61
40 changed files with 0 additions and 8030 deletions

View File

@ -107,7 +107,6 @@
<programlisting>
<smbconfsection name="[global]"/>
<smbconfoption name="rpc_daemon:fssd">fork</smbconfoption>
<smbconfoption name="registry shares">yes</smbconfoption>
<smbconfoption name="include">registry</smbconfoption>

View File

@ -128,7 +128,6 @@
<programlisting>
<smbconfsection name="[global]"/>
<smbconfoption name="rpc_daemon:fssd">fork</smbconfoption>
<smbconfoption name="registry shares">yes</smbconfoption>
<smbconfoption name="include">registry</smbconfoption>
</programlisting>

View File

@ -70,7 +70,6 @@
<programlisting>
<smbconfsection name="[global]"/>
<smbconfoption name="rpc_daemon:fssd">fork</smbconfoption>
<smbconfoption name="registry shares">yes</smbconfoption>
<smbconfoption name="include">registry</smbconfoption>
</programlisting>

View File

@ -1,76 +0,0 @@
<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>

View File

@ -1,94 +0,0 @@
<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>

View File

@ -18,11 +18,6 @@
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>
@ -31,26 +26,6 @@
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>

View File

@ -1697,7 +1697,6 @@ sub setup_fileserver
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

View File

@ -1335,15 +1335,6 @@ winbindd:use external pipes = true
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

View File

@ -1,698 +0,0 @@
/*
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;
}

View File

@ -1,312 +0,0 @@
/*
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_ */

View File

@ -1,169 +0,0 @@
/*
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);
}

View File

@ -1,52 +0,0 @@
/*
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_ */

View File

@ -1,300 +0,0 @@
/*
* 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: */

View File

@ -1,77 +0,0 @@
/*
* 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_ */

View File

@ -1,822 +0,0 @@
/*
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);
}

View File

@ -1,32 +0,0 @@
/*
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_ */

View File

@ -72,13 +72,6 @@ struct dcesrv_epm_endpoint {
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;

View File

@ -1,246 +0,0 @@
/*
* 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: */

View File

@ -1,34 +0,0 @@
/*
* 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

View File

@ -1,238 +0,0 @@
/*
* 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);
}

View File

@ -1,34 +0,0 @@
/*
* 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

View File

@ -1,775 +0,0 @@
/*
* 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);
}

View File

@ -1,34 +0,0 @@
/*
* 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

View File

@ -1,691 +0,0 @@
/*
* 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);
}

View File

@ -1,34 +0,0 @@
/*
* 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

View File

@ -73,131 +73,3 @@ void global_dcesrv_context_free(void)
{
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

View File

@ -23,54 +23,6 @@
#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);

View File

@ -1,279 +0,0 @@
/*
* 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;
}

View File

@ -1,51 +0,0 @@
/*
* 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: */

View File

@ -1,102 +0,0 @@
/*
* 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;
}

View File

@ -1,39 +0,0 @@
/*
* 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

File diff suppressed because it is too large Load Diff

View File

@ -26,7 +26,6 @@
#include "source3/librpc/rpc/dcerpc.h"
struct dcesrv_ep_entry_list;
struct tsocket_address;
struct pipes_struct;
struct dcesrv_context;
@ -46,8 +45,6 @@ struct pipes_struct {
struct auth_session_info *session_info;
struct messaging_context *msg_ctx;
struct dcesrv_ep_entry_list *ep_entries;
struct pipe_auth_data auth;
/*

View File

@ -51,157 +51,6 @@ struct dcerpc_ncacn_listen_state {
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,
@ -231,331 +80,9 @@ NTSTATUS dcerpc_ncacn_conn_init(TALLOC_CTX *mem_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,

View File

@ -1,941 +0,0 @@
/*
* 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: */

View File

@ -1,63 +0,0 @@
/*
* 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: */

View File

@ -25,7 +25,6 @@
#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

View File

@ -1,83 +0,0 @@
/*
* 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;
}

View File

@ -1,32 +0,0 @@
/*
* 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_ */

View File

@ -378,8 +378,6 @@ bld.SAMBA3_SUBSYSTEM('samba3core',
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