1/* 2 Unix SMB/CIFS implementation. 3 4 In-Child server implementation of the routines defined in wbint.idl 5 6 Copyright (C) Volker Lendecke 2009 7 Copyright (C) Guenther Deschner 2009 8 9 This program is free software; you can redistribute it and/or modify 10 it under the terms of the GNU General Public License as published by 11 the Free Software Foundation; either version 3 of the License, or 12 (at your option) any later version. 13 14 This program is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 GNU General Public License for more details. 18 19 You should have received a copy of the GNU General Public License 20 along with this program. If not, see <http://www.gnu.org/licenses/>. 21*/ 22 23#include "includes.h" 24#include "winbindd/winbindd.h" 25#include "winbindd/winbindd_proto.h" 26#include "librpc/gen_ndr/srv_wbint.h" 27#include "../librpc/gen_ndr/cli_netlogon.h" 28 29void _wbint_Ping(pipes_struct *p, struct wbint_Ping *r) 30{ 31 *r->out.out_data = r->in.in_data; 32} 33 34NTSTATUS _wbint_LookupSid(pipes_struct *p, struct wbint_LookupSid *r) 35{ 36 struct winbindd_domain *domain = wb_child_domain(); 37 char *dom_name; 38 char *name; 39 enum lsa_SidType type; 40 NTSTATUS status; 41 42 if (domain == NULL) { 43 return NT_STATUS_REQUEST_NOT_ACCEPTED; 44 } 45 46 status = domain->methods->sid_to_name(domain, p->mem_ctx, r->in.sid, 47 &dom_name, &name, &type); 48 if (!NT_STATUS_IS_OK(status)) { 49 return status; 50 } 51 52 *r->out.domain = dom_name; 53 *r->out.name = name; 54 *r->out.type = type; 55 return NT_STATUS_OK; 56} 57 58NTSTATUS _wbint_LookupName(pipes_struct *p, struct wbint_LookupName *r) 59{ 60 struct winbindd_domain *domain = wb_child_domain(); 61 62 if (domain == NULL) { 63 return NT_STATUS_REQUEST_NOT_ACCEPTED; 64 } 65 66 return domain->methods->name_to_sid( 67 domain, p->mem_ctx, r->in.domain, r->in.name, r->in.flags, 68 r->out.sid, r->out.type); 69} 70 71NTSTATUS _wbint_Sid2Uid(pipes_struct *p, struct wbint_Sid2Uid *r) 72{ 73 uid_t uid; 74 NTSTATUS status; 75 76 status = idmap_sid_to_uid(r->in.dom_name ? r->in.dom_name : "", 77 r->in.sid, &uid); 78 if (!NT_STATUS_IS_OK(status)) { 79 return status; 80 } 81 *r->out.uid = uid; 82 return NT_STATUS_OK; 83} 84 85NTSTATUS _wbint_Sid2Gid(pipes_struct *p, struct wbint_Sid2Gid *r) 86{ 87 gid_t gid; 88 NTSTATUS status; 89 90 status = idmap_sid_to_gid(r->in.dom_name ? r->in.dom_name : "", 91 r->in.sid, &gid); 92 if (!NT_STATUS_IS_OK(status)) { 93 return status; 94 } 95 *r->out.gid = gid; 96 return NT_STATUS_OK; 97} 98 99NTSTATUS _wbint_Uid2Sid(pipes_struct *p, struct wbint_Uid2Sid *r) 100{ 101 return idmap_uid_to_sid(r->in.dom_name ? r->in.dom_name : "", 102 r->out.sid, r->in.uid); 103} 104 105NTSTATUS _wbint_Gid2Sid(pipes_struct *p, struct wbint_Gid2Sid *r) 106{ 107 return idmap_gid_to_sid(r->in.dom_name ? r->in.dom_name : "", 108 r->out.sid, r->in.gid); 109} 110 111NTSTATUS _wbint_AllocateUid(pipes_struct *p, struct wbint_AllocateUid *r) 112{ 113 struct unixid xid; 114 NTSTATUS status; 115 116 status = idmap_allocate_uid(&xid); 117 if (!NT_STATUS_IS_OK(status)) { 118 return status; 119 } 120 *r->out.uid = xid.id; 121 return NT_STATUS_OK; 122} 123 124NTSTATUS _wbint_AllocateGid(pipes_struct *p, struct wbint_AllocateGid *r) 125{ 126 struct unixid xid; 127 NTSTATUS status; 128 129 status = idmap_allocate_gid(&xid); 130 if (!NT_STATUS_IS_OK(status)) { 131 return status; 132 } 133 *r->out.gid = xid.id; 134 return NT_STATUS_OK; 135} 136 137NTSTATUS _wbint_QueryUser(pipes_struct *p, struct wbint_QueryUser *r) 138{ 139 struct winbindd_domain *domain = wb_child_domain(); 140 141 if (domain == NULL) { 142 return NT_STATUS_REQUEST_NOT_ACCEPTED; 143 } 144 145 return domain->methods->query_user(domain, p->mem_ctx, r->in.sid, 146 r->out.info); 147} 148 149NTSTATUS _wbint_LookupUserAliases(pipes_struct *p, 150 struct wbint_LookupUserAliases *r) 151{ 152 struct winbindd_domain *domain = wb_child_domain(); 153 154 if (domain == NULL) { 155 return NT_STATUS_REQUEST_NOT_ACCEPTED; 156 } 157 158 return domain->methods->lookup_useraliases( 159 domain, p->mem_ctx, r->in.sids->num_sids, r->in.sids->sids, 160 &r->out.rids->num_rids, &r->out.rids->rids); 161} 162 163NTSTATUS _wbint_LookupUserGroups(pipes_struct *p, 164 struct wbint_LookupUserGroups *r) 165{ 166 struct winbindd_domain *domain = wb_child_domain(); 167 168 if (domain == NULL) { 169 return NT_STATUS_REQUEST_NOT_ACCEPTED; 170 } 171 172 return domain->methods->lookup_usergroups( 173 domain, p->mem_ctx, r->in.sid, 174 &r->out.sids->num_sids, &r->out.sids->sids); 175} 176 177NTSTATUS _wbint_QuerySequenceNumber(pipes_struct *p, 178 struct wbint_QuerySequenceNumber *r) 179{ 180 struct winbindd_domain *domain = wb_child_domain(); 181 182 if (domain == NULL) { 183 return NT_STATUS_REQUEST_NOT_ACCEPTED; 184 } 185 186 return domain->methods->sequence_number(domain, r->out.sequence); 187} 188 189NTSTATUS _wbint_LookupGroupMembers(pipes_struct *p, 190 struct wbint_LookupGroupMembers *r) 191{ 192 struct winbindd_domain *domain = wb_child_domain(); 193 uint32_t i, num_names; 194 struct dom_sid *sid_mem; 195 char **names; 196 uint32_t *name_types; 197 NTSTATUS status; 198 199 if (domain == NULL) { 200 return NT_STATUS_REQUEST_NOT_ACCEPTED; 201 } 202 203 status = domain->methods->lookup_groupmem( 204 domain, p->mem_ctx, r->in.sid, r->in.type, 205 &num_names, &sid_mem, &names, &name_types); 206 if (!NT_STATUS_IS_OK(status)) { 207 return status; 208 } 209 210 r->out.members->num_principals = num_names; 211 r->out.members->principals = talloc_array( 212 r->out.members, struct wbint_Principal, num_names); 213 if (r->out.members->principals == NULL) { 214 return NT_STATUS_NO_MEMORY; 215 } 216 217 for (i=0; i<num_names; i++) { 218 struct wbint_Principal *m = &r->out.members->principals[i]; 219 sid_copy(&m->sid, &sid_mem[i]); 220 m->name = talloc_move(r->out.members->principals, &names[i]); 221 m->type = (enum lsa_SidType)name_types[i]; 222 } 223 224 return NT_STATUS_OK; 225} 226 227NTSTATUS _wbint_QueryUserList(pipes_struct *p, struct wbint_QueryUserList *r) 228{ 229 struct winbindd_domain *domain = wb_child_domain(); 230 231 if (domain == NULL) { 232 return NT_STATUS_REQUEST_NOT_ACCEPTED; 233 } 234 235 return domain->methods->query_user_list( 236 domain, p->mem_ctx, &r->out.users->num_userinfos, 237 &r->out.users->userinfos); 238} 239 240NTSTATUS _wbint_QueryGroupList(pipes_struct *p, struct wbint_QueryGroupList *r) 241{ 242 struct winbindd_domain *domain = wb_child_domain(); 243 uint32_t i, num_groups; 244 struct acct_info *groups; 245 struct wbint_Principal *result; 246 NTSTATUS status; 247 248 if (domain == NULL) { 249 return NT_STATUS_REQUEST_NOT_ACCEPTED; 250 } 251 252 status = domain->methods->enum_dom_groups(domain, talloc_tos(), 253 &num_groups, &groups); 254 if (!NT_STATUS_IS_OK(status)) { 255 return status; 256 } 257 258 result = talloc_array(r->out.groups, struct wbint_Principal, 259 num_groups); 260 if (result == NULL) { 261 return NT_STATUS_NO_MEMORY; 262 } 263 264 for (i=0; i<num_groups; i++) { 265 sid_compose(&result[i].sid, &domain->sid, groups[i].rid); 266 result[i].type = SID_NAME_DOM_GRP; 267 result[i].name = talloc_strdup(result, groups[i].acct_name); 268 if (result[i].name == NULL) { 269 TALLOC_FREE(result); 270 TALLOC_FREE(groups); 271 return NT_STATUS_NO_MEMORY; 272 } 273 } 274 275 r->out.groups->num_principals = num_groups; 276 r->out.groups->principals = result; 277 return NT_STATUS_OK; 278} 279 280NTSTATUS _wbint_DsGetDcName(pipes_struct *p, struct wbint_DsGetDcName *r) 281{ 282 struct winbindd_domain *domain = wb_child_domain(); 283 struct rpc_pipe_client *netlogon_pipe; 284 struct netr_DsRGetDCNameInfo *dc_info; 285 NTSTATUS status; 286 WERROR werr; 287 unsigned int orig_timeout; 288 289 if (domain == NULL) { 290 return dsgetdcname(p->mem_ctx, winbind_messaging_context(), 291 r->in.domain_name, r->in.domain_guid, 292 r->in.site_name ? r->in.site_name : "", 293 r->in.flags, 294 r->out.dc_info); 295 } 296 297 status = cm_connect_netlogon(domain, &netlogon_pipe); 298 299 if (!NT_STATUS_IS_OK(status)) { 300 DEBUG(10, ("Can't contact the NETLOGON pipe\n")); 301 return status; 302 } 303 304 /* This call can take a long time - allow the server to time out. 305 35 seconds should do it. */ 306 307 orig_timeout = rpccli_set_timeout(netlogon_pipe, 35000); 308 309 if (domain->active_directory) { 310 status = rpccli_netr_DsRGetDCName( 311 netlogon_pipe, p->mem_ctx, domain->dcname, 312 r->in.domain_name, NULL, r->in.domain_guid, 313 r->in.flags, r->out.dc_info, &werr); 314 if (NT_STATUS_IS_OK(status) && W_ERROR_IS_OK(werr)) { 315 goto done; 316 } 317 } 318 319 /* 320 * Fallback to less capable methods 321 */ 322 323 dc_info = talloc_zero(r->out.dc_info, struct netr_DsRGetDCNameInfo); 324 if (dc_info == NULL) { 325 status = NT_STATUS_NO_MEMORY; 326 goto done; 327 } 328 329 if (r->in.flags & DS_PDC_REQUIRED) { 330 status = rpccli_netr_GetDcName( 331 netlogon_pipe, p->mem_ctx, domain->dcname, 332 r->in.domain_name, &dc_info->dc_unc, &werr); 333 } else { 334 status = rpccli_netr_GetAnyDCName( 335 netlogon_pipe, p->mem_ctx, domain->dcname, 336 r->in.domain_name, &dc_info->dc_unc, &werr); 337 } 338 339 if (!NT_STATUS_IS_OK(status)) { 340 DEBUG(10, ("rpccli_netr_Get[Any]DCName failed: %s\n", 341 nt_errstr(status))); 342 goto done; 343 } 344 if (!W_ERROR_IS_OK(werr)) { 345 DEBUG(10, ("rpccli_netr_Get[Any]DCName failed: %s\n", 346 win_errstr(werr))); 347 status = werror_to_ntstatus(werr); 348 goto done; 349 } 350 351 *r->out.dc_info = dc_info; 352 status = NT_STATUS_OK; 353 354done: 355 /* And restore our original timeout. */ 356 rpccli_set_timeout(netlogon_pipe, orig_timeout); 357 358 return status; 359} 360 361NTSTATUS _wbint_LookupRids(pipes_struct *p, struct wbint_LookupRids *r) 362{ 363 struct winbindd_domain *domain = wb_child_domain(); 364 char *domain_name; 365 char **names; 366 enum lsa_SidType *types; 367 struct wbint_Principal *result; 368 NTSTATUS status; 369 int i; 370 371 if (domain == NULL) { 372 return NT_STATUS_REQUEST_NOT_ACCEPTED; 373 } 374 375 status = domain->methods->rids_to_names( 376 domain, talloc_tos(), &domain->sid, r->in.rids->rids, 377 r->in.rids->num_rids, &domain_name, &names, &types); 378 if (!NT_STATUS_IS_OK(status)) { 379 return status; 380 } 381 382 *r->out.domain_name = talloc_move(r->out.domain_name, &domain_name); 383 384 result = talloc_array(p->mem_ctx, struct wbint_Principal, 385 r->in.rids->num_rids); 386 if (result == NULL) { 387 return NT_STATUS_NO_MEMORY; 388 } 389 390 for (i=0; i<r->in.rids->num_rids; i++) { 391 sid_compose(&result[i].sid, &domain->sid, r->in.rids->rids[i]); 392 result[i].type = types[i]; 393 result[i].name = talloc_move(result, &names[i]); 394 } 395 TALLOC_FREE(types); 396 TALLOC_FREE(names); 397 398 r->out.names->num_principals = r->in.rids->num_rids; 399 r->out.names->principals = result; 400 return NT_STATUS_OK; 401} 402 403NTSTATUS _wbint_CheckMachineAccount(pipes_struct *p, 404 struct wbint_CheckMachineAccount *r) 405{ 406 struct winbindd_domain *domain; 407 int num_retries = 0; 408 NTSTATUS status; 409 410 domain = wb_child_domain(); 411 if (domain == NULL) { 412 return NT_STATUS_REQUEST_NOT_ACCEPTED; 413 } 414 415again: 416 invalidate_cm_connection(&domain->conn); 417 418 { 419 struct rpc_pipe_client *netlogon_pipe; 420 status = cm_connect_netlogon(domain, &netlogon_pipe); 421 } 422 423 /* There is a race condition between fetching the trust account 424 password and the periodic machine password change. So it's 425 possible that the trust account password has been changed on us. 426 We are returned NT_STATUS_ACCESS_DENIED if this happens. */ 427 428#define MAX_RETRIES 3 429 430 if ((num_retries < MAX_RETRIES) 431 && NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) { 432 num_retries++; 433 goto again; 434 } 435 436 if (!NT_STATUS_IS_OK(status)) { 437 DEBUG(3, ("could not open handle to NETLOGON pipe\n")); 438 goto done; 439 } 440 441 /* Pass back result code - zero for success, other values for 442 specific failures. */ 443 444 DEBUG(3,("domain %s secret is %s\n", domain->name, 445 NT_STATUS_IS_OK(status) ? "good" : "bad")); 446 447 done: 448 DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2, 449 ("Checking the trust account password for domain %s returned %s\n", 450 domain->name, nt_errstr(status))); 451 452 return status; 453} 454 455NTSTATUS _wbint_ChangeMachineAccount(pipes_struct *p, 456 struct wbint_ChangeMachineAccount *r) 457{ 458 struct winbindd_domain *domain; 459 int num_retries = 0; 460 NTSTATUS status; 461 struct rpc_pipe_client *netlogon_pipe; 462 TALLOC_CTX *tmp_ctx; 463 464again: 465 domain = wb_child_domain(); 466 if (domain == NULL) { 467 return NT_STATUS_REQUEST_NOT_ACCEPTED; 468 } 469 470 invalidate_cm_connection(&domain->conn); 471 472 { 473 status = cm_connect_netlogon(domain, &netlogon_pipe); 474 } 475 476 /* There is a race condition between fetching the trust account 477 password and the periodic machine password change. So it's 478 possible that the trust account password has been changed on us. 479 We are returned NT_STATUS_ACCESS_DENIED if this happens. */ 480 481#define MAX_RETRIES 3 482 483 if ((num_retries < MAX_RETRIES) 484 && NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) { 485 num_retries++; 486 goto again; 487 } 488 489 if (!NT_STATUS_IS_OK(status)) { 490 DEBUG(3, ("could not open handle to NETLOGON pipe\n")); 491 goto done; 492 } 493 494 tmp_ctx = talloc_new(p->mem_ctx); 495 496 status = trust_pw_find_change_and_store_it(netlogon_pipe, 497 tmp_ctx, 498 domain->name); 499 talloc_destroy(tmp_ctx); 500 501 /* Pass back result code - zero for success, other values for 502 specific failures. */ 503 504 DEBUG(3,("domain %s secret %s\n", domain->name, 505 NT_STATUS_IS_OK(status) ? "changed" : "unchanged")); 506 507 done: 508 DEBUG(NT_STATUS_IS_OK(status) ? 5 : 2, 509 ("Changing the trust account password for domain %s returned %s\n", 510 domain->name, nt_errstr(status))); 511 512 return status; 513} 514 515NTSTATUS _wbint_PingDc(pipes_struct *p, struct wbint_PingDc *r) 516{ 517 NTSTATUS status; 518 struct winbindd_domain *domain; 519 struct rpc_pipe_client *netlogon_pipe; 520 union netr_CONTROL_QUERY_INFORMATION info; 521 WERROR werr; 522 fstring logon_server; 523 524 domain = wb_child_domain(); 525 if (domain == NULL) { 526 return NT_STATUS_REQUEST_NOT_ACCEPTED; 527 } 528 529 status = cm_connect_netlogon(domain, &netlogon_pipe); 530 if (!NT_STATUS_IS_OK(status)) { 531 DEBUG(3, ("could not open handle to NETLOGON pipe\n")); 532 return status; 533 } 534 535 fstr_sprintf(logon_server, "\\\\%s", domain->dcname); 536 537 /* 538 * This provokes a WERR_NOT_SUPPORTED error message. This is 539 * documented in the wspp docs. I could not get a successful 540 * call to work, but the main point here is testing that the 541 * netlogon pipe works. 542 */ 543 status = rpccli_netr_LogonControl(netlogon_pipe, p->mem_ctx, 544 logon_server, NETLOGON_CONTROL_QUERY, 545 2, &info, &werr); 546 547 if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) { 548 DEBUG(2, ("rpccli_netr_LogonControl timed out\n")); 549 invalidate_cm_connection(&domain->conn); 550 return status; 551 } 552 553 if (!NT_STATUS_EQUAL(status, NT_STATUS_CTL_FILE_NOT_SUPPORTED)) { 554 DEBUG(2, ("rpccli_netr_LogonControl returned %s, expected " 555 "NT_STATUS_CTL_FILE_NOT_SUPPORTED\n", 556 nt_errstr(status))); 557 return status; 558 } 559 560 DEBUG(5, ("winbindd_dual_ping_dc succeeded\n")); 561 return NT_STATUS_OK; 562} 563 564NTSTATUS _wbint_SetMapping(pipes_struct *p, struct wbint_SetMapping *r) 565{ 566 struct id_map map; 567 568 map.sid = r->in.sid; 569 map.xid.id = r->in.id; 570 map.status = ID_MAPPED; 571 572 switch (r->in.type) { 573 case WBINT_ID_TYPE_UID: 574 map.xid.type = ID_TYPE_UID; 575 break; 576 case WBINT_ID_TYPE_GID: 577 map.xid.type = ID_TYPE_GID; 578 break; 579 default: 580 return NT_STATUS_INVALID_PARAMETER; 581 } 582 583 return idmap_set_mapping(&map); 584} 585 586NTSTATUS _wbint_RemoveMapping(pipes_struct *p, struct wbint_RemoveMapping *r) 587{ 588 struct id_map map; 589 590 map.sid = r->in.sid; 591 map.xid.id = r->in.id; 592 map.status = ID_MAPPED; 593 594 switch (r->in.type) { 595 case WBINT_ID_TYPE_UID: 596 map.xid.type = ID_TYPE_UID; 597 break; 598 case WBINT_ID_TYPE_GID: 599 map.xid.type = ID_TYPE_GID; 600 break; 601 default: 602 return NT_STATUS_INVALID_PARAMETER; 603 } 604 605 return idmap_remove_mapping(&map); 606} 607 608NTSTATUS _wbint_SetHWM(pipes_struct *p, struct wbint_SetHWM *r) 609{ 610 struct unixid id; 611 NTSTATUS status; 612 613 id.id = r->in.id; 614 615 switch (r->in.type) { 616 case WBINT_ID_TYPE_UID: 617 id.type = ID_TYPE_UID; 618 status = idmap_set_uid_hwm(&id); 619 break; 620 case WBINT_ID_TYPE_GID: 621 id.type = ID_TYPE_GID; 622 status = idmap_set_gid_hwm(&id); 623 break; 624 default: 625 status = NT_STATUS_INVALID_PARAMETER; 626 break; 627 } 628 return status; 629} 630