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 /*
23 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
25 */
26
27 /*
28 * NETR SamLogon and SamLogoff RPC client functions.
29 */
30
31 #include <stdio.h>
32 #include <strings.h>
33 #include <stdlib.h>
34 #include <time.h>
35 #include <alloca.h>
36 #include <unistd.h>
37 #include <netdb.h>
38 #include <thread.h>
39
40 #include <smbsrv/libsmb.h>
41 #include <smbsrv/libmlrpc.h>
42 #include <smbsrv/libmlsvc.h>
43 #include <smbsrv/ndl/netlogon.ndl>
44 #include <smbsrv/netrauth.h>
45 #include <smbsrv/smbinfo.h>
46 #include <smbsrv/smb_token.h>
47 #include <mlsvc.h>
48
49 #define NETLOGON_ATTEMPTS 2
50
51 static uint32_t netlogon_logon(smb_logon_t *, smb_token_t *);
52 static uint32_t netr_server_samlogon(mlsvc_handle_t *, netr_info_t *, char *,
53 smb_logon_t *, smb_token_t *);
54 static void netr_invalidate_chain(void);
55 static void netr_interactive_samlogon(netr_info_t *, smb_logon_t *,
56 struct netr_logon_info1 *);
57 static void netr_network_samlogon(ndr_heap_t *, netr_info_t *,
58 smb_logon_t *, struct netr_logon_info2 *);
59 static void netr_setup_identity(ndr_heap_t *, smb_logon_t *,
60 netr_logon_id_t *);
61 static boolean_t netr_isadmin(struct netr_validation_info3 *);
62 static uint32_t netr_setup_domain_groups(struct netr_validation_info3 *,
63 smb_ids_t *);
64 static uint32_t netr_setup_token_wingrps(struct netr_validation_info3 *,
65 smb_token_t *);
66
67 /*
68 * Shared with netr_auth.c
69 */
70 extern netr_info_t netr_global_info;
71
72 static mutex_t netlogon_mutex;
73 static cond_t netlogon_cv;
74 static boolean_t netlogon_busy = B_FALSE;
75 static boolean_t netlogon_abort = B_FALSE;
76
77 /*
78 * Abort impending domain logon requests.
79 */
80 void
smb_logon_abort(void)81 smb_logon_abort(void)
82 {
83 (void) mutex_lock(&netlogon_mutex);
84 if (netlogon_busy && !netlogon_abort)
85 syslog(LOG_DEBUG, "logon abort");
86 netlogon_abort = B_TRUE;
87 (void) cond_broadcast(&netlogon_cv);
88 (void) mutex_unlock(&netlogon_mutex);
89 }
90
91 /*
92 * This is the entry point for authenticating domain users.
93 *
94 * If we are not going to attempt to authenticate the user,
95 * this function must return without updating the status.
96 *
97 * If the user is successfully authenticated, we build an
98 * access token and the status will be NT_STATUS_SUCCESS.
99 * Otherwise, the token contents are invalid.
100 */
101 void
smb_logon_domain(smb_logon_t * user_info,smb_token_t * token)102 smb_logon_domain(smb_logon_t *user_info, smb_token_t *token)
103 {
104 uint32_t status;
105 int i;
106
107 if (user_info->lg_secmode != SMB_SECMODE_DOMAIN)
108 return;
109
110 if (user_info->lg_domain_type == SMB_DOMAIN_LOCAL)
111 return;
112
113 for (i = 0; i < NETLOGON_ATTEMPTS; ++i) {
114 (void) mutex_lock(&netlogon_mutex);
115 while (netlogon_busy && !netlogon_abort)
116 (void) cond_wait(&netlogon_cv, &netlogon_mutex);
117
118 if (netlogon_abort) {
119 (void) mutex_unlock(&netlogon_mutex);
120 user_info->lg_status = NT_STATUS_REQUEST_ABORTED;
121 return;
122 }
123
124 netlogon_busy = B_TRUE;
125 (void) mutex_unlock(&netlogon_mutex);
126
127 status = netlogon_logon(user_info, token);
128
129 (void) mutex_lock(&netlogon_mutex);
130 netlogon_busy = B_FALSE;
131 if (netlogon_abort)
132 status = NT_STATUS_REQUEST_ABORTED;
133 (void) cond_signal(&netlogon_cv);
134 (void) mutex_unlock(&netlogon_mutex);
135
136 if (status != NT_STATUS_CANT_ACCESS_DOMAIN_INFO)
137 break;
138 }
139
140 if (status != NT_STATUS_SUCCESS)
141 syslog(LOG_INFO, "logon[%s\\%s]: %s", user_info->lg_e_domain,
142 user_info->lg_e_username, xlate_nt_status(status));
143
144 user_info->lg_status = status;
145 }
146
147 static uint32_t
netlogon_logon(smb_logon_t * user_info,smb_token_t * token)148 netlogon_logon(smb_logon_t *user_info, smb_token_t *token)
149 {
150 char resource_domain[SMB_PI_MAX_DOMAIN];
151 char server[NETBIOS_NAME_SZ * 2];
152 mlsvc_handle_t netr_handle;
153 smb_domainex_t di;
154 uint32_t status;
155 int retries = 0;
156
157 (void) smb_getdomainname(resource_domain, SMB_PI_MAX_DOMAIN);
158
159 /* Avoid interfering with DC discovery. */
160 if (smb_ddiscover_wait() != 0 ||
161 !smb_domain_getinfo(&di)) {
162 netr_invalidate_chain();
163 return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
164 }
165
166 do {
167 if (netr_open(di.d_dc, di.d_primary.di_nbname, &netr_handle)
168 != 0)
169 return (NT_STATUS_OPEN_FAILED);
170
171 if (di.d_dc && (*netr_global_info.server != '\0')) {
172 (void) snprintf(server, sizeof (server),
173 "\\\\%s", di.d_dc);
174 if (strncasecmp(netr_global_info.server,
175 server, strlen(server)) != 0)
176 netr_invalidate_chain();
177 }
178
179 if ((netr_global_info.flags & NETR_FLG_VALID) == 0 ||
180 !smb_match_netlogon_seqnum()) {
181 status = netlogon_auth(di.d_dc, &netr_handle,
182 NETR_FLG_NULL);
183
184 if (status != 0) {
185 (void) netr_close(&netr_handle);
186 return (NT_STATUS_LOGON_FAILURE);
187 }
188
189 netr_global_info.flags |= NETR_FLG_VALID;
190 }
191
192 status = netr_server_samlogon(&netr_handle,
193 &netr_global_info, di.d_dc, user_info, token);
194
195 (void) netr_close(&netr_handle);
196 } while (status == NT_STATUS_INSUFFICIENT_LOGON_INFO && retries++ < 3);
197
198 if (retries >= 3)
199 status = NT_STATUS_LOGON_FAILURE;
200
201 return (status);
202 }
203
204 static uint32_t
netr_setup_token(struct netr_validation_info3 * info3,smb_logon_t * user_info,netr_info_t * netr_info,smb_token_t * token)205 netr_setup_token(struct netr_validation_info3 *info3, smb_logon_t *user_info,
206 netr_info_t *netr_info, smb_token_t *token)
207 {
208 char *username, *domain;
209 unsigned char rc4key[SMBAUTH_SESSION_KEY_SZ];
210 smb_sid_t *domsid;
211 uint32_t status;
212 char nbdomain[NETBIOS_NAME_SZ];
213
214 domsid = (smb_sid_t *)info3->LogonDomainId;
215
216 token->tkn_user.i_sid = smb_sid_splice(domsid, info3->UserId);
217 if (token->tkn_user.i_sid == NULL)
218 return (NT_STATUS_NO_MEMORY);
219
220 token->tkn_primary_grp.i_sid = smb_sid_splice(domsid,
221 info3->PrimaryGroupId);
222 if (token->tkn_primary_grp.i_sid == NULL)
223 return (NT_STATUS_NO_MEMORY);
224
225 username = (info3->EffectiveName.str)
226 ? (char *)info3->EffectiveName.str : user_info->lg_e_username;
227
228 if (info3->LogonDomainName.str) {
229 domain = (char *)info3->LogonDomainName.str;
230 } else if (*user_info->lg_e_domain != '\0') {
231 domain = user_info->lg_e_domain;
232 } else {
233 (void) smb_getdomainname(nbdomain, sizeof (nbdomain));
234 domain = nbdomain;
235 }
236
237 if (username)
238 token->tkn_account_name = strdup(username);
239 if (domain)
240 token->tkn_domain_name = strdup(domain);
241
242 if (token->tkn_account_name == NULL || token->tkn_domain_name == NULL)
243 return (NT_STATUS_NO_MEMORY);
244
245 status = netr_setup_token_wingrps(info3, token);
246 if (status != NT_STATUS_SUCCESS)
247 return (status);
248
249 /*
250 * The UserSessionKey in NetrSamLogon RPC is obfuscated using the
251 * session key obtained in the NETLOGON credential chain.
252 * An 8 byte session key is zero extended to 16 bytes. This 16 byte
253 * key is the key to the RC4 algorithm. The RC4 byte stream is
254 * exclusively ored with the 16 byte UserSessionKey to recover
255 * the the clear form.
256 */
257 if ((token->tkn_session_key = malloc(SMBAUTH_SESSION_KEY_SZ)) == NULL)
258 return (NT_STATUS_NO_MEMORY);
259 bzero(rc4key, SMBAUTH_SESSION_KEY_SZ);
260 bcopy(netr_info->session_key.key, rc4key, netr_info->session_key.len);
261 bcopy(info3->UserSessionKey.data, token->tkn_session_key,
262 SMBAUTH_SESSION_KEY_SZ);
263 rand_hash((unsigned char *)token->tkn_session_key,
264 SMBAUTH_SESSION_KEY_SZ, rc4key, SMBAUTH_SESSION_KEY_SZ);
265
266 return (NT_STATUS_SUCCESS);
267 }
268
269 /*
270 * netr_server_samlogon
271 *
272 * NetrServerSamLogon RPC: interactive or network. It is assumed that
273 * we have already authenticated with the PDC. If everything works,
274 * we build a user info structure and return it, where the caller will
275 * probably build an access token.
276 *
277 * Returns an NT status. There are numerous possibilities here.
278 * For example:
279 * NT_STATUS_INVALID_INFO_CLASS
280 * NT_STATUS_INVALID_PARAMETER
281 * NT_STATUS_ACCESS_DENIED
282 * NT_STATUS_PASSWORD_MUST_CHANGE
283 * NT_STATUS_NO_SUCH_USER
284 * NT_STATUS_WRONG_PASSWORD
285 * NT_STATUS_LOGON_FAILURE
286 * NT_STATUS_ACCOUNT_RESTRICTION
287 * NT_STATUS_INVALID_LOGON_HOURS
288 * NT_STATUS_INVALID_WORKSTATION
289 * NT_STATUS_INTERNAL_ERROR
290 * NT_STATUS_PASSWORD_EXPIRED
291 * NT_STATUS_ACCOUNT_DISABLED
292 */
293 uint32_t
netr_server_samlogon(mlsvc_handle_t * netr_handle,netr_info_t * netr_info,char * server,smb_logon_t * user_info,smb_token_t * token)294 netr_server_samlogon(mlsvc_handle_t *netr_handle, netr_info_t *netr_info,
295 char *server, smb_logon_t *user_info, smb_token_t *token)
296 {
297 struct netr_SamLogon arg;
298 struct netr_authenticator auth;
299 struct netr_authenticator ret_auth;
300 struct netr_logon_info1 info1;
301 struct netr_logon_info2 info2;
302 struct netr_validation_info3 *info3;
303 ndr_heap_t *heap;
304 int opnum;
305 int rc, len;
306 uint32_t status;
307
308 bzero(&arg, sizeof (struct netr_SamLogon));
309 opnum = NETR_OPNUM_SamLogon;
310
311 /*
312 * Should we get the server and hostname from netr_info?
313 */
314
315 len = strlen(server) + 4;
316 arg.servername = ndr_rpc_malloc(netr_handle, len);
317 arg.hostname = ndr_rpc_malloc(netr_handle, NETBIOS_NAME_SZ);
318 if (arg.servername == NULL || arg.hostname == NULL) {
319 ndr_rpc_release(netr_handle);
320 return (NT_STATUS_INTERNAL_ERROR);
321 }
322
323 (void) snprintf((char *)arg.servername, len, "\\\\%s", server);
324 if (smb_getnetbiosname((char *)arg.hostname, NETBIOS_NAME_SZ) != 0) {
325 ndr_rpc_release(netr_handle);
326 return (NT_STATUS_INTERNAL_ERROR);
327 }
328
329 rc = netr_setup_authenticator(netr_info, &auth, &ret_auth);
330 if (rc != SMBAUTH_SUCCESS) {
331 ndr_rpc_release(netr_handle);
332 return (NT_STATUS_INTERNAL_ERROR);
333 }
334
335 arg.auth = &auth;
336 arg.ret_auth = &ret_auth;
337 arg.validation_level = NETR_VALIDATION_LEVEL3;
338 arg.logon_info.logon_level = user_info->lg_level;
339 arg.logon_info.switch_value = user_info->lg_level;
340
341 heap = ndr_rpc_get_heap(netr_handle);
342
343 switch (user_info->lg_level) {
344 case NETR_INTERACTIVE_LOGON:
345 netr_setup_identity(heap, user_info, &info1.identity);
346 netr_interactive_samlogon(netr_info, user_info, &info1);
347 arg.logon_info.ru.info1 = &info1;
348 break;
349
350 case NETR_NETWORK_LOGON:
351 if (user_info->lg_challenge_key.len < 8 ||
352 user_info->lg_challenge_key.val == NULL) {
353 ndr_rpc_release(netr_handle);
354 return (NT_STATUS_INVALID_PARAMETER);
355 }
356 netr_setup_identity(heap, user_info, &info2.identity);
357 netr_network_samlogon(heap, netr_info, user_info, &info2);
358 arg.logon_info.ru.info2 = &info2;
359 break;
360
361 default:
362 ndr_rpc_release(netr_handle);
363 return (NT_STATUS_INVALID_PARAMETER);
364 }
365
366 rc = ndr_rpc_call(netr_handle, opnum, &arg);
367 if (rc != 0) {
368 bzero(netr_info, sizeof (netr_info_t));
369 status = NT_STATUS_INVALID_PARAMETER;
370 } else if (arg.status != 0) {
371 status = NT_SC_VALUE(arg.status);
372
373 /*
374 * We need to validate the chain even though we have
375 * a non-zero status. If the status is ACCESS_DENIED
376 * this will trigger a new credential chain. However,
377 * a valid credential is returned with some status
378 * codes; for example, WRONG_PASSWORD.
379 */
380 (void) netr_validate_chain(netr_info, arg.ret_auth);
381 } else {
382 status = netr_validate_chain(netr_info, arg.ret_auth);
383 if (status == NT_STATUS_INSUFFICIENT_LOGON_INFO) {
384 ndr_rpc_release(netr_handle);
385 return (status);
386 }
387
388 info3 = arg.ru.info3;
389 status = netr_setup_token(info3, user_info, netr_info, token);
390 }
391
392 ndr_rpc_release(netr_handle);
393 return (status);
394 }
395
396 /*
397 * netr_interactive_samlogon
398 *
399 * Set things up for an interactive SamLogon. Copy the NT and LM
400 * passwords to the logon structure and hash them with the session
401 * key.
402 */
403 static void
netr_interactive_samlogon(netr_info_t * netr_info,smb_logon_t * user_info,struct netr_logon_info1 * info1)404 netr_interactive_samlogon(netr_info_t *netr_info, smb_logon_t *user_info,
405 struct netr_logon_info1 *info1)
406 {
407 BYTE key[NETR_OWF_PASSWORD_SZ];
408
409 (void) memcpy(&info1->lm_owf_password,
410 user_info->lg_lm_password.val, sizeof (netr_owf_password_t));
411
412 (void) memcpy(&info1->nt_owf_password,
413 user_info->lg_nt_password.val, sizeof (netr_owf_password_t));
414
415 (void) memset(key, 0, NETR_OWF_PASSWORD_SZ);
416 (void) memcpy(key, netr_info->session_key.key,
417 netr_info->session_key.len);
418
419 rand_hash((unsigned char *)&info1->lm_owf_password,
420 NETR_OWF_PASSWORD_SZ, key, NETR_OWF_PASSWORD_SZ);
421
422 rand_hash((unsigned char *)&info1->nt_owf_password,
423 NETR_OWF_PASSWORD_SZ, key, NETR_OWF_PASSWORD_SZ);
424 }
425
426 /*
427 * netr_network_samlogon
428 *
429 * Set things up for a network SamLogon. We provide a copy of the random
430 * challenge, that we sent to the client, to the domain controller. This
431 * is the key that the client will have used to encrypt the NT and LM
432 * passwords. Note that Windows 9x clients may not provide both passwords.
433 */
434 /*ARGSUSED*/
435 static void
netr_network_samlogon(ndr_heap_t * heap,netr_info_t * netr_info,smb_logon_t * user_info,struct netr_logon_info2 * info2)436 netr_network_samlogon(ndr_heap_t *heap, netr_info_t *netr_info,
437 smb_logon_t *user_info, struct netr_logon_info2 *info2)
438 {
439 uint32_t len;
440
441 if (user_info->lg_challenge_key.len >= 8 &&
442 user_info->lg_challenge_key.val != 0) {
443 bcopy(user_info->lg_challenge_key.val,
444 info2->lm_challenge.data, 8);
445 } else {
446 bzero(info2->lm_challenge.data, 8);
447 }
448
449 if ((len = user_info->lg_nt_password.len) != 0) {
450 ndr_heap_mkvcb(heap, user_info->lg_nt_password.val, len,
451 (ndr_vcbuf_t *)&info2->nt_response);
452 } else {
453 bzero(&info2->nt_response, sizeof (netr_vcbuf_t));
454 }
455
456 if ((len = user_info->lg_lm_password.len) != 0) {
457 ndr_heap_mkvcb(heap, user_info->lg_lm_password.val, len,
458 (ndr_vcbuf_t *)&info2->lm_response);
459 } else {
460 bzero(&info2->lm_response, sizeof (netr_vcbuf_t));
461 }
462 }
463
464 /*
465 * netr_setup_authenticator
466 *
467 * Set up the request and return authenticators. A new credential is
468 * generated from the session key, the current client credential and
469 * the current time, i.e.
470 *
471 * NewCredential = Cred(SessionKey, OldCredential, time);
472 *
473 * The timestamp, which is used as a random seed, is stored in both
474 * the request and return authenticators.
475 *
476 * If any difficulties occur using the cryptographic framework, the
477 * function returns SMBAUTH_FAILURE. Otherwise SMBAUTH_SUCCESS is
478 * returned.
479 */
480 int
netr_setup_authenticator(netr_info_t * netr_info,struct netr_authenticator * auth,struct netr_authenticator * ret_auth)481 netr_setup_authenticator(netr_info_t *netr_info,
482 struct netr_authenticator *auth, struct netr_authenticator *ret_auth)
483 {
484 bzero(auth, sizeof (struct netr_authenticator));
485
486 netr_info->timestamp = time(0);
487 auth->timestamp = netr_info->timestamp;
488
489 if (netr_gen_credentials(netr_info->session_key.key,
490 &netr_info->client_credential,
491 netr_info->timestamp,
492 (netr_cred_t *)&auth->credential) != SMBAUTH_SUCCESS)
493 return (SMBAUTH_FAILURE);
494
495 if (ret_auth) {
496 bzero(ret_auth, sizeof (struct netr_authenticator));
497 ret_auth->timestamp = netr_info->timestamp;
498 }
499
500 return (SMBAUTH_SUCCESS);
501 }
502
503 /*
504 * Validate the returned credentials and update the credential chain.
505 * The server returns an updated client credential rather than a new
506 * server credential. The server uses (timestamp + 1) when generating
507 * the credential.
508 *
509 * Generate the new seed for the credential chain. The new seed is
510 * formed by adding (timestamp + 1) to the current client credential.
511 * The only quirk is the uint32_t style addition.
512 *
513 * Returns NT_STATUS_INSUFFICIENT_LOGON_INFO if auth->credential is a
514 * NULL pointer. The Authenticator field of the SamLogon response packet
515 * sent by the Samba 3 PDC always return NULL pointer if the received
516 * SamLogon request is not immediately followed by the ServerReqChallenge
517 * and ServerAuthenticate2 requests.
518 *
519 * Returns NT_STATUS_SUCCESS if the server returned a valid credential.
520 * Otherwise we retirm NT_STATUS_UNSUCCESSFUL.
521 */
522 uint32_t
netr_validate_chain(netr_info_t * netr_info,struct netr_authenticator * auth)523 netr_validate_chain(netr_info_t *netr_info, struct netr_authenticator *auth)
524 {
525 netr_cred_t cred;
526 uint32_t result = NT_STATUS_SUCCESS;
527 uint32_t *dwp;
528
529 ++netr_info->timestamp;
530
531 if (netr_gen_credentials(netr_info->session_key.key,
532 &netr_info->client_credential,
533 netr_info->timestamp, &cred) != SMBAUTH_SUCCESS)
534 return (NT_STATUS_INTERNAL_ERROR);
535
536 if (&auth->credential == 0) {
537 /*
538 * If the validation fails, destroy the credential chain.
539 * This should trigger a new authentication chain.
540 */
541 bzero(netr_info, sizeof (netr_info_t));
542 return (NT_STATUS_INSUFFICIENT_LOGON_INFO);
543 }
544
545 result = memcmp(&cred, &auth->credential, sizeof (netr_cred_t));
546 if (result != 0) {
547 /*
548 * If the validation fails, destroy the credential chain.
549 * This should trigger a new authentication chain.
550 */
551 bzero(netr_info, sizeof (netr_info_t));
552 result = NT_STATUS_UNSUCCESSFUL;
553 } else {
554 /*
555 * Otherwise generate the next step in the chain.
556 */
557 /*LINTED E_BAD_PTR_CAST_ALIGN*/
558 dwp = (uint32_t *)&netr_info->client_credential;
559 dwp[0] += netr_info->timestamp;
560
561 netr_info->flags |= NETR_FLG_VALID;
562 }
563
564 return (result);
565 }
566
567 /*
568 * netr_invalidate_chain
569 *
570 * Mark the credential chain as invalid so that it will be recreated
571 * on the next attempt.
572 */
573 static void
netr_invalidate_chain(void)574 netr_invalidate_chain(void)
575 {
576 netr_global_info.flags &= ~NETR_FLG_VALID;
577 }
578
579 /*
580 * netr_setup_identity
581 *
582 * Set up the client identity information. All of this information is
583 * specifically related to the client user and workstation attempting
584 * to access this system. It may not be in our primary domain.
585 *
586 * I don't know what logon_id is, it seems to be a unique identifier.
587 * Increment it before each use.
588 */
589 static void
netr_setup_identity(ndr_heap_t * heap,smb_logon_t * user_info,netr_logon_id_t * identity)590 netr_setup_identity(ndr_heap_t *heap, smb_logon_t *user_info,
591 netr_logon_id_t *identity)
592 {
593 static mutex_t logon_id_mutex;
594 static uint32_t logon_id;
595
596 (void) mutex_lock(&logon_id_mutex);
597
598 if (logon_id == 0)
599 logon_id = 0xDCD0;
600
601 ++logon_id;
602 user_info->lg_logon_id = logon_id;
603
604 (void) mutex_unlock(&logon_id_mutex);
605
606 identity->parameter_control = 0;
607 identity->logon_id.LowPart = logon_id;
608 identity->logon_id.HighPart = 0;
609
610 ndr_heap_mkvcs(heap, user_info->lg_domain,
611 (ndr_vcstr_t *)&identity->domain_name);
612
613 ndr_heap_mkvcs(heap, user_info->lg_username,
614 (ndr_vcstr_t *)&identity->username);
615
616 /*
617 * Some systems prefix the client workstation name with \\.
618 * It doesn't seem to make any difference whether it's there
619 * or not.
620 */
621 ndr_heap_mkvcs(heap, user_info->lg_workstation,
622 (ndr_vcstr_t *)&identity->workstation);
623 }
624
625 /*
626 * Sets up domain, local and well-known group membership for the given
627 * token. Two assumptions have been made here:
628 *
629 * a) token already contains a valid user SID so that group
630 * memberships can be established
631 *
632 * b) token belongs to a domain user
633 */
634 static uint32_t
netr_setup_token_wingrps(struct netr_validation_info3 * info3,smb_token_t * token)635 netr_setup_token_wingrps(struct netr_validation_info3 *info3,
636 smb_token_t *token)
637 {
638 smb_ids_t tkn_grps;
639 uint32_t status;
640
641 tkn_grps.i_cnt = 0;
642 tkn_grps.i_ids = NULL;
643
644 status = netr_setup_domain_groups(info3, &tkn_grps);
645 if (status != NT_STATUS_SUCCESS) {
646 smb_ids_free(&tkn_grps);
647 return (status);
648 }
649
650 status = smb_sam_usr_groups(token->tkn_user.i_sid, &tkn_grps);
651 if (status != NT_STATUS_SUCCESS) {
652 smb_ids_free(&tkn_grps);
653 return (status);
654 }
655
656 if (netr_isadmin(info3))
657 token->tkn_flags |= SMB_ATF_ADMIN;
658
659 status = smb_wka_token_groups(token->tkn_flags, &tkn_grps);
660 if (status == NT_STATUS_SUCCESS)
661 token->tkn_win_grps = tkn_grps;
662 else
663 smb_ids_free(&tkn_grps);
664
665 return (status);
666 }
667
668 /*
669 * Converts groups information in the returned structure by domain controller
670 * (info3) to an internal representation (gids)
671 */
672 static uint32_t
netr_setup_domain_groups(struct netr_validation_info3 * info3,smb_ids_t * gids)673 netr_setup_domain_groups(struct netr_validation_info3 *info3, smb_ids_t *gids)
674 {
675 smb_sid_t *domain_sid;
676 smb_id_t *ids;
677 int i, total_cnt;
678
679 if ((i = info3->GroupCount) == 0)
680 i++;
681 i += info3->SidCount;
682
683 total_cnt = gids->i_cnt + i;
684
685 gids->i_ids = realloc(gids->i_ids, total_cnt * sizeof (smb_id_t));
686 if (gids->i_ids == NULL)
687 return (NT_STATUS_NO_MEMORY);
688
689 domain_sid = (smb_sid_t *)info3->LogonDomainId;
690
691 ids = gids->i_ids + gids->i_cnt;
692 for (i = 0; i < info3->GroupCount; i++, gids->i_cnt++, ids++) {
693 ids->i_sid = smb_sid_splice(domain_sid, info3->GroupIds[i].rid);
694 if (ids->i_sid == NULL)
695 return (NT_STATUS_NO_MEMORY);
696
697 ids->i_attrs = info3->GroupIds[i].attributes;
698 }
699
700 if (info3->GroupCount == 0) {
701 /*
702 * if there's no global group should add the primary group.
703 */
704 ids->i_sid = smb_sid_splice(domain_sid, info3->PrimaryGroupId);
705 if (ids->i_sid == NULL)
706 return (NT_STATUS_NO_MEMORY);
707
708 ids->i_attrs = 0x7;
709 gids->i_cnt++;
710 ids++;
711 }
712
713 /* Add the extra SIDs */
714 for (i = 0; i < info3->SidCount; i++, gids->i_cnt++, ids++) {
715 ids->i_sid = smb_sid_dup((smb_sid_t *)info3->ExtraSids[i].sid);
716 if (ids->i_sid == NULL)
717 return (NT_STATUS_NO_MEMORY);
718
719 ids->i_attrs = info3->ExtraSids[i].attributes;
720 }
721
722 return (NT_STATUS_SUCCESS);
723 }
724
725 /*
726 * Determines if the given user is the domain Administrator or a
727 * member of Domain Admins
728 */
729 static boolean_t
netr_isadmin(struct netr_validation_info3 * info3)730 netr_isadmin(struct netr_validation_info3 *info3)
731 {
732 smb_domain_t di;
733 int i;
734
735 if (!smb_domain_lookup_sid((smb_sid_t *)info3->LogonDomainId, &di))
736 return (B_FALSE);
737
738 if (di.di_type != SMB_DOMAIN_PRIMARY)
739 return (B_FALSE);
740
741 if ((info3->UserId == DOMAIN_USER_RID_ADMIN) ||
742 (info3->PrimaryGroupId == DOMAIN_GROUP_RID_ADMINS))
743 return (B_TRUE);
744
745 for (i = 0; i < info3->GroupCount; i++)
746 if (info3->GroupIds[i].rid == DOMAIN_GROUP_RID_ADMINS)
747 return (B_TRUE);
748
749 return (B_FALSE);
750 }
751