2 Unix SMB/CIFS implementation.
4 In-Child server implementation of the routines defined in wbint.idl
6 Copyright (C) Volker Lendecke 2009
7 Copyright (C) Guenther Deschner 2009
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.
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.
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/>.
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"
29 void _wbint_Ping(pipes_struct *p, struct wbint_Ping *r)
31 *r->out.out_data = r->in.in_data;
34 NTSTATUS _wbint_LookupSid(pipes_struct *p, struct wbint_LookupSid *r)
36 struct winbindd_domain *domain = wb_child_domain();
39 enum lsa_SidType type;
43 return NT_STATUS_REQUEST_NOT_ACCEPTED;
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)) {
52 *r->out.domain = dom_name;
58 NTSTATUS _wbint_LookupName(pipes_struct *p, struct wbint_LookupName *r)
60 struct winbindd_domain *domain = wb_child_domain();
63 return NT_STATUS_REQUEST_NOT_ACCEPTED;
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);
71 NTSTATUS _wbint_Sid2Uid(pipes_struct *p, struct wbint_Sid2Uid *r)
76 status = idmap_sid_to_uid(r->in.dom_name ? r->in.dom_name : "",
78 if (!NT_STATUS_IS_OK(status)) {
85 NTSTATUS _wbint_Sid2Gid(pipes_struct *p, struct wbint_Sid2Gid *r)
90 status = idmap_sid_to_gid(r->in.dom_name ? r->in.dom_name : "",
92 if (!NT_STATUS_IS_OK(status)) {
99 NTSTATUS _wbint_Uid2Sid(pipes_struct *p, struct wbint_Uid2Sid *r)
101 return idmap_uid_to_sid(r->in.dom_name ? r->in.dom_name : "",
102 r->out.sid, r->in.uid);
105 NTSTATUS _wbint_Gid2Sid(pipes_struct *p, struct wbint_Gid2Sid *r)
107 return idmap_gid_to_sid(r->in.dom_name ? r->in.dom_name : "",
108 r->out.sid, r->in.gid);
111 NTSTATUS _wbint_AllocateUid(pipes_struct *p, struct wbint_AllocateUid *r)
116 status = idmap_allocate_uid(&xid);
117 if (!NT_STATUS_IS_OK(status)) {
120 *r->out.uid = xid.id;
124 NTSTATUS _wbint_AllocateGid(pipes_struct *p, struct wbint_AllocateGid *r)
129 status = idmap_allocate_gid(&xid);
130 if (!NT_STATUS_IS_OK(status)) {
133 *r->out.gid = xid.id;
137 NTSTATUS _wbint_QueryUser(pipes_struct *p, struct wbint_QueryUser *r)
139 struct winbindd_domain *domain = wb_child_domain();
141 if (domain == NULL) {
142 return NT_STATUS_REQUEST_NOT_ACCEPTED;
145 return domain->methods->query_user(domain, p->mem_ctx, r->in.sid,
149 NTSTATUS _wbint_LookupUserAliases(pipes_struct *p,
150 struct wbint_LookupUserAliases *r)
152 struct winbindd_domain *domain = wb_child_domain();
154 if (domain == NULL) {
155 return NT_STATUS_REQUEST_NOT_ACCEPTED;
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);
163 NTSTATUS _wbint_LookupUserGroups(pipes_struct *p,
164 struct wbint_LookupUserGroups *r)
166 struct winbindd_domain *domain = wb_child_domain();
168 if (domain == NULL) {
169 return NT_STATUS_REQUEST_NOT_ACCEPTED;
172 return domain->methods->lookup_usergroups(
173 domain, p->mem_ctx, r->in.sid,
174 &r->out.sids->num_sids, &r->out.sids->sids);
177 NTSTATUS _wbint_QuerySequenceNumber(pipes_struct *p,
178 struct wbint_QuerySequenceNumber *r)
180 struct winbindd_domain *domain = wb_child_domain();
182 if (domain == NULL) {
183 return NT_STATUS_REQUEST_NOT_ACCEPTED;
186 return domain->methods->sequence_number(domain, r->out.sequence);
189 NTSTATUS _wbint_LookupGroupMembers(pipes_struct *p,
190 struct wbint_LookupGroupMembers *r)
192 struct winbindd_domain *domain = wb_child_domain();
193 uint32_t i, num_names;
194 struct dom_sid *sid_mem;
196 uint32_t *name_types;
199 if (domain == NULL) {
200 return NT_STATUS_REQUEST_NOT_ACCEPTED;
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)) {
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;
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];
227 NTSTATUS _wbint_QueryUserList(pipes_struct *p, struct wbint_QueryUserList *r)
229 struct winbindd_domain *domain = wb_child_domain();
231 if (domain == NULL) {
232 return NT_STATUS_REQUEST_NOT_ACCEPTED;
235 return domain->methods->query_user_list(
236 domain, p->mem_ctx, &r->out.users->num_userinfos,
237 &r->out.users->userinfos);
240 NTSTATUS _wbint_QueryGroupList(pipes_struct *p, struct wbint_QueryGroupList *r)
242 struct winbindd_domain *domain = wb_child_domain();
243 uint32_t i, num_groups;
244 struct acct_info *groups;
245 struct wbint_Principal *result;
248 if (domain == NULL) {
249 return NT_STATUS_REQUEST_NOT_ACCEPTED;
252 status = domain->methods->enum_dom_groups(domain, talloc_tos(),
253 &num_groups, &groups);
254 if (!NT_STATUS_IS_OK(status)) {
258 result = talloc_array(r->out.groups, struct wbint_Principal,
260 if (result == NULL) {
261 return NT_STATUS_NO_MEMORY;
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) {
271 return NT_STATUS_NO_MEMORY;
275 r->out.groups->num_principals = num_groups;
276 r->out.groups->principals = result;
282 NTSTATUS _wbint_DsGetDcName(pipes_struct *p, struct wbint_DsGetDcName *r)
284 struct winbindd_domain *domain = wb_child_domain();
285 struct rpc_pipe_client *netlogon_pipe;
286 struct netr_DsRGetDCNameInfo *dc_info;
289 unsigned int orig_timeout;
291 if (domain == NULL) {
292 return dsgetdcname(p->mem_ctx, winbind_messaging_context(),
293 r->in.domain_name, r->in.domain_guid,
294 r->in.site_name ? r->in.site_name : "",
299 status = cm_connect_netlogon(domain, &netlogon_pipe);
301 if (!NT_STATUS_IS_OK(status)) {
302 DEBUG(10, ("Can't contact the NETLOGON pipe\n"));
306 /* This call can take a long time - allow the server to time out.
307 35 seconds should do it. */
309 orig_timeout = rpccli_set_timeout(netlogon_pipe, 35000);
311 if (domain->active_directory) {
312 status = rpccli_netr_DsRGetDCName(
313 netlogon_pipe, p->mem_ctx, domain->dcname,
314 r->in.domain_name, NULL, r->in.domain_guid,
315 r->in.flags, r->out.dc_info, &werr);
316 if (NT_STATUS_IS_OK(status) && W_ERROR_IS_OK(werr)) {
322 * Fallback to less capable methods
325 dc_info = talloc_zero(r->out.dc_info, struct netr_DsRGetDCNameInfo);
326 if (dc_info == NULL) {
327 status = NT_STATUS_NO_MEMORY;
331 if (r->in.flags & DS_PDC_REQUIRED) {
332 status = rpccli_netr_GetDcName(
333 netlogon_pipe, p->mem_ctx, domain->dcname,
334 r->in.domain_name, &dc_info->dc_unc, &werr);
336 status = rpccli_netr_GetAnyDCName(
337 netlogon_pipe, p->mem_ctx, domain->dcname,
338 r->in.domain_name, &dc_info->dc_unc, &werr);
341 if (!NT_STATUS_IS_OK(status)) {
342 DEBUG(10, ("rpccli_netr_Get[Any]DCName failed: %s\n",
346 if (!W_ERROR_IS_OK(werr)) {
347 DEBUG(10, ("rpccli_netr_Get[Any]DCName failed: %s\n",
349 status = werror_to_ntstatus(werr);
353 *r->out.dc_info = dc_info;
354 status = NT_STATUS_OK;
357 /* And restore our original timeout. */
358 rpccli_set_timeout(netlogon_pipe, orig_timeout);
363 NTSTATUS _wbint_LookupRids(pipes_struct *p, struct wbint_LookupRids *r)
365 struct winbindd_domain *domain = wb_child_domain();
368 enum lsa_SidType *types;
369 struct wbint_Principal *result;
373 if (domain == NULL) {
374 return NT_STATUS_REQUEST_NOT_ACCEPTED;
377 status = domain->methods->rids_to_names(
378 domain, talloc_tos(), &domain->sid, r->in.rids->rids,
379 r->in.rids->num_rids, &domain_name, &names, &types);
380 if (!NT_STATUS_IS_OK(status)) {
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;
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]);
398 r->out.names->num_principals = r->in.rids->num_rids;
399 r->out.names->principals = result;
403 NTSTATUS _wbint_CheckMachineAccount(pipes_struct *p,
404 struct wbint_CheckMachineAccount *r)
406 struct winbindd_domain *domain;
410 domain = wb_child_domain();
411 if (domain == NULL) {
412 return NT_STATUS_REQUEST_NOT_ACCEPTED;
416 invalidate_cm_connection(&domain->conn);
419 struct rpc_pipe_client *netlogon_pipe;
420 status = cm_connect_netlogon(domain, &netlogon_pipe);
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. */
428 #define MAX_RETRIES 3
430 if ((num_retries < MAX_RETRIES)
431 && NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
436 if (!NT_STATUS_IS_OK(status)) {
437 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
441 /* Pass back result code - zero for success, other values for
442 specific failures. */
444 DEBUG(3,("domain %s secret is %s\n", domain->name,
445 NT_STATUS_IS_OK(status) ? "good" : "bad"));
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)));
455 NTSTATUS _wbint_ChangeMachineAccount(pipes_struct *p,
456 struct wbint_ChangeMachineAccount *r)
458 struct winbindd_domain *domain;
461 struct rpc_pipe_client *netlogon_pipe;
465 domain = wb_child_domain();
466 if (domain == NULL) {
467 return NT_STATUS_REQUEST_NOT_ACCEPTED;
470 invalidate_cm_connection(&domain->conn);
473 status = cm_connect_netlogon(domain, &netlogon_pipe);
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. */
481 #define MAX_RETRIES 3
483 if ((num_retries < MAX_RETRIES)
484 && NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) {
489 if (!NT_STATUS_IS_OK(status)) {
490 DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
494 tmp_ctx = talloc_new(p->mem_ctx);
496 status = trust_pw_find_change_and_store_it(netlogon_pipe,
499 talloc_destroy(tmp_ctx);
501 /* Pass back result code - zero for success, other values for
502 specific failures. */
504 DEBUG(3,("domain %s secret %s\n", domain->name,
505 NT_STATUS_IS_OK(status) ? "changed" : "unchanged"));
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)));
515 NTSTATUS _wbint_PingDc(pipes_struct *p, struct wbint_PingDc *r)
518 struct winbindd_domain *domain;
519 struct rpc_pipe_client *netlogon_pipe;
520 union netr_CONTROL_QUERY_INFORMATION info;
522 fstring logon_server;
524 domain = wb_child_domain();
525 if (domain == NULL) {
526 return NT_STATUS_REQUEST_NOT_ACCEPTED;
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"));
535 fstr_sprintf(logon_server, "\\\\%s", domain->dcname);
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.
543 status = rpccli_netr_LogonControl(netlogon_pipe, p->mem_ctx,
544 logon_server, NETLOGON_CONTROL_QUERY,
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);
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",
560 DEBUG(5, ("winbindd_dual_ping_dc succeeded\n"));
564 NTSTATUS _wbint_SetMapping(pipes_struct *p, struct wbint_SetMapping *r)
569 map.xid.id = r->in.id;
570 map.status = ID_MAPPED;
572 switch (r->in.type) {
573 case WBINT_ID_TYPE_UID:
574 map.xid.type = ID_TYPE_UID;
576 case WBINT_ID_TYPE_GID:
577 map.xid.type = ID_TYPE_GID;
580 return NT_STATUS_INVALID_PARAMETER;
583 return idmap_set_mapping(&map);
586 NTSTATUS _wbint_RemoveMapping(pipes_struct *p, struct wbint_RemoveMapping *r)
591 map.xid.id = r->in.id;
592 map.status = ID_MAPPED;
594 switch (r->in.type) {
595 case WBINT_ID_TYPE_UID:
596 map.xid.type = ID_TYPE_UID;
598 case WBINT_ID_TYPE_GID:
599 map.xid.type = ID_TYPE_GID;
602 return NT_STATUS_INVALID_PARAMETER;
605 return idmap_remove_mapping(&map);
608 NTSTATUS _wbint_SetHWM(pipes_struct *p, struct wbint_SetHWM *r)
615 switch (r->in.type) {
616 case WBINT_ID_TYPE_UID:
617 id.type = ID_TYPE_UID;
618 status = idmap_set_uid_hwm(&id);
621 id.type = ID_TYPE_GID;
622 status = idmap_set_gid_hwm(&id);
625 status = NT_STATUS_INVALID_PARAMETER;