xref: /titanic_44/usr/src/uts/common/fs/smbsrv/smb_user.c (revision 48a4016cae8aa2b8b3d8b258eb22e0c781912bed)
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 (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23  * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
24  */
25 
26 /*
27  * General Structures Layout
28  * -------------------------
29  *
30  * This is a simplified diagram showing the relationship between most of the
31  * main structures.
32  *
33  * +-------------------+
34  * |     SMB_INFO      |
35  * +-------------------+
36  *          |
37  *          |
38  *          v
39  * +-------------------+       +-------------------+      +-------------------+
40  * |     SESSION       |<----->|     SESSION       |......|      SESSION      |
41  * +-------------------+       +-------------------+      +-------------------+
42  *   |          |
43  *   |          |
44  *   |          v
45  *   |  +-------------------+     +-------------------+   +-------------------+
46  *   |  |       USER        |<--->|       USER        |...|       USER        |
47  *   |  +-------------------+     +-------------------+   +-------------------+
48  *   |
49  *   |
50  *   v
51  * +-------------------+       +-------------------+      +-------------------+
52  * |       TREE        |<----->|       TREE        |......|       TREE        |
53  * +-------------------+       +-------------------+      +-------------------+
54  *      |         |
55  *      |         |
56  *      |         v
57  *      |     +-------+       +-------+      +-------+
58  *      |     | OFILE |<----->| OFILE |......| OFILE |
59  *      |     +-------+       +-------+      +-------+
60  *      |
61  *      |
62  *      v
63  *  +-------+       +------+      +------+
64  *  | ODIR  |<----->| ODIR |......| ODIR |
65  *  +-------+       +------+      +------+
66  *
67  *
68  * User State Machine
69  * ------------------
70  *
71  *    +-----------------------------+	 T0
72  *    |  SMB_USER_STATE_LOGGED_IN   |<----------- Creation/Allocation
73  *    +-----------------------------+
74  *		    |
75  *		    | T1
76  *		    |
77  *		    v
78  *    +-----------------------------+
79  *    |  SMB_USER_STATE_LOGGING_OFF |
80  *    +-----------------------------+
81  *		    |
82  *		    | T2
83  *		    |
84  *		    v
85  *    +-----------------------------+    T3
86  *    |  SMB_USER_STATE_LOGGED_OFF  |----------> Deletion/Free
87  *    +-----------------------------+
88  *
89  * SMB_USER_STATE_LOGGED_IN
90  *
91  *    While in this state:
92  *      - The user is queued in the list of users of his session.
93  *      - References will be given out if the user is looked up.
94  *      - The user can access files and pipes.
95  *
96  * SMB_USER_STATE_LOGGING_OFF
97  *
98  *    While in this state:
99  *      - The user is queued in the list of users of his session.
100  *      - References will not be given out if the user is looked up.
101  *      - The trees the user connected are being disconnected.
102  *      - The resources associated with the user remain.
103  *
104  * SMB_USER_STATE_LOGGING_OFF
105  *
106  *    While in this state:
107  *      - The user is queued in the list of users of his session.
108  *      - References will not be given out if the user is looked up.
109  *      - The user has no more trees connected.
110  *      - The resources associated with the user remain.
111  *
112  * Transition T0
113  *
114  *    This transition occurs in smb_user_login(). A new user is created and
115  *    added to the list of users of a session.
116  *
117  * Transition T1
118  *
119  *    This transition occurs in smb_user_logoff().
120  *
121  * Transition T2
122  *
123  *    This transition occurs in smb_user_release(). The resources associated
124  *    with the user are deleted as well as the user. For the transition to
125  *    occur, the user must be in the SMB_USER_STATE_LOGGED_OFF state and the
126  *    reference count be zero.
127  *
128  * Comments
129  * --------
130  *
131  *    The state machine of the user structures is controlled by 3 elements:
132  *      - The list of users of the session he belongs to.
133  *      - The mutex embedded in the structure itself.
134  *      - The reference count.
135  *
136  *    There's a mutex embedded in the user structure used to protect its fields
137  *    and there's a lock embedded in the list of users of a session. To
138  *    increment or to decrement the reference count the mutex must be entered.
139  *    To insert the user into the list of users of the session and to remove
140  *    the user from it, the lock must be entered in RW_WRITER mode.
141  *
142  *    Rules of access to a user structure:
143  *
144  *    1) In order to avoid deadlocks, when both (mutex and lock of the session
145  *       list) have to be entered, the lock must be entered first.
146  *
147  *    2) All actions applied to a user require a reference count.
148  *
149  *    3) There are 2 ways of getting a reference count. One is when the user
150  *       logs in. The other when the user is looked up.
151  *
152  *    It should be noted that the reference count of a user registers the
153  *    number of references to the user in other structures (such as an smb
154  *    request). The reference count is not incremented in these 2 instances:
155  *
156  *    1) The user is logged in. An user is anchored by his state. If there's
157  *       no activity involving a user currently logged in, the reference
158  *       count of that user is zero.
159  *
160  *    2) The user is queued in the list of users of the session. The fact of
161  *       being queued in that list is NOT registered by incrementing the
162  *       reference count.
163  */
164 #include <sys/types.h>
165 #include <sys/sid.h>
166 #include <sys/priv_names.h>
167 #include <smbsrv/smb_kproto.h>
168 #include <smbsrv/smb_door.h>
169 
170 #define	ADMINISTRATORS_SID	"S-1-5-32-544"
171 
172 static boolean_t smb_user_is_logged_in(smb_user_t *);
173 static int smb_user_enum_private(smb_user_t *, smb_svcenum_t *);
174 static void smb_user_nonauth_logon(smb_user_t *);
175 static void smb_user_auth_logoff(smb_user_t *);
176 
177 
178 /*
179  * Create a new user.
180  */
181 smb_user_t *
182 smb_user_login(
183     smb_session_t	*session,
184     cred_t		*cr,
185     char		*domain_name,
186     char		*account_name,
187     uint32_t		flags,
188     uint32_t		privileges,
189     uint32_t		audit_sid)
190 {
191 	smb_user_t	*user;
192 
193 	ASSERT(session);
194 	ASSERT(session->s_magic == SMB_SESSION_MAGIC);
195 	ASSERT(cr);
196 	ASSERT(account_name);
197 	ASSERT(domain_name);
198 
199 	user = kmem_cache_alloc(smb_cache_user, KM_SLEEP);
200 	bzero(user, sizeof (smb_user_t));
201 	user->u_refcnt = 1;
202 	user->u_session = session;
203 	user->u_server = session->s_server;
204 	user->u_logon_time = gethrestime_sec();
205 	user->u_flags = flags;
206 	user->u_name_len = strlen(account_name) + 1;
207 	user->u_domain_len = strlen(domain_name) + 1;
208 	user->u_name = smb_mem_strdup(account_name);
209 	user->u_domain = smb_mem_strdup(domain_name);
210 	user->u_audit_sid = audit_sid;
211 
212 	if (!smb_idpool_alloc(&session->s_uid_pool, &user->u_uid)) {
213 		mutex_init(&user->u_mutex, NULL, MUTEX_DEFAULT, NULL);
214 		smb_user_setcred(user, cr, privileges);
215 		user->u_state = SMB_USER_STATE_LOGGED_IN;
216 		user->u_magic = SMB_USER_MAGIC;
217 		smb_llist_enter(&session->s_user_list, RW_WRITER);
218 		smb_llist_insert_tail(&session->s_user_list, user);
219 		smb_llist_exit(&session->s_user_list);
220 		smb_server_inc_users(session->s_server);
221 		return (user);
222 	}
223 	smb_mem_free(user->u_name);
224 	smb_mem_free(user->u_domain);
225 	kmem_cache_free(smb_cache_user, user);
226 	return (NULL);
227 }
228 
229 /*
230  * Create a new user based on an existing user, used to support
231  * additional SessionSetupX requests for a user on a session.
232  *
233  * Assumes the caller has a reference on the original user from
234  * a user_lookup_by_x call.
235  */
236 smb_user_t *
237 smb_user_dup(
238     smb_user_t		*orig_user)
239 {
240 	smb_user_t	*user;
241 
242 	ASSERT(orig_user->u_magic == SMB_USER_MAGIC);
243 	ASSERT(orig_user->u_refcnt);
244 
245 	user = smb_user_login(orig_user->u_session, orig_user->u_cred,
246 	    orig_user->u_domain, orig_user->u_name, orig_user->u_flags,
247 	    orig_user->u_privileges, orig_user->u_audit_sid);
248 
249 	if (user)
250 		smb_user_nonauth_logon(orig_user);
251 
252 	return (user);
253 }
254 
255 /*
256  * smb_user_logoff
257  *
258  * Change the user state and disconnect trees.
259  * The user list must not be entered or modified here.
260  */
261 void
262 smb_user_logoff(
263     smb_user_t		*user)
264 {
265 	ASSERT(user->u_magic == SMB_USER_MAGIC);
266 
267 	mutex_enter(&user->u_mutex);
268 	ASSERT(user->u_refcnt);
269 	switch (user->u_state) {
270 	case SMB_USER_STATE_LOGGED_IN: {
271 		/*
272 		 * The user is moved into a state indicating that the log off
273 		 * process has started.
274 		 */
275 		user->u_state = SMB_USER_STATE_LOGGING_OFF;
276 		mutex_exit(&user->u_mutex);
277 		smb_session_disconnect_owned_trees(user->u_session, user);
278 		smb_user_auth_logoff(user);
279 		mutex_enter(&user->u_mutex);
280 		user->u_state = SMB_USER_STATE_LOGGED_OFF;
281 		smb_server_dec_users(user->u_server);
282 		break;
283 	}
284 	case SMB_USER_STATE_LOGGED_OFF:
285 	case SMB_USER_STATE_LOGGING_OFF:
286 		break;
287 
288 	default:
289 		ASSERT(0);
290 		break;
291 	}
292 	mutex_exit(&user->u_mutex);
293 }
294 
295 /*
296  * Take a reference on a user.  Do not return a reference unless the user is in
297  * the logged-in state.
298  */
299 boolean_t
300 smb_user_hold(smb_user_t *user)
301 {
302 	SMB_USER_VALID(user);
303 
304 	mutex_enter(&user->u_mutex);
305 
306 	if (smb_user_is_logged_in(user)) {
307 		user->u_refcnt++;
308 		mutex_exit(&user->u_mutex);
309 		return (B_TRUE);
310 	}
311 
312 	mutex_exit(&user->u_mutex);
313 	return (B_FALSE);
314 }
315 
316 /*
317  * Unconditionally take a reference on a user.
318  */
319 void
320 smb_user_hold_internal(smb_user_t *user)
321 {
322 	SMB_USER_VALID(user);
323 
324 	mutex_enter(&user->u_mutex);
325 	user->u_refcnt++;
326 	mutex_exit(&user->u_mutex);
327 }
328 
329 /*
330  * Release a reference on a user.  If the reference count falls to
331  * zero and the user has logged off, post the object for deletion.
332  * Object deletion is deferred to avoid modifying a list while an
333  * iteration may be in progress.
334  */
335 void
336 smb_user_release(
337     smb_user_t		*user)
338 {
339 	ASSERT(user->u_magic == SMB_USER_MAGIC);
340 
341 	mutex_enter(&user->u_mutex);
342 	ASSERT(user->u_refcnt);
343 	user->u_refcnt--;
344 
345 	switch (user->u_state) {
346 	case SMB_USER_STATE_LOGGED_OFF:
347 		if (user->u_refcnt == 0)
348 			smb_session_post_user(user->u_session, user);
349 		break;
350 
351 	case SMB_USER_STATE_LOGGED_IN:
352 	case SMB_USER_STATE_LOGGING_OFF:
353 		break;
354 
355 	default:
356 		ASSERT(0);
357 		break;
358 	}
359 	mutex_exit(&user->u_mutex);
360 }
361 
362 /*
363  * Determine whether or not the user is an administrator.
364  * Members of the administrators group have administrative rights.
365  */
366 boolean_t
367 smb_user_is_admin(smb_user_t *user)
368 {
369 #ifdef	_KERNEL
370 	char		sidstr[SMB_SID_STRSZ];
371 	ksidlist_t	*ksidlist;
372 	ksid_t		ksid1;
373 	ksid_t		*ksid2;
374 	int		i;
375 #endif	/* _KERNEL */
376 	boolean_t	rc = B_FALSE;
377 
378 	ASSERT(user);
379 	ASSERT(user->u_cred);
380 
381 	if (SMB_USER_IS_ADMIN(user))
382 		return (B_TRUE);
383 
384 #ifdef	_KERNEL
385 	bzero(&ksid1, sizeof (ksid_t));
386 	(void) strlcpy(sidstr, ADMINISTRATORS_SID, SMB_SID_STRSZ);
387 	ASSERT(smb_sid_splitstr(sidstr, &ksid1.ks_rid) == 0);
388 	ksid1.ks_domain = ksid_lookupdomain(sidstr);
389 
390 	ksidlist = crgetsidlist(user->u_cred);
391 	ASSERT(ksidlist);
392 	ASSERT(ksid1.ks_domain);
393 	ASSERT(ksid1.ks_domain->kd_name);
394 
395 	i = 0;
396 	ksid2 = crgetsid(user->u_cred, KSID_USER);
397 	do {
398 		ASSERT(ksid2->ks_domain);
399 		ASSERT(ksid2->ks_domain->kd_name);
400 
401 		if (strcmp(ksid1.ks_domain->kd_name,
402 		    ksid2->ks_domain->kd_name) == 0 &&
403 		    ksid1.ks_rid == ksid2->ks_rid) {
404 			user->u_flags |= SMB_USER_FLAG_ADMIN;
405 			rc = B_TRUE;
406 			break;
407 		}
408 
409 		ksid2 = &ksidlist->ksl_sids[i];
410 	} while (i++ < ksidlist->ksl_nsid);
411 
412 	ksid_rele(&ksid1);
413 #endif	/* _KERNEL */
414 	return (rc);
415 }
416 
417 /*
418  * This function should be called with a hold on the user.
419  */
420 boolean_t
421 smb_user_namecmp(smb_user_t *user, const char *name)
422 {
423 	char		*fq_name;
424 	boolean_t	match;
425 
426 	if (smb_strcasecmp(name, user->u_name, 0) == 0)
427 		return (B_TRUE);
428 
429 	fq_name = kmem_alloc(MAXNAMELEN, KM_SLEEP);
430 
431 	(void) snprintf(fq_name, MAXNAMELEN, "%s\\%s",
432 	    user->u_domain, user->u_name);
433 
434 	match = (smb_strcasecmp(name, fq_name, 0) == 0);
435 	if (!match) {
436 		(void) snprintf(fq_name, MAXNAMELEN, "%s@%s",
437 		    user->u_name, user->u_domain);
438 
439 		match = (smb_strcasecmp(name, fq_name, 0) == 0);
440 	}
441 
442 	kmem_free(fq_name, MAXNAMELEN);
443 	return (match);
444 }
445 
446 /*
447  * If the enumeration request is for user data, handle the request
448  * here.  Otherwise, pass it on to the trees.
449  *
450  * This function should be called with a hold on the user.
451  */
452 int
453 smb_user_enum(smb_user_t *user, smb_svcenum_t *svcenum)
454 {
455 	int		rc = 0;
456 
457 	ASSERT(user);
458 	ASSERT(user->u_magic == SMB_USER_MAGIC);
459 
460 	if (svcenum->se_type == SMB_SVCENUM_TYPE_USER)
461 		return (smb_user_enum_private(user, svcenum));
462 
463 	return (rc);
464 }
465 
466 /* *************************** Static Functions ***************************** */
467 
468 /*
469  * Determine whether or not a user is logged in.
470  * Typically, a reference can only be taken on a logged-in user.
471  *
472  * This is a private function and must be called with the user
473  * mutex held.
474  */
475 static boolean_t
476 smb_user_is_logged_in(smb_user_t *user)
477 {
478 	switch (user->u_state) {
479 	case SMB_USER_STATE_LOGGED_IN:
480 		return (B_TRUE);
481 
482 	case SMB_USER_STATE_LOGGING_OFF:
483 	case SMB_USER_STATE_LOGGED_OFF:
484 		return (B_FALSE);
485 
486 	default:
487 		ASSERT(0);
488 		return (B_FALSE);
489 	}
490 }
491 
492 /*
493  * Delete a user.  The tree list should be empty.
494  *
495  * Remove the user from the session's user list before freeing resources
496  * associated with the user.
497  */
498 void
499 smb_user_delete(void *arg)
500 {
501 	smb_session_t	*session;
502 	smb_user_t	*user = (smb_user_t *)arg;
503 
504 	SMB_USER_VALID(user);
505 	ASSERT(user->u_refcnt == 0);
506 	ASSERT(user->u_state == SMB_USER_STATE_LOGGED_OFF);
507 
508 	session = user->u_session;
509 	smb_llist_enter(&session->s_user_list, RW_WRITER);
510 	smb_llist_remove(&session->s_user_list, user);
511 	smb_idpool_free(&session->s_uid_pool, user->u_uid);
512 	smb_llist_exit(&session->s_user_list);
513 
514 	mutex_enter(&user->u_mutex);
515 	mutex_exit(&user->u_mutex);
516 
517 	user->u_magic = (uint32_t)~SMB_USER_MAGIC;
518 	mutex_destroy(&user->u_mutex);
519 	if (user->u_cred)
520 		crfree(user->u_cred);
521 	if (user->u_privcred)
522 		crfree(user->u_privcred);
523 	smb_mem_free(user->u_name);
524 	smb_mem_free(user->u_domain);
525 	kmem_cache_free(smb_cache_user, user);
526 }
527 
528 cred_t *
529 smb_user_getcred(smb_user_t *user)
530 {
531 	return (user->u_cred);
532 }
533 
534 cred_t *
535 smb_user_getprivcred(smb_user_t *user)
536 {
537 	return ((user->u_privcred)? user->u_privcred : user->u_cred);
538 }
539 
540 #ifdef	_KERNEL
541 /*
542  * Assign the user cred and privileges.
543  *
544  * If the user has backup and/or restore privleges, dup the cred
545  * and add those privileges to this new privileged cred.
546  */
547 void
548 smb_user_setcred(smb_user_t *user, cred_t *cr, uint32_t privileges)
549 {
550 	cred_t *privcred = NULL;
551 
552 	ASSERT(cr);
553 	crhold(cr);
554 
555 	if (privileges & (SMB_USER_PRIV_BACKUP | SMB_USER_PRIV_RESTORE))
556 		privcred = crdup(cr);
557 
558 	if (privcred != NULL) {
559 		if (privileges & SMB_USER_PRIV_BACKUP) {
560 			(void) crsetpriv(privcred, PRIV_FILE_DAC_READ,
561 			    PRIV_FILE_DAC_SEARCH, PRIV_SYS_MOUNT, NULL);
562 		}
563 
564 		if (privileges & SMB_USER_PRIV_RESTORE) {
565 			(void) crsetpriv(privcred, PRIV_FILE_DAC_WRITE,
566 			    PRIV_FILE_CHOWN, PRIV_FILE_CHOWN_SELF,
567 			    PRIV_FILE_DAC_SEARCH, PRIV_FILE_LINK_ANY,
568 			    PRIV_FILE_OWNER, PRIV_FILE_SETID,
569 			    PRIV_SYS_LINKDIR, PRIV_SYS_MOUNT, NULL);
570 		}
571 	}
572 
573 	user->u_cred = cr;
574 	user->u_privcred = privcred;
575 	user->u_privileges = privileges;
576 }
577 #endif	/* _KERNEL */
578 
579 /*
580  * Private function to support smb_user_enum.
581  */
582 static int
583 smb_user_enum_private(smb_user_t *user, smb_svcenum_t *svcenum)
584 {
585 	uint8_t *pb;
586 	uint_t nbytes;
587 	int rc;
588 
589 	if (svcenum->se_nskip > 0) {
590 		svcenum->se_nskip--;
591 		return (0);
592 	}
593 
594 	if (svcenum->se_nitems >= svcenum->se_nlimit) {
595 		svcenum->se_nitems = svcenum->se_nlimit;
596 		return (0);
597 	}
598 
599 	pb = &svcenum->se_buf[svcenum->se_bused];
600 	rc = smb_user_netinfo_encode(user, pb, svcenum->se_bavail, &nbytes);
601 	if (rc == 0) {
602 		svcenum->se_bavail -= nbytes;
603 		svcenum->se_bused += nbytes;
604 		svcenum->se_nitems++;
605 	}
606 
607 	return (rc);
608 }
609 
610 /*
611  * Encode the NetInfo for a user into a buffer.  NetInfo contains
612  * information that is often needed in user space to support RPC
613  * requests.
614  */
615 int
616 smb_user_netinfo_encode(smb_user_t *user, uint8_t *buf, size_t buflen,
617     uint32_t *nbytes)
618 {
619 	smb_netuserinfo_t	info;
620 	int			rc;
621 
622 	smb_user_netinfo_init(user, &info);
623 	rc = smb_netuserinfo_encode(&info, buf, buflen, nbytes);
624 	smb_user_netinfo_fini(&info);
625 
626 	return (rc);
627 }
628 
629 void
630 smb_user_netinfo_init(smb_user_t *user, smb_netuserinfo_t *info)
631 {
632 	smb_session_t	*session;
633 	char		*buf;
634 
635 	ASSERT(user);
636 	ASSERT(user->u_domain);
637 	ASSERT(user->u_name);
638 
639 	session = user->u_session;
640 	ASSERT(session);
641 	ASSERT(session->workstation);
642 
643 	info->ui_session_id = session->s_kid;
644 	info->ui_native_os = session->native_os;
645 	info->ui_ipaddr = session->ipaddr;
646 	info->ui_numopens = session->s_file_cnt;
647 	info->ui_smb_uid = user->u_uid;
648 	info->ui_logon_time = user->u_logon_time;
649 	info->ui_flags = user->u_flags;
650 	info->ui_posix_uid = crgetuid(user->u_cred);
651 
652 	info->ui_domain_len = user->u_domain_len;
653 	info->ui_domain = smb_mem_strdup(user->u_domain);
654 
655 	info->ui_account_len = user->u_name_len;
656 	info->ui_account = smb_mem_strdup(user->u_name);
657 
658 	buf = kmem_alloc(MAXNAMELEN, KM_SLEEP);
659 	smb_session_getclient(session, buf, MAXNAMELEN);
660 	info->ui_workstation_len = strlen(buf) + 1;
661 	info->ui_workstation = smb_mem_strdup(buf);
662 	kmem_free(buf, MAXNAMELEN);
663 }
664 
665 void
666 smb_user_netinfo_fini(smb_netuserinfo_t *info)
667 {
668 	if (info == NULL)
669 		return;
670 
671 	if (info->ui_domain)
672 		smb_mem_free(info->ui_domain);
673 	if (info->ui_account)
674 		smb_mem_free(info->ui_account);
675 	if (info->ui_workstation)
676 		smb_mem_free(info->ui_workstation);
677 
678 	bzero(info, sizeof (smb_netuserinfo_t));
679 }
680 
681 static void
682 smb_user_nonauth_logon(smb_user_t *user)
683 {
684 	uint32_t audit_sid = user->u_audit_sid;
685 
686 	(void) smb_kdoor_upcall(user->u_server, SMB_DR_USER_NONAUTH_LOGON,
687 	    &audit_sid, xdr_uint32_t, NULL, NULL);
688 }
689 
690 static void
691 smb_user_auth_logoff(smb_user_t *user)
692 {
693 	uint32_t audit_sid = user->u_audit_sid;
694 
695 	(void) smb_kdoor_upcall(user->u_server, SMB_DR_USER_AUTH_LOGOFF,
696 	    &audit_sid, xdr_uint32_t, NULL, NULL);
697 }
698 
699 smb_token_t *
700 smb_get_token(smb_session_t *session, smb_logon_t *user_info)
701 {
702 	smb_token_t	*token;
703 	int		rc;
704 
705 	token = kmem_zalloc(sizeof (smb_token_t), KM_SLEEP);
706 
707 	rc = smb_kdoor_upcall(session->s_server, SMB_DR_USER_AUTH_LOGON,
708 	    user_info, smb_logon_xdr, token, smb_token_xdr);
709 
710 	if (rc != 0) {
711 		kmem_free(token, sizeof (smb_token_t));
712 		return (NULL);
713 	}
714 
715 	if (!smb_token_valid(token)) {
716 		smb_token_free(token);
717 		return (NULL);
718 	}
719 
720 	return (token);
721 }
722