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