/*
* This file and its contents are supplied under the terms of the
* Common Development and Distribution License ("CDDL"), version 1.0.
* You may only use this file in accordance with the terms of version
* 1.0 of the CDDL.
*
* A full copy of the text of the CDDL should have accompanied this
* source. A copy of the CDDL is also available via the Internet at
*/
/*
* Copyright 2015 Nexenta Systems, Inc. All rights reserved.
*/
/*
* This is the named pipe service for smbd.
*/
#include <stdio.h>
#include <strings.h>
#include <stdlib.h>
#include <synch.h>
#include <unistd.h>
#include <fcntl.h>
#include <door.h>
#include <errno.h>
#include <pthread.h>
#include <signal.h>
#include <smbsrv/libmlsvc.h>
#include "smbd.h"
struct pipe_listener {
const char *name;
int max_allowed;
int max_seen;
int current;
};
static void *pipesvc_listener(void *);
static void *pipesvc_worker(void *);
int pipesvc_workers_cur = 0;
/*
* Allow more opens on SRVSVC because that's used by many clients
* to get the share list, etc.
*/
static struct pipe_listener
{ "eventlog", DEF_MAX_OPENS, 0, 0 },
{ "lsarpc", DEF_MAX_OPENS, 0, 0 },
{ "lsass", DEF_MAX_OPENS, 0, 0 },
{ "netdfs", DEF_MAX_OPENS, 0, 0 },
{ "netlogon", DEF_MAX_OPENS, 0, 0 },
{ "samr", DEF_MAX_OPENS, 0, 0 },
{ "spoolss", DEF_MAX_OPENS, 0, 0 },
{ "srvsvc", SRVSVC_MAX_OPENS, 0, 0 },
{ "svcctl", DEF_MAX_OPENS, 0, 0 },
{ "winreg", DEF_MAX_OPENS, 0, 0 },
{ "wkssvc", DEF_MAX_OPENS, 0, 0 },
};
static ndr_pipe_t *
{
/*
* Allocating ndr_pipe_t + smb_netuserinfo_t as one.
* We could just make that part of ndr_pipe_t, but
* that struct is opaque to libmlrpc.
*/
return (NULL);
return (np);
}
static void
{
}
/*
* Create the smbd opipe door service.
* Returns the door descriptor on success. Otherwise returns -1.
*/
int
smbd_pipesvc_start(void)
{
int i, rc;
if (mlsvc_init() != 0) {
smbd_report("msrpc initialization failed");
return (-1);
}
(void) pthread_attr_init(&tattr);
for (i = 0; i < NLISTENERS; i++) {
pl = &pipe_listeners[i];
continue;
if (rc != 0)
break;
}
if (rc != 0) {
}
(void) pthread_attr_destroy(&tattr);
return (rc);
}
void
smbd_pipesvc_stop(void)
{
int i;
(void) mutex_lock(&pipesvc_mutex);
for (i = 0; i < NLISTENERS; i++) {
if (pipe_listeners[i].tid == 0)
continue;
pipe_listeners[i].tid = 0;
}
(void) mutex_unlock(&pipesvc_mutex);
}
static void *
{
int rc;
if (listen_fd < 0) {
return (NULL);
}
/* Bind it to a listening name. */
return (NULL);
}
return (NULL);
}
for (;;) {
if (newfd < 0) {
switch (err) {
case ECONNABORTED:
continue;
case EINTR:
/* normal termination */
goto out;
default:
smbd_report("pipesvc_listener, "
"accept failed: %d", errno);
}
break;
}
smbd_report("pipesvc_listener, alloc1 failed");
continue;
}
if (rc != 0) {
smbd_report("pipesvc_listener, pthread_create: %d",
errno);
continue;
}
(void) pthread_detach(tid);
/* Note: np_free in pipesvc_worker */
}
out:
return (NULL);
}
static void *
{
(void) mutex_lock(&pipesvc_mutex);
if (pipesvc_workers_cur >= pipesvc_workers_max ||
(void) mutex_unlock(&pipesvc_mutex);
goto out_free_np;
}
(void) mutex_unlock(&pipesvc_mutex);
/*
* The smbsrv kmod sends us one initial message containing an
* XDR encoded smb_netuserinfo_t that we read and decode here,
* all unbeknownst to libmlrpc.
*
* Might be nice to enhance getpeerucred() so it can give us
* all the info smb_netuserinfo_t carries, and then use that,
* which would allow using a more generic RPC service.
*/
if (rc != 0) {
goto out_decr;
}
smbd_report("pipesvc_worker, bad hdr");
goto out_decr;
}
smbd_report("pipesvc_worker, alloc1 failed");
goto out_decr;
}
if (rc != 0) {
goto out_decr;
}
smbd_report("pipesvc_worker, bad uinfo");
goto out_free_buf;
}
/*
* Later, could disallow opens of some pipes by
* anonymous users, etc. For now, reply "OK".
*/
status = 0;
if (rc != 0) {
goto out_free_buf;
}
/*
* Run the RPC service loop worker, which
* returns when it sees the pipe close.
*/
xdr_destroy(&xdrs);
(void) mutex_lock(&pipesvc_mutex);
(void) mutex_unlock(&pipesvc_mutex);
/* Cleanup what came in by varg. */
return (NULL);
}
/*
* via the ndr_pipe_t object to the libmlrpc`ndr_pipe_worker.
* These are called only with known PDU sizes and should
* loop as needed to transfer the entire message.
*/
static int
{
int x;
while (len > 0) {
if (x < 0)
return (errno);
if (x == 0)
return (EIO);
len -= x;
}
return (0);
}
static int
{
int x;
while (len > 0) {
if (x < 0)
return (errno);
if (x == 0)
return (EIO);
len -= x;
}
return (0);
}