xref: /illumos-gate/usr/src/cmd/smbsrv/smbd/smbd_pipesvc.c (revision 68b2bbf26c7040fea4281dcb58b81e7627e46f34)
1*68b2bbf2SGordon Ross /*
2*68b2bbf2SGordon Ross  * This file and its contents are supplied under the terms of the
3*68b2bbf2SGordon Ross  * Common Development and Distribution License ("CDDL"), version 1.0.
4*68b2bbf2SGordon Ross  * You may only use this file in accordance with the terms of version
5*68b2bbf2SGordon Ross  * 1.0 of the CDDL.
6*68b2bbf2SGordon Ross  *
7*68b2bbf2SGordon Ross  * A full copy of the text of the CDDL should have accompanied this
8*68b2bbf2SGordon Ross  * source.  A copy of the CDDL is also available via the Internet at
9*68b2bbf2SGordon Ross  * http://www.illumos.org/license/CDDL.
10*68b2bbf2SGordon Ross  */
11*68b2bbf2SGordon Ross 
12*68b2bbf2SGordon Ross /*
13*68b2bbf2SGordon Ross  * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
14*68b2bbf2SGordon Ross  */
15*68b2bbf2SGordon Ross 
16*68b2bbf2SGordon Ross /*
17*68b2bbf2SGordon Ross  * This is the named pipe service for smbd.
18*68b2bbf2SGordon Ross  */
19*68b2bbf2SGordon Ross 
20*68b2bbf2SGordon Ross #include <sys/types.h>
21*68b2bbf2SGordon Ross #include <sys/stat.h>
22*68b2bbf2SGordon Ross 
23*68b2bbf2SGordon Ross #include <stdio.h>
24*68b2bbf2SGordon Ross #include <strings.h>
25*68b2bbf2SGordon Ross #include <stdlib.h>
26*68b2bbf2SGordon Ross #include <synch.h>
27*68b2bbf2SGordon Ross #include <unistd.h>
28*68b2bbf2SGordon Ross #include <fcntl.h>
29*68b2bbf2SGordon Ross #include <door.h>
30*68b2bbf2SGordon Ross #include <errno.h>
31*68b2bbf2SGordon Ross #include <pthread.h>
32*68b2bbf2SGordon Ross #include <signal.h>
33*68b2bbf2SGordon Ross 
34*68b2bbf2SGordon Ross #include <smbsrv/libsmb.h>
35*68b2bbf2SGordon Ross #include <smbsrv/libmlsvc.h>
36*68b2bbf2SGordon Ross #include <smbsrv/smb_xdr.h>
37*68b2bbf2SGordon Ross #include "smbd.h"
38*68b2bbf2SGordon Ross 
39*68b2bbf2SGordon Ross struct pipe_listener {
40*68b2bbf2SGordon Ross 	const char *name;
41*68b2bbf2SGordon Ross 	int max_allowed;
42*68b2bbf2SGordon Ross 	int max_seen;
43*68b2bbf2SGordon Ross 	int current;
44*68b2bbf2SGordon Ross 	pthread_t tid;
45*68b2bbf2SGordon Ross };
46*68b2bbf2SGordon Ross 
47*68b2bbf2SGordon Ross static void *pipesvc_listener(void *);
48*68b2bbf2SGordon Ross static void *pipesvc_worker(void *);
49*68b2bbf2SGordon Ross static int pipe_send(ndr_pipe_t *, void *, size_t);
50*68b2bbf2SGordon Ross static int pipe_recv(ndr_pipe_t *, void *, size_t);
51*68b2bbf2SGordon Ross 
52*68b2bbf2SGordon Ross mutex_t  pipesvc_mutex = DEFAULTMUTEX;
53*68b2bbf2SGordon Ross int pipesvc_workers_max = 500;
54*68b2bbf2SGordon Ross int pipesvc_workers_cur = 0;
55*68b2bbf2SGordon Ross 
56*68b2bbf2SGordon Ross uint16_t pipe_max_msgsize = SMB_PIPE_MAX_MSGSIZE;
57*68b2bbf2SGordon Ross 
58*68b2bbf2SGordon Ross /*
59*68b2bbf2SGordon Ross  * Allow more opens on SRVSVC because that's used by many clients
60*68b2bbf2SGordon Ross  * to get the share list, etc.
61*68b2bbf2SGordon Ross  */
62*68b2bbf2SGordon Ross #define	SRVSVC_MAX_OPENS	200
63*68b2bbf2SGordon Ross #define	DEF_MAX_OPENS		50
64*68b2bbf2SGordon Ross 
65*68b2bbf2SGordon Ross #define	NLISTENERS	11
66*68b2bbf2SGordon Ross static struct pipe_listener
67*68b2bbf2SGordon Ross pipe_listeners[NLISTENERS] = {
68*68b2bbf2SGordon Ross 	{ "eventlog",	DEF_MAX_OPENS, 0, 0 },
69*68b2bbf2SGordon Ross 	{ "lsarpc",	DEF_MAX_OPENS, 0, 0 },
70*68b2bbf2SGordon Ross 	{ "lsass",	DEF_MAX_OPENS, 0, 0 },
71*68b2bbf2SGordon Ross 	{ "netdfs",	DEF_MAX_OPENS, 0, 0 },
72*68b2bbf2SGordon Ross 	{ "netlogon",	DEF_MAX_OPENS, 0, 0 },
73*68b2bbf2SGordon Ross 	{ "samr",	DEF_MAX_OPENS, 0, 0 },
74*68b2bbf2SGordon Ross 	{ "spoolss",	DEF_MAX_OPENS, 0, 0 },
75*68b2bbf2SGordon Ross 	{ "srvsvc",	SRVSVC_MAX_OPENS, 0, 0 },
76*68b2bbf2SGordon Ross 	{ "svcctl",	DEF_MAX_OPENS, 0, 0 },
77*68b2bbf2SGordon Ross 	{ "winreg",	DEF_MAX_OPENS, 0, 0 },
78*68b2bbf2SGordon Ross 	{ "wkssvc",	DEF_MAX_OPENS, 0, 0 },
79*68b2bbf2SGordon Ross };
80*68b2bbf2SGordon Ross 
81*68b2bbf2SGordon Ross static ndr_pipe_t *
82*68b2bbf2SGordon Ross np_new(struct pipe_listener *pl, int fid)
83*68b2bbf2SGordon Ross {
84*68b2bbf2SGordon Ross 	ndr_pipe_t *np;
85*68b2bbf2SGordon Ross 	size_t len;
86*68b2bbf2SGordon Ross 
87*68b2bbf2SGordon Ross 	/*
88*68b2bbf2SGordon Ross 	 * Allocating ndr_pipe_t + smb_netuserinfo_t as one.
89*68b2bbf2SGordon Ross 	 * We could just make that part of ndr_pipe_t, but
90*68b2bbf2SGordon Ross 	 * that struct is opaque to libmlrpc.
91*68b2bbf2SGordon Ross 	 */
92*68b2bbf2SGordon Ross 	len = sizeof (*np) + sizeof (smb_netuserinfo_t);
93*68b2bbf2SGordon Ross 	np = malloc(len);
94*68b2bbf2SGordon Ross 	if (np == NULL)
95*68b2bbf2SGordon Ross 		return (NULL);
96*68b2bbf2SGordon Ross 
97*68b2bbf2SGordon Ross 	bzero(np, len);
98*68b2bbf2SGordon Ross 	np->np_listener = pl;
99*68b2bbf2SGordon Ross 	np->np_endpoint = pl->name;
100*68b2bbf2SGordon Ross 	np->np_user = (void*)(np + 1);
101*68b2bbf2SGordon Ross 	np->np_send = pipe_send;
102*68b2bbf2SGordon Ross 	np->np_recv = pipe_recv;
103*68b2bbf2SGordon Ross 	np->np_fid = fid;
104*68b2bbf2SGordon Ross 	np->np_max_xmit_frag = pipe_max_msgsize;
105*68b2bbf2SGordon Ross 	np->np_max_recv_frag = pipe_max_msgsize;
106*68b2bbf2SGordon Ross 
107*68b2bbf2SGordon Ross 	return (np);
108*68b2bbf2SGordon Ross }
109*68b2bbf2SGordon Ross 
110*68b2bbf2SGordon Ross static void
111*68b2bbf2SGordon Ross np_free(ndr_pipe_t *np)
112*68b2bbf2SGordon Ross {
113*68b2bbf2SGordon Ross 	(void) close(np->np_fid);
114*68b2bbf2SGordon Ross 	free(np);
115*68b2bbf2SGordon Ross }
116*68b2bbf2SGordon Ross 
117*68b2bbf2SGordon Ross /*
118*68b2bbf2SGordon Ross  * Create the smbd opipe door service.
119*68b2bbf2SGordon Ross  * Returns the door descriptor on success.  Otherwise returns -1.
120*68b2bbf2SGordon Ross  */
121*68b2bbf2SGordon Ross int
122*68b2bbf2SGordon Ross smbd_pipesvc_start(void)
123*68b2bbf2SGordon Ross {
124*68b2bbf2SGordon Ross 	pthread_t tid;
125*68b2bbf2SGordon Ross 	pthread_attr_t tattr;
126*68b2bbf2SGordon Ross 	struct pipe_listener *pl;
127*68b2bbf2SGordon Ross 	int i, rc;
128*68b2bbf2SGordon Ross 
129*68b2bbf2SGordon Ross 	if (mlsvc_init() != 0) {
130*68b2bbf2SGordon Ross 		smbd_report("msrpc initialization failed");
131*68b2bbf2SGordon Ross 		return (-1);
132*68b2bbf2SGordon Ross 	}
133*68b2bbf2SGordon Ross 
134*68b2bbf2SGordon Ross 	(void) pthread_attr_init(&tattr);
135*68b2bbf2SGordon Ross 	(void) pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
136*68b2bbf2SGordon Ross 
137*68b2bbf2SGordon Ross 	for (i = 0; i < NLISTENERS; i++) {
138*68b2bbf2SGordon Ross 		pl = &pipe_listeners[i];
139*68b2bbf2SGordon Ross 		pl->max_seen = 0;
140*68b2bbf2SGordon Ross 
141*68b2bbf2SGordon Ross 		if (strcasecmp(pl->name, "spoolss") == 0 &&
142*68b2bbf2SGordon Ross 		    smb_config_getbool(SMB_CI_PRINT_ENABLE) == B_FALSE)
143*68b2bbf2SGordon Ross 			continue;
144*68b2bbf2SGordon Ross 
145*68b2bbf2SGordon Ross 		rc = pthread_create(&tid, &tattr, pipesvc_listener, pl);
146*68b2bbf2SGordon Ross 		if (rc != 0)
147*68b2bbf2SGordon Ross 			break;
148*68b2bbf2SGordon Ross 		pipe_listeners[i].tid = tid;
149*68b2bbf2SGordon Ross 	}
150*68b2bbf2SGordon Ross 
151*68b2bbf2SGordon Ross 	if (rc != 0) {
152*68b2bbf2SGordon Ross 		smbd_report("pipesvc pthread_create, %d", rc);
153*68b2bbf2SGordon Ross 	}
154*68b2bbf2SGordon Ross 
155*68b2bbf2SGordon Ross 	(void) pthread_attr_destroy(&tattr);
156*68b2bbf2SGordon Ross 
157*68b2bbf2SGordon Ross 	return (rc);
158*68b2bbf2SGordon Ross }
159*68b2bbf2SGordon Ross 
160*68b2bbf2SGordon Ross void
161*68b2bbf2SGordon Ross smbd_pipesvc_stop(void)
162*68b2bbf2SGordon Ross {
163*68b2bbf2SGordon Ross 	int i;
164*68b2bbf2SGordon Ross 
165*68b2bbf2SGordon Ross 	(void) mutex_lock(&pipesvc_mutex);
166*68b2bbf2SGordon Ross 	for (i = 0; i < NLISTENERS; i++) {
167*68b2bbf2SGordon Ross 		if (pipe_listeners[i].tid == 0)
168*68b2bbf2SGordon Ross 			continue;
169*68b2bbf2SGordon Ross 		(void) pthread_kill(pipe_listeners[i].tid, SIGTERM);
170*68b2bbf2SGordon Ross 		pipe_listeners[i].tid = 0;
171*68b2bbf2SGordon Ross 	}
172*68b2bbf2SGordon Ross 	(void) mutex_unlock(&pipesvc_mutex);
173*68b2bbf2SGordon Ross }
174*68b2bbf2SGordon Ross 
175*68b2bbf2SGordon Ross static void *
176*68b2bbf2SGordon Ross pipesvc_listener(void *varg)
177*68b2bbf2SGordon Ross {
178*68b2bbf2SGordon Ross 	struct sockaddr_un sa;
179*68b2bbf2SGordon Ross 	int err, listen_fd, newfd, snlen;
180*68b2bbf2SGordon Ross 	struct pipe_listener *pl = varg;
181*68b2bbf2SGordon Ross 	ndr_pipe_t *np;
182*68b2bbf2SGordon Ross 	pthread_t tid;
183*68b2bbf2SGordon Ross 	int rc;
184*68b2bbf2SGordon Ross 
185*68b2bbf2SGordon Ross 	listen_fd = socket(AF_UNIX, SOCK_STREAM, 0);
186*68b2bbf2SGordon Ross 	if (listen_fd < 0) {
187*68b2bbf2SGordon Ross 		smbd_report("pipesvc_listener, so_create: %d", errno);
188*68b2bbf2SGordon Ross 		return (NULL);
189*68b2bbf2SGordon Ross 	}
190*68b2bbf2SGordon Ross 
191*68b2bbf2SGordon Ross 	bzero(&sa, sizeof (sa));
192*68b2bbf2SGordon Ross 	sa.sun_family = AF_UNIX;
193*68b2bbf2SGordon Ross 	(void) snprintf(sa.sun_path, sizeof (sa.sun_path),
194*68b2bbf2SGordon Ross 	    "%s/%s", SMB_PIPE_DIR, pl->name);
195*68b2bbf2SGordon Ross 
196*68b2bbf2SGordon Ross 	/* Bind it to a listening name. */
197*68b2bbf2SGordon Ross 	(void) unlink(sa.sun_path);
198*68b2bbf2SGordon Ross 	if (bind(listen_fd, (struct sockaddr *)&sa, sizeof (sa)) < 0) {
199*68b2bbf2SGordon Ross 		smbd_report("pipesvc_listener, so_bind: %d", errno);
200*68b2bbf2SGordon Ross 		(void) close(listen_fd);
201*68b2bbf2SGordon Ross 		return (NULL);
202*68b2bbf2SGordon Ross 	}
203*68b2bbf2SGordon Ross 
204*68b2bbf2SGordon Ross 	if (listen(listen_fd, SOMAXCONN) < 0) {
205*68b2bbf2SGordon Ross 		smbd_report("pipesvc_listener, listen: %d", errno);
206*68b2bbf2SGordon Ross 		(void) close(listen_fd);
207*68b2bbf2SGordon Ross 		return (NULL);
208*68b2bbf2SGordon Ross 	}
209*68b2bbf2SGordon Ross 
210*68b2bbf2SGordon Ross 	for (;;) {
211*68b2bbf2SGordon Ross 
212*68b2bbf2SGordon Ross 		snlen = sizeof (sa);
213*68b2bbf2SGordon Ross 		newfd = accept(listen_fd, (struct sockaddr *)&sa, &snlen);
214*68b2bbf2SGordon Ross 		if (newfd < 0) {
215*68b2bbf2SGordon Ross 			err = errno;
216*68b2bbf2SGordon Ross 			switch (err) {
217*68b2bbf2SGordon Ross 			case ECONNABORTED:
218*68b2bbf2SGordon Ross 				continue;
219*68b2bbf2SGordon Ross 			case EINTR:
220*68b2bbf2SGordon Ross 				/* normal termination */
221*68b2bbf2SGordon Ross 				goto out;
222*68b2bbf2SGordon Ross 			default:
223*68b2bbf2SGordon Ross 				smbd_report("pipesvc_listener, "
224*68b2bbf2SGordon Ross 				    "accept failed: %d", errno);
225*68b2bbf2SGordon Ross 			}
226*68b2bbf2SGordon Ross 			smbd_report("pipesvc_listener, accept: %d", err);
227*68b2bbf2SGordon Ross 			break;
228*68b2bbf2SGordon Ross 		}
229*68b2bbf2SGordon Ross 
230*68b2bbf2SGordon Ross 		np = np_new(pl, newfd);
231*68b2bbf2SGordon Ross 		if (np == NULL) {
232*68b2bbf2SGordon Ross 			smbd_report("pipesvc_listener, alloc1 failed");
233*68b2bbf2SGordon Ross 			(void) close(newfd);
234*68b2bbf2SGordon Ross 			continue;
235*68b2bbf2SGordon Ross 		}
236*68b2bbf2SGordon Ross 
237*68b2bbf2SGordon Ross 		rc = pthread_create(&tid, NULL, pipesvc_worker, np);
238*68b2bbf2SGordon Ross 		if (rc != 0) {
239*68b2bbf2SGordon Ross 			smbd_report("pipesvc_listener, pthread_create: %d",
240*68b2bbf2SGordon Ross 			    errno);
241*68b2bbf2SGordon Ross 			np_free(np);
242*68b2bbf2SGordon Ross 			continue;
243*68b2bbf2SGordon Ross 		}
244*68b2bbf2SGordon Ross 		(void) pthread_detach(tid);
245*68b2bbf2SGordon Ross 
246*68b2bbf2SGordon Ross 		/* Note: np_free in pipesvc_worker */
247*68b2bbf2SGordon Ross 		np = NULL;
248*68b2bbf2SGordon Ross 	}
249*68b2bbf2SGordon Ross 
250*68b2bbf2SGordon Ross out:
251*68b2bbf2SGordon Ross 	(void) close(listen_fd);
252*68b2bbf2SGordon Ross 	pl->tid = 0;
253*68b2bbf2SGordon Ross 	return (NULL);
254*68b2bbf2SGordon Ross }
255*68b2bbf2SGordon Ross 
256*68b2bbf2SGordon Ross static void *
257*68b2bbf2SGordon Ross pipesvc_worker(void *varg)
258*68b2bbf2SGordon Ross {
259*68b2bbf2SGordon Ross 	XDR xdrs;
260*68b2bbf2SGordon Ross 	smb_pipehdr_t phdr;
261*68b2bbf2SGordon Ross 	ndr_pipe_t *np = varg;
262*68b2bbf2SGordon Ross 	struct pipe_listener *pl = np->np_listener;
263*68b2bbf2SGordon Ross 	void *buf = NULL;
264*68b2bbf2SGordon Ross 	uint32_t status;
265*68b2bbf2SGordon Ross 	ssize_t rc;
266*68b2bbf2SGordon Ross 
267*68b2bbf2SGordon Ross 	(void) mutex_lock(&pipesvc_mutex);
268*68b2bbf2SGordon Ross 	if (pipesvc_workers_cur >= pipesvc_workers_max ||
269*68b2bbf2SGordon Ross 	    pl->current >= pl->max_allowed) {
270*68b2bbf2SGordon Ross 		(void) mutex_unlock(&pipesvc_mutex);
271*68b2bbf2SGordon Ross 		status = NT_STATUS_PIPE_NOT_AVAILABLE;
272*68b2bbf2SGordon Ross 		(void) send(np->np_fid, &status, sizeof (status), 0);
273*68b2bbf2SGordon Ross 		goto out_free_np;
274*68b2bbf2SGordon Ross 	}
275*68b2bbf2SGordon Ross 	pipesvc_workers_cur++;
276*68b2bbf2SGordon Ross 	pl->current++;
277*68b2bbf2SGordon Ross 	if (pl->max_seen < pl->current)
278*68b2bbf2SGordon Ross 		pl->max_seen = pl->current;
279*68b2bbf2SGordon Ross 	(void) mutex_unlock(&pipesvc_mutex);
280*68b2bbf2SGordon Ross 
281*68b2bbf2SGordon Ross 	/*
282*68b2bbf2SGordon Ross 	 * The smbsrv kmod sends us one initial message containing an
283*68b2bbf2SGordon Ross 	 * XDR encoded smb_netuserinfo_t that we read and decode here,
284*68b2bbf2SGordon Ross 	 * all unbeknownst to libmlrpc.
285*68b2bbf2SGordon Ross 	 *
286*68b2bbf2SGordon Ross 	 * Might be nice to enhance getpeerucred() so it can give us
287*68b2bbf2SGordon Ross 	 * all the info smb_netuserinfo_t carries, and then use that,
288*68b2bbf2SGordon Ross 	 * which would allow using a more generic RPC service.
289*68b2bbf2SGordon Ross 	 */
290*68b2bbf2SGordon Ross 	rc = pipe_recv(np, &phdr, sizeof (phdr));
291*68b2bbf2SGordon Ross 	if (rc != 0) {
292*68b2bbf2SGordon Ross 		smbd_report("pipesvc_worker, recv1: %d", rc);
293*68b2bbf2SGordon Ross 		goto out_decr;
294*68b2bbf2SGordon Ross 	}
295*68b2bbf2SGordon Ross 	if (phdr.ph_magic != SMB_PIPE_HDR_MAGIC ||
296*68b2bbf2SGordon Ross 	    phdr.ph_uilen > 8192) {
297*68b2bbf2SGordon Ross 		smbd_report("pipesvc_worker, bad hdr");
298*68b2bbf2SGordon Ross 		goto out_decr;
299*68b2bbf2SGordon Ross 	}
300*68b2bbf2SGordon Ross 	buf = malloc(phdr.ph_uilen);
301*68b2bbf2SGordon Ross 	if (buf == NULL) {
302*68b2bbf2SGordon Ross 		smbd_report("pipesvc_worker, alloc1 failed");
303*68b2bbf2SGordon Ross 		goto out_decr;
304*68b2bbf2SGordon Ross 	}
305*68b2bbf2SGordon Ross 	rc = pipe_recv(np, buf, phdr.ph_uilen);
306*68b2bbf2SGordon Ross 	if (rc != 0) {
307*68b2bbf2SGordon Ross 		smbd_report("pipesvc_worker, recv2: %d", rc);
308*68b2bbf2SGordon Ross 		goto out_decr;
309*68b2bbf2SGordon Ross 	}
310*68b2bbf2SGordon Ross 
311*68b2bbf2SGordon Ross 	xdrmem_create(&xdrs, buf, phdr.ph_uilen, XDR_DECODE);
312*68b2bbf2SGordon Ross 	if (!smb_netuserinfo_xdr(&xdrs, np->np_user)) {
313*68b2bbf2SGordon Ross 		smbd_report("pipesvc_worker, bad uinfo");
314*68b2bbf2SGordon Ross 		goto out_free_buf;
315*68b2bbf2SGordon Ross 	}
316*68b2bbf2SGordon Ross 
317*68b2bbf2SGordon Ross 	/*
318*68b2bbf2SGordon Ross 	 * Later, could disallow opens of some pipes by
319*68b2bbf2SGordon Ross 	 * anonymous users, etc.  For now, reply "OK".
320*68b2bbf2SGordon Ross 	 */
321*68b2bbf2SGordon Ross 	status = 0;
322*68b2bbf2SGordon Ross 	rc = pipe_send(np, &status, sizeof (status));
323*68b2bbf2SGordon Ross 	if (rc != 0) {
324*68b2bbf2SGordon Ross 		smbd_report("pipesvc_worker, send1: %d", rc);
325*68b2bbf2SGordon Ross 		goto out_free_buf;
326*68b2bbf2SGordon Ross 	}
327*68b2bbf2SGordon Ross 
328*68b2bbf2SGordon Ross 	/*
329*68b2bbf2SGordon Ross 	 * Run the RPC service loop worker, which
330*68b2bbf2SGordon Ross 	 * returns when it sees the pipe close.
331*68b2bbf2SGordon Ross 	 */
332*68b2bbf2SGordon Ross 	ndr_pipe_worker(np);
333*68b2bbf2SGordon Ross 
334*68b2bbf2SGordon Ross 	xdrs.x_op = XDR_FREE;
335*68b2bbf2SGordon Ross 	(void) smb_netuserinfo_xdr(&xdrs, np->np_user);
336*68b2bbf2SGordon Ross 
337*68b2bbf2SGordon Ross out_free_buf:
338*68b2bbf2SGordon Ross 	free(buf);
339*68b2bbf2SGordon Ross 	xdr_destroy(&xdrs);
340*68b2bbf2SGordon Ross 
341*68b2bbf2SGordon Ross out_decr:
342*68b2bbf2SGordon Ross 	(void) mutex_lock(&pipesvc_mutex);
343*68b2bbf2SGordon Ross 	pipesvc_workers_cur--;
344*68b2bbf2SGordon Ross 	pl->current--;
345*68b2bbf2SGordon Ross 	(void) mutex_unlock(&pipesvc_mutex);
346*68b2bbf2SGordon Ross 
347*68b2bbf2SGordon Ross out_free_np:
348*68b2bbf2SGordon Ross 	/* Cleanup what came in by varg. */
349*68b2bbf2SGordon Ross 	(void) shutdown(np->np_fid, SHUT_RDWR);
350*68b2bbf2SGordon Ross 	np_free(np);
351*68b2bbf2SGordon Ross 	return (NULL);
352*68b2bbf2SGordon Ross }
353*68b2bbf2SGordon Ross 
354*68b2bbf2SGordon Ross /*
355*68b2bbf2SGordon Ross  * These are the transport get/put callback functions provided
356*68b2bbf2SGordon Ross  * via the ndr_pipe_t object to the libmlrpc`ndr_pipe_worker.
357*68b2bbf2SGordon Ross  * These are called only with known PDU sizes and should
358*68b2bbf2SGordon Ross  * loop as needed to transfer the entire message.
359*68b2bbf2SGordon Ross  */
360*68b2bbf2SGordon Ross static int
361*68b2bbf2SGordon Ross pipe_recv(ndr_pipe_t *np, void *buf, size_t len)
362*68b2bbf2SGordon Ross {
363*68b2bbf2SGordon Ross 	int x;
364*68b2bbf2SGordon Ross 
365*68b2bbf2SGordon Ross 	while (len > 0) {
366*68b2bbf2SGordon Ross 		x = recv(np->np_fid, buf, len, 0);
367*68b2bbf2SGordon Ross 		if (x < 0)
368*68b2bbf2SGordon Ross 			return (errno);
369*68b2bbf2SGordon Ross 		if (x == 0)
370*68b2bbf2SGordon Ross 			return (EIO);
371*68b2bbf2SGordon Ross 		buf = (char *)buf + x;
372*68b2bbf2SGordon Ross 		len -= x;
373*68b2bbf2SGordon Ross 	}
374*68b2bbf2SGordon Ross 
375*68b2bbf2SGordon Ross 	return (0);
376*68b2bbf2SGordon Ross }
377*68b2bbf2SGordon Ross 
378*68b2bbf2SGordon Ross static int
379*68b2bbf2SGordon Ross pipe_send(ndr_pipe_t *np, void *buf, size_t len)
380*68b2bbf2SGordon Ross {
381*68b2bbf2SGordon Ross 	int x;
382*68b2bbf2SGordon Ross 
383*68b2bbf2SGordon Ross 	while (len > 0) {
384*68b2bbf2SGordon Ross 		x = send(np->np_fid, buf, len, 0);
385*68b2bbf2SGordon Ross 		if (x < 0)
386*68b2bbf2SGordon Ross 			return (errno);
387*68b2bbf2SGordon Ross 		if (x == 0)
388*68b2bbf2SGordon Ross 			return (EIO);
389*68b2bbf2SGordon Ross 		buf = (char *)buf + x;
390*68b2bbf2SGordon Ross 		len -= x;
391*68b2bbf2SGordon Ross 	}
392*68b2bbf2SGordon Ross 
393*68b2bbf2SGordon Ross 	return (0);
394*68b2bbf2SGordon Ross }
395