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 *
smb_user_login(smb_session_t * session,cred_t * cr,char * domain_name,char * account_name,uint32_t flags,uint32_t privileges,uint32_t audit_sid)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 *
smb_user_dup(smb_user_t * orig_user)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
smb_user_logoff(smb_user_t * user)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
smb_user_hold(smb_user_t * user)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
smb_user_hold_internal(smb_user_t * user)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
smb_user_release(smb_user_t * user)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
smb_user_is_admin(smb_user_t * user)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
smb_user_namecmp(smb_user_t * user,const char * name)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
smb_user_enum(smb_user_t * user,smb_svcenum_t * svcenum)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
smb_user_is_logged_in(smb_user_t * user)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
smb_user_delete(void * arg)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 *
smb_user_getcred(smb_user_t * user)529 smb_user_getcred(smb_user_t *user)
530 {
531 return (user->u_cred);
532 }
533
534 cred_t *
smb_user_getprivcred(smb_user_t * user)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
smb_user_setcred(smb_user_t * user,cred_t * cr,uint32_t privileges)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
smb_user_enum_private(smb_user_t * user,smb_svcenum_t * svcenum)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
smb_user_netinfo_encode(smb_user_t * user,uint8_t * buf,size_t buflen,uint32_t * nbytes)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
smb_user_netinfo_init(smb_user_t * user,smb_netuserinfo_t * info)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
smb_user_netinfo_fini(smb_netuserinfo_t * info)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
smb_user_nonauth_logon(smb_user_t * user)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
smb_user_auth_logoff(smb_user_t * user)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 *
smb_get_token(smb_session_t * session,smb_logon_t * user_info)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