Print this page
NEX-18708 Domain logons may get STATUS_ACCESS_DENIED
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
1575 untangle libmlrpc from SMB server
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Toomas Soome <tsoome@me.com>
Approved by: Richard Lowe <richlowe@richlowe.net>
NEX-15558 SMB logon fails during 1st second after service start
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-15558 SMB logon fails during 1st second after service start
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Evan Layton <evan.layton@nexenta.com>
NEX-9106 SMB should support "Resource SID Compression"
Reviewed by: Dan Fields <dan.fields@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
NEX-4272 Allow authenticating computer accounts
Reviewed by: Gordon Ross <gwr@nexenta.com>
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
NEX-3080 SMB1 signing problem with Kerberos auth.
Reviewed by: Bayard Bell <bayard.bell@nexenta.com>
Reviewed by: Dan Fields <dan.fields@nexenta.com>
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
Reviewed by: Matt Barden <Matt.Barden@nexenta.com>
NEX-2225 Unable to join NexentaStor to 2008 AD
NEX-1810 extended security Kerberos (inbound)
re #7126 rb4153 smbd panic with missing negotiate challenge
| 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
|
↓ open down ↓ |
13 lines elided |
↑ open up ↑ |
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 - * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
24 + * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
25 25 */
26 26
27 27 /*
28 28 * NETR SamLogon and SamLogoff RPC client functions.
29 29 */
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 -#define NETLOGON_ATTEMPTS 2
50 -
51 -static uint32_t netlogon_logon(smb_logon_t *, smb_token_t *);
49 +static uint32_t netlogon_logon(smb_logon_t *, smb_token_t *, smb_domainex_t *);
52 50 static uint32_t netr_server_samlogon(mlsvc_handle_t *, netr_info_t *, char *,
53 51 smb_logon_t *, smb_token_t *);
54 52 static void netr_invalidate_chain(void);
55 53 static void netr_interactive_samlogon(netr_info_t *, smb_logon_t *,
56 54 struct netr_logon_info1 *);
57 55 static void netr_network_samlogon(ndr_heap_t *, netr_info_t *,
58 56 smb_logon_t *, struct netr_logon_info2 *);
59 57 static void netr_setup_identity(ndr_heap_t *, smb_logon_t *,
60 58 netr_logon_id_t *);
61 59 static boolean_t netr_isadmin(struct netr_validation_info3 *);
62 60 static uint32_t netr_setup_domain_groups(struct netr_validation_info3 *,
63 61 smb_ids_t *);
64 -static uint32_t netr_setup_token_info3(struct netr_validation_info3 *,
65 - smb_token_t *);
62 +static uint32_t netr_setup_krb5res_groups(struct krb5_validation_info *,
63 + smb_ids_t *);
66 64 static uint32_t netr_setup_token_wingrps(struct netr_validation_info3 *,
67 65 smb_token_t *);
68 66
69 67 /*
70 68 * Shared with netr_auth.c
71 69 */
72 70 extern netr_info_t netr_global_info;
73 71
74 72 static mutex_t netlogon_mutex;
75 73 static cond_t netlogon_cv;
76 74 static boolean_t netlogon_busy = B_FALSE;
|
↓ open down ↓ |
1 lines elided |
↑ open up ↑ |
77 75 static boolean_t netlogon_abort = B_FALSE;
78 76
79 77 /*
80 78 * Helper for Kerberos authentication
81 79 */
82 80 uint32_t
83 81 smb_decode_krb5_pac(smb_token_t *token, char *data, uint_t len)
84 82 {
85 83 struct krb5_validation_info info;
86 84 ndr_buf_t *nbuf;
85 + smb_sid_t *domsid;
87 86 uint32_t status = NT_STATUS_NO_MEMORY;
88 87 int rc;
89 88
90 89 bzero(&info, sizeof (info));
91 90
92 91 /* Need to keep this until we're done with &info */
93 92 nbuf = ndr_buf_init(&TYPEINFO(netr_interface));
94 93 if (nbuf == NULL)
95 94 goto out;
96 95
97 96 rc = ndr_buf_decode(nbuf, NDR_PTYPE_PAC,
98 97 NETR_OPNUM_decode_krb5_pac, data, len, &info);
99 98 if (rc != NDR_DRC_OK) {
100 99 status = RPC_NT_PROTOCOL_ERROR;
101 100 goto out;
102 101 }
103 102
104 - status = netr_setup_token_info3(&info.info3, token);
103 + /*
104 + * Copy the decoded info into the token,
105 + * similar to netr_setup_token()
106 + */
107 + domsid = (smb_sid_t *)info.info3.LogonDomainId;
105 108
106 - /* Deal with the "resource groups"? */
107 -
108 -
109 -out:
110 - if (nbuf != NULL)
111 - ndr_buf_fini(nbuf);
112 -
113 - return (status);
114 -}
115 -
116 -/*
117 - * Code factored out of netr_setup_token()
118 - */
119 -static uint32_t
120 -netr_setup_token_info3(struct netr_validation_info3 *info3,
121 - smb_token_t *token)
122 -{
123 - smb_sid_t *domsid;
124 -
125 - domsid = (smb_sid_t *)info3->LogonDomainId;
126 -
127 109 token->tkn_user.i_sid = smb_sid_splice(domsid,
128 - info3->UserId);
110 + info.info3.UserId);
129 111 if (token->tkn_user.i_sid == NULL)
130 - goto errout;
112 + goto out;
131 113
132 114 token->tkn_primary_grp.i_sid = smb_sid_splice(domsid,
133 - info3->PrimaryGroupId);
115 + info.info3.PrimaryGroupId);
134 116 if (token->tkn_primary_grp.i_sid == NULL)
135 - goto errout;
117 + goto out;
136 118
137 - if (info3->EffectiveName.str) {
119 + if (info.info3.EffectiveName.str) {
138 120 token->tkn_account_name =
139 - strdup((char *)info3->EffectiveName.str);
121 + strdup((char *)info.info3.EffectiveName.str);
140 122 if (token->tkn_account_name == NULL)
141 - goto errout;
123 + goto out;
142 124 }
143 125
144 - if (info3->LogonDomainName.str) {
126 + if (info.info3.LogonDomainName.str) {
145 127 token->tkn_domain_name =
146 - strdup((char *)info3->LogonDomainName.str);
128 + strdup((char *)info.info3.LogonDomainName.str);
147 129 if (token->tkn_domain_name == NULL)
148 - goto errout;
130 + goto out;
149 131 }
150 132
151 - return (netr_setup_token_wingrps(info3, token));
152 -errout:
153 - return (NT_STATUS_INSUFF_SERVER_RESOURCES);
133 + status = netr_setup_domain_groups(&info.info3, &token->tkn_win_grps);
134 + if (status != NT_STATUS_SUCCESS)
135 + goto out;
136 +
137 + if (info.rg_rid_cnt != 0) {
138 + status = netr_setup_krb5res_groups(&info, &token->tkn_win_grps);
139 + if (status != NT_STATUS_SUCCESS)
140 + goto out;
141 + }
142 +
143 + status = netr_setup_token_wingrps(&info.info3, token);
144 +
145 +out:
146 + if (nbuf != NULL)
147 + ndr_buf_fini(nbuf);
148 +
149 + return (status);
154 150 }
155 151
156 152 /*
157 153 * Abort impending domain logon requests.
158 154 */
159 155 void
160 156 smb_logon_abort(void)
161 157 {
162 158 (void) mutex_lock(&netlogon_mutex);
163 159 if (netlogon_busy && !netlogon_abort)
164 160 syslog(LOG_DEBUG, "logon abort");
165 161 netlogon_abort = B_TRUE;
166 162 (void) cond_broadcast(&netlogon_cv);
167 163 (void) mutex_unlock(&netlogon_mutex);
168 164 }
|
↓ open down ↓ |
5 lines elided |
↑ open up ↑ |
169 165
170 166 /*
171 167 * This is the entry point for authenticating domain users.
172 168 *
173 169 * If we are not going to attempt to authenticate the user,
174 170 * this function must return without updating the status.
175 171 *
176 172 * If the user is successfully authenticated, we build an
177 173 * access token and the status will be NT_STATUS_SUCCESS.
178 174 * Otherwise, the token contents are invalid.
175 + *
176 + * This will retry a few times for errors indicating that the
177 + * current DC might have gone off-line or become too busy etc.
178 + * With such errors, smb_ddiscover_bad_dc is called and then
179 + * the smb_domain_getinfo call here waits for new DC info.
179 180 */
181 +int smb_netr_logon_retries = 3;
180 182 void
181 183 smb_logon_domain(smb_logon_t *user_info, smb_token_t *token)
182 184 {
185 + smb_domainex_t di;
183 186 uint32_t status;
184 - int i;
187 + int retries = smb_netr_logon_retries;
185 188
186 189 if (user_info->lg_secmode != SMB_SECMODE_DOMAIN)
187 190 return;
188 191
189 192 if (user_info->lg_domain_type == SMB_DOMAIN_LOCAL)
190 193 return;
191 194
192 - for (i = 0; i < NETLOGON_ATTEMPTS; ++i) {
195 + while (--retries > 0) {
196 +
197 + if (!smb_domain_getinfo(&di)) {
198 + syslog(LOG_ERR, "logon DC getinfo failed");
199 + status = NT_STATUS_NO_LOGON_SERVERS;
200 + goto out;
201 + }
202 +
193 203 (void) mutex_lock(&netlogon_mutex);
194 204 while (netlogon_busy && !netlogon_abort)
195 205 (void) cond_wait(&netlogon_cv, &netlogon_mutex);
196 206
197 207 if (netlogon_abort) {
198 208 (void) mutex_unlock(&netlogon_mutex);
199 - user_info->lg_status = NT_STATUS_REQUEST_ABORTED;
200 - return;
209 + status = NT_STATUS_REQUEST_ABORTED;
210 + goto out;
201 211 }
202 212
203 213 netlogon_busy = B_TRUE;
204 214 (void) mutex_unlock(&netlogon_mutex);
205 215
206 - status = netlogon_logon(user_info, token);
216 + status = netlogon_logon(user_info, token, &di);
207 217
208 218 (void) mutex_lock(&netlogon_mutex);
209 219 netlogon_busy = B_FALSE;
210 220 if (netlogon_abort)
211 221 status = NT_STATUS_REQUEST_ABORTED;
212 222 (void) cond_signal(&netlogon_cv);
213 223 (void) mutex_unlock(&netlogon_mutex);
214 224
215 - if (status != NT_STATUS_CANT_ACCESS_DOMAIN_INFO)
225 + switch (status) {
226 + case NT_STATUS_BAD_NETWORK_PATH:
227 + case NT_STATUS_BAD_NETWORK_NAME:
228 + case RPC_NT_SERVER_TOO_BUSY:
229 + /*
230 + * May retry with a new DC, or if we're
231 + * out of retries, will return...
232 + */
233 + status = NT_STATUS_NO_LOGON_SERVERS;
216 234 break;
235 + default:
236 + goto out;
237 + }
217 238 }
218 239
240 +out:
219 241 if (status != NT_STATUS_SUCCESS)
220 242 syslog(LOG_INFO, "logon[%s\\%s]: %s", user_info->lg_e_domain,
221 243 user_info->lg_e_username, xlate_nt_status(status));
222 -
223 244 user_info->lg_status = status;
224 245 }
225 246
247 +/*
248 + * Run a netr_server_samlogon call, dealing with the possible need to
249 + * re-establish the NetLogon credential chain. If that fails, return
250 + * NT_STATUS_DOMAIN_TRUST_INCONSISTENT indicating the machine account
251 + * needs it's password reset (or whatever). Other errors are from the
252 + * netr_server_samlogon() call including the many possibilities listed
253 + * above that function.
254 + */
226 255 static uint32_t
227 -netlogon_logon(smb_logon_t *user_info, smb_token_t *token)
256 +netlogon_logon(smb_logon_t *user_info, smb_token_t *token, smb_domainex_t *di)
228 257 {
229 - char resource_domain[SMB_PI_MAX_DOMAIN];
230 258 char server[MAXHOSTNAMELEN];
231 259 mlsvc_handle_t netr_handle;
232 - smb_domainex_t di;
233 260 uint32_t status;
234 - int retries = 0;
261 + boolean_t did_reauth = B_FALSE;
235 262
236 - (void) smb_getdomainname(resource_domain, SMB_PI_MAX_DOMAIN);
263 + /*
264 + * This netr_open call does the work to connect to the DC,
265 + * get the IPC share, open the named pipe, RPC bind, etc.
266 + */
267 + status = netr_open(di->d_dci.dc_name, di->d_primary.di_nbname,
268 + &netr_handle);
269 + if (status != 0) {
270 + syslog(LOG_ERR, "netlogon remote open failed (%s)",
271 + xlate_nt_status(status));
272 + return (status);
273 + }
237 274
238 - /* Avoid interfering with DC discovery. */
239 - if (smb_ddiscover_wait() != 0 ||
240 - !smb_domain_getinfo(&di)) {
241 - netr_invalidate_chain();
242 - return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
275 + if (di->d_dci.dc_name[0] != '\0' &&
276 + (*netr_global_info.server != '\0')) {
277 + (void) snprintf(server, sizeof (server),
278 + "\\\\%s", di->d_dci.dc_name);
279 + if (strncasecmp(netr_global_info.server,
280 + server, strlen(server)) != 0)
281 + netr_invalidate_chain();
243 282 }
244 283
245 - do {
246 - if (netr_open(di.d_dci.dc_name, di.d_primary.di_nbname,
247 - &netr_handle) != 0)
248 - return (NT_STATUS_OPEN_FAILED);
284 +reauth:
285 + if ((netr_global_info.flags & NETR_FLG_VALID) == 0 ||
286 + !smb_match_netlogon_seqnum()) {
287 + /*
288 + * This does netr_server_req_challenge() and
289 + * netr_server_authenticate2(), updating the
290 + * current netlogon sequence number.
291 + */
292 + status = netlogon_auth(di->d_dci.dc_name, &netr_handle,
293 + NETR_FLG_NULL);
249 294
250 - if (di.d_dci.dc_name[0] != '\0' &&
251 - (*netr_global_info.server != '\0')) {
252 - (void) snprintf(server, sizeof (server),
253 - "\\\\%s", di.d_dci.dc_name);
254 - if (strncasecmp(netr_global_info.server,
255 - server, strlen(server)) != 0)
256 - netr_invalidate_chain();
295 + if (status != 0) {
296 + syslog(LOG_ERR, "netlogon remote auth failed (%s)",
297 + xlate_nt_status(status));
298 + (void) netr_close(&netr_handle);
299 + return (NT_STATUS_DOMAIN_TRUST_INCONSISTENT);
257 300 }
258 301
259 - if ((netr_global_info.flags & NETR_FLG_VALID) == 0 ||
260 - !smb_match_netlogon_seqnum()) {
261 - status = netlogon_auth(di.d_dci.dc_name, &netr_handle,
262 - NETR_FLG_NULL);
302 + netr_global_info.flags |= NETR_FLG_VALID;
303 + }
263 304
264 - if (status != 0) {
265 - (void) netr_close(&netr_handle);
266 - return (NT_STATUS_LOGON_FAILURE);
267 - }
305 + status = netr_server_samlogon(&netr_handle,
306 + &netr_global_info, di->d_dci.dc_name, user_info, token);
268 307
269 - netr_global_info.flags |= NETR_FLG_VALID;
308 + if (status == NT_STATUS_INSUFFICIENT_LOGON_INFO) {
309 + if (!did_reauth) {
310 + /* Call netlogon_auth() again, just once. */
311 + did_reauth = B_TRUE;
312 + goto reauth;
270 313 }
314 + status = NT_STATUS_DOMAIN_TRUST_INCONSISTENT;
315 + }
271 316
272 - status = netr_server_samlogon(&netr_handle,
273 - &netr_global_info, di.d_dci.dc_name, user_info, token);
317 + (void) netr_close(&netr_handle);
274 318
275 - (void) netr_close(&netr_handle);
276 - } while (status == NT_STATUS_INSUFFICIENT_LOGON_INFO && retries++ < 3);
319 + return (status);
320 +}
277 321
278 - if (retries >= 3)
279 - status = NT_STATUS_LOGON_FAILURE;
322 +/*
323 + * Helper for mlsvc_netlogon
324 + *
325 + * Call netlogon_auth with appropriate locks etc.
326 + * Serialize like smb_logon_domain does for
327 + * netlogon_logon / netlogon_auth
328 + */
329 +uint32_t
330 +smb_netlogon_check(char *server, char *domain)
331 +{
332 + mlsvc_handle_t netr_handle;
333 + uint32_t status;
280 334
335 + (void) mutex_lock(&netlogon_mutex);
336 + while (netlogon_busy)
337 + (void) cond_wait(&netlogon_cv, &netlogon_mutex);
338 +
339 + netlogon_busy = B_TRUE;
340 + (void) mutex_unlock(&netlogon_mutex);
341 +
342 + /*
343 + * This section like netlogon_logon(), but only does
344 + * one pass and no netr_server_samlogon call.
345 + */
346 +
347 + status = netr_open(server, domain,
348 + &netr_handle);
349 + if (status != 0) {
350 + syslog(LOG_ERR, "netlogon remote open failed (%s)",
351 + xlate_nt_status(status));
352 + goto unlock_out;
353 + }
354 +
355 + if ((netr_global_info.flags & NETR_FLG_VALID) == 0 ||
356 + !smb_match_netlogon_seqnum()) {
357 + /*
358 + * This does netr_server_req_challenge() and
359 + * netr_server_authenticate2(), updating the
360 + * current netlogon sequence number.
361 + */
362 + status = netlogon_auth(server, &netr_handle,
363 + NETR_FLG_NULL);
364 + if (status != 0) {
365 + syslog(LOG_ERR, "netlogon remote auth failed (%s)",
366 + xlate_nt_status(status));
367 + } else {
368 + netr_global_info.flags |= NETR_FLG_VALID;
369 + }
370 + }
371 +
372 + (void) netr_close(&netr_handle);
373 +
374 +unlock_out:
375 + (void) mutex_lock(&netlogon_mutex);
376 + netlogon_busy = B_FALSE;
377 + (void) cond_signal(&netlogon_cv);
378 + (void) mutex_unlock(&netlogon_mutex);
379 +
281 380 return (status);
282 381 }
283 382
284 383 static uint32_t
285 384 netr_setup_token(struct netr_validation_info3 *info3, smb_logon_t *user_info,
286 385 netr_info_t *netr_info, smb_token_t *token)
287 386 {
288 387 char *username, *domain;
289 388 unsigned char rc4key[SMBAUTH_SESSION_KEY_SZ];
290 389 smb_sid_t *domsid;
291 390 uint32_t status;
292 391 char nbdomain[NETBIOS_NAME_SZ];
293 392
294 393 domsid = (smb_sid_t *)info3->LogonDomainId;
295 394
296 395 token->tkn_user.i_sid = smb_sid_splice(domsid, info3->UserId);
297 396 if (token->tkn_user.i_sid == NULL)
298 397 return (NT_STATUS_NO_MEMORY);
299 398
300 399 token->tkn_primary_grp.i_sid = smb_sid_splice(domsid,
301 400 info3->PrimaryGroupId);
302 401 if (token->tkn_primary_grp.i_sid == NULL)
303 402 return (NT_STATUS_NO_MEMORY);
304 403
305 404 username = (info3->EffectiveName.str)
306 405 ? (char *)info3->EffectiveName.str : user_info->lg_e_username;
307 406
308 407 if (info3->LogonDomainName.str) {
309 408 domain = (char *)info3->LogonDomainName.str;
310 409 } else if (*user_info->lg_e_domain != '\0') {
311 410 domain = user_info->lg_e_domain;
312 411 } else {
313 412 (void) smb_getdomainname(nbdomain, sizeof (nbdomain));
314 413 domain = nbdomain;
|
↓ open down ↓ |
24 lines elided |
↑ open up ↑ |
315 414 }
316 415
317 416 if (username)
318 417 token->tkn_account_name = strdup(username);
319 418 if (domain)
320 419 token->tkn_domain_name = strdup(domain);
321 420
322 421 if (token->tkn_account_name == NULL || token->tkn_domain_name == NULL)
323 422 return (NT_STATUS_NO_MEMORY);
324 423
424 + status = netr_setup_domain_groups(info3, &token->tkn_win_grps);
425 + if (status != NT_STATUS_SUCCESS)
426 + return (status);
427 +
325 428 status = netr_setup_token_wingrps(info3, token);
326 429 if (status != NT_STATUS_SUCCESS)
327 430 return (status);
328 431
329 432 /*
330 433 * The UserSessionKey in NetrSamLogon RPC is obfuscated using the
331 434 * session key obtained in the NETLOGON credential chain.
332 435 * An 8 byte session key is zero extended to 16 bytes. This 16 byte
333 436 * key is the key to the RC4 algorithm. The RC4 byte stream is
334 437 * exclusively ored with the 16 byte UserSessionKey to recover
335 438 * the the clear form.
336 439 */
337 440 if ((token->tkn_ssnkey.val = malloc(SMBAUTH_SESSION_KEY_SZ)) == NULL)
338 441 return (NT_STATUS_NO_MEMORY);
339 442 token->tkn_ssnkey.len = SMBAUTH_SESSION_KEY_SZ;
340 443 bzero(rc4key, SMBAUTH_SESSION_KEY_SZ);
341 444 bcopy(netr_info->session_key.key, rc4key, netr_info->session_key.len);
342 445 bcopy(info3->UserSessionKey.data, token->tkn_ssnkey.val,
343 446 SMBAUTH_SESSION_KEY_SZ);
344 447 rand_hash((unsigned char *)token->tkn_ssnkey.val,
345 448 SMBAUTH_SESSION_KEY_SZ, rc4key, SMBAUTH_SESSION_KEY_SZ);
346 449
347 450 return (NT_STATUS_SUCCESS);
348 451 }
349 452
350 453 /*
351 454 * netr_server_samlogon
352 455 *
353 456 * NetrServerSamLogon RPC: interactive or network. It is assumed that
354 457 * we have already authenticated with the PDC. If everything works,
355 458 * we build a user info structure and return it, where the caller will
356 459 * probably build an access token.
357 460 *
358 461 * Returns an NT status. There are numerous possibilities here.
359 462 * For example:
360 463 * NT_STATUS_INVALID_INFO_CLASS
361 464 * NT_STATUS_INVALID_PARAMETER
362 465 * NT_STATUS_ACCESS_DENIED
363 466 * NT_STATUS_PASSWORD_MUST_CHANGE
364 467 * NT_STATUS_NO_SUCH_USER
365 468 * NT_STATUS_WRONG_PASSWORD
366 469 * NT_STATUS_LOGON_FAILURE
367 470 * NT_STATUS_ACCOUNT_RESTRICTION
368 471 * NT_STATUS_INVALID_LOGON_HOURS
369 472 * NT_STATUS_INVALID_WORKSTATION
370 473 * NT_STATUS_INTERNAL_ERROR
371 474 * NT_STATUS_PASSWORD_EXPIRED
372 475 * NT_STATUS_ACCOUNT_DISABLED
373 476 */
374 477 uint32_t
375 478 netr_server_samlogon(mlsvc_handle_t *netr_handle, netr_info_t *netr_info,
376 479 char *server, smb_logon_t *user_info, smb_token_t *token)
377 480 {
378 481 struct netr_SamLogon arg;
379 482 struct netr_authenticator auth;
380 483 struct netr_authenticator ret_auth;
381 484 struct netr_logon_info1 info1;
382 485 struct netr_logon_info2 info2;
383 486 struct netr_validation_info3 *info3;
384 487 ndr_heap_t *heap;
385 488 int opnum;
386 489 int rc, len;
387 490 uint32_t status;
388 491
389 492 bzero(&arg, sizeof (struct netr_SamLogon));
390 493 opnum = NETR_OPNUM_SamLogon;
391 494
392 495 /*
393 496 * Should we get the server and hostname from netr_info?
394 497 */
395 498
396 499 len = strlen(server) + 4;
397 500 arg.servername = ndr_rpc_malloc(netr_handle, len);
398 501 arg.hostname = ndr_rpc_malloc(netr_handle, NETBIOS_NAME_SZ);
399 502 if (arg.servername == NULL || arg.hostname == NULL) {
400 503 ndr_rpc_release(netr_handle);
401 504 return (NT_STATUS_INTERNAL_ERROR);
402 505 }
403 506
404 507 (void) snprintf((char *)arg.servername, len, "\\\\%s", server);
405 508 if (smb_getnetbiosname((char *)arg.hostname, NETBIOS_NAME_SZ) != 0) {
406 509 ndr_rpc_release(netr_handle);
407 510 return (NT_STATUS_INTERNAL_ERROR);
408 511 }
409 512
410 513 rc = netr_setup_authenticator(netr_info, &auth, &ret_auth);
411 514 if (rc != SMBAUTH_SUCCESS) {
412 515 ndr_rpc_release(netr_handle);
413 516 return (NT_STATUS_INTERNAL_ERROR);
414 517 }
415 518
416 519 arg.auth = &auth;
417 520 arg.ret_auth = &ret_auth;
418 521 arg.validation_level = NETR_VALIDATION_LEVEL3;
419 522 arg.logon_info.logon_level = user_info->lg_level;
420 523 arg.logon_info.switch_value = user_info->lg_level;
421 524
422 525 heap = ndr_rpc_get_heap(netr_handle);
423 526
424 527 switch (user_info->lg_level) {
425 528 case NETR_INTERACTIVE_LOGON:
426 529 netr_setup_identity(heap, user_info, &info1.identity);
427 530 netr_interactive_samlogon(netr_info, user_info, &info1);
428 531 arg.logon_info.ru.info1 = &info1;
429 532 break;
430 533
431 534 case NETR_NETWORK_LOGON:
432 535 if (user_info->lg_challenge_key.len < 8 ||
433 536 user_info->lg_challenge_key.val == NULL) {
434 537 ndr_rpc_release(netr_handle);
435 538 return (NT_STATUS_INVALID_PARAMETER);
436 539 }
437 540 netr_setup_identity(heap, user_info, &info2.identity);
438 541 netr_network_samlogon(heap, netr_info, user_info, &info2);
439 542 arg.logon_info.ru.info2 = &info2;
440 543 break;
441 544
442 545 default:
443 546 ndr_rpc_release(netr_handle);
444 547 return (NT_STATUS_INVALID_PARAMETER);
445 548 }
446 549
447 550 rc = ndr_rpc_call(netr_handle, opnum, &arg);
448 551 if (rc != 0) {
449 552 bzero(netr_info, sizeof (netr_info_t));
450 553 status = NT_STATUS_INVALID_PARAMETER;
451 554 } else if (arg.status != 0) {
452 555 status = NT_SC_VALUE(arg.status);
453 556
454 557 /*
455 558 * We need to validate the chain even though we have
456 559 * a non-zero status. If the status is ACCESS_DENIED
457 560 * this will trigger a new credential chain. However,
458 561 * a valid credential is returned with some status
459 562 * codes; for example, WRONG_PASSWORD.
460 563 */
461 564 (void) netr_validate_chain(netr_info, arg.ret_auth);
462 565 } else {
463 566 status = netr_validate_chain(netr_info, arg.ret_auth);
464 567 if (status == NT_STATUS_INSUFFICIENT_LOGON_INFO) {
465 568 ndr_rpc_release(netr_handle);
466 569 return (status);
467 570 }
468 571
469 572 info3 = arg.ru.info3;
470 573 status = netr_setup_token(info3, user_info, netr_info, token);
471 574 }
472 575
473 576 ndr_rpc_release(netr_handle);
474 577 return (status);
475 578 }
476 579
477 580 /*
478 581 * netr_interactive_samlogon
479 582 *
480 583 * Set things up for an interactive SamLogon. Copy the NT and LM
481 584 * passwords to the logon structure and hash them with the session
482 585 * key.
483 586 */
484 587 static void
485 588 netr_interactive_samlogon(netr_info_t *netr_info, smb_logon_t *user_info,
486 589 struct netr_logon_info1 *info1)
487 590 {
488 591 BYTE key[NETR_OWF_PASSWORD_SZ];
489 592
490 593 (void) memcpy(&info1->lm_owf_password,
491 594 user_info->lg_lm_password.val, sizeof (netr_owf_password_t));
492 595
493 596 (void) memcpy(&info1->nt_owf_password,
494 597 user_info->lg_nt_password.val, sizeof (netr_owf_password_t));
495 598
496 599 (void) memset(key, 0, NETR_OWF_PASSWORD_SZ);
497 600 (void) memcpy(key, netr_info->session_key.key,
498 601 netr_info->session_key.len);
499 602
500 603 rand_hash((unsigned char *)&info1->lm_owf_password,
501 604 NETR_OWF_PASSWORD_SZ, key, NETR_OWF_PASSWORD_SZ);
502 605
503 606 rand_hash((unsigned char *)&info1->nt_owf_password,
504 607 NETR_OWF_PASSWORD_SZ, key, NETR_OWF_PASSWORD_SZ);
505 608 }
506 609
507 610 /*
508 611 * netr_network_samlogon
509 612 *
510 613 * Set things up for a network SamLogon. We provide a copy of the random
511 614 * challenge, that we sent to the client, to the domain controller. This
512 615 * is the key that the client will have used to encrypt the NT and LM
513 616 * passwords. Note that Windows 9x clients may not provide both passwords.
514 617 */
515 618 /*ARGSUSED*/
516 619 static void
517 620 netr_network_samlogon(ndr_heap_t *heap, netr_info_t *netr_info,
518 621 smb_logon_t *user_info, struct netr_logon_info2 *info2)
519 622 {
520 623 uint32_t len;
521 624
522 625 if (user_info->lg_challenge_key.len >= 8 &&
523 626 user_info->lg_challenge_key.val != 0) {
524 627 bcopy(user_info->lg_challenge_key.val,
525 628 info2->lm_challenge.data, 8);
526 629 } else {
527 630 bzero(info2->lm_challenge.data, 8);
528 631 }
529 632
530 633 if ((len = user_info->lg_nt_password.len) != 0) {
531 634 ndr_heap_mkvcb(heap, user_info->lg_nt_password.val, len,
532 635 (ndr_vcbuf_t *)&info2->nt_response);
533 636 } else {
534 637 bzero(&info2->nt_response, sizeof (netr_vcbuf_t));
535 638 }
536 639
537 640 if ((len = user_info->lg_lm_password.len) != 0) {
538 641 ndr_heap_mkvcb(heap, user_info->lg_lm_password.val, len,
539 642 (ndr_vcbuf_t *)&info2->lm_response);
540 643 } else {
541 644 bzero(&info2->lm_response, sizeof (netr_vcbuf_t));
542 645 }
543 646 }
544 647
545 648 /*
546 649 * netr_setup_authenticator
547 650 *
548 651 * Set up the request and return authenticators. A new credential is
549 652 * generated from the session key, the current client credential and
550 653 * the current time, i.e.
551 654 *
552 655 * NewCredential = Cred(SessionKey, OldCredential, time);
553 656 *
554 657 * The timestamp, which is used as a random seed, is stored in both
555 658 * the request and return authenticators.
556 659 *
557 660 * If any difficulties occur using the cryptographic framework, the
558 661 * function returns SMBAUTH_FAILURE. Otherwise SMBAUTH_SUCCESS is
559 662 * returned.
560 663 */
561 664 int
562 665 netr_setup_authenticator(netr_info_t *netr_info,
563 666 struct netr_authenticator *auth, struct netr_authenticator *ret_auth)
564 667 {
565 668 bzero(auth, sizeof (struct netr_authenticator));
566 669
567 670 netr_info->timestamp = time(0);
568 671 auth->timestamp = netr_info->timestamp;
569 672
570 673 if (netr_gen_credentials(netr_info->session_key.key,
571 674 &netr_info->client_credential,
572 675 netr_info->timestamp,
573 676 (netr_cred_t *)&auth->credential) != SMBAUTH_SUCCESS)
574 677 return (SMBAUTH_FAILURE);
575 678
576 679 if (ret_auth) {
577 680 bzero(ret_auth, sizeof (struct netr_authenticator));
578 681 ret_auth->timestamp = netr_info->timestamp;
579 682 }
580 683
581 684 return (SMBAUTH_SUCCESS);
582 685 }
583 686
584 687 /*
585 688 * Validate the returned credentials and update the credential chain.
586 689 * The server returns an updated client credential rather than a new
587 690 * server credential. The server uses (timestamp + 1) when generating
588 691 * the credential.
589 692 *
590 693 * Generate the new seed for the credential chain. The new seed is
591 694 * formed by adding (timestamp + 1) to the current client credential.
592 695 * The only quirk is the uint32_t style addition.
593 696 *
594 697 * Returns NT_STATUS_INSUFFICIENT_LOGON_INFO if auth->credential is a
595 698 * NULL pointer. The Authenticator field of the SamLogon response packet
596 699 * sent by the Samba 3 PDC always return NULL pointer if the received
597 700 * SamLogon request is not immediately followed by the ServerReqChallenge
598 701 * and ServerAuthenticate2 requests.
599 702 *
600 703 * Returns NT_STATUS_SUCCESS if the server returned a valid credential.
601 704 * Otherwise we retirm NT_STATUS_UNSUCCESSFUL.
602 705 */
603 706 uint32_t
604 707 netr_validate_chain(netr_info_t *netr_info, struct netr_authenticator *auth)
605 708 {
606 709 netr_cred_t cred;
607 710 uint32_t result = NT_STATUS_SUCCESS;
608 711 uint32_t *dwp;
609 712
610 713 ++netr_info->timestamp;
611 714
612 715 if (netr_gen_credentials(netr_info->session_key.key,
613 716 &netr_info->client_credential,
614 717 netr_info->timestamp, &cred) != SMBAUTH_SUCCESS)
615 718 return (NT_STATUS_INTERNAL_ERROR);
616 719
617 720 if (&auth->credential == 0) {
618 721 /*
619 722 * If the validation fails, destroy the credential chain.
620 723 * This should trigger a new authentication chain.
621 724 */
622 725 bzero(netr_info, sizeof (netr_info_t));
623 726 return (NT_STATUS_INSUFFICIENT_LOGON_INFO);
624 727 }
625 728
626 729 result = memcmp(&cred, &auth->credential, sizeof (netr_cred_t));
627 730 if (result != 0) {
628 731 /*
629 732 * If the validation fails, destroy the credential chain.
630 733 * This should trigger a new authentication chain.
631 734 */
632 735 bzero(netr_info, sizeof (netr_info_t));
633 736 result = NT_STATUS_UNSUCCESSFUL;
634 737 } else {
635 738 /*
636 739 * Otherwise generate the next step in the chain.
637 740 */
638 741 /*LINTED E_BAD_PTR_CAST_ALIGN*/
639 742 dwp = (uint32_t *)&netr_info->client_credential;
640 743 dwp[0] += netr_info->timestamp;
641 744
642 745 netr_info->flags |= NETR_FLG_VALID;
643 746 }
644 747
645 748 return (result);
646 749 }
647 750
648 751 /*
649 752 * netr_invalidate_chain
650 753 *
651 754 * Mark the credential chain as invalid so that it will be recreated
652 755 * on the next attempt.
653 756 */
654 757 static void
655 758 netr_invalidate_chain(void)
656 759 {
657 760 netr_global_info.flags &= ~NETR_FLG_VALID;
658 761 }
659 762
660 763 /*
661 764 * netr_setup_identity
662 765 *
663 766 * Set up the client identity information. All of this information is
664 767 * specifically related to the client user and workstation attempting
665 768 * to access this system. It may not be in our primary domain.
666 769 *
667 770 * I don't know what logon_id is, it seems to be a unique identifier.
668 771 * Increment it before each use.
669 772 */
670 773 static void
671 774 netr_setup_identity(ndr_heap_t *heap, smb_logon_t *user_info,
672 775 netr_logon_id_t *identity)
673 776 {
674 777 static mutex_t logon_id_mutex;
675 778 static uint32_t logon_id;
676 779
677 780 (void) mutex_lock(&logon_id_mutex);
678 781
679 782 if (logon_id == 0)
680 783 logon_id = 0xDCD0;
681 784
682 785 ++logon_id;
683 786 user_info->lg_logon_id = logon_id;
684 787
685 788 (void) mutex_unlock(&logon_id_mutex);
686 789
687 790 /*
688 791 * [MS-APDS] 3.1.5.2 "NTLM Network Logon" says to set
689 792 * ParameterControl to the 'E' + 'K' bits. Those are:
690 793 * (1 << 5) | (1 << 11), a.k.a
691 794 */
692 795 identity->parameter_control =
693 796 MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT |
694 797 MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT;
695 798 identity->logon_id.LowPart = logon_id;
696 799 identity->logon_id.HighPart = 0;
697 800
698 801 ndr_heap_mkvcs(heap, user_info->lg_domain,
699 802 (ndr_vcstr_t *)&identity->domain_name);
700 803
701 804 ndr_heap_mkvcs(heap, user_info->lg_username,
702 805 (ndr_vcstr_t *)&identity->username);
703 806
|
↓ open down ↓ |
369 lines elided |
↑ open up ↑ |
704 807 /*
705 808 * Some systems prefix the client workstation name with \\.
706 809 * It doesn't seem to make any difference whether it's there
707 810 * or not.
708 811 */
709 812 ndr_heap_mkvcs(heap, user_info->lg_workstation,
710 813 (ndr_vcstr_t *)&identity->workstation);
711 814 }
712 815
713 816 /*
714 - * Sets up domain, local and well-known group membership for the given
715 - * token. Two assumptions have been made here:
716 - *
717 - * a) token already contains a valid user SID so that group
718 - * memberships can be established
719 - *
720 - * b) token belongs to a domain user
817 + * Add local and well-known group membership to the given
818 + * token. Called after domain groups have been added.
721 819 */
722 820 static uint32_t
723 821 netr_setup_token_wingrps(struct netr_validation_info3 *info3,
724 822 smb_token_t *token)
725 823 {
726 - smb_ids_t tkn_grps;
727 824 uint32_t status;
728 825
729 - tkn_grps.i_cnt = 0;
730 - tkn_grps.i_ids = NULL;
731 -
732 - status = netr_setup_domain_groups(info3, &tkn_grps);
733 - if (status != NT_STATUS_SUCCESS) {
734 - smb_ids_free(&tkn_grps);
826 + status = smb_sam_usr_groups(token->tkn_user.i_sid,
827 + &token->tkn_win_grps);
828 + if (status != NT_STATUS_SUCCESS)
735 829 return (status);
736 - }
737 830
738 - status = smb_sam_usr_groups(token->tkn_user.i_sid, &tkn_grps);
739 - if (status != NT_STATUS_SUCCESS) {
740 - smb_ids_free(&tkn_grps);
741 - return (status);
742 - }
743 -
744 831 if (netr_isadmin(info3))
745 832 token->tkn_flags |= SMB_ATF_ADMIN;
746 833
747 - status = smb_wka_token_groups(token->tkn_flags, &tkn_grps);
748 - if (status == NT_STATUS_SUCCESS)
749 - token->tkn_win_grps = tkn_grps;
750 - else
751 - smb_ids_free(&tkn_grps);
834 + status = smb_wka_token_groups(token->tkn_flags, &token->tkn_win_grps);
752 835
753 836 return (status);
754 837 }
755 838
756 839 /*
757 840 * Converts groups information in the returned structure by domain controller
758 841 * (info3) to an internal representation (gids)
759 842 */
760 843 static uint32_t
761 844 netr_setup_domain_groups(struct netr_validation_info3 *info3, smb_ids_t *gids)
762 845 {
763 846 smb_sid_t *domain_sid;
764 847 smb_id_t *ids;
765 848 int i, total_cnt;
766 849
767 850 if ((i = info3->GroupCount) == 0)
768 851 i++;
769 852 i += info3->SidCount;
770 853
771 854 total_cnt = gids->i_cnt + i;
772 855
773 856 gids->i_ids = realloc(gids->i_ids, total_cnt * sizeof (smb_id_t));
774 857 if (gids->i_ids == NULL)
775 858 return (NT_STATUS_NO_MEMORY);
776 859
777 860 domain_sid = (smb_sid_t *)info3->LogonDomainId;
778 861
779 862 ids = gids->i_ids + gids->i_cnt;
780 863 for (i = 0; i < info3->GroupCount; i++, gids->i_cnt++, ids++) {
781 864 ids->i_sid = smb_sid_splice(domain_sid, info3->GroupIds[i].rid);
782 865 if (ids->i_sid == NULL)
783 866 return (NT_STATUS_NO_MEMORY);
784 867
785 868 ids->i_attrs = info3->GroupIds[i].attributes;
786 869 }
787 870
788 871 if (info3->GroupCount == 0) {
789 872 /*
790 873 * if there's no global group should add the primary group.
791 874 */
792 875 ids->i_sid = smb_sid_splice(domain_sid, info3->PrimaryGroupId);
793 876 if (ids->i_sid == NULL)
794 877 return (NT_STATUS_NO_MEMORY);
795 878
796 879 ids->i_attrs = 0x7;
797 880 gids->i_cnt++;
798 881 ids++;
799 882 }
800 883
801 884 /* Add the extra SIDs */
802 885 for (i = 0; i < info3->SidCount; i++, gids->i_cnt++, ids++) {
|
↓ open down ↓ |
41 lines elided |
↑ open up ↑ |
803 886 ids->i_sid = smb_sid_dup((smb_sid_t *)info3->ExtraSids[i].sid);
804 887 if (ids->i_sid == NULL)
805 888 return (NT_STATUS_NO_MEMORY);
806 889
807 890 ids->i_attrs = info3->ExtraSids[i].attributes;
808 891 }
809 892
810 893 return (NT_STATUS_SUCCESS);
811 894 }
812 895
896 +/*
897 + * Converts additional "resource" groups (from krb5_validation_info)
898 + * into the internal representation (gids), appending to the list
899 + * already put in place by netr_setup_domain_groups().
900 + */
901 +static uint32_t netr_setup_krb5res_groups(struct krb5_validation_info *info,
902 + smb_ids_t *gids)
903 +{
904 + smb_sid_t *domain_sid;
905 + smb_id_t *ids;
906 + int i, total_cnt;
907 +
908 + total_cnt = gids->i_cnt + info->rg_rid_cnt;
909 +
910 + gids->i_ids = realloc(gids->i_ids, total_cnt * sizeof (smb_id_t));
911 + if (gids->i_ids == NULL)
912 + return (NT_STATUS_NO_MEMORY);
913 +
914 + domain_sid = (smb_sid_t *)info->rg_dom_sid;
915 +
916 + ids = gids->i_ids + gids->i_cnt;
917 + for (i = 0; i < info->rg_rid_cnt; i++, gids->i_cnt++, ids++) {
918 + ids->i_sid = smb_sid_splice(domain_sid, info->rg_rids[i].rid);
919 + if (ids->i_sid == NULL)
920 + return (NT_STATUS_NO_MEMORY);
921 + ids->i_attrs = info->rg_rids[i].attributes;
922 + }
923 +
924 + return (0);
925 +}
926 +
813 927 /*
814 928 * Determines if the given user is the domain Administrator or a
815 929 * member of Domain Admins
816 930 */
817 931 static boolean_t
818 932 netr_isadmin(struct netr_validation_info3 *info3)
819 933 {
820 934 smb_domain_t di;
821 935 int i;
822 936
823 937 if (!smb_domain_lookup_sid((smb_sid_t *)info3->LogonDomainId, &di))
824 938 return (B_FALSE);
825 939
826 940 if (di.di_type != SMB_DOMAIN_PRIMARY)
827 941 return (B_FALSE);
828 942
829 943 if ((info3->UserId == DOMAIN_USER_RID_ADMIN) ||
830 944 (info3->PrimaryGroupId == DOMAIN_GROUP_RID_ADMINS))
831 945 return (B_TRUE);
832 946
833 947 for (i = 0; i < info3->GroupCount; i++)
834 948 if (info3->GroupIds[i].rid == DOMAIN_GROUP_RID_ADMINS)
835 949 return (B_TRUE);
836 950
837 951 return (B_FALSE);
838 952 }
|
↓ open down ↓ |
16 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX