Print this page
NEX-14666 Need to provide SMB 2.1 Client
NEX-17187 panic in smbfs_acl_store
NEX-17231 smbfs create xattr files finds wrong file
NEX-17224 smbfs lookup EINVAL should be ENOENT
NEX-17260 SMB1 client fails to list directory after NEX-14666
Reviewed by: Evan Layton <evan.layton@nexenta.com>
Reviewed by: Matt Barden <matt.barden@nexenta.com>
Reviewed by: Rick McNeal <rick.mcneal@nexenta.com>
Reviewed by: Saso Kiselkov <saso.kiselkov@nexenta.com>
Reviewed by: Joyce McIntosh <joyce.mcintosh@nexenta.com>
and: (cleanup)
NEX-2667 Wrong error when join domain with wrong password
Reviewed by: Kevin Crowe <kevin.crowe@nexenta.com>
Reviewed by: Bayard Bell <bayard.bell@nexenta.com>
re #12435 rb3958 r10 is added 2 times to panic info
re #12393 rb3935 Kerberos and smbd disagree about who is our AD server
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/lib/smbsrv/libmlsvc/common/samlib.c
+++ new/usr/src/lib/smbsrv/libmlsvc/common/samlib.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 * This module provides the high level interface to the SAM RPC
29 29 * functions.
30 30 */
31 31
32 32 #include <sys/types.h>
33 33 #include <sys/isa_defs.h>
34 34 #include <sys/byteorder.h>
35 35
36 36 #include <alloca.h>
37 37
38 38 #include <smbsrv/libsmb.h>
39 39 #include <smbsrv/libmlsvc.h>
40 -#include <smbsrv/ntaccess.h>
40 +#include <smb/ntaccess.h>
41 41 #include <lsalib.h>
42 42 #include <samlib.h>
43 43
44 44 #ifdef _LITTLE_ENDIAN
45 45 /* little-endian values on little-endian */
46 46 #define htolel(x) ((uint32_t)(x))
47 47 #define letohl(x) ((uint32_t)(x))
48 48 #else /* (BYTE_ORDER == LITTLE_ENDIAN) */
49 49 /* little-endian values on big-endian (swap) */
50 50 #define letohl(x) BSWAP_32(x)
51 51 #define htolel(x) BSWAP_32(x)
52 52 #endif /* (BYTE_ORDER == LITTLE_ENDIAN) */
53 53
54 54 /*
55 55 * Valid values for the OEM OWF password encryption.
56 56 */
57 57 #define SAM_KEYLEN 16
58 58
59 59 static void samr_fill_userpw(struct samr_user_password *, const char *);
60 60 static void samr_make_encrypted_password(
61 61 struct samr_encr_passwd *epw,
62 62 char *new_pw_clear,
63 63 uint8_t *crypt_key);
64 64
65 65
66 66 /*
67 67 * Todo: Implement "unjoin" domain, which would use the
68 68 * sam_remove_trust_account code below.
69 69 */
70 70
71 71 /*
72 72 * sam_remove_trust_account
73 73 *
74 74 * Attempt to remove the workstation trust account for this system.
75 75 * Administrator access is required to perform this operation.
76 76 *
77 77 * Returns NT status codes.
78 78 */
79 79 DWORD
80 80 sam_remove_trust_account(char *server, char *domain)
81 81 {
82 82 char account_name[SMB_SAMACCT_MAXLEN];
83 83
84 84 if (smb_getsamaccount(account_name, SMB_SAMACCT_MAXLEN) != 0)
85 85 return (NT_STATUS_INTERNAL_ERROR);
86 86
87 87 return (sam_delete_account(server, domain, account_name));
88 88 }
89 89
90 90
91 91 /*
92 92 * sam_delete_account
93 93 *
94 94 * Attempt to remove an account from the SAM database on the specified
95 95 * server.
96 96 *
97 97 * Returns NT status codes.
98 98 */
99 99 DWORD
100 100 sam_delete_account(char *server, char *domain_name, char *account_name)
101 101 {
102 102 mlsvc_handle_t samr_handle;
103 103 mlsvc_handle_t domain_handle;
104 104 mlsvc_handle_t user_handle;
105 105 smb_account_t ainfo;
106 106 smb_sid_t *sid;
107 107 DWORD access_mask;
108 108 DWORD status;
109 109 int rc;
110 110 char user[SMB_USERNAME_MAXLEN];
111 111
112 112 smb_ipc_get_user(user, SMB_USERNAME_MAXLEN);
113 113
114 114 rc = samr_open(server, domain_name, user, SAM_LOOKUP_INFORMATION,
115 115 &samr_handle);
116 116 if (rc != 0)
117 117 return (NT_STATUS_CANT_ACCESS_DOMAIN_INFO);
118 118
119 119 sid = samr_lookup_domain(&samr_handle, domain_name);
120 120 if (sid == NULL) {
121 121 status = NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
122 122 goto out_samr_hdl;
123 123 }
124 124
125 125 status = samr_open_domain(&samr_handle, SAM_LOOKUP_INFORMATION,
126 126 (struct samr_sid *)sid, &domain_handle);
127 127 if (status != NT_STATUS_SUCCESS)
128 128 goto out_sid_ptr;
129 129
130 130 status = samr_lookup_domain_names(&domain_handle, account_name, &ainfo);
131 131 if (status != NT_STATUS_SUCCESS)
132 132 goto out_dom_hdl;
133 133
134 134 access_mask = STANDARD_RIGHTS_EXECUTE | DELETE;
135 135 status = samr_open_user(&domain_handle, access_mask,
136 136 ainfo.a_rid, &user_handle);
137 137 if (status != NT_STATUS_SUCCESS)
138 138 goto out_dom_hdl;
139 139
140 140 status = samr_delete_user(&user_handle);
141 141
142 142 (void) samr_close_handle(&user_handle);
143 143 out_dom_hdl:
144 144 (void) samr_close_handle(&domain_handle);
145 145 out_sid_ptr:
146 146 free(sid);
147 147 out_samr_hdl:
148 148 (void) samr_close_handle(&samr_handle);
149 149
150 150 return (status);
151 151 }
152 152
153 153
154 154 /*
155 155 * sam_lookup_name
156 156 *
157 157 * Lookup an account name in the SAM database on the specified domain
158 158 * controller. Provides the account RID on success.
159 159 *
160 160 * Returns NT status codes.
161 161 */
162 162 DWORD
163 163 sam_lookup_name(char *server, char *domain_name, char *account_name,
164 164 DWORD *rid_ret)
165 165 {
166 166 mlsvc_handle_t samr_handle;
167 167 mlsvc_handle_t domain_handle;
168 168 smb_account_t ainfo;
169 169 struct samr_sid *domain_sid;
170 170 int rc;
171 171 DWORD status;
172 172 char user[SMB_USERNAME_MAXLEN];
173 173
174 174 smb_ipc_get_user(user, SMB_USERNAME_MAXLEN);
175 175
176 176 *rid_ret = 0;
177 177
178 178 rc = samr_open(server, domain_name, user, SAM_LOOKUP_INFORMATION,
179 179 &samr_handle);
180 180
181 181 if (rc != 0)
182 182 return (NT_STATUS_OPEN_FAILED);
183 183
184 184 domain_sid = (struct samr_sid *)samr_lookup_domain(&samr_handle,
185 185 domain_name);
186 186 if (domain_sid == NULL) {
187 187 (void) samr_close_handle(&samr_handle);
188 188 return (NT_STATUS_NO_SUCH_DOMAIN);
189 189 }
190 190
191 191 status = samr_open_domain(&samr_handle, SAM_LOOKUP_INFORMATION,
192 192 domain_sid, &domain_handle);
193 193 if (status == NT_STATUS_SUCCESS) {
194 194 status = samr_lookup_domain_names(&domain_handle,
195 195 account_name, &ainfo);
196 196 if (status == NT_STATUS_SUCCESS)
197 197 *rid_ret = ainfo.a_rid;
198 198
199 199 (void) samr_close_handle(&domain_handle);
200 200 }
201 201
202 202 (void) samr_close_handle(&samr_handle);
203 203 return (status);
204 204 }
205 205
206 206 /*
207 207 * sam_get_local_domains
208 208 *
209 209 * Query a remote server to get the list of local domains that it
210 210 * supports.
211 211 *
212 212 * Returns NT status codes.
213 213 */
214 214 DWORD
215 215 sam_get_local_domains(char *server, char *domain_name)
216 216 {
217 217 mlsvc_handle_t samr_handle;
218 218 DWORD status;
219 219 int rc;
220 220 char user[SMB_USERNAME_MAXLEN];
221 221
222 222 smb_ipc_get_user(user, SMB_USERNAME_MAXLEN);
223 223
224 224 rc = samr_open(server, domain_name, user, SAM_ENUM_LOCAL_DOMAIN,
225 225 &samr_handle);
226 226 if (rc != 0)
227 227 return (NT_STATUS_OPEN_FAILED);
228 228
229 229 status = samr_enum_local_domains(&samr_handle);
230 230 (void) samr_close_handle(&samr_handle);
231 231 return (status);
232 232 }
233 233
234 234 /*
235 235 * Set the account control flags on some account for which we
236 236 * have already opened a SAM handle with appropriate rights,
237 237 * passed in here as sam_handle, along with the new flags.
238 238 */
239 239 DWORD
240 240 netr_set_user_control(
241 241 mlsvc_handle_t *user_handle,
242 242 DWORD UserAccountControl)
243 243 {
244 244 struct samr_SetUserInfo16 info;
245 245
246 246 info.UserAccountControl = UserAccountControl;
247 247 return (samr_set_user_info(user_handle, 16, &info));
248 248 }
249 249
250 250 /*
251 251 * Set the password on some account, for which we have already
252 252 * opened a SAM handle with appropriate rights, passed in here
253 253 * as sam_handle, along with the new password as cleartext.
254 254 *
255 255 * This builds a struct SAMPR_USER_INTERNAL5_INFORMATION [MS-SAMR]
256 256 * containing the new password, encrypted with our session key.
257 257 */
258 258 DWORD
259 259 netr_set_user_password(
260 260 mlsvc_handle_t *user_handle,
261 261 char *new_pw_clear)
262 262 {
263 263 unsigned char ssn_key[SMBAUTH_HASH_SZ];
264 264 struct samr_SetUserInfo24 info;
265 265
266 266 if (ndr_rpc_get_ssnkey(user_handle, ssn_key, SMBAUTH_HASH_SZ))
267 267 return (NT_STATUS_INTERNAL_ERROR);
268 268
269 269 (void) memset(&info, 0, sizeof (info));
270 270 samr_make_encrypted_password(&info.encr_pw, new_pw_clear, ssn_key);
271 271
272 272 /* Rather not leave the session key around. */
273 273 (void) memset(ssn_key, 0, sizeof (ssn_key));
274 274
275 275 return (samr_set_user_info(user_handle, 24, &info));
276 276 }
277 277
278 278 /*
279 279 * Change a password like NetUserChangePassword(),
280 280 * but where we already know which AD server to use,
281 281 * so we don't request the domain name or search for
282 282 * an AD server for that domain here.
283 283 */
284 284 DWORD
285 285 netr_change_password(
286 286 char *server,
287 287 char *account,
288 288 char *old_pw_clear,
289 289 char *new_pw_clear)
290 290 {
291 291 struct samr_encr_passwd epw;
292 292 struct samr_encr_hash old_hash;
293 293 uint8_t old_nt_hash[SAMR_PWHASH_LEN];
294 294 uint8_t new_nt_hash[SAMR_PWHASH_LEN];
295 295 mlsvc_handle_t handle;
296 296 DWORD status;
297 297
298 298 /*
299 299 * Create an RPC handle to this server, bound to SAMR.
300 300 */
301 301 status = ndr_rpc_bind(&handle, server, "", "", "SAMR");
302 302 if (status != NT_STATUS_SUCCESS)
303 303 return (status);
304 304
305 305 /*
306 306 * Encrypt the new p/w (plus random filler) with the
307 307 * old password, and send the old p/w encrypted with
308 308 * the new p/w hash to prove we know the old p/w.
309 309 * Details: [MS-SAMR 3.1.5.10.3]
310 310 */
311 311 (void) smb_auth_ntlm_hash(old_pw_clear, old_nt_hash);
312 312 (void) smb_auth_ntlm_hash(new_pw_clear, new_nt_hash);
313 313 samr_make_encrypted_password(&epw, new_pw_clear, old_nt_hash);
314 314
315 315 (void) smb_auth_DES(old_hash.data, SAMR_PWHASH_LEN,
316 316 new_nt_hash, 14, /* key */
317 317 old_nt_hash, SAMR_PWHASH_LEN);
318 318
319 319 /*
320 320 * Finally, ready to try the OtW call.
321 321 */
322 322 status = samr_change_password(
323 323 &handle, server, account,
324 324 &epw, &old_hash);
325 325
326 326 /* Avoid leaving cleartext (or equivalent) around. */
327 327 (void) memset(old_nt_hash, 0, sizeof (old_nt_hash));
328 328 (void) memset(new_nt_hash, 0, sizeof (new_nt_hash));
329 329
330 330 ndr_rpc_unbind(&handle);
331 331 return (status);
332 332 }
333 333
334 334 /*
335 335 * Build an encrypted password, as used by samr_set_user_info
336 336 * and samr_change_password. Note: This builds the unencrypted
337 337 * form in one union arm, and encrypts it in the other union arm.
338 338 */
339 339 void
340 340 samr_make_encrypted_password(
341 341 struct samr_encr_passwd *epw,
342 342 char *new_pw_clear,
343 343 uint8_t *crypt_key)
344 344 {
345 345 union {
346 346 struct samr_user_password u;
347 347 struct samr_encr_passwd e;
348 348 } pwu;
349 349
350 350 samr_fill_userpw(&pwu.u, new_pw_clear);
351 351
352 352 (void) smb_auth_RC4(pwu.e.data, sizeof (pwu.e.data),
353 353 crypt_key, SAMR_PWHASH_LEN,
354 354 pwu.e.data, sizeof (pwu.e.data));
355 355
356 356 (void) memcpy(epw->data, pwu.e.data, sizeof (pwu.e.data));
357 357 (void) memset(pwu.e.data, 0, sizeof (pwu.e.data));
358 358 }
359 359
360 360 /*
361 361 * This fills in a samr_user_password (a.k.a. SAMPR_USER_PASSWORD
362 362 * in the MS Net API) which has the new password "right justified"
363 363 * in the buffer, and any space on the left filled with random junk
364 364 * to improve the quality of the encryption that is subsequently
365 365 * applied to this buffer before it goes over the wire.
366 366 */
367 367 static void
368 368 samr_fill_userpw(struct samr_user_password *upw, const char *new_pw)
369 369 {
370 370 smb_wchar_t *pbuf;
371 371 uint32_t pwlen_bytes;
372 372 size_t pwlen_wchars;
373 373
374 374 /*
375 375 * First fill the whole buffer with the random junk.
376 376 * (Slightly less random when debugging:)
377 377 */
378 378 #ifdef DEBUG
379 379 (void) memset(upw->Buffer, '*', sizeof (upw->Buffer));
380 380 #else
381 381 randomize((char *)upw->Buffer, sizeof (upw->Buffer));
382 382 #endif
383 383
384 384 /*
385 385 * Now overwrite the last pwlen characters of
386 386 * that buffer with the password, and set the
387 387 * length field so the receiving end knows where
388 388 * the junk ends and the real password starts.
389 389 */
390 390 pwlen_wchars = smb_wcequiv_strlen(new_pw) / 2;
391 391 if (pwlen_wchars > SAMR_USER_PWLEN)
392 392 pwlen_wchars = SAMR_USER_PWLEN;
393 393 pwlen_bytes = pwlen_wchars * 2;
394 394
395 395 pbuf = &upw->Buffer[SAMR_USER_PWLEN - pwlen_wchars];
396 396 (void) smb_mbstowcs(pbuf, new_pw, pwlen_wchars);
397 397
398 398 /* Yes, this is in Bytes, not wchars. */
399 399 upw->Length = htolel(pwlen_bytes);
400 400 }
|
↓ open down ↓ |
350 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX