1/*
2   Unix SMB/CIFS implementation.
3   async gettoken
4   Copyright (C) Volker Lendecke 2009
5
6   This program is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation; either version 3 of the License, or
9   (at your option) any later version.
10
11   This program is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   GNU General Public License for more details.
15
16   You should have received a copy of the GNU General Public License
17   along with this program.  If not, see <http://www.gnu.org/licenses/>.
18*/
19
20#include "includes.h"
21#include "winbindd.h"
22#include "librpc/gen_ndr/cli_wbint.h"
23
24struct wb_gettoken_state {
25	struct tevent_context *ev;
26	struct dom_sid usersid;
27	int num_sids;
28	struct dom_sid *sids;
29};
30
31static bool wb_add_rids_to_sids(TALLOC_CTX *mem_ctx,
32				int *pnum_sids, struct dom_sid **psids,
33				const struct dom_sid *domain_sid,
34				int num_rids, uint32_t *rids);
35
36static void wb_gettoken_gotgroups(struct tevent_req *subreq);
37static void wb_gettoken_gotlocalgroups(struct tevent_req *subreq);
38static void wb_gettoken_gotbuiltins(struct tevent_req *subreq);
39
40struct tevent_req *wb_gettoken_send(TALLOC_CTX *mem_ctx,
41				    struct tevent_context *ev,
42				    const struct dom_sid *sid)
43{
44	struct tevent_req *req, *subreq;
45	struct wb_gettoken_state *state;
46	struct winbindd_domain *domain;
47
48	req = tevent_req_create(mem_ctx, &state, struct wb_gettoken_state);
49	if (req == NULL) {
50		return NULL;
51	}
52	sid_copy(&state->usersid, sid);
53	state->ev = ev;
54
55	domain = find_domain_from_sid_noinit(sid);
56	if (domain == NULL) {
57		DEBUG(5, ("Could not find domain from SID %s\n",
58			  sid_string_dbg(sid)));
59		tevent_req_nterror(req, NT_STATUS_NO_SUCH_USER);
60		return tevent_req_post(req, ev);
61	}
62
63	if (lp_winbind_trusted_domains_only() && domain->primary) {
64		DEBUG(7, ("wb_gettoken: My domain -- rejecting getgroups() "
65			  "for %s.\n", sid_string_tos(sid)));
66		tevent_req_nterror(req, NT_STATUS_NO_SUCH_USER);
67		return tevent_req_post(req, ev);
68	}
69
70	subreq = wb_lookupusergroups_send(state, ev, domain, &state->usersid);
71	if (tevent_req_nomem(subreq, req)) {
72		return tevent_req_post(req, ev);
73	}
74	tevent_req_set_callback(subreq, wb_gettoken_gotgroups, req);
75	return req;
76}
77
78static void wb_gettoken_gotgroups(struct tevent_req *subreq)
79{
80	struct tevent_req *req = tevent_req_callback_data(
81		subreq, struct tevent_req);
82	struct wb_gettoken_state *state = tevent_req_data(
83		req, struct wb_gettoken_state);
84        struct dom_sid *sids;
85	struct winbindd_domain *domain;
86	NTSTATUS status;
87
88	status = wb_lookupusergroups_recv(subreq, state, &state->num_sids,
89					  &state->sids);
90	TALLOC_FREE(subreq);
91	if (!NT_STATUS_IS_OK(status)) {
92		tevent_req_nterror(req, status);
93		return;
94	}
95
96	sids = talloc_realloc(state, state->sids, struct dom_sid,
97			      state->num_sids + 1);
98	if (tevent_req_nomem(sids, req)) {
99		return;
100	}
101	memmove(&sids[1], &sids[0], state->num_sids * sizeof(sids[0]));
102	sid_copy(&sids[0], &state->usersid);
103	state->num_sids += 1;
104	state->sids = sids;
105
106	/*
107	 * Expand our domain's aliases
108	 */
109	domain = find_domain_from_sid_noinit(get_global_sam_sid());
110	if (domain == NULL) {
111		tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
112		return;
113	}
114
115	subreq = wb_lookupuseraliases_send(state, state->ev, domain,
116					   state->num_sids, state->sids);
117	if (tevent_req_nomem(subreq, req)) {
118		return;
119	}
120	tevent_req_set_callback(subreq, wb_gettoken_gotlocalgroups, req);
121}
122
123static void wb_gettoken_gotlocalgroups(struct tevent_req *subreq)
124{
125	struct tevent_req *req = tevent_req_callback_data(
126		subreq, struct tevent_req);
127	struct wb_gettoken_state *state = tevent_req_data(
128		req, struct wb_gettoken_state);
129	uint32_t num_rids;
130	uint32_t *rids;
131	struct winbindd_domain *domain;
132	NTSTATUS status;
133
134	status = wb_lookupuseraliases_recv(subreq, state, &num_rids, &rids);
135	TALLOC_FREE(subreq);
136	if (!NT_STATUS_IS_OK(status)) {
137		tevent_req_nterror(req, status);
138		return;
139	}
140	domain = find_domain_from_sid_noinit(get_global_sam_sid());
141	if (!wb_add_rids_to_sids(state, &state->num_sids, &state->sids,
142				 &domain->sid, num_rids, rids)) {
143		tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
144		return;
145	}
146	TALLOC_FREE(rids);
147
148	/*
149	 * Now expand the builtin groups
150	 */
151
152	domain = find_builtin_domain();
153	if (domain == NULL) {
154		tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
155		return;
156	}
157
158	subreq = wb_lookupuseraliases_send(state, state->ev, domain,
159					   state->num_sids, state->sids);
160	if (tevent_req_nomem(subreq, req)) {
161		return;
162	}
163	tevent_req_set_callback(subreq, wb_gettoken_gotbuiltins, req);
164}
165
166static void wb_gettoken_gotbuiltins(struct tevent_req *subreq)
167{
168	struct tevent_req *req = tevent_req_callback_data(
169		subreq, struct tevent_req);
170	struct wb_gettoken_state *state = tevent_req_data(
171		req, struct wb_gettoken_state);
172	uint32_t num_rids;
173        uint32_t *rids;
174	NTSTATUS status;
175
176	status = wb_lookupuseraliases_recv(subreq, state, &num_rids, &rids);
177	TALLOC_FREE(subreq);
178	if (!NT_STATUS_IS_OK(status)) {
179		tevent_req_nterror(req, status);
180		return;
181	}
182	if (!wb_add_rids_to_sids(state, &state->num_sids, &state->sids,
183				 &global_sid_Builtin, num_rids, rids)) {
184		tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
185		return;
186	}
187	tevent_req_done(req);
188}
189
190NTSTATUS wb_gettoken_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
191			  int *num_sids, struct dom_sid **sids)
192{
193	struct wb_gettoken_state *state = tevent_req_data(
194		req, struct wb_gettoken_state);
195	NTSTATUS status;
196
197	if (tevent_req_is_nterror(req, &status)) {
198		return status;
199	}
200	*num_sids = state->num_sids;
201	*sids = talloc_move(mem_ctx, &state->sids);
202	return NT_STATUS_OK;
203}
204
205static bool wb_add_rids_to_sids(TALLOC_CTX *mem_ctx,
206				int *pnum_sids, struct dom_sid **psids,
207				const struct dom_sid *domain_sid,
208				int num_rids, uint32_t *rids)
209{
210	struct dom_sid *sids;
211	int i;
212
213	sids = talloc_realloc(mem_ctx, *psids, struct dom_sid,
214			      *pnum_sids + num_rids);
215	if (sids == NULL) {
216		return false;
217	}
218	for (i=0; i<num_rids; i++) {
219		sid_compose(&sids[i+*pnum_sids], domain_sid, rids[i]);
220	}
221
222	*pnum_sids += num_rids;
223	*psids = sids;
224	return true;
225}
226