xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_opipe.c (revision 56e2cc86321ec889bf83a888d902c60d6fb2ef8d)
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 static void smb_user_context_fini(smb_opipe_context_t *);
60 
61 /*
62  * smb_opipe_open
63  *
64  * Open a well-known RPC named pipe. This routine should be called if
65  * a file open is requested on a share of type STYPE_IPC.
66  * If we recognize the pipe, we setup a new ofile.
67  *
68  * Returns 0 on success, Otherwise an NT status is returned to indicate
69  * an error.
70  */
71 int
72 smb_opipe_open(smb_request_t *sr)
73 {
74 	open_param_t *op = &sr->arg.open;
75 	smb_ofile_t *of;
76 	smb_opipe_t *opipe;
77 	smb_opipe_hdr_t hdr;
78 	smb_error_t err;
79 	char *pipe_name;
80 
81 	if ((pipe_name = smb_opipe_lookup(op->fqi.fq_path.pn_path)) == NULL)
82 		return (NT_STATUS_OBJECT_NAME_NOT_FOUND);
83 
84 	op->create_options = 0;
85 
86 	of = smb_ofile_open(sr->tid_tree, NULL, sr->smb_pid, op,
87 	    SMB_FTYPE_MESG_PIPE, SMB_UNIQ_FID(), &err);
88 
89 	if (of == NULL)
90 		return (err.status);
91 
92 	if (!smb_tree_is_connected(sr->tid_tree)) {
93 		smb_ofile_close(of, 0);
94 		smb_ofile_release(of);
95 		return (NT_STATUS_OBJECT_NAME_NOT_FOUND);
96 	}
97 
98 	op->dsize = 0x01000;
99 	op->dattr = FILE_ATTRIBUTE_NORMAL;
100 	op->ftype = SMB_FTYPE_MESG_PIPE;
101 	op->action_taken = SMB_OACT_LOCK | SMB_OACT_OPENED; /* 0x8001 */
102 	op->devstate = SMB_PIPE_READMODE_MESSAGE
103 	    | SMB_PIPE_TYPE_MESSAGE
104 	    | SMB_PIPE_UNLIMITED_INSTANCES; /* 0x05ff */
105 	op->fileid = of->f_fid;
106 
107 	sr->smb_fid = of->f_fid;
108 	sr->fid_ofile = of;
109 
110 	opipe = of->f_pipe;
111 	mutex_init(&opipe->p_mutex, NULL, MUTEX_DEFAULT, NULL);
112 	cv_init(&opipe->p_cv, NULL, CV_DEFAULT, NULL);
113 	smb_opipe_enter(opipe);
114 
115 	opipe->p_name = pipe_name;
116 	opipe->p_doorbuf = kmem_zalloc(SMB_OPIPE_DOOR_BUFSIZE, KM_SLEEP);
117 
118 	/*
119 	 * p_data points to the offset within p_doorbuf at which
120 	 * data will be written or read.
121 	 */
122 	opipe->p_data = opipe->p_doorbuf + xdr_sizeof(smb_opipe_hdr_xdr, &hdr);
123 
124 	if (smb_opipe_do_open(sr, opipe) != 0) {
125 		/*
126 		 * On error, reset the header to clear the fid,
127 		 * which avoids confusion when smb_opipe_close() is
128 		 * called by smb_ofile_close().
129 		 */
130 		bzero(&opipe->p_hdr, sizeof (smb_opipe_hdr_t));
131 		kmem_free(opipe->p_doorbuf, SMB_OPIPE_DOOR_BUFSIZE);
132 		smb_opipe_exit(opipe);
133 		smb_ofile_close(of, 0);
134 		return (NT_STATUS_NO_MEMORY);
135 	}
136 	smb_opipe_exit(opipe);
137 	return (NT_STATUS_SUCCESS);
138 }
139 
140 /*
141  * smb_opipe_lookup
142  *
143  * Lookup a path to see if it's a well-known RPC named pipe that we support.
144  * The full pipe path will be in the form \\PIPE\\SERVICE.  The first part
145  * can be assumed, so all we need here are the service names.
146  *
147  * Returns a pointer to the pipe name (without any leading \'s) on sucess.
148  * Otherwise returns a null pointer.
149  */
150 static char *
151 smb_opipe_lookup(const char *path)
152 {
153 	static char *named_pipes[] = {
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 (utf8_strncasecmp(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 (utf8_strcasecmp(name, named_pipes[i]) == 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_opipe_context_t *ctx = &opipe->p_context;
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_context_init(user, ctx);
199 	len = xdr_sizeof(smb_opipe_context_xdr, ctx);
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_opipe_context_encode(ctx, buf, buflen) == -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_context_fini(&opipe->p_context);
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 
625 void
626 smb_user_context_init(smb_user_t *user, smb_opipe_context_t *ctx)
627 {
628 	smb_session_t *session;
629 
630 	ASSERT(user);
631 	ASSERT(user->u_domain);
632 	ASSERT(user->u_name);
633 
634 	session = user->u_session;
635 	ASSERT(session);
636 	ASSERT(session->workstation);
637 
638 	ctx->oc_session_id = session->s_kid;
639 	ctx->oc_native_os = session->native_os;
640 	ctx->oc_ipaddr = session->ipaddr;
641 	ctx->oc_uid = user->u_uid;
642 	ctx->oc_logon_time = user->u_logon_time;
643 	ctx->oc_flags = user->u_flags;
644 
645 	ctx->oc_domain_len = user->u_domain_len;
646 	ctx->oc_domain = smb_kstrdup(user->u_domain, ctx->oc_domain_len);
647 
648 	ctx->oc_account_len = user->u_name_len;
649 	ctx->oc_account = smb_kstrdup(user->u_name, ctx->oc_account_len);
650 
651 	ctx->oc_workstation_len = strlen(session->workstation) + 1;
652 	ctx->oc_workstation = smb_kstrdup(session->workstation,
653 	    ctx->oc_workstation_len);
654 }
655 
656 static void
657 smb_user_context_fini(smb_opipe_context_t *ctx)
658 {
659 	if (ctx) {
660 		if (ctx->oc_domain)
661 			kmem_free(ctx->oc_domain, ctx->oc_domain_len);
662 		if (ctx->oc_account)
663 			kmem_free(ctx->oc_account, ctx->oc_account_len);
664 		if (ctx->oc_workstation)
665 			kmem_free(ctx->oc_workstation, ctx->oc_workstation_len);
666 		bzero(ctx, sizeof (smb_opipe_context_t));
667 	}
668 }
669 
670 void
671 smb_user_list_free(smb_dr_ulist_t *userlist)
672 {
673 	int i;
674 
675 	if (userlist) {
676 		for (i = 0; i < userlist->dul_cnt; i++)
677 			smb_user_context_fini(&userlist->dul_users[i]);
678 	}
679 }
680