Print this page
1575 untangle libmlrpc ... (smbsrv)
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/lib/smbsrv/libmlsvc/common/samr_clnt.c
+++ new/usr/src/lib/smbsrv/libmlsvc/common/samr_clnt.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) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
24 24 * Copyright 2014 Nexenta Systems, Inc. All rights reserved.
25 25 */
26 26
27 27 /*
28 28 * Security Accounts Manager RPC (SAMR) client-side interface.
29 29 *
30 30 * The SAM is a hierarchical database:
31 31 * - If you want to talk to the SAM you need a SAM handle.
32 32 * - If you want to work with a domain, use the SAM handle.
33 33 * to obtain a domain handle.
34 34 * - Use domain handles to obtain user handles etc.
35 35 *
36 36 * Be careful about returning null handles to the application. Use of a
↓ open down ↓ |
36 lines elided |
↑ open up ↑ |
37 37 * null handle may crash the domain controller if you attempt to use it.
38 38 */
39 39
40 40 #include <stdio.h>
41 41 #include <strings.h>
42 42 #include <stdlib.h>
43 43 #include <unistd.h>
44 44 #include <netdb.h>
45 45 #include <sys/param.h>
46 46
47 +#include <libmlrpc/libmlrpc.h>
47 48 #include <smbsrv/libsmb.h>
48 -#include <smbsrv/libmlrpc.h>
49 49 #include <smbsrv/libmlsvc.h>
50 50 #include <smbsrv/smbinfo.h>
51 51 #include <smbsrv/ntaccess.h>
52 52 #include <smbsrv/smb_sid.h>
53 53 #include <samlib.h>
54 54
55 55 static DWORD samr_connect2(char *, char *, char *, DWORD, mlsvc_handle_t *);
56 56 static DWORD samr_connect4(char *, char *, char *, DWORD, mlsvc_handle_t *);
57 57 static DWORD samr_connect5(char *, char *, char *, DWORD, mlsvc_handle_t *);
58 58
59 59 typedef DWORD (*samr_connop_t)(char *, char *, char *, DWORD,
60 60 mlsvc_handle_t *);
61 61
62 62 static int samr_setup_user_info(WORD, struct samr_QueryUserInfo *,
63 63 union samr_user_info *);
64 64
65 65 /*
66 66 * samr_open
67 67 *
68 68 * Wrapper round samr_connect to ensure that we connect using the server
69 69 * and domain. We default to the resource domain if the caller doesn't
70 70 * supply a server name and a domain name.
71 71 *
72 72 * If username argument is NULL, an anonymous connection will be established.
73 73 * Otherwise, an authenticated connection will be established.
74 74 *
75 75 * On success 0 is returned. Otherwise a -ve error code.
76 76 */
77 77 DWORD
78 78 samr_open(char *server, char *domain, char *username, DWORD access_mask,
79 79 mlsvc_handle_t *samr_handle)
80 80 {
81 81 smb_domainex_t di;
82 82 DWORD status;
83 83
84 84 if (server == NULL || domain == NULL) {
85 85 if (!smb_domain_getinfo(&di))
86 86 return (NT_STATUS_INTERNAL_ERROR);
87 87 server = di.d_dci.dc_name;
88 88 domain = di.d_primary.di_nbname;
89 89 }
90 90
91 91 if (username == NULL)
92 92 username = MLSVC_ANON_USER;
93 93
94 94 status = samr_connect(server, domain, username, access_mask,
95 95 samr_handle);
96 96
97 97 return (status);
98 98 }
99 99
100 100
101 101 /*
102 102 * samr_connect
103 103 *
104 104 * Connect to the SAMR service on the specified server (domain controller).
105 105 * New SAM connect calls have been added to Windows over time:
106 106 *
107 107 * Windows NT3.x: SamrConnect
108 108 * Windows NT4.0: SamrConnect2
109 109 * Windows 2000: SamrConnect4
110 110 * Windows XP: SamrConnect5
111 111 *
112 112 * Try the calls from most recent to oldest until the server responds with
113 113 * something other than an RPC protocol error. We don't use the original
114 114 * connect call because all supported servers should support SamrConnect2.
115 115 */
116 116 DWORD
117 117 samr_connect(char *server, char *domain, char *username, DWORD access_mask,
118 118 mlsvc_handle_t *samr_handle)
119 119 {
120 120 static samr_connop_t samr_connop[] = {
121 121 samr_connect5,
122 122 samr_connect4,
123 123 samr_connect2
124 124 };
125 125
126 126 int n_op = (sizeof (samr_connop) / sizeof (samr_connop[0]));
127 127 DWORD status;
128 128 int i;
129 129
130 130 status = ndr_rpc_bind(samr_handle, server, domain, username, "SAMR");
131 131 if (status)
132 132 return (status);
133 133
134 134 for (i = 0; i < n_op; ++i) {
135 135 status = (*samr_connop[i])(server, domain, username,
136 136 access_mask, samr_handle);
137 137
138 138 if (status == NT_STATUS_SUCCESS)
139 139 return (status);
140 140 }
141 141
142 142 ndr_rpc_unbind(samr_handle);
143 143 return (status);
144 144 }
145 145
146 146 /*
147 147 * samr_connect2
148 148 *
149 149 * Connect to the SAM on a Windows NT 4.0 server (domain controller).
150 150 * We need the domain controller name and, if everything works, we
151 151 * return a handle. This function adds the double backslash prefx to
152 152 * make it easy for applications.
153 153 *
154 154 * Returns 0 on success. Otherwise returns a -ve error code.
155 155 */
156 156 /*ARGSUSED*/
157 157 static DWORD
158 158 samr_connect2(char *server, char *domain, char *username, DWORD access_mask,
159 159 mlsvc_handle_t *samr_handle)
160 160 {
161 161 struct samr_Connect2 arg;
162 162 int opnum;
163 163 DWORD status;
164 164 int len;
165 165
166 166 bzero(&arg, sizeof (struct samr_Connect2));
167 167 opnum = SAMR_OPNUM_Connect2;
168 168 status = NT_STATUS_SUCCESS;
169 169
170 170 len = strlen(server) + 4;
171 171 arg.servername = ndr_rpc_malloc(samr_handle, len);
172 172 (void) snprintf((char *)arg.servername, len, "\\\\%s", server);
173 173 arg.access_mask = access_mask;
174 174
175 175 if (ndr_rpc_call(samr_handle, opnum, &arg) != 0) {
176 176 status = NT_STATUS_UNSUCCESSFUL;
177 177 } else if (arg.status != 0) {
178 178 status = NT_SC_VALUE(arg.status);
179 179 } else {
180 180 (void) memcpy(&samr_handle->handle, &arg.handle,
181 181 sizeof (ndr_hdid_t));
182 182
183 183 if (ndr_is_null_handle(samr_handle))
184 184 status = NT_STATUS_INVALID_HANDLE;
185 185 }
186 186
187 187 ndr_rpc_release(samr_handle);
188 188 return (status);
189 189 }
190 190
191 191 /*
192 192 * samr_connect4
193 193 *
194 194 * Connect to the SAM on a Windows 2000 domain controller.
195 195 */
196 196 /*ARGSUSED*/
197 197 static DWORD
198 198 samr_connect4(char *server, char *domain, char *username, DWORD access_mask,
199 199 mlsvc_handle_t *samr_handle)
200 200 {
201 201 struct samr_Connect4 arg;
202 202 int opnum;
203 203 DWORD status;
204 204 int len;
205 205
206 206 bzero(&arg, sizeof (struct samr_Connect4));
207 207 opnum = SAMR_OPNUM_Connect4;
208 208 status = NT_STATUS_SUCCESS;
209 209
210 210 len = strlen(server) + 4;
211 211 arg.servername = ndr_rpc_malloc(samr_handle, len);
212 212 (void) snprintf((char *)arg.servername, len, "\\\\%s", server);
213 213 arg.revision = SAMR_REVISION_2;
214 214 arg.access_mask = access_mask;
215 215
216 216 if (ndr_rpc_call(samr_handle, opnum, &arg) != 0) {
217 217 status = NT_STATUS_UNSUCCESSFUL;
218 218 } else if (arg.status != 0) {
219 219 status = NT_SC_VALUE(arg.status);
220 220 } else {
221 221 (void) memcpy(&samr_handle->handle, &arg.handle,
222 222 sizeof (ndr_hdid_t));
223 223
224 224 if (ndr_is_null_handle(samr_handle))
225 225 status = NT_STATUS_INVALID_HANDLE;
226 226 }
227 227
228 228 ndr_rpc_release(samr_handle);
229 229 return (status);
230 230 }
231 231
232 232 /*
233 233 * samr_connect5
234 234 *
235 235 * Connect to the SAM on a Windows XP domain controller. On Windows
236 236 * XP, the server should be the fully qualified DNS domain name with
237 237 * a double backslash prefix. At this point, it is assumed that we
238 238 * need to add the prefix and the DNS domain name here.
239 239 *
240 240 * If this call succeeds, a SAMR handle is placed in samr_handle and
241 241 * zero is returned. Otherwise, a -ve error code is returned.
242 242 */
243 243 /*ARGSUSED*/
244 244 static DWORD
245 245 samr_connect5(char *server, char *domain, char *username, DWORD access_mask,
246 246 mlsvc_handle_t *samr_handle)
247 247 {
248 248 struct samr_Connect5 arg;
249 249 int len;
250 250 int opnum;
251 251 DWORD status;
252 252
253 253 bzero(&arg, sizeof (struct samr_Connect5));
254 254 opnum = SAMR_OPNUM_Connect5;
255 255 status = NT_STATUS_SUCCESS;
256 256
257 257 len = strlen(server) + 4;
258 258 arg.servername = ndr_rpc_malloc(samr_handle, len);
259 259 (void) snprintf((char *)arg.servername, len, "\\\\%s", server);
260 260
261 261 arg.access_mask = SAM_ENUM_LOCAL_DOMAIN;
262 262 arg.unknown2_00000001 = 0x00000001;
263 263 arg.unknown3_00000001 = 0x00000001;
264 264 arg.unknown4_00000003 = 0x00000003;
265 265 arg.unknown5_00000000 = 0x00000000;
266 266
267 267 if (ndr_rpc_call(samr_handle, opnum, &arg) != 0) {
268 268 status = NT_STATUS_UNSUCCESSFUL;
269 269 } else if (arg.status != 0) {
270 270 status = NT_SC_VALUE(arg.status);
271 271 } else {
272 272
273 273 (void) memcpy(&samr_handle->handle, &arg.handle,
274 274 sizeof (ndr_hdid_t));
275 275
276 276 if (ndr_is_null_handle(samr_handle))
277 277 status = NT_STATUS_INVALID_HANDLE;
278 278 }
279 279
280 280 ndr_rpc_release(samr_handle);
281 281 return (status);
282 282 }
283 283
284 284
285 285 /*
286 286 * samr_close_handle
287 287 *
288 288 * This is function closes any valid handle, i.e. sam, domain, user etc.
289 289 * If the handle being closed is the top level connect handle, we unbind.
290 290 * Then we zero out the handle to invalidate it.
291 291 */
292 292 void
293 293 samr_close_handle(mlsvc_handle_t *samr_handle)
294 294 {
295 295 struct samr_CloseHandle arg;
296 296 int opnum;
297 297
298 298 if (ndr_is_null_handle(samr_handle))
299 299 return;
300 300
301 301 opnum = SAMR_OPNUM_CloseHandle;
302 302 bzero(&arg, sizeof (struct samr_CloseHandle));
303 303 (void) memcpy(&arg.handle, &samr_handle->handle, sizeof (ndr_hdid_t));
304 304
305 305 (void) ndr_rpc_call(samr_handle, opnum, &arg);
306 306 ndr_rpc_release(samr_handle);
307 307
308 308 if (ndr_is_bind_handle(samr_handle))
309 309 ndr_rpc_unbind(samr_handle);
310 310
311 311 bzero(samr_handle, sizeof (mlsvc_handle_t));
312 312 }
313 313
314 314 /*
315 315 * samr_open_domain
316 316 *
317 317 * We use a SAM handle to obtain a handle for a domain, specified by
318 318 * the SID. The SID can be obtain via the LSA interface. A handle for
319 319 * the domain is returned in domain_handle.
320 320 */
321 321 DWORD
322 322 samr_open_domain(mlsvc_handle_t *samr_handle, DWORD access_mask,
323 323 struct samr_sid *sid, mlsvc_handle_t *domain_handle)
324 324 {
325 325 struct samr_OpenDomain arg;
326 326 int opnum;
327 327 DWORD status;
328 328
329 329 if (ndr_is_null_handle(samr_handle) ||
330 330 sid == NULL || domain_handle == NULL) {
331 331 return (NT_STATUS_INVALID_PARAMETER);
332 332 }
333 333
334 334 opnum = SAMR_OPNUM_OpenDomain;
335 335 bzero(&arg, sizeof (struct samr_OpenDomain));
336 336 (void) memcpy(&arg.handle, &samr_handle->handle, sizeof (ndr_hdid_t));
337 337
338 338 arg.access_mask = access_mask;
339 339 arg.sid = sid;
340 340
341 341 if (ndr_rpc_call(samr_handle, opnum, &arg) != 0) {
342 342 status = NT_STATUS_UNSUCCESSFUL;
343 343 } else if (arg.status != 0) {
344 344 status = arg.status;
345 345 } else {
346 346 status = NT_STATUS_SUCCESS;
347 347 ndr_inherit_handle(domain_handle, samr_handle);
348 348
349 349 (void) memcpy(&domain_handle->handle, &arg.domain_handle,
350 350 sizeof (ndr_hdid_t));
351 351
352 352 if (ndr_is_null_handle(domain_handle))
353 353 status = NT_STATUS_INVALID_HANDLE;
354 354 }
355 355
356 356 if (status != NT_STATUS_SUCCESS)
357 357 ndr_rpc_status(samr_handle, opnum, status);
358 358
359 359 ndr_rpc_release(samr_handle);
360 360 return (status);
361 361 }
362 362
363 363 /*
364 364 * samr_open_user
365 365 *
366 366 * Use a domain handle to obtain a handle for a user, specified by the
367 367 * user RID. A user RID (effectively a uid) can be obtained via the
368 368 * LSA interface. A handle for the user is returned in user_handle.
369 369 * Once you have a user handle it should be possible to query the SAM
370 370 * for information on that user.
371 371 */
372 372 DWORD
373 373 samr_open_user(mlsvc_handle_t *domain_handle, DWORD access_mask, DWORD rid,
374 374 mlsvc_handle_t *user_handle)
375 375 {
376 376 struct samr_OpenUser arg;
377 377 int opnum;
378 378 DWORD status = NT_STATUS_SUCCESS;
379 379
380 380 if (ndr_is_null_handle(domain_handle) || user_handle == NULL)
381 381 return (NT_STATUS_INVALID_PARAMETER);
382 382
383 383 opnum = SAMR_OPNUM_OpenUser;
384 384 bzero(&arg, sizeof (struct samr_OpenUser));
385 385 (void) memcpy(&arg.handle, &domain_handle->handle,
386 386 sizeof (ndr_hdid_t));
387 387 arg.access_mask = access_mask;
388 388 arg.rid = rid;
389 389
390 390 if (ndr_rpc_call(domain_handle, opnum, &arg) != 0) {
391 391 status = NT_STATUS_UNSUCCESSFUL;
392 392 } else if (arg.status != 0) {
393 393 ndr_rpc_status(domain_handle, opnum, arg.status);
394 394 status = NT_SC_VALUE(arg.status);
395 395 } else {
396 396 ndr_inherit_handle(user_handle, domain_handle);
397 397
398 398 (void) memcpy(&user_handle->handle, &arg.user_handle,
399 399 sizeof (ndr_hdid_t));
400 400
401 401 if (ndr_is_null_handle(user_handle))
402 402 status = NT_STATUS_INVALID_HANDLE;
403 403 }
404 404
405 405 ndr_rpc_release(domain_handle);
406 406 return (status);
407 407 }
408 408
409 409 /*
410 410 * samr_delete_user
411 411 *
412 412 * Delete the user specified by the user_handle.
413 413 */
414 414 DWORD
415 415 samr_delete_user(mlsvc_handle_t *user_handle)
416 416 {
417 417 struct samr_DeleteUser arg;
418 418 int opnum;
419 419 DWORD status;
420 420
421 421 if (ndr_is_null_handle(user_handle))
422 422 return (NT_STATUS_INVALID_PARAMETER);
423 423
424 424 opnum = SAMR_OPNUM_DeleteUser;
425 425 bzero(&arg, sizeof (struct samr_DeleteUser));
426 426 (void) memcpy(&arg.user_handle, &user_handle->handle,
427 427 sizeof (ndr_hdid_t));
428 428
429 429 if (ndr_rpc_call(user_handle, opnum, &arg) != 0) {
430 430 status = NT_STATUS_INVALID_PARAMETER;
431 431 } else if (arg.status != 0) {
432 432 ndr_rpc_status(user_handle, opnum, arg.status);
433 433 status = NT_SC_VALUE(arg.status);
434 434 } else {
435 435 status = 0;
436 436 }
437 437
438 438 ndr_rpc_release(user_handle);
439 439 return (status);
440 440 }
441 441
442 442 /*
443 443 * samr_open_group
444 444 *
445 445 * Use a domain handle to obtain a handle for a group, specified by the
446 446 * group RID. A group RID (effectively a gid) can be obtained via the
447 447 * LSA interface. A handle for the group is returned in group_handle.
448 448 * Once you have a group handle it should be possible to query the SAM
449 449 * for information on that group.
450 450 */
451 451 int
452 452 samr_open_group(
453 453 mlsvc_handle_t *domain_handle,
454 454 DWORD rid,
455 455 mlsvc_handle_t *group_handle)
456 456 {
457 457 struct samr_OpenGroup arg;
458 458 int opnum;
459 459 int rc;
460 460
461 461 if (ndr_is_null_handle(domain_handle) || group_handle == NULL)
462 462 return (-1);
463 463
464 464 opnum = SAMR_OPNUM_OpenGroup;
465 465 bzero(&arg, sizeof (struct samr_OpenUser));
466 466 (void) memcpy(&arg.handle, &domain_handle->handle,
467 467 sizeof (ndr_hdid_t));
468 468 arg.access_mask = SAM_LOOKUP_INFORMATION | SAM_ACCESS_USER_READ;
469 469 arg.rid = rid;
470 470
471 471 if ((rc = ndr_rpc_call(domain_handle, opnum, &arg)) != 0)
472 472 return (-1);
473 473
474 474 if (arg.status != 0) {
475 475 ndr_rpc_status(domain_handle, opnum, arg.status);
476 476 rc = -1;
477 477 } else {
478 478 ndr_inherit_handle(group_handle, domain_handle);
479 479
480 480 (void) memcpy(&group_handle->handle, &arg.group_handle,
481 481 sizeof (ndr_hdid_t));
482 482
483 483 if (ndr_is_null_handle(group_handle))
484 484 rc = -1;
485 485 }
486 486
487 487 ndr_rpc_release(domain_handle);
488 488 return (rc);
489 489 }
490 490
491 491 /*
492 492 * samr_create_user
493 493 *
494 494 * Create a user in the domain specified by the domain handle. If this
495 495 * call is successful, the server will return the RID for the user and
496 496 * a user handle, which may be used to set or query the SAM.
497 497 *
498 498 * Observed status codes:
499 499 * NT_STATUS_INVALID_PARAMETER
500 500 * NT_STATUS_INVALID_ACCOUNT_NAME
501 501 * NT_STATUS_ACCESS_DENIED
502 502 * NT_STATUS_USER_EXISTS
503 503 *
504 504 * Returns 0 on success. Otherwise returns an NT status code.
505 505 */
506 506 DWORD
507 507 samr_create_user(mlsvc_handle_t *domain_handle, char *username,
508 508 DWORD account_flags, DWORD *rid, mlsvc_handle_t *user_handle)
509 509 {
510 510 struct samr_CreateUser arg;
511 511 ndr_heap_t *heap;
512 512 int opnum;
513 513 int rc;
514 514 DWORD status = 0;
515 515
516 516 if (ndr_is_null_handle(domain_handle) ||
517 517 username == NULL || rid == NULL) {
518 518 return (NT_STATUS_INVALID_PARAMETER);
519 519 }
520 520
521 521 opnum = SAMR_OPNUM_CreateUser;
522 522
523 523 bzero(&arg, sizeof (struct samr_CreateUser));
524 524 (void) memcpy(&arg.handle, &domain_handle->handle,
525 525 sizeof (ndr_hdid_t));
526 526
527 527 heap = ndr_rpc_get_heap(domain_handle);
528 528 ndr_heap_mkvcs(heap, username, (ndr_vcstr_t *)&arg.username);
529 529
530 530 arg.account_flags = account_flags;
531 531 arg.desired_access = 0xE00500B0;
532 532
533 533 rc = ndr_rpc_call(domain_handle, opnum, &arg);
534 534 if (rc != 0) {
535 535 status = NT_STATUS_INVALID_PARAMETER;
536 536 } else if (arg.status != 0) {
537 537 status = NT_SC_VALUE(arg.status);
538 538
539 539 if (status != NT_STATUS_USER_EXISTS) {
540 540 smb_tracef("SamrCreateUser[%s]: %s",
541 541 username, xlate_nt_status(status));
542 542 }
543 543 } else {
544 544 ndr_inherit_handle(user_handle, domain_handle);
545 545
546 546 (void) memcpy(&user_handle->handle, &arg.user_handle,
547 547 sizeof (ndr_hdid_t));
548 548
549 549 *rid = arg.rid;
550 550
551 551 if (ndr_is_null_handle(user_handle))
552 552 status = NT_STATUS_INVALID_HANDLE;
553 553 else
554 554 status = 0;
555 555 }
556 556
557 557 ndr_rpc_release(domain_handle);
558 558 return (status);
559 559 }
560 560
561 561 /*
562 562 * samr_lookup_domain
563 563 *
564 564 * Lookup up the domain SID for the specified domain name. The handle
565 565 * should be one returned from samr_connect. The allocated memory for
566 566 * the returned SID must be freed by caller.
567 567 */
568 568 smb_sid_t *
569 569 samr_lookup_domain(mlsvc_handle_t *samr_handle, char *domain_name)
570 570 {
571 571 struct samr_LookupDomain arg;
572 572 smb_sid_t *domsid = NULL;
573 573 int opnum;
574 574 size_t length;
575 575
576 576 if (ndr_is_null_handle(samr_handle) || domain_name == NULL)
577 577 return (NULL);
578 578
579 579 opnum = SAMR_OPNUM_LookupDomain;
580 580 bzero(&arg, sizeof (struct samr_LookupDomain));
581 581
582 582 (void) memcpy(&arg.handle, &samr_handle->handle,
583 583 sizeof (samr_handle_t));
584 584
585 585 length = smb_wcequiv_strlen(domain_name);
586 586 length += sizeof (smb_wchar_t);
587 587
588 588 arg.domain_name.length = length;
589 589 arg.domain_name.allosize = length;
590 590 arg.domain_name.str = (unsigned char *)domain_name;
591 591
592 592 if (ndr_rpc_call(samr_handle, opnum, &arg) == 0)
593 593 domsid = smb_sid_dup((smb_sid_t *)arg.sid);
594 594
595 595 ndr_rpc_release(samr_handle);
596 596 return (domsid);
597 597 }
598 598
599 599 /*
600 600 * samr_enum_local_domains
601 601 *
602 602 * Get the list of local domains supported by a server.
603 603 *
604 604 * Returns NT status codes.
605 605 */
606 606 DWORD
607 607 samr_enum_local_domains(mlsvc_handle_t *samr_handle)
608 608 {
609 609 struct samr_EnumLocalDomain arg;
610 610 int opnum;
611 611 DWORD status;
612 612
613 613 if (ndr_is_null_handle(samr_handle))
614 614 return (NT_STATUS_INVALID_PARAMETER);
615 615
616 616 opnum = SAMR_OPNUM_EnumLocalDomains;
617 617 bzero(&arg, sizeof (struct samr_EnumLocalDomain));
618 618
619 619 (void) memcpy(&arg.handle, &samr_handle->handle,
620 620 sizeof (samr_handle_t));
621 621 arg.enum_context = 0;
622 622 arg.max_length = 0x00002000; /* Value used by NT */
623 623
624 624 if (ndr_rpc_call(samr_handle, opnum, &arg) != 0) {
625 625 status = NT_STATUS_INVALID_PARAMETER;
626 626 } else {
627 627 status = NT_SC_VALUE(arg.status);
628 628
629 629 /*
630 630 * Handle none-mapped status quietly.
631 631 */
632 632 if (status != NT_STATUS_NONE_MAPPED)
633 633 ndr_rpc_status(samr_handle, opnum, arg.status);
634 634 }
635 635
636 636 ndr_rpc_release(samr_handle);
637 637 return (status);
638 638 }
639 639
640 640 /*
641 641 * samr_lookup_domain_names
642 642 *
643 643 * Lookup up the given name in the domain specified by domain_handle.
644 644 * Upon a successful lookup the information is returned in the account
645 645 * arg and caller must free allocated memories by calling smb_account_free().
646 646 *
647 647 * Returns NT status codes.
648 648 */
649 649 uint32_t
650 650 samr_lookup_domain_names(mlsvc_handle_t *domain_handle, char *name,
651 651 smb_account_t *account)
652 652 {
653 653 struct samr_LookupNames arg;
654 654 int opnum;
655 655 uint32_t status;
656 656 size_t length;
657 657
658 658 if (ndr_is_null_handle(domain_handle) ||
659 659 name == NULL || account == NULL) {
660 660 return (NT_STATUS_INVALID_PARAMETER);
661 661 }
662 662
663 663 bzero(account, sizeof (smb_account_t));
664 664 opnum = SAMR_OPNUM_LookupNames;
665 665 bzero(&arg, sizeof (struct samr_LookupNames));
666 666
667 667 (void) memcpy(&arg.handle, &domain_handle->handle,
668 668 sizeof (samr_handle_t));
669 669 arg.n_entry = 1;
670 670 arg.max_n_entry = 1000;
671 671 arg.index = 0;
672 672 arg.total = 1;
673 673
674 674 length = smb_wcequiv_strlen(name);
675 675 length += sizeof (smb_wchar_t);
676 676
677 677 arg.name.length = length;
678 678 arg.name.allosize = length;
679 679 arg.name.str = (unsigned char *)name;
680 680
681 681 if (ndr_rpc_call(domain_handle, opnum, &arg) != 0) {
682 682 status = NT_STATUS_INVALID_PARAMETER;
683 683 } else if (arg.status != NT_STATUS_SUCCESS) {
684 684 status = NT_SC_VALUE(arg.status);
685 685
686 686 /*
687 687 * Handle none-mapped status quietly.
688 688 */
689 689 if (status != NT_STATUS_NONE_MAPPED)
690 690 ndr_rpc_status(domain_handle, opnum, arg.status);
691 691 } else {
692 692 account->a_type = arg.rid_types.rid_type[0];
693 693 account->a_rid = arg.rids.rid[0];
694 694 status = NT_STATUS_SUCCESS;
695 695 }
696 696
697 697 ndr_rpc_release(domain_handle);
698 698 return (status);
699 699 }
700 700
701 701 /*
702 702 * samr_query_user_info
703 703 *
704 704 * Query information on a specific user. The handle must be a valid
705 705 * user handle obtained via samr_open_user.
706 706 *
707 707 * Returns 0 on success, otherwise returns NT status code.
708 708 */
709 709 DWORD
710 710 samr_query_user_info(mlsvc_handle_t *user_handle, WORD switch_value,
711 711 union samr_user_info *user_info)
712 712 {
713 713 struct samr_QueryUserInfo arg;
714 714 int opnum;
715 715
716 716 if (ndr_is_null_handle(user_handle) || user_info == 0)
717 717 return (NT_STATUS_INTERNAL_ERROR);
718 718
719 719 opnum = SAMR_OPNUM_QueryUserInfo;
720 720 bzero(&arg, sizeof (struct samr_QueryUserInfo));
721 721
722 722 (void) memcpy(&arg.user_handle, &user_handle->handle,
723 723 sizeof (samr_handle_t));
724 724 arg.switch_value = switch_value;
725 725
726 726 if (ndr_rpc_call(user_handle, opnum, &arg) != 0)
727 727 arg.status = RPC_NT_CALL_FAILED;
728 728
729 729 if (arg.status == 0)
730 730 (void) samr_setup_user_info(switch_value, &arg, user_info);
731 731
732 732 return (arg.status);
733 733 }
734 734
735 735 /*
736 736 * samr_setup_user_info
737 737 *
738 738 * Private function to set up the samr_user_info data. Dependent on
739 739 * the switch value this function may use strdup which will malloc
740 740 * memory. The caller is responsible for deallocating this memory.
741 741 *
742 742 * Returns 0 on success, otherwise returns -1.
743 743 */
744 744 static int
745 745 samr_setup_user_info(WORD switch_value,
746 746 struct samr_QueryUserInfo *arg, union samr_user_info *user_info)
747 747 {
748 748 struct samr_QueryUserInfo1 *info1;
749 749 struct samr_QueryUserInfo6 *info6;
750 750
751 751 switch (switch_value) {
752 752 case 1:
753 753 info1 = &arg->ru.info1;
754 754 user_info->info1.username = strdup(
755 755 (char const *)info1->username.str);
756 756 user_info->info1.fullname = strdup(
757 757 (char const *)info1->fullname.str);
758 758 user_info->info1.description = strdup(
759 759 (char const *)info1->description.str);
760 760 user_info->info1.unknown = 0;
761 761 user_info->info1.group_rid = info1->group_rid;
762 762 return (0);
763 763
764 764 case 6:
765 765 info6 = &arg->ru.info6;
766 766 user_info->info6.username = strdup(
767 767 (char const *)info6->username.str);
768 768 user_info->info6.fullname = strdup(
769 769 (char const *)info6->fullname.str);
770 770 return (0);
771 771
772 772 case 7:
773 773 user_info->info7.username = strdup(
774 774 (char const *)arg->ru.info7.username.str);
775 775 return (0);
776 776
777 777 case 8:
778 778 user_info->info8.fullname = strdup(
779 779 (char const *)arg->ru.info8.fullname.str);
780 780 return (0);
781 781
782 782 case 9:
783 783 user_info->info9.group_rid = arg->ru.info9.group_rid;
784 784 return (0);
785 785
786 786 case 16:
787 787 user_info->info16.acct_ctrl =
788 788 arg->ru.info16.UserAccountControl;
789 789 return (0);
790 790
791 791 default:
792 792 break;
793 793 };
794 794
795 795 return (-1);
796 796 }
797 797
798 798 /*
799 799 * samr_query_user_groups
800 800 *
801 801 * Query the groups for a specific user. The handle must be a valid
802 802 * user handle obtained via samr_open_user. The list of groups is
803 803 * returned in group_info. Note that group_info->groups is allocated
804 804 * using malloc. The caller is responsible for deallocating this
805 805 * memory when it is no longer required. If group_info->n_entry is 0
806 806 * then no memory was allocated.
807 807 *
808 808 * Returns 0 on success, otherwise returns -1.
809 809 */
810 810 int
811 811 samr_query_user_groups(mlsvc_handle_t *user_handle, int *n_groups,
812 812 struct samr_UserGroups **groups)
813 813 {
814 814 struct samr_QueryUserGroups arg;
815 815 int opnum;
816 816 int rc;
817 817 int nbytes;
818 818
819 819 if (ndr_is_null_handle(user_handle))
820 820 return (-1);
821 821
822 822 opnum = SAMR_OPNUM_QueryUserGroups;
823 823 bzero(&arg, sizeof (struct samr_QueryUserGroups));
824 824
825 825 (void) memcpy(&arg.user_handle, &user_handle->handle,
826 826 sizeof (samr_handle_t));
827 827
828 828 rc = ndr_rpc_call(user_handle, opnum, &arg);
829 829 if (rc == 0) {
830 830 if (arg.info == 0) {
831 831 rc = -1;
832 832 } else {
833 833 nbytes = arg.info->n_entry *
834 834 sizeof (struct samr_UserGroups);
835 835
836 836 if ((*groups = malloc(nbytes)) == NULL) {
837 837 *n_groups = 0;
838 838 rc = -1;
839 839 } else {
840 840 *n_groups = arg.info->n_entry;
841 841 bcopy(arg.info->groups, *groups, nbytes);
842 842 }
843 843 }
844 844 }
845 845
846 846 ndr_rpc_release(user_handle);
847 847 return (rc);
848 848 }
849 849
850 850 /*
851 851 * samr_get_user_pwinfo
852 852 *
853 853 * Get some user password info. I'm not sure what this is yet but it is
854 854 * part of the create user sequence. The handle must be a valid user
855 855 * handle. Since I don't know what this is returning, I haven't provided
856 856 * any return data yet.
857 857 *
858 858 * Returns 0 on success. Otherwise returns an NT status code.
859 859 */
860 860 DWORD
861 861 samr_get_user_pwinfo(mlsvc_handle_t *user_handle)
862 862 {
863 863 struct samr_GetUserPwInfo arg;
864 864 int opnum;
865 865 DWORD status;
866 866
867 867 if (ndr_is_null_handle(user_handle))
868 868 return (NT_STATUS_INVALID_PARAMETER);
869 869
870 870 opnum = SAMR_OPNUM_GetUserPwInfo;
871 871 bzero(&arg, sizeof (struct samr_GetUserPwInfo));
872 872 (void) memcpy(&arg.user_handle, &user_handle->handle,
873 873 sizeof (samr_handle_t));
874 874
875 875 if (ndr_rpc_call(user_handle, opnum, &arg) != 0) {
876 876 status = NT_STATUS_INVALID_PARAMETER;
877 877 } else if (arg.status != 0) {
878 878 ndr_rpc_status(user_handle, opnum, arg.status);
879 879 status = NT_SC_VALUE(arg.status);
880 880 } else {
881 881 status = 0;
882 882 }
883 883
884 884 ndr_rpc_release(user_handle);
885 885 return (status);
886 886 }
887 887
888 888 DECL_FIXUP_STRUCT(samr_SetUserInfo_u);
889 889 DECL_FIXUP_STRUCT(samr_SetUserInfo_s);
890 890 DECL_FIXUP_STRUCT(samr_SetUserInfo);
891 891
892 892 /*
893 893 * samr_set_user_info
894 894 *
895 895 * Returns 0 on success. Otherwise returns an NT status code.
896 896 * NT status codes observed so far:
897 897 * NT_STATUS_WRONG_PASSWORD
898 898 */
899 899 DWORD
900 900 samr_set_user_info(
901 901 mlsvc_handle_t *user_handle,
902 902 int info_level,
903 903 void *info_buf)
904 904 {
905 905 struct samr_SetUserInfo arg;
906 906 uint16_t usize, tsize;
907 907 int opnum;
908 908
909 909 if (ndr_is_null_handle(user_handle))
910 910 return (NT_STATUS_INTERNAL_ERROR);
911 911
912 912 /*
913 913 * Only support a few levels
914 914 * MS-SAMR: UserInternal4Information
915 915 */
916 916 switch (info_level) {
917 917 case 16: /* samr_SetUserInfo16 */
918 918 usize = sizeof (struct samr_SetUserInfo16);
919 919 break;
920 920 case 21: /* samr_SetUserInfo21 */
921 921 usize = sizeof (struct samr_SetUserInfo21);
922 922 break;
923 923 case 23: /* samr_SetUserInfo23 */
924 924 usize = sizeof (struct samr_SetUserInfo23);
925 925 break;
926 926 case 24: /* samr_SetUserInfo24 */
927 927 usize = sizeof (struct samr_SetUserInfo24);
928 928 break;
929 929 default:
930 930 return (NT_STATUS_INVALID_LEVEL);
931 931 }
932 932
933 933 /*
934 934 * OK, now this gets really ugly, because
935 935 * ndrgen doesn't do unions correctly.
936 936 */
937 937 FIXUP_PDU_SIZE(samr_SetUserInfo_u, usize);
938 938 tsize = usize + (2 * sizeof (WORD));
939 939 FIXUP_PDU_SIZE(samr_SetUserInfo_s, tsize);
940 940 tsize += sizeof (ndr_request_hdr_t) + sizeof (DWORD);
941 941 FIXUP_PDU_SIZE(samr_SetUserInfo, tsize);
942 942
943 943 opnum = SAMR_OPNUM_SetUserInfo;
944 944 bzero(&arg, sizeof (arg));
945 945 (void) memcpy(&arg.user_handle, &user_handle->handle,
946 946 sizeof (samr_handle_t));
947 947 arg.info.info_level = info_level;
948 948 arg.info.switch_value = info_level;
949 949 (void) memcpy(&arg.info.ru, info_buf, usize);
950 950
951 951 if (ndr_rpc_call(user_handle, opnum, &arg) != 0)
952 952 arg.status = RPC_NT_CALL_FAILED;
953 953 else if (arg.status != 0)
954 954 ndr_rpc_status(user_handle, opnum, arg.status);
955 955
956 956 ndr_rpc_release(user_handle);
957 957 return (arg.status);
958 958 }
959 959
960 960 /*
961 961 * Client side wrapper for SamrUnicodeChangePasswordUser2
962 962 * [MS-SAMR 3.1.5.10.3]
963 963 */
964 964
965 965 DWORD
966 966 samr_change_password(
967 967 mlsvc_handle_t *handle,
968 968 char *server,
969 969 char *account,
970 970 struct samr_encr_passwd *newpw,
971 971 struct samr_encr_hash *oldpw)
972 972 {
973 973 static struct samr_encr_passwd zero_newpw;
974 974 static struct samr_encr_hash zero_oldpw;
975 975 struct samr_ChangePasswordUser2 arg;
976 976 int opnum = SAMR_OPNUM_ChangePasswordUser2;
977 977 char *slashserver;
978 978 int len;
979 979
980 980 (void) memset(&arg, 0, sizeof (arg));
981 981
982 982 /* Need server name with slashes */
983 983 len = 2 + strlen(server) + 1;
984 984 slashserver = ndr_rpc_malloc(handle, len);
985 985 if (slashserver == NULL)
986 986 return (NT_STATUS_NO_MEMORY);
987 987 (void) snprintf(slashserver, len, "\\\\%s", server);
988 988
989 989 arg.servername = ndr_rpc_malloc(handle, sizeof (samr_string_t));
990 990 if (arg.servername == NULL)
991 991 return (NT_STATUS_NO_MEMORY);
992 992 len = smb_wcequiv_strlen(slashserver);
993 993 if (len < 1)
994 994 return (NT_STATUS_INVALID_PARAMETER);
995 995 len += 2; /* the WC null */
996 996 arg.servername->length = len;
997 997 arg.servername->allosize = len;
998 998 arg.servername->str = (uint8_t *)slashserver;
999 999
1000 1000 arg.username = ndr_rpc_malloc(handle, sizeof (samr_string_t));
1001 1001 if (arg.username == NULL)
1002 1002 return (NT_STATUS_NO_MEMORY);
1003 1003 len = smb_wcequiv_strlen(account);
1004 1004 if (len < 1)
1005 1005 return (NT_STATUS_INVALID_PARAMETER);
1006 1006 len += 2; /* the WC null */
1007 1007 arg.username->length = len;
1008 1008 arg.username->allosize = len;
1009 1009 arg.username->str = (uint8_t *)account;
1010 1010
1011 1011 arg.nt_newpw = newpw;
1012 1012 arg.nt_oldpw = oldpw;
1013 1013
1014 1014 arg.lm_newpw = &zero_newpw;
1015 1015 arg.lm_oldpw = &zero_oldpw;
1016 1016
1017 1017 if (ndr_rpc_call(handle, opnum, &arg) != 0)
1018 1018 arg.status = RPC_NT_CALL_FAILED;
1019 1019 else if (arg.status != 0)
1020 1020 ndr_rpc_status(handle, opnum, arg.status);
1021 1021
1022 1022 ndr_rpc_release(handle);
1023 1023 return (arg.status);
1024 1024 }
↓ open down ↓ |
966 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX