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