xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_opipe.c (revision 29bd28862cfb8abbd3a0f0a4b17e08bbc3652836)
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_incl.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 sucess.
147  * Otherwise returns a null pointer.
148  */
149 static char *
150 smb_opipe_lookup(const char *path)
151 {
152 	static char *named_pipes[] = {
153 		"LSARPC",
154 		"NETLOGON",
155 		"SAMR",
156 		"SPOOLSS",
157 		"SRVSVC",
158 		"SVCCTL",
159 		"WINREG",
160 		"WKSSVC",
161 		"EVENTLOG"
162 	};
163 
164 	const char *name;
165 	int i;
166 
167 	if (path == NULL)
168 		return (NULL);
169 
170 	name = path;
171 	name += strspn(name, "\\");
172 	if (utf8_strncasecmp(name, "PIPE", 4) == 0) {
173 		path += 4;
174 		name += strspn(name, "\\");
175 	}
176 
177 	for (i = 0; i < sizeof (named_pipes) / sizeof (named_pipes[0]); ++i) {
178 		if (utf8_strcasecmp(name, named_pipes[i]) == 0)
179 			return (named_pipes[i]);
180 	}
181 
182 	return (NULL);
183 }
184 
185 /*
186  * Initialize the opipe header and context, and make the door call.
187  */
188 static int
189 smb_opipe_do_open(smb_request_t *sr, smb_opipe_t *opipe)
190 {
191 	smb_opipe_context_t *ctx = &opipe->p_context;
192 	smb_user_t *user = sr->uid_user;
193 	uint8_t *buf = opipe->p_doorbuf;
194 	uint32_t buflen = SMB_OPIPE_DOOR_BUFSIZE;
195 	uint32_t len;
196 
197 	smb_user_context_init(user, ctx);
198 	len = xdr_sizeof(smb_opipe_context_xdr, ctx);
199 
200 	bzero(&opipe->p_hdr, sizeof (smb_opipe_hdr_t));
201 	opipe->p_hdr.oh_magic = SMB_OPIPE_HDR_MAGIC;
202 	opipe->p_hdr.oh_fid = smb_opipe_fid();
203 
204 	if (smb_opipe_set_hdr(opipe, SMB_OPIPE_OPEN, len) == -1)
205 		return (-1);
206 
207 	len = xdr_sizeof(smb_opipe_hdr_xdr, &opipe->p_hdr);
208 	buf += len;
209 	buflen -= len;
210 
211 	if (smb_opipe_context_encode(ctx, buf, buflen, NULL) == -1)
212 		return (-1);
213 
214 	return (smb_opipe_door_call(opipe));
215 }
216 
217 /*
218  * smb_opipe_fid
219  *
220  * The opipe_fid is an arbitrary id used to associate RPC requests
221  * with a binding handle.  A new fid is returned on each call.
222  * 0 or -1 are not assigned: 0 is used to indicate an invalid fid
223  * and SMB sometimes uses -1 to indicate all open fid's.
224  */
225 static uint32_t
226 smb_opipe_fid(void)
227 {
228 	static uint32_t opipe_fid;
229 	static kmutex_t smb_opipe_fid_mutex;
230 
231 	mutex_enter(&smb_opipe_fid_mutex);
232 
233 	if (opipe_fid == 0)
234 		opipe_fid = lbolt << 11;
235 
236 	do {
237 		++opipe_fid;
238 	} while (opipe_fid == 0 || opipe_fid == (uint32_t)-1);
239 
240 	mutex_exit(&smb_opipe_fid_mutex);
241 
242 	return (opipe_fid);
243 }
244 
245 /*
246  * smb_opipe_close
247  *
248  * Called whenever an IPC file/pipe is closed.
249  */
250 void
251 smb_opipe_close(smb_ofile_t *of)
252 {
253 	smb_opipe_t *opipe;
254 
255 	ASSERT(of);
256 	ASSERT(of->f_ftype == SMB_FTYPE_MESG_PIPE);
257 	ASSERT(of->f_pipe != NULL);
258 
259 	opipe = of->f_pipe;
260 	smb_opipe_enter(opipe);
261 
262 	if (SMB_OPIPE_ISOPEN(opipe)) {
263 		(void) smb_opipe_set_hdr(opipe, SMB_OPIPE_CLOSE, 0);
264 		(void) smb_opipe_door_call(opipe);
265 		bzero(&opipe->p_hdr, sizeof (smb_opipe_hdr_t));
266 		kmem_free(opipe->p_doorbuf, SMB_OPIPE_DOOR_BUFSIZE);
267 	}
268 
269 	smb_user_context_fini(&opipe->p_context);
270 	smb_opipe_exit(opipe);
271 	cv_destroy(&opipe->p_cv);
272 	mutex_destroy(&opipe->p_mutex);
273 }
274 
275 static int
276 smb_opipe_set_hdr(smb_opipe_t *opipe, uint32_t cmd, uint32_t datalen)
277 {
278 	opipe->p_hdr.oh_op = cmd;
279 	opipe->p_hdr.oh_datalen = datalen;
280 	opipe->p_hdr.oh_resid = 0;
281 	opipe->p_hdr.oh_status = 0;
282 
283 	return (smb_opipe_hdr_encode(&opipe->p_hdr, opipe->p_doorbuf,
284 	    SMB_OPIPE_DOOR_BUFSIZE));
285 }
286 
287 /*
288  * smb_opipe_transact
289  *
290  * This is the entry point for RPC bind and request transactions.
291  * The fid is an arbitrary id used to associate RPC requests with a
292  * particular binding handle.
293  *
294  * If the data to be returned is larger than the client expects, we
295  * return as much as the client can handle and report a buffer overflow
296  * warning, which informs the client that we have more data to return.
297  * The residual data remains in the pipe until the client claims it or
298  * closes the pipe.
299  */
300 smb_sdrc_t
301 smb_opipe_transact(smb_request_t *sr, struct uio *uio)
302 {
303 	smb_xa_t *xa;
304 	smb_opipe_t *opipe;
305 	struct mbuf *mhead;
306 	int mdrcnt;
307 	int nbytes;
308 	int rc;
309 
310 	if ((rc = smb_opipe_write(sr, uio)) != 0) {
311 		if (rc == EBADF)
312 			smbsr_error(sr, NT_STATUS_INVALID_HANDLE,
313 			    ERRDOS, ERROR_INVALID_HANDLE);
314 		else
315 			smbsr_error(sr, NT_STATUS_INTERNAL_ERROR,
316 			    ERRDOS, ERROR_INTERNAL_ERROR);
317 		return (SDRC_ERROR);
318 	}
319 
320 	xa = sr->r_xa;
321 	mdrcnt = xa->smb_mdrcnt;
322 	opipe = sr->fid_ofile->f_pipe;
323 	smb_opipe_enter(opipe);
324 
325 	if (smb_opipe_set_hdr(opipe, SMB_OPIPE_READ, mdrcnt) == -1) {
326 		smb_opipe_exit(opipe);
327 		smbsr_error(sr, NT_STATUS_INTERNAL_ERROR,
328 		    ERRDOS, ERROR_INTERNAL_ERROR);
329 		return (SDRC_ERROR);
330 	}
331 
332 	rc = smb_opipe_door_call(opipe);
333 	nbytes = opipe->p_hdr.oh_datalen;
334 
335 	if (rc != 0) {
336 		smb_opipe_exit(opipe);
337 		smbsr_error(sr, NT_STATUS_INTERNAL_ERROR,
338 		    ERRDOS, ERROR_INTERNAL_ERROR);
339 		return (SDRC_ERROR);
340 	}
341 
342 	if (nbytes) {
343 		mhead = smb_mbuf_get(opipe->p_data, nbytes);
344 		xa->rep_data_mb.max_bytes = nbytes;
345 		MBC_ATTACH_MBUF(&xa->rep_data_mb, mhead);
346 	}
347 
348 	if (opipe->p_hdr.oh_resid) {
349 		/*
350 		 * The pipe contains more data than mdrcnt, warn the
351 		 * client that there is more data in the pipe.
352 		 * Typically, the client will call SmbReadX, which
353 		 * will call smb_opipe_read, to get the data.
354 		 */
355 		smbsr_warn(sr, NT_STATUS_BUFFER_OVERFLOW,
356 		    ERRDOS, ERROR_MORE_DATA);
357 	}
358 
359 	smb_opipe_exit(opipe);
360 	return (SDRC_SUCCESS);
361 }
362 
363 /*
364  * smb_opipe_write
365  *
366  * Write RPC request data to the pipe.  The client should call smb_opipe_read
367  * to complete the exchange and obtain the RPC response.
368  *
369  * Returns 0 on success or an errno on failure.
370  */
371 int
372 smb_opipe_write(smb_request_t *sr, struct uio *uio)
373 {
374 	smb_opipe_t *opipe;
375 	uint32_t buflen;
376 	uint32_t len;
377 	int rc;
378 
379 	ASSERT(sr->fid_ofile);
380 	ASSERT(sr->fid_ofile->f_ftype == SMB_FTYPE_MESG_PIPE);
381 	ASSERT(sr->fid_ofile->f_pipe != NULL);
382 
383 	opipe = sr->fid_ofile->f_pipe;
384 	smb_opipe_enter(opipe);
385 
386 	if (!SMB_OPIPE_ISOPEN(opipe)) {
387 		smb_opipe_exit(opipe);
388 		return (EBADF);
389 	}
390 
391 	rc = smb_opipe_set_hdr(opipe, SMB_OPIPE_WRITE, uio->uio_resid);
392 	len = xdr_sizeof(smb_opipe_hdr_xdr, &opipe->p_hdr);
393 	if (rc == -1 || len == 0) {
394 		smb_opipe_exit(opipe);
395 		return (ENOMEM);
396 	}
397 
398 	buflen = SMB_OPIPE_DOOR_BUFSIZE - len;
399 	(void) uiomove((caddr_t)opipe->p_data, buflen, UIO_WRITE, uio);
400 
401 	rc = smb_opipe_door_call(opipe);
402 
403 	smb_opipe_exit(opipe);
404 	return ((rc == 0) ? 0 : EIO);
405 }
406 
407 /*
408  * smb_opipe_read
409  *
410  * This interface may be called because smb_opipe_transact could not return
411  * all of the data in the original transaction or to form the second half
412  * of a transaction set up using smb_opipe_write.  Either way, we just need
413  * to read data from the pipe and return it.
414  *
415  * The response data is encoded into raw_data as required by the smb_read
416  * functions.  The uio_resid value indicates the number of bytes read.
417  */
418 int
419 smb_opipe_read(smb_request_t *sr, struct uio *uio)
420 {
421 	smb_opipe_t *opipe;
422 	struct mbuf *mhead;
423 	uint32_t nbytes;
424 	int rc;
425 
426 	ASSERT(sr->fid_ofile);
427 	ASSERT(sr->fid_ofile->f_ftype == SMB_FTYPE_MESG_PIPE);
428 	ASSERT(sr->fid_ofile->f_pipe != NULL);
429 
430 	opipe = sr->fid_ofile->f_pipe;
431 	smb_opipe_enter(opipe);
432 
433 	if (!SMB_OPIPE_ISOPEN(opipe)) {
434 		smb_opipe_exit(opipe);
435 		return (EBADF);
436 	}
437 
438 	if (smb_opipe_set_hdr(opipe, SMB_OPIPE_READ, uio->uio_resid) == -1) {
439 		smb_opipe_exit(opipe);
440 		return (ENOMEM);
441 	}
442 
443 	rc = smb_opipe_door_call(opipe);
444 	nbytes = opipe->p_hdr.oh_datalen;
445 
446 	if (rc != 0 || nbytes > uio->uio_resid) {
447 		smb_opipe_exit(opipe);
448 		return (EIO);
449 	}
450 
451 	if (nbytes) {
452 		mhead = smb_mbuf_get(opipe->p_data, nbytes);
453 		MBC_SETUP(&sr->raw_data, nbytes);
454 		MBC_ATTACH_MBUF(&sr->raw_data, mhead);
455 		uio->uio_resid -= nbytes;
456 	}
457 
458 	smb_opipe_exit(opipe);
459 	return (rc);
460 }
461 
462 /*
463  * Named pipe I/O is serialized per fid to ensure that each request
464  * has exclusive opipe access for the duration of the request.
465  */
466 static void
467 smb_opipe_enter(smb_opipe_t *opipe)
468 {
469 	mutex_enter(&opipe->p_mutex);
470 
471 	while (opipe->p_busy)
472 		cv_wait(&opipe->p_cv, &opipe->p_mutex);
473 
474 	opipe->p_busy = 1;
475 	mutex_exit(&opipe->p_mutex);
476 }
477 
478 static void
479 smb_opipe_exit(smb_opipe_t *opipe)
480 {
481 	mutex_enter(&opipe->p_mutex);
482 	opipe->p_busy = 0;
483 	cv_signal(&opipe->p_cv);
484 	mutex_exit(&opipe->p_mutex);
485 }
486 
487 /*
488  * opipe door client (to user space door server).
489  */
490 void
491 smb_opipe_door_init(void)
492 {
493 	mutex_init(&smb_opipe_door_mutex, NULL, MUTEX_DEFAULT, NULL);
494 	cv_init(&smb_opipe_door_cv, NULL, CV_DEFAULT, NULL);
495 }
496 
497 void
498 smb_opipe_door_fini(void)
499 {
500 	smb_opipe_door_close();
501 	cv_destroy(&smb_opipe_door_cv);
502 	mutex_destroy(&smb_opipe_door_mutex);
503 }
504 
505 /*
506  * Open the (user space) door.  If the door is already open,
507  * close it first because the door-id has probably changed.
508  */
509 int
510 smb_opipe_door_open(int door_id)
511 {
512 	smb_opipe_door_close();
513 
514 	mutex_enter(&smb_opipe_door_mutex);
515 	smb_opipe_door_ncall = 0;
516 
517 	if (smb_opipe_door_hd == NULL) {
518 		smb_opipe_door_id = door_id;
519 		smb_opipe_door_hd = door_ki_lookup(door_id);
520 	}
521 
522 	mutex_exit(&smb_opipe_door_mutex);
523 	return ((smb_opipe_door_hd == NULL)  ? -1 : 0);
524 }
525 
526 /*
527  * Close the (user space) door.
528  */
529 void
530 smb_opipe_door_close(void)
531 {
532 	mutex_enter(&smb_opipe_door_mutex);
533 
534 	if (smb_opipe_door_hd != NULL) {
535 		while (smb_opipe_door_ncall > 0)
536 			cv_wait(&smb_opipe_door_cv, &smb_opipe_door_mutex);
537 
538 		door_ki_rele(smb_opipe_door_hd);
539 		smb_opipe_door_hd = NULL;
540 	}
541 
542 	mutex_exit(&smb_opipe_door_mutex);
543 }
544 
545 /*
546  * opipe door call interface.
547  * Door serialization and call reference accounting is handled here.
548  */
549 static int
550 smb_opipe_door_call(smb_opipe_t *opipe)
551 {
552 	int rc;
553 
554 	mutex_enter(&smb_opipe_door_mutex);
555 
556 	if (smb_opipe_door_hd == NULL) {
557 		mutex_exit(&smb_opipe_door_mutex);
558 
559 		if (smb_opipe_door_open(smb_opipe_door_id) != 0)
560 			return (-1);
561 
562 		mutex_enter(&smb_opipe_door_mutex);
563 	}
564 
565 	++smb_opipe_door_ncall;
566 	mutex_exit(&smb_opipe_door_mutex);
567 
568 	rc = smb_opipe_door_upcall(opipe);
569 
570 	mutex_enter(&smb_opipe_door_mutex);
571 	--smb_opipe_door_ncall;
572 	cv_signal(&smb_opipe_door_cv);
573 	mutex_exit(&smb_opipe_door_mutex);
574 	return (rc);
575 }
576 
577 /*
578  * Door upcall wrapper - handles data marshalling.
579  * This function should only be called by smb_opipe_door_call.
580  */
581 static int
582 smb_opipe_door_upcall(smb_opipe_t *opipe)
583 {
584 	door_arg_t da;
585 	smb_opipe_hdr_t hdr;
586 	int i;
587 	int rc;
588 
589 	da.data_ptr = (char *)opipe->p_doorbuf;
590 	da.data_size = SMB_OPIPE_DOOR_BUFSIZE;
591 	da.desc_ptr = NULL;
592 	da.desc_num = 0;
593 	da.rbuf = (char *)opipe->p_doorbuf;
594 	da.rsize = SMB_OPIPE_DOOR_BUFSIZE;
595 
596 	for (i = 0; i < 3; ++i) {
597 		if ((rc = door_ki_upcall_limited(smb_opipe_door_hd, &da,
598 		    NULL, SIZE_MAX, 0)) == 0)
599 			break;
600 
601 		if (rc != EAGAIN && rc != EINTR)
602 			return (-1);
603 	}
604 
605 	if (rc != 0)
606 		return (-1);
607 
608 	if (smb_opipe_hdr_decode(&hdr, (uint8_t *)da.rbuf, da.rsize) == -1)
609 		return (-1);
610 
611 	if ((hdr.oh_magic != SMB_OPIPE_HDR_MAGIC) ||
612 	    (hdr.oh_fid != opipe->p_hdr.oh_fid) ||
613 	    (hdr.oh_op != opipe->p_hdr.oh_op) ||
614 	    (hdr.oh_status != 0) ||
615 	    (hdr.oh_datalen > SMB_OPIPE_DOOR_BUFSIZE)) {
616 		return (-1);
617 	}
618 
619 	opipe->p_hdr.oh_datalen = hdr.oh_datalen;
620 	opipe->p_hdr.oh_resid = hdr.oh_resid;
621 	return (0);
622 }
623 
624 void
625 smb_user_context_init(smb_user_t *user, smb_opipe_context_t *ctx)
626 {
627 	smb_session_t *session;
628 
629 	ASSERT(user);
630 	ASSERT(user->u_domain);
631 	ASSERT(user->u_name);
632 
633 	session = user->u_session;
634 	ASSERT(session);
635 	ASSERT(session->workstation);
636 
637 	ctx->oc_session_id = session->s_kid;
638 	ctx->oc_native_os = session->native_os;
639 	ctx->oc_ipaddr = session->ipaddr;
640 	ctx->oc_uid = user->u_uid;
641 	ctx->oc_logon_time = user->u_logon_time;
642 	ctx->oc_flags = user->u_flags;
643 
644 	ctx->oc_domain_len = user->u_domain_len;
645 	ctx->oc_domain = smb_kstrdup(user->u_domain, ctx->oc_domain_len);
646 
647 	ctx->oc_account_len = user->u_name_len;
648 	ctx->oc_account = smb_kstrdup(user->u_name, ctx->oc_account_len);
649 
650 	ctx->oc_workstation_len = strlen(session->workstation) + 1;
651 	ctx->oc_workstation = smb_kstrdup(session->workstation,
652 	    ctx->oc_workstation_len);
653 }
654 
655 void
656 smb_user_context_fini(smb_opipe_context_t *ctx)
657 {
658 	if (ctx) {
659 		if (ctx->oc_domain)
660 			kmem_free(ctx->oc_domain, ctx->oc_domain_len);
661 		if (ctx->oc_account)
662 			kmem_free(ctx->oc_account, ctx->oc_account_len);
663 		if (ctx->oc_workstation)
664 			kmem_free(ctx->oc_workstation, ctx->oc_workstation_len);
665 		bzero(ctx, sizeof (smb_opipe_context_t));
666 	}
667 }
668