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