168b2bbf2SGordon Ross /*
268b2bbf2SGordon Ross  * This file and its contents are supplied under the terms of the
368b2bbf2SGordon Ross  * Common Development and Distribution License ("CDDL"), version 1.0.
468b2bbf2SGordon Ross  * You may only use this file in accordance with the terms of version
568b2bbf2SGordon Ross  * 1.0 of the CDDL.
668b2bbf2SGordon Ross  *
768b2bbf2SGordon Ross  * A full copy of the text of the CDDL should have accompanied this
868b2bbf2SGordon Ross  * source.  A copy of the CDDL is also available via the Internet at
968b2bbf2SGordon Ross  * http://www.illumos.org/license/CDDL.
1068b2bbf2SGordon Ross  */
1168b2bbf2SGordon Ross 
1268b2bbf2SGordon Ross /*
1368b2bbf2SGordon Ross  * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
14*5d8538b6SGordon Ross  * Copyright 2022-2023 RackTop Systems, Inc.
1568b2bbf2SGordon Ross  */
1668b2bbf2SGordon Ross 
1768b2bbf2SGordon Ross /*
1868b2bbf2SGordon Ross  * This is the named pipe service for smbd.
1968b2bbf2SGordon Ross  */
2068b2bbf2SGordon Ross 
2168b2bbf2SGordon Ross #include <sys/types.h>
2268b2bbf2SGordon Ross #include <sys/stat.h>
2368b2bbf2SGordon Ross 
2468b2bbf2SGordon Ross #include <stdio.h>
2568b2bbf2SGordon Ross #include <strings.h>
2668b2bbf2SGordon Ross #include <stdlib.h>
2768b2bbf2SGordon Ross #include <synch.h>
2868b2bbf2SGordon Ross #include <unistd.h>
2968b2bbf2SGordon Ross #include <fcntl.h>
3068b2bbf2SGordon Ross #include <door.h>
3168b2bbf2SGordon Ross #include <errno.h>
3268b2bbf2SGordon Ross #include <pthread.h>
3368b2bbf2SGordon Ross #include <signal.h>
34b6b7639aSGordon Ross #include <ucred.h>
35b6b7639aSGordon Ross #include <priv.h>
3668b2bbf2SGordon Ross 
3768b2bbf2SGordon Ross #include <smbsrv/libsmb.h>
3868b2bbf2SGordon Ross #include <smbsrv/libmlsvc.h>
3968b2bbf2SGordon Ross #include <smbsrv/smb_xdr.h>
4068b2bbf2SGordon Ross #include "smbd.h"
4168b2bbf2SGordon Ross 
4268b2bbf2SGordon Ross struct pipe_listener {
4368b2bbf2SGordon Ross 	const char *name;
4468b2bbf2SGordon Ross 	int max_allowed;
4568b2bbf2SGordon Ross 	int max_seen;
4668b2bbf2SGordon Ross 	int current;
4768b2bbf2SGordon Ross 	pthread_t tid;
4868b2bbf2SGordon Ross };
4968b2bbf2SGordon Ross 
5068b2bbf2SGordon Ross static void *pipesvc_listener(void *);
5168b2bbf2SGordon Ross static void *pipesvc_worker(void *);
5268b2bbf2SGordon Ross static int pipe_send(ndr_pipe_t *, void *, size_t);
5368b2bbf2SGordon Ross static int pipe_recv(ndr_pipe_t *, void *, size_t);
5468b2bbf2SGordon Ross 
5568b2bbf2SGordon Ross mutex_t  pipesvc_mutex = DEFAULTMUTEX;
5668b2bbf2SGordon Ross int pipesvc_workers_max = 500;
5768b2bbf2SGordon Ross int pipesvc_workers_cur = 0;
5868b2bbf2SGordon Ross 
5968b2bbf2SGordon Ross uint16_t pipe_max_msgsize = SMB_PIPE_MAX_MSGSIZE;
6068b2bbf2SGordon Ross 
6168b2bbf2SGordon Ross /*
6268b2bbf2SGordon Ross  * Allow more opens on SRVSVC because that's used by many clients
6368b2bbf2SGordon Ross  * to get the share list, etc.
6468b2bbf2SGordon Ross  */
6568b2bbf2SGordon Ross #define	SRVSVC_MAX_OPENS	200
6668b2bbf2SGordon Ross #define	DEF_MAX_OPENS		50
6768b2bbf2SGordon Ross 
6868b2bbf2SGordon Ross #define	NLISTENERS	11
6968b2bbf2SGordon Ross static struct pipe_listener
7068b2bbf2SGordon Ross pipe_listeners[NLISTENERS] = {
7168b2bbf2SGordon Ross 	{ "eventlog",	DEF_MAX_OPENS, 0, 0 },
7268b2bbf2SGordon Ross 	{ "lsarpc",	DEF_MAX_OPENS, 0, 0 },
7368b2bbf2SGordon Ross 	{ "lsass",	DEF_MAX_OPENS, 0, 0 },
7468b2bbf2SGordon Ross 	{ "netdfs",	DEF_MAX_OPENS, 0, 0 },
7568b2bbf2SGordon Ross 	{ "netlogon",	DEF_MAX_OPENS, 0, 0 },
7668b2bbf2SGordon Ross 	{ "samr",	DEF_MAX_OPENS, 0, 0 },
7768b2bbf2SGordon Ross 	{ "spoolss",	DEF_MAX_OPENS, 0, 0 },
7868b2bbf2SGordon Ross 	{ "srvsvc",	SRVSVC_MAX_OPENS, 0, 0 },
7968b2bbf2SGordon Ross 	{ "svcctl",	DEF_MAX_OPENS, 0, 0 },
8068b2bbf2SGordon Ross 	{ "winreg",	DEF_MAX_OPENS, 0, 0 },
8168b2bbf2SGordon Ross 	{ "wkssvc",	DEF_MAX_OPENS, 0, 0 },
8268b2bbf2SGordon Ross };
8368b2bbf2SGordon Ross 
8468b2bbf2SGordon Ross static ndr_pipe_t *
np_new(struct pipe_listener * pl,int fid)8568b2bbf2SGordon Ross np_new(struct pipe_listener *pl, int fid)
8668b2bbf2SGordon Ross {
8768b2bbf2SGordon Ross 	ndr_pipe_t *np;
8868b2bbf2SGordon Ross 	size_t len;
8968b2bbf2SGordon Ross 
9068b2bbf2SGordon Ross 	/*
9168b2bbf2SGordon Ross 	 * Allocating ndr_pipe_t + smb_netuserinfo_t as one.
9268b2bbf2SGordon Ross 	 * We could just make that part of ndr_pipe_t, but
9368b2bbf2SGordon Ross 	 * that struct is opaque to libmlrpc.
9468b2bbf2SGordon Ross 	 */
9568b2bbf2SGordon Ross 	len = sizeof (*np) + sizeof (smb_netuserinfo_t);
9668b2bbf2SGordon Ross 	np = malloc(len);
9768b2bbf2SGordon Ross 	if (np == NULL)
9868b2bbf2SGordon Ross 		return (NULL);
9968b2bbf2SGordon Ross 
10068b2bbf2SGordon Ross 	bzero(np, len);
10168b2bbf2SGordon Ross 	np->np_listener = pl;
10268b2bbf2SGordon Ross 	np->np_endpoint = pl->name;
10368b2bbf2SGordon Ross 	np->np_user = (void*)(np + 1);
10468b2bbf2SGordon Ross 	np->np_send = pipe_send;
10568b2bbf2SGordon Ross 	np->np_recv = pipe_recv;
10668b2bbf2SGordon Ross 	np->np_fid = fid;
10768b2bbf2SGordon Ross 	np->np_max_xmit_frag = pipe_max_msgsize;
10868b2bbf2SGordon Ross 	np->np_max_recv_frag = pipe_max_msgsize;
10968b2bbf2SGordon Ross 
11068b2bbf2SGordon Ross 	return (np);
11168b2bbf2SGordon Ross }
11268b2bbf2SGordon Ross 
11368b2bbf2SGordon Ross static void
np_free(ndr_pipe_t * np)11468b2bbf2SGordon Ross np_free(ndr_pipe_t *np)
11568b2bbf2SGordon Ross {
11668b2bbf2SGordon Ross 	(void) close(np->np_fid);
11768b2bbf2SGordon Ross 	free(np);
11868b2bbf2SGordon Ross }
11968b2bbf2SGordon Ross 
12068b2bbf2SGordon Ross /*
12168b2bbf2SGordon Ross  * Create the smbd opipe door service.
12268b2bbf2SGordon Ross  * Returns the door descriptor on success.  Otherwise returns -1.
12368b2bbf2SGordon Ross  */
12468b2bbf2SGordon Ross int
smbd_pipesvc_start(void)12568b2bbf2SGordon Ross smbd_pipesvc_start(void)
12668b2bbf2SGordon Ross {
12768b2bbf2SGordon Ross 	pthread_t tid;
12868b2bbf2SGordon Ross 	pthread_attr_t tattr;
12968b2bbf2SGordon Ross 	struct pipe_listener *pl;
13068b2bbf2SGordon Ross 	int i, rc;
13168b2bbf2SGordon Ross 
13268b2bbf2SGordon Ross 	if (mlsvc_init() != 0) {
13368b2bbf2SGordon Ross 		smbd_report("msrpc initialization failed");
13468b2bbf2SGordon Ross 		return (-1);
13568b2bbf2SGordon Ross 	}
13668b2bbf2SGordon Ross 
13768b2bbf2SGordon Ross 	(void) pthread_attr_init(&tattr);
13868b2bbf2SGordon Ross 	(void) pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
13968b2bbf2SGordon Ross 
14068b2bbf2SGordon Ross 	for (i = 0; i < NLISTENERS; i++) {
14168b2bbf2SGordon Ross 		pl = &pipe_listeners[i];
14268b2bbf2SGordon Ross 		pl->max_seen = 0;
14368b2bbf2SGordon Ross 
14468b2bbf2SGordon Ross 		if (strcasecmp(pl->name, "spoolss") == 0 &&
14568b2bbf2SGordon Ross 		    smb_config_getbool(SMB_CI_PRINT_ENABLE) == B_FALSE)
14668b2bbf2SGordon Ross 			continue;
14768b2bbf2SGordon Ross 
14868b2bbf2SGordon Ross 		rc = pthread_create(&tid, &tattr, pipesvc_listener, pl);
14968b2bbf2SGordon Ross 		if (rc != 0)
15068b2bbf2SGordon Ross 			break;
15168b2bbf2SGordon Ross 		pipe_listeners[i].tid = tid;
15268b2bbf2SGordon Ross 	}
15368b2bbf2SGordon Ross 
15468b2bbf2SGordon Ross 	if (rc != 0) {
15568b2bbf2SGordon Ross 		smbd_report("pipesvc pthread_create, %d", rc);
15668b2bbf2SGordon Ross 	}
15768b2bbf2SGordon Ross 
15868b2bbf2SGordon Ross 	(void) pthread_attr_destroy(&tattr);
15968b2bbf2SGordon Ross 
16068b2bbf2SGordon Ross 	return (rc);
16168b2bbf2SGordon Ross }
16268b2bbf2SGordon Ross 
16368b2bbf2SGordon Ross void
smbd_pipesvc_stop(void)16468b2bbf2SGordon Ross smbd_pipesvc_stop(void)
16568b2bbf2SGordon Ross {
16668b2bbf2SGordon Ross 	int i;
16768b2bbf2SGordon Ross 
16868b2bbf2SGordon Ross 	(void) mutex_lock(&pipesvc_mutex);
16968b2bbf2SGordon Ross 	for (i = 0; i < NLISTENERS; i++) {
17068b2bbf2SGordon Ross 		if (pipe_listeners[i].tid == 0)
17168b2bbf2SGordon Ross 			continue;
17268b2bbf2SGordon Ross 		(void) pthread_kill(pipe_listeners[i].tid, SIGTERM);
17368b2bbf2SGordon Ross 		pipe_listeners[i].tid = 0;
17468b2bbf2SGordon Ross 	}
17568b2bbf2SGordon Ross 	(void) mutex_unlock(&pipesvc_mutex);
17668b2bbf2SGordon Ross }
17768b2bbf2SGordon Ross 
17868b2bbf2SGordon Ross static void *
pipesvc_listener(void * varg)17968b2bbf2SGordon Ross pipesvc_listener(void *varg)
18068b2bbf2SGordon Ross {
18168b2bbf2SGordon Ross 	struct sockaddr_un sa;
18268b2bbf2SGordon Ross 	int err, listen_fd, newfd, snlen;
18368b2bbf2SGordon Ross 	struct pipe_listener *pl = varg;
18468b2bbf2SGordon Ross 	ndr_pipe_t *np;
18568b2bbf2SGordon Ross 	pthread_t tid;
18668b2bbf2SGordon Ross 	int rc;
18768b2bbf2SGordon Ross 
18868b2bbf2SGordon Ross 	listen_fd = socket(AF_UNIX, SOCK_STREAM, 0);
18968b2bbf2SGordon Ross 	if (listen_fd < 0) {
19068b2bbf2SGordon Ross 		smbd_report("pipesvc_listener, so_create: %d", errno);
19168b2bbf2SGordon Ross 		return (NULL);
19268b2bbf2SGordon Ross 	}
19368b2bbf2SGordon Ross 
19468b2bbf2SGordon Ross 	bzero(&sa, sizeof (sa));
19568b2bbf2SGordon Ross 	sa.sun_family = AF_UNIX;
19668b2bbf2SGordon Ross 	(void) snprintf(sa.sun_path, sizeof (sa.sun_path),
19768b2bbf2SGordon Ross 	    "%s/%s", SMB_PIPE_DIR, pl->name);
19868b2bbf2SGordon Ross 
19968b2bbf2SGordon Ross 	/* Bind it to a listening name. */
20068b2bbf2SGordon Ross 	(void) unlink(sa.sun_path);
20168b2bbf2SGordon Ross 	if (bind(listen_fd, (struct sockaddr *)&sa, sizeof (sa)) < 0) {
20268b2bbf2SGordon Ross 		smbd_report("pipesvc_listener, so_bind: %d", errno);
20368b2bbf2SGordon Ross 		(void) close(listen_fd);
20468b2bbf2SGordon Ross 		return (NULL);
20568b2bbf2SGordon Ross 	}
20668b2bbf2SGordon Ross 
20768b2bbf2SGordon Ross 	if (listen(listen_fd, SOMAXCONN) < 0) {
20868b2bbf2SGordon Ross 		smbd_report("pipesvc_listener, listen: %d", errno);
20968b2bbf2SGordon Ross 		(void) close(listen_fd);
21068b2bbf2SGordon Ross 		return (NULL);
21168b2bbf2SGordon Ross 	}
21268b2bbf2SGordon Ross 
21368b2bbf2SGordon Ross 	for (;;) {
21468b2bbf2SGordon Ross 
21568b2bbf2SGordon Ross 		snlen = sizeof (sa);
21668b2bbf2SGordon Ross 		newfd = accept(listen_fd, (struct sockaddr *)&sa, &snlen);
21768b2bbf2SGordon Ross 		if (newfd < 0) {
21868b2bbf2SGordon Ross 			err = errno;
21968b2bbf2SGordon Ross 			switch (err) {
22068b2bbf2SGordon Ross 			case ECONNABORTED:
22168b2bbf2SGordon Ross 				continue;
22268b2bbf2SGordon Ross 			case EINTR:
22368b2bbf2SGordon Ross 				/* normal termination */
22468b2bbf2SGordon Ross 				goto out;
22568b2bbf2SGordon Ross 			default:
22668b2bbf2SGordon Ross 				smbd_report("pipesvc_listener, "
22768b2bbf2SGordon Ross 				    "accept failed: %d", errno);
22868b2bbf2SGordon Ross 			}
22968b2bbf2SGordon Ross 			smbd_report("pipesvc_listener, accept: %d", err);
23068b2bbf2SGordon Ross 			break;
23168b2bbf2SGordon Ross 		}
23268b2bbf2SGordon Ross 
23368b2bbf2SGordon Ross 		np = np_new(pl, newfd);
23468b2bbf2SGordon Ross 		if (np == NULL) {
23568b2bbf2SGordon Ross 			smbd_report("pipesvc_listener, alloc1 failed");
23668b2bbf2SGordon Ross 			(void) close(newfd);
2376926de2eSGordon Ross 			smbd_nomem();
23868b2bbf2SGordon Ross 		}
23968b2bbf2SGordon Ross 
24068b2bbf2SGordon Ross 		rc = pthread_create(&tid, NULL, pipesvc_worker, np);
24168b2bbf2SGordon Ross 		if (rc != 0) {
24268b2bbf2SGordon Ross 			smbd_report("pipesvc_listener, pthread_create: %d",
24368b2bbf2SGordon Ross 			    errno);
24468b2bbf2SGordon Ross 			np_free(np);
2456926de2eSGordon Ross 			smbd_nomem();
24668b2bbf2SGordon Ross 		}
24768b2bbf2SGordon Ross 		(void) pthread_detach(tid);
24868b2bbf2SGordon Ross 
24968b2bbf2SGordon Ross 		/* Note: np_free in pipesvc_worker */
25068b2bbf2SGordon Ross 		np = NULL;
25168b2bbf2SGordon Ross 	}
25268b2bbf2SGordon Ross 
25368b2bbf2SGordon Ross out:
25468b2bbf2SGordon Ross 	(void) close(listen_fd);
25568b2bbf2SGordon Ross 	pl->tid = 0;
25668b2bbf2SGordon Ross 	return (NULL);
25768b2bbf2SGordon Ross }
25868b2bbf2SGordon Ross 
259b6b7639aSGordon Ross #ifndef FKSMBD
260*5d8538b6SGordon Ross /*
261*5d8538b6SGordon Ross  * Decide whether we should trust the (in-band) user information
262*5d8538b6SGordon Ross  * that the client sends us over the named pipe.  The (in-kernel)
263*5d8538b6SGordon Ross  * SMB service calls this with the credential of the logged-on
264*5d8538b6SGordon Ross  * SMB user.  The privileges are normally:
265*5d8538b6SGordon Ross  *	  effective: basic,file_dac_search
266*5d8538b6SGordon Ross  *	inheritable: basic
267*5d8538b6SGordon Ross  *	  permitted: basic,file_dac_search,sys_smb
268*5d8538b6SGordon Ross  *	      limit: all
269*5d8538b6SGordon Ross  * This tests the permitted set for the presence of PRIV_SYS_SMB,
270*5d8538b6SGordon Ross  * which should only be granted to the SMB server.
271*5d8538b6SGordon Ross  */
272b6b7639aSGordon Ross static boolean_t
pipe_has_priv(ndr_pipe_t * np)273b6b7639aSGordon Ross pipe_has_priv(ndr_pipe_t *np)
274b6b7639aSGordon Ross {
275b6b7639aSGordon Ross 	ucred_t *uc = NULL;
276b6b7639aSGordon Ross 	const priv_set_t *ps = NULL;
277b6b7639aSGordon Ross 	boolean_t ret = B_FALSE;
278b6b7639aSGordon Ross 	pid_t  clpid;
279b6b7639aSGordon Ross 
280b6b7639aSGordon Ross 	if (getpeerucred(np->np_fid, &uc) != 0) {
281b6b7639aSGordon Ross 		smbd_report("pipesvc: getpeerucred err %d", errno);
282b6b7639aSGordon Ross 		return (B_FALSE);
283b6b7639aSGordon Ross 	}
284b6b7639aSGordon Ross 	clpid = ucred_getpid(uc);
285*5d8538b6SGordon Ross 	ps = ucred_getprivset(uc, PRIV_PERMITTED);
286b6b7639aSGordon Ross 	if (ps == NULL) {
287b6b7639aSGordon Ross 		smbd_report("pipesvc: ucred_getprivset failed");
288b6b7639aSGordon Ross 		goto out;
289b6b7639aSGordon Ross 	}
290b6b7639aSGordon Ross 
291b6b7639aSGordon Ross 	/*
292*5d8538b6SGordon Ross 	 * Require sys_smb priv.
293b6b7639aSGordon Ross 	 */
294b6b7639aSGordon Ross 	if (priv_ismember(ps, PRIV_SYS_SMB)) {
295b6b7639aSGordon Ross 		ret = B_TRUE;
296b6b7639aSGordon Ross 		goto out;
297b6b7639aSGordon Ross 	}
298b6b7639aSGordon Ross 
299b6b7639aSGordon Ross 	if (smbd.s_debug) {
300b6b7639aSGordon Ross 		smbd_report("pipesvc: non-privileged client "
301b6b7639aSGordon Ross 		    "PID = %d UID = %d",
302b6b7639aSGordon Ross 		    (int)clpid, ucred_getruid(uc));
303b6b7639aSGordon Ross 	}
304b6b7639aSGordon Ross 
305b6b7639aSGordon Ross out:
306b6b7639aSGordon Ross 	/* ps is free'd with the ucred */
307b6b7639aSGordon Ross 	if (uc != NULL)
308b6b7639aSGordon Ross 		ucred_free(uc);
309b6b7639aSGordon Ross 
310b6b7639aSGordon Ross 	return (ret);
311b6b7639aSGordon Ross }
312b6b7639aSGordon Ross #endif
313b6b7639aSGordon Ross 
31468b2bbf2SGordon Ross static void *
pipesvc_worker(void * varg)31568b2bbf2SGordon Ross pipesvc_worker(void *varg)
31668b2bbf2SGordon Ross {
31768b2bbf2SGordon Ross 	XDR xdrs;
31868b2bbf2SGordon Ross 	smb_pipehdr_t phdr;
31968b2bbf2SGordon Ross 	ndr_pipe_t *np = varg;
32068b2bbf2SGordon Ross 	struct pipe_listener *pl = np->np_listener;
32168b2bbf2SGordon Ross 	void *buf = NULL;
32268b2bbf2SGordon Ross 	uint32_t status;
32368b2bbf2SGordon Ross 	ssize_t rc;
32468b2bbf2SGordon Ross 
32568b2bbf2SGordon Ross 	(void) mutex_lock(&pipesvc_mutex);
32668b2bbf2SGordon Ross 	if (pipesvc_workers_cur >= pipesvc_workers_max ||
32768b2bbf2SGordon Ross 	    pl->current >= pl->max_allowed) {
32868b2bbf2SGordon Ross 		(void) mutex_unlock(&pipesvc_mutex);
32968b2bbf2SGordon Ross 		status = NT_STATUS_PIPE_NOT_AVAILABLE;
33068b2bbf2SGordon Ross 		(void) send(np->np_fid, &status, sizeof (status), 0);
33168b2bbf2SGordon Ross 		goto out_free_np;
33268b2bbf2SGordon Ross 	}
33368b2bbf2SGordon Ross 	pipesvc_workers_cur++;
33468b2bbf2SGordon Ross 	pl->current++;
33568b2bbf2SGordon Ross 	if (pl->max_seen < pl->current)
33668b2bbf2SGordon Ross 		pl->max_seen = pl->current;
33768b2bbf2SGordon Ross 	(void) mutex_unlock(&pipesvc_mutex);
33868b2bbf2SGordon Ross 
33968b2bbf2SGordon Ross 	/*
34068b2bbf2SGordon Ross 	 * The smbsrv kmod sends us one initial message containing an
34168b2bbf2SGordon Ross 	 * XDR encoded smb_netuserinfo_t that we read and decode here,
34268b2bbf2SGordon Ross 	 * all unbeknownst to libmlrpc.
34368b2bbf2SGordon Ross 	 *
34468b2bbf2SGordon Ross 	 * Might be nice to enhance getpeerucred() so it can give us
34568b2bbf2SGordon Ross 	 * all the info smb_netuserinfo_t carries, and then use that,
34668b2bbf2SGordon Ross 	 * which would allow using a more generic RPC service.
34768b2bbf2SGordon Ross 	 */
34868b2bbf2SGordon Ross 	rc = pipe_recv(np, &phdr, sizeof (phdr));
34968b2bbf2SGordon Ross 	if (rc != 0) {
35068b2bbf2SGordon Ross 		smbd_report("pipesvc_worker, recv1: %d", rc);
35168b2bbf2SGordon Ross 		goto out_decr;
35268b2bbf2SGordon Ross 	}
35368b2bbf2SGordon Ross 	if (phdr.ph_magic != SMB_PIPE_HDR_MAGIC ||
35468b2bbf2SGordon Ross 	    phdr.ph_uilen > 8192) {
35568b2bbf2SGordon Ross 		smbd_report("pipesvc_worker, bad hdr");
35668b2bbf2SGordon Ross 		goto out_decr;
35768b2bbf2SGordon Ross 	}
35868b2bbf2SGordon Ross 	buf = malloc(phdr.ph_uilen);
35968b2bbf2SGordon Ross 	if (buf == NULL) {
36068b2bbf2SGordon Ross 		smbd_report("pipesvc_worker, alloc1 failed");
36168b2bbf2SGordon Ross 		goto out_decr;
36268b2bbf2SGordon Ross 	}
36368b2bbf2SGordon Ross 	rc = pipe_recv(np, buf, phdr.ph_uilen);
36468b2bbf2SGordon Ross 	if (rc != 0) {
36568b2bbf2SGordon Ross 		smbd_report("pipesvc_worker, recv2: %d", rc);
36668b2bbf2SGordon Ross 		goto out_decr;
36768b2bbf2SGordon Ross 	}
36868b2bbf2SGordon Ross 
36968b2bbf2SGordon Ross 	xdrmem_create(&xdrs, buf, phdr.ph_uilen, XDR_DECODE);
37068b2bbf2SGordon Ross 	if (!smb_netuserinfo_xdr(&xdrs, np->np_user)) {
37168b2bbf2SGordon Ross 		smbd_report("pipesvc_worker, bad uinfo");
37268b2bbf2SGordon Ross 		goto out_free_buf;
37368b2bbf2SGordon Ross 	}
37468b2bbf2SGordon Ross 
375b6b7639aSGordon Ross 	/*
376b6b7639aSGordon Ross 	 * Don't trust the netuserinfo unless the client side
377b6b7639aSGordon Ross 	 * has the necessary privileges
378b6b7639aSGordon Ross 	 */
379b6b7639aSGordon Ross #ifndef FKSMBD
380b6b7639aSGordon Ross 	if (!pipe_has_priv(np)) {
381b6b7639aSGordon Ross 		np->np_user->ui_flags = SMB_ATF_ANON;
382b6b7639aSGordon Ross 	}
383b6b7639aSGordon Ross #endif
384b6b7639aSGordon Ross 
38568b2bbf2SGordon Ross 	/*
38668b2bbf2SGordon Ross 	 * Later, could disallow opens of some pipes by
38768b2bbf2SGordon Ross 	 * anonymous users, etc.  For now, reply "OK".
38868b2bbf2SGordon Ross 	 */
38968b2bbf2SGordon Ross 	status = 0;
39068b2bbf2SGordon Ross 	rc = pipe_send(np, &status, sizeof (status));
39168b2bbf2SGordon Ross 	if (rc != 0) {
39268b2bbf2SGordon Ross 		smbd_report("pipesvc_worker, send1: %d", rc);
39368b2bbf2SGordon Ross 		goto out_free_buf;
39468b2bbf2SGordon Ross 	}
39568b2bbf2SGordon Ross 
39668b2bbf2SGordon Ross 	/*
39768b2bbf2SGordon Ross 	 * Run the RPC service loop worker, which
39868b2bbf2SGordon Ross 	 * returns when it sees the pipe close.
39968b2bbf2SGordon Ross 	 */
40068b2bbf2SGordon Ross 	ndr_pipe_worker(np);
40168b2bbf2SGordon Ross 
40268b2bbf2SGordon Ross 	xdrs.x_op = XDR_FREE;
40368b2bbf2SGordon Ross 	(void) smb_netuserinfo_xdr(&xdrs, np->np_user);
40468b2bbf2SGordon Ross 
40568b2bbf2SGordon Ross out_free_buf:
40668b2bbf2SGordon Ross 	free(buf);
40768b2bbf2SGordon Ross 	xdr_destroy(&xdrs);
40868b2bbf2SGordon Ross 
40968b2bbf2SGordon Ross out_decr:
41068b2bbf2SGordon Ross 	(void) mutex_lock(&pipesvc_mutex);
41168b2bbf2SGordon Ross 	pipesvc_workers_cur--;
41268b2bbf2SGordon Ross 	pl->current--;
41368b2bbf2SGordon Ross 	(void) mutex_unlock(&pipesvc_mutex);
41468b2bbf2SGordon Ross 
41568b2bbf2SGordon Ross out_free_np:
41668b2bbf2SGordon Ross 	/* Cleanup what came in by varg. */
41768b2bbf2SGordon Ross 	(void) shutdown(np->np_fid, SHUT_RDWR);
41868b2bbf2SGordon Ross 	np_free(np);
41968b2bbf2SGordon Ross 	return (NULL);
42068b2bbf2SGordon Ross }
42168b2bbf2SGordon Ross 
42268b2bbf2SGordon Ross /*
42368b2bbf2SGordon Ross  * These are the transport get/put callback functions provided
42468b2bbf2SGordon Ross  * via the ndr_pipe_t object to the libmlrpc`ndr_pipe_worker.
42568b2bbf2SGordon Ross  * These are called only with known PDU sizes and should
42668b2bbf2SGordon Ross  * loop as needed to transfer the entire message.
42768b2bbf2SGordon Ross  */
42868b2bbf2SGordon Ross static int
pipe_recv(ndr_pipe_t * np,void * buf,size_t len)42968b2bbf2SGordon Ross pipe_recv(ndr_pipe_t *np, void *buf, size_t len)
43068b2bbf2SGordon Ross {
43168b2bbf2SGordon Ross 	int x;
43268b2bbf2SGordon Ross 
43368b2bbf2SGordon Ross 	while (len > 0) {
43468b2bbf2SGordon Ross 		x = recv(np->np_fid, buf, len, 0);
43568b2bbf2SGordon Ross 		if (x < 0)
43668b2bbf2SGordon Ross 			return (errno);
43768b2bbf2SGordon Ross 		if (x == 0)
43868b2bbf2SGordon Ross 			return (EIO);
43968b2bbf2SGordon Ross 		buf = (char *)buf + x;
44068b2bbf2SGordon Ross 		len -= x;
44168b2bbf2SGordon Ross 	}
44268b2bbf2SGordon Ross 
44368b2bbf2SGordon Ross 	return (0);
44468b2bbf2SGordon Ross }
44568b2bbf2SGordon Ross 
44668b2bbf2SGordon Ross static int
pipe_send(ndr_pipe_t * np,void * buf,size_t len)44768b2bbf2SGordon Ross pipe_send(ndr_pipe_t *np, void *buf, size_t len)
44868b2bbf2SGordon Ross {
44968b2bbf2SGordon Ross 	int x;
45068b2bbf2SGordon Ross 
45168b2bbf2SGordon Ross 	while (len > 0) {
45268b2bbf2SGordon Ross 		x = send(np->np_fid, buf, len, 0);
45368b2bbf2SGordon Ross 		if (x < 0)
45468b2bbf2SGordon Ross 			return (errno);
45568b2bbf2SGordon Ross 		if (x == 0)
45668b2bbf2SGordon Ross 			return (EIO);
45768b2bbf2SGordon Ross 		buf = (char *)buf + x;
45868b2bbf2SGordon Ross 		len -= x;
45968b2bbf2SGordon Ross 	}
46068b2bbf2SGordon Ross 
46168b2bbf2SGordon Ross 	return (0);
46268b2bbf2SGordon Ross }
463