xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_opipe.c (revision bbf6f00c25b6a2bed23c35eac6d62998ecdb338c)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*
27  * This module provides the interface to NDR RPC.
28  */
29 
30 #include <sys/stat.h>
31 #include <sys/door.h>
32 #include <sys/door_data.h>
33 #include <sys/uio.h>
34 #include <sys/ksynch.h>
35 #include <smbsrv/smb_kproto.h>
36 #include <smbsrv/smb_xdr.h>
37 
38 #define	SMB_OPIPE_ISOPEN(OPIPE)	\
39 	(((OPIPE)->p_hdr.oh_magic == SMB_OPIPE_HDR_MAGIC) && \
40 	((OPIPE)->p_hdr.oh_fid))
41 
42 extern volatile uint32_t smb_fids;
43 
44 static int smb_opipe_do_open(smb_request_t *, smb_opipe_t *);
45 static char *smb_opipe_lookup(const char *path);
46 static uint32_t smb_opipe_fid(void);
47 static int smb_opipe_set_hdr(smb_opipe_t *opipe, uint32_t, uint32_t);
48 static void smb_opipe_enter(smb_opipe_t *);
49 static void smb_opipe_exit(smb_opipe_t *);
50 
51 static door_handle_t smb_opipe_door_hd = NULL;
52 static int smb_opipe_door_id = -1;
53 static uint64_t smb_opipe_door_ncall = 0;
54 static kmutex_t smb_opipe_door_mutex;
55 static kcondvar_t smb_opipe_door_cv;
56 
57 static int smb_opipe_door_call(smb_opipe_t *);
58 static int smb_opipe_door_upcall(smb_opipe_t *);
59 
60 /*
61  * smb_opipe_open
62  *
63  * Open a well-known RPC named pipe. This routine should be called if
64  * a file open is requested on a share of type STYPE_IPC.
65  * If we recognize the pipe, we setup a new ofile.
66  *
67  * Returns 0 on success, Otherwise an NT status is returned to indicate
68  * an error.
69  */
70 int
71 smb_opipe_open(smb_request_t *sr)
72 {
73 	open_param_t *op = &sr->arg.open;
74 	smb_ofile_t *of;
75 	smb_opipe_t *opipe;
76 	smb_opipe_hdr_t hdr;
77 	smb_error_t err;
78 	char *pipe_name;
79 
80 	if ((pipe_name = smb_opipe_lookup(op->fqi.fq_path.pn_path)) == NULL)
81 		return (NT_STATUS_OBJECT_NAME_NOT_FOUND);
82 
83 	op->create_options = 0;
84 
85 	of = smb_ofile_open(sr->tid_tree, NULL, sr->smb_pid, op,
86 	    SMB_FTYPE_MESG_PIPE, SMB_UNIQ_FID(), &err);
87 
88 	if (of == NULL)
89 		return (err.status);
90 
91 	if (!smb_tree_is_connected(sr->tid_tree)) {
92 		smb_ofile_close(of, 0);
93 		smb_ofile_release(of);
94 		return (NT_STATUS_OBJECT_NAME_NOT_FOUND);
95 	}
96 
97 	op->dsize = 0x01000;
98 	op->dattr = FILE_ATTRIBUTE_NORMAL;
99 	op->ftype = SMB_FTYPE_MESG_PIPE;
100 	op->action_taken = SMB_OACT_LOCK | SMB_OACT_OPENED; /* 0x8001 */
101 	op->devstate = SMB_PIPE_READMODE_MESSAGE
102 	    | SMB_PIPE_TYPE_MESSAGE
103 	    | SMB_PIPE_UNLIMITED_INSTANCES; /* 0x05ff */
104 	op->fileid = of->f_fid;
105 
106 	sr->smb_fid = of->f_fid;
107 	sr->fid_ofile = of;
108 
109 	opipe = of->f_pipe;
110 	mutex_init(&opipe->p_mutex, NULL, MUTEX_DEFAULT, NULL);
111 	cv_init(&opipe->p_cv, NULL, CV_DEFAULT, NULL);
112 	smb_opipe_enter(opipe);
113 
114 	opipe->p_name = pipe_name;
115 	opipe->p_doorbuf = kmem_zalloc(SMB_OPIPE_DOOR_BUFSIZE, KM_SLEEP);
116 
117 	/*
118 	 * p_data points to the offset within p_doorbuf at which
119 	 * data will be written or read.
120 	 */
121 	opipe->p_data = opipe->p_doorbuf + xdr_sizeof(smb_opipe_hdr_xdr, &hdr);
122 
123 	if (smb_opipe_do_open(sr, opipe) != 0) {
124 		/*
125 		 * On error, reset the header to clear the fid,
126 		 * which avoids confusion when smb_opipe_close() is
127 		 * called by smb_ofile_close().
128 		 */
129 		bzero(&opipe->p_hdr, sizeof (smb_opipe_hdr_t));
130 		kmem_free(opipe->p_doorbuf, SMB_OPIPE_DOOR_BUFSIZE);
131 		smb_opipe_exit(opipe);
132 		smb_ofile_close(of, 0);
133 		return (NT_STATUS_NO_MEMORY);
134 	}
135 	smb_opipe_exit(opipe);
136 	return (NT_STATUS_SUCCESS);
137 }
138 
139 /*
140  * smb_opipe_lookup
141  *
142  * Lookup a path to see if it's a well-known RPC named pipe that we support.
143  * The full pipe path will be in the form \\PIPE\\SERVICE.  The first part
144  * can be assumed, so all we need here are the service names.
145  *
146  * Returns a pointer to the pipe name (without any leading \'s) on success.
147  * Otherwise returns a null pointer.
148  */
149 static char *
150 smb_opipe_lookup(const char *path)
151 {
152 	static char *named_pipes[] = {
153 		"lsass",
154 		"LSARPC",
155 		"NETLOGON",
156 		"SAMR",
157 		"SPOOLSS",
158 		"SRVSVC",
159 		"SVCCTL",
160 		"WINREG",
161 		"WKSSVC",
162 		"EVENTLOG"
163 	};
164 
165 	const char *name;
166 	int i;
167 
168 	if (path == NULL)
169 		return (NULL);
170 
171 	name = path;
172 	name += strspn(name, "\\");
173 	if (smb_strcasecmp(name, "PIPE", 4) == 0) {
174 		path += 4;
175 		name += strspn(name, "\\");
176 	}
177 
178 	for (i = 0; i < sizeof (named_pipes) / sizeof (named_pipes[0]); ++i) {
179 		if (smb_strcasecmp(name, named_pipes[i], 0) == 0)
180 			return (named_pipes[i]);
181 	}
182 
183 	return (NULL);
184 }
185 
186 /*
187  * Initialize the opipe header and context, and make the door call.
188  */
189 static int
190 smb_opipe_do_open(smb_request_t *sr, smb_opipe_t *opipe)
191 {
192 	smb_netuserinfo_t *userinfo = &opipe->p_user;
193 	smb_user_t *user = sr->uid_user;
194 	uint8_t *buf = opipe->p_doorbuf;
195 	uint32_t buflen = SMB_OPIPE_DOOR_BUFSIZE;
196 	uint32_t len;
197 
198 	smb_user_netinfo_init(user, userinfo);
199 	len = xdr_sizeof(smb_netuserinfo_xdr, userinfo);
200 
201 	bzero(&opipe->p_hdr, sizeof (smb_opipe_hdr_t));
202 	opipe->p_hdr.oh_magic = SMB_OPIPE_HDR_MAGIC;
203 	opipe->p_hdr.oh_fid = smb_opipe_fid();
204 
205 	if (smb_opipe_set_hdr(opipe, SMB_OPIPE_OPEN, len) == -1)
206 		return (-1);
207 
208 	len = xdr_sizeof(smb_opipe_hdr_xdr, &opipe->p_hdr);
209 	buf += len;
210 	buflen -= len;
211 
212 	if (smb_netuserinfo_encode(userinfo, buf, buflen, NULL) == -1)
213 		return (-1);
214 
215 	return (smb_opipe_door_call(opipe));
216 }
217 
218 /*
219  * smb_opipe_fid
220  *
221  * The opipe_fid is an arbitrary id used to associate RPC requests
222  * with a binding handle.  A new fid is returned on each call.
223  * 0 or -1 are not assigned: 0 is used to indicate an invalid fid
224  * and SMB sometimes uses -1 to indicate all open fid's.
225  */
226 static uint32_t
227 smb_opipe_fid(void)
228 {
229 	static uint32_t opipe_fid;
230 	static kmutex_t smb_opipe_fid_mutex;
231 
232 	mutex_enter(&smb_opipe_fid_mutex);
233 
234 	if (opipe_fid == 0)
235 		opipe_fid = lbolt << 11;
236 
237 	do {
238 		++opipe_fid;
239 	} while (opipe_fid == 0 || opipe_fid == (uint32_t)-1);
240 
241 	mutex_exit(&smb_opipe_fid_mutex);
242 
243 	return (opipe_fid);
244 }
245 
246 /*
247  * smb_opipe_close
248  *
249  * Called whenever an IPC file/pipe is closed.
250  */
251 void
252 smb_opipe_close(smb_ofile_t *of)
253 {
254 	smb_opipe_t *opipe;
255 
256 	ASSERT(of);
257 	ASSERT(of->f_ftype == SMB_FTYPE_MESG_PIPE);
258 	ASSERT(of->f_pipe != NULL);
259 
260 	opipe = of->f_pipe;
261 	smb_opipe_enter(opipe);
262 
263 	if (SMB_OPIPE_ISOPEN(opipe)) {
264 		(void) smb_opipe_set_hdr(opipe, SMB_OPIPE_CLOSE, 0);
265 		(void) smb_opipe_door_call(opipe);
266 		bzero(&opipe->p_hdr, sizeof (smb_opipe_hdr_t));
267 		kmem_free(opipe->p_doorbuf, SMB_OPIPE_DOOR_BUFSIZE);
268 	}
269 
270 	smb_user_netinfo_fini(&opipe->p_user);
271 	smb_opipe_exit(opipe);
272 	cv_destroy(&opipe->p_cv);
273 	mutex_destroy(&opipe->p_mutex);
274 }
275 
276 static int
277 smb_opipe_set_hdr(smb_opipe_t *opipe, uint32_t cmd, uint32_t datalen)
278 {
279 	opipe->p_hdr.oh_op = cmd;
280 	opipe->p_hdr.oh_datalen = datalen;
281 	opipe->p_hdr.oh_resid = 0;
282 	opipe->p_hdr.oh_status = 0;
283 
284 	return (smb_opipe_hdr_encode(&opipe->p_hdr, opipe->p_doorbuf,
285 	    SMB_OPIPE_DOOR_BUFSIZE));
286 }
287 
288 /*
289  * smb_opipe_transact
290  *
291  * This is the entry point for RPC bind and request transactions.
292  * The fid is an arbitrary id used to associate RPC requests with a
293  * particular binding handle.
294  *
295  * If the data to be returned is larger than the client expects, we
296  * return as much as the client can handle and report a buffer overflow
297  * warning, which informs the client that we have more data to return.
298  * The residual data remains in the pipe until the client claims it or
299  * closes the pipe.
300  */
301 smb_sdrc_t
302 smb_opipe_transact(smb_request_t *sr, struct uio *uio)
303 {
304 	smb_xa_t *xa;
305 	smb_opipe_t *opipe;
306 	struct mbuf *mhead;
307 	int mdrcnt;
308 	int nbytes;
309 	int rc;
310 
311 	if ((rc = smb_opipe_write(sr, uio)) != 0) {
312 		if (rc == EBADF)
313 			smbsr_error(sr, NT_STATUS_INVALID_HANDLE,
314 			    ERRDOS, ERROR_INVALID_HANDLE);
315 		else
316 			smbsr_error(sr, NT_STATUS_INTERNAL_ERROR,
317 			    ERRDOS, ERROR_INTERNAL_ERROR);
318 		return (SDRC_ERROR);
319 	}
320 
321 	xa = sr->r_xa;
322 	mdrcnt = xa->smb_mdrcnt;
323 	opipe = sr->fid_ofile->f_pipe;
324 	smb_opipe_enter(opipe);
325 
326 	if (smb_opipe_set_hdr(opipe, SMB_OPIPE_READ, mdrcnt) == -1) {
327 		smb_opipe_exit(opipe);
328 		smbsr_error(sr, NT_STATUS_INTERNAL_ERROR,
329 		    ERRDOS, ERROR_INTERNAL_ERROR);
330 		return (SDRC_ERROR);
331 	}
332 
333 	rc = smb_opipe_door_call(opipe);
334 	nbytes = opipe->p_hdr.oh_datalen;
335 
336 	if (rc != 0) {
337 		smb_opipe_exit(opipe);
338 		smbsr_error(sr, NT_STATUS_INTERNAL_ERROR,
339 		    ERRDOS, ERROR_INTERNAL_ERROR);
340 		return (SDRC_ERROR);
341 	}
342 
343 	if (nbytes) {
344 		mhead = smb_mbuf_get(opipe->p_data, nbytes);
345 		xa->rep_data_mb.max_bytes = nbytes;
346 		MBC_ATTACH_MBUF(&xa->rep_data_mb, mhead);
347 	}
348 
349 	if (opipe->p_hdr.oh_resid) {
350 		/*
351 		 * The pipe contains more data than mdrcnt, warn the
352 		 * client that there is more data in the pipe.
353 		 * Typically, the client will call SmbReadX, which
354 		 * will call smb_opipe_read, to get the data.
355 		 */
356 		smbsr_warn(sr, NT_STATUS_BUFFER_OVERFLOW,
357 		    ERRDOS, ERROR_MORE_DATA);
358 	}
359 
360 	smb_opipe_exit(opipe);
361 	return (SDRC_SUCCESS);
362 }
363 
364 /*
365  * smb_opipe_write
366  *
367  * Write RPC request data to the pipe.  The client should call smb_opipe_read
368  * to complete the exchange and obtain the RPC response.
369  *
370  * Returns 0 on success or an errno on failure.
371  */
372 int
373 smb_opipe_write(smb_request_t *sr, struct uio *uio)
374 {
375 	smb_opipe_t *opipe;
376 	uint32_t buflen;
377 	uint32_t len;
378 	int rc;
379 
380 	ASSERT(sr->fid_ofile);
381 	ASSERT(sr->fid_ofile->f_ftype == SMB_FTYPE_MESG_PIPE);
382 	ASSERT(sr->fid_ofile->f_pipe != NULL);
383 
384 	opipe = sr->fid_ofile->f_pipe;
385 	smb_opipe_enter(opipe);
386 
387 	if (!SMB_OPIPE_ISOPEN(opipe)) {
388 		smb_opipe_exit(opipe);
389 		return (EBADF);
390 	}
391 
392 	rc = smb_opipe_set_hdr(opipe, SMB_OPIPE_WRITE, uio->uio_resid);
393 	len = xdr_sizeof(smb_opipe_hdr_xdr, &opipe->p_hdr);
394 	if (rc == -1 || len == 0) {
395 		smb_opipe_exit(opipe);
396 		return (ENOMEM);
397 	}
398 
399 	buflen = SMB_OPIPE_DOOR_BUFSIZE - len;
400 	(void) uiomove((caddr_t)opipe->p_data, buflen, UIO_WRITE, uio);
401 
402 	rc = smb_opipe_door_call(opipe);
403 
404 	smb_opipe_exit(opipe);
405 	return ((rc == 0) ? 0 : EIO);
406 }
407 
408 /*
409  * smb_opipe_read
410  *
411  * This interface may be called because smb_opipe_transact could not return
412  * all of the data in the original transaction or to form the second half
413  * of a transaction set up using smb_opipe_write.  Either way, we just need
414  * to read data from the pipe and return it.
415  *
416  * The response data is encoded into raw_data as required by the smb_read
417  * functions.  The uio_resid value indicates the number of bytes read.
418  */
419 int
420 smb_opipe_read(smb_request_t *sr, struct uio *uio)
421 {
422 	smb_opipe_t *opipe;
423 	struct mbuf *mhead;
424 	uint32_t nbytes;
425 	int rc;
426 
427 	ASSERT(sr->fid_ofile);
428 	ASSERT(sr->fid_ofile->f_ftype == SMB_FTYPE_MESG_PIPE);
429 	ASSERT(sr->fid_ofile->f_pipe != NULL);
430 
431 	opipe = sr->fid_ofile->f_pipe;
432 	smb_opipe_enter(opipe);
433 
434 	if (!SMB_OPIPE_ISOPEN(opipe)) {
435 		smb_opipe_exit(opipe);
436 		return (EBADF);
437 	}
438 
439 	if (smb_opipe_set_hdr(opipe, SMB_OPIPE_READ, uio->uio_resid) == -1) {
440 		smb_opipe_exit(opipe);
441 		return (ENOMEM);
442 	}
443 
444 	rc = smb_opipe_door_call(opipe);
445 	nbytes = opipe->p_hdr.oh_datalen;
446 
447 	if (rc != 0 || nbytes > uio->uio_resid) {
448 		smb_opipe_exit(opipe);
449 		return (EIO);
450 	}
451 
452 	if (nbytes) {
453 		mhead = smb_mbuf_get(opipe->p_data, nbytes);
454 		MBC_SETUP(&sr->raw_data, nbytes);
455 		MBC_ATTACH_MBUF(&sr->raw_data, mhead);
456 		uio->uio_resid -= nbytes;
457 	}
458 
459 	smb_opipe_exit(opipe);
460 	return (rc);
461 }
462 
463 /*
464  * Named pipe I/O is serialized per fid to ensure that each request
465  * has exclusive opipe access for the duration of the request.
466  */
467 static void
468 smb_opipe_enter(smb_opipe_t *opipe)
469 {
470 	mutex_enter(&opipe->p_mutex);
471 
472 	while (opipe->p_busy)
473 		cv_wait(&opipe->p_cv, &opipe->p_mutex);
474 
475 	opipe->p_busy = 1;
476 	mutex_exit(&opipe->p_mutex);
477 }
478 
479 static void
480 smb_opipe_exit(smb_opipe_t *opipe)
481 {
482 	mutex_enter(&opipe->p_mutex);
483 	opipe->p_busy = 0;
484 	cv_signal(&opipe->p_cv);
485 	mutex_exit(&opipe->p_mutex);
486 }
487 
488 /*
489  * opipe door client (to user space door server).
490  */
491 void
492 smb_opipe_door_init(void)
493 {
494 	mutex_init(&smb_opipe_door_mutex, NULL, MUTEX_DEFAULT, NULL);
495 	cv_init(&smb_opipe_door_cv, NULL, CV_DEFAULT, NULL);
496 }
497 
498 void
499 smb_opipe_door_fini(void)
500 {
501 	smb_opipe_door_close();
502 	cv_destroy(&smb_opipe_door_cv);
503 	mutex_destroy(&smb_opipe_door_mutex);
504 }
505 
506 /*
507  * Open the (user space) door.  If the door is already open,
508  * close it first because the door-id has probably changed.
509  */
510 int
511 smb_opipe_door_open(int door_id)
512 {
513 	smb_opipe_door_close();
514 
515 	mutex_enter(&smb_opipe_door_mutex);
516 	smb_opipe_door_ncall = 0;
517 
518 	if (smb_opipe_door_hd == NULL) {
519 		smb_opipe_door_id = door_id;
520 		smb_opipe_door_hd = door_ki_lookup(door_id);
521 	}
522 
523 	mutex_exit(&smb_opipe_door_mutex);
524 	return ((smb_opipe_door_hd == NULL)  ? -1 : 0);
525 }
526 
527 /*
528  * Close the (user space) door.
529  */
530 void
531 smb_opipe_door_close(void)
532 {
533 	mutex_enter(&smb_opipe_door_mutex);
534 
535 	if (smb_opipe_door_hd != NULL) {
536 		while (smb_opipe_door_ncall > 0)
537 			cv_wait(&smb_opipe_door_cv, &smb_opipe_door_mutex);
538 
539 		door_ki_rele(smb_opipe_door_hd);
540 		smb_opipe_door_hd = NULL;
541 	}
542 
543 	mutex_exit(&smb_opipe_door_mutex);
544 }
545 
546 /*
547  * opipe door call interface.
548  * Door serialization and call reference accounting is handled here.
549  */
550 static int
551 smb_opipe_door_call(smb_opipe_t *opipe)
552 {
553 	int rc;
554 
555 	mutex_enter(&smb_opipe_door_mutex);
556 
557 	if (smb_opipe_door_hd == NULL) {
558 		mutex_exit(&smb_opipe_door_mutex);
559 
560 		if (smb_opipe_door_open(smb_opipe_door_id) != 0)
561 			return (-1);
562 
563 		mutex_enter(&smb_opipe_door_mutex);
564 	}
565 
566 	++smb_opipe_door_ncall;
567 	mutex_exit(&smb_opipe_door_mutex);
568 
569 	rc = smb_opipe_door_upcall(opipe);
570 
571 	mutex_enter(&smb_opipe_door_mutex);
572 	--smb_opipe_door_ncall;
573 	cv_signal(&smb_opipe_door_cv);
574 	mutex_exit(&smb_opipe_door_mutex);
575 	return (rc);
576 }
577 
578 /*
579  * Door upcall wrapper - handles data marshalling.
580  * This function should only be called by smb_opipe_door_call.
581  */
582 static int
583 smb_opipe_door_upcall(smb_opipe_t *opipe)
584 {
585 	door_arg_t da;
586 	smb_opipe_hdr_t hdr;
587 	int i;
588 	int rc;
589 
590 	da.data_ptr = (char *)opipe->p_doorbuf;
591 	da.data_size = SMB_OPIPE_DOOR_BUFSIZE;
592 	da.desc_ptr = NULL;
593 	da.desc_num = 0;
594 	da.rbuf = (char *)opipe->p_doorbuf;
595 	da.rsize = SMB_OPIPE_DOOR_BUFSIZE;
596 
597 	for (i = 0; i < 3; ++i) {
598 		if ((rc = door_ki_upcall_limited(smb_opipe_door_hd, &da,
599 		    NULL, SIZE_MAX, 0)) == 0)
600 			break;
601 
602 		if (rc != EAGAIN && rc != EINTR)
603 			return (-1);
604 	}
605 
606 	if (rc != 0)
607 		return (-1);
608 
609 	if (smb_opipe_hdr_decode(&hdr, (uint8_t *)da.rbuf, da.rsize) == -1)
610 		return (-1);
611 
612 	if ((hdr.oh_magic != SMB_OPIPE_HDR_MAGIC) ||
613 	    (hdr.oh_fid != opipe->p_hdr.oh_fid) ||
614 	    (hdr.oh_op != opipe->p_hdr.oh_op) ||
615 	    (hdr.oh_status != 0) ||
616 	    (hdr.oh_datalen > SMB_OPIPE_DOOR_BUFSIZE)) {
617 		return (-1);
618 	}
619 
620 	opipe->p_hdr.oh_datalen = hdr.oh_datalen;
621 	opipe->p_hdr.oh_resid = hdr.oh_resid;
622 	return (0);
623 }
624