r11517: Cleanup time, this looks larger than it is. This mainly gets rid of
[kai/samba.git] / source4 / winbind / wb_sid2domain.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    Find and init a domain struct for a SID
5
6    Copyright (C) Volker Lendecke 2005
7    
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #include "includes.h"
24 #include "libcli/composite/composite.h"
25 #include "winbind/wb_server.h"
26 #include "smbd/service_stream.h"
27 #include "smbd/service_task.h"
28 #include "lib/events/events.h"
29 #include "librpc/gen_ndr/nbt.h"
30 #include "librpc/gen_ndr/ndr_netlogon.h"
31 #include "winbind/wb_async_helpers.h"
32 #include "include/dlinklist.h"
33
34 static const char *sam_name(void)
35 {
36         if (lp_server_role() == ROLE_STANDALONE) {
37                 return lp_netbios_name();
38         }
39         return lp_workgroup();
40 }
41
42 static struct wbsrv_domain *find_primary_domain(struct wbsrv_service *service)
43 {
44         const char *my_domain_name = sam_name();
45         struct wbsrv_domain *domain;
46
47         for (domain = service->domains; domain!=NULL; domain = domain->next) {
48                 if (strcasecmp(domain->name, my_domain_name) == 0) {
49                         break;
50                 }
51         }
52         return domain;
53 }
54
55 static struct wbsrv_domain *find_domain_from_sid(struct wbsrv_service *service,
56                                                  const struct dom_sid *sid)
57 {
58         struct wbsrv_domain *domain;
59
60         for (domain = service->domains; domain!=NULL; domain = domain->next) {
61                 if (dom_sid_equal(domain->sid, sid)) {
62                         break;
63                 }
64                 if (dom_sid_in_domain(domain->sid, sid)) {
65                         break;
66                 }
67         }
68         return domain;
69 }
70
71 struct sid2domain_state {
72         struct composite_context *ctx;
73         struct wbsrv_service *service;
74         const struct dom_sid *sid;
75
76         const char *domain_name;
77         const char *dc_name;
78         struct dom_sid *domain_sid;
79
80         struct wbsrv_domain *my_domain;
81         struct wbsrv_domain *result;
82
83         struct netr_DsRGetDCName dsr_getdcname;
84         struct netr_GetAnyDCName getdcname;
85 };
86
87 static void sid2domain_recv_name(struct composite_context *ctx);
88 static void sid2domain_recv_dsr_dcname(struct rpc_request *req);
89 static void sid2domain_recv_dcname(struct composite_context *ctx);
90 static void sid2domain_recv_init(struct composite_context *ctx);
91
92 struct composite_context *wb_sid2domain_send(TALLOC_CTX *mem_ctx,
93                                              struct wbsrv_service *service,
94                                              const struct dom_sid *sid)
95 {
96         struct composite_context *result, *ctx;
97         struct sid2domain_state *state;
98
99         result = talloc_zero(mem_ctx, struct composite_context);
100         if (result == NULL) goto failed;
101         result->state = COMPOSITE_STATE_IN_PROGRESS;
102         result->async.fn = NULL;
103         result->event_ctx = service->task->event_ctx;
104
105         state = talloc(result, struct sid2domain_state);
106         if (state == NULL) goto failed;
107         state->ctx = result;
108         result->private_data = state;
109
110         state->service = service;
111         state->sid = dom_sid_dup(state, sid);
112         if (state->sid == NULL) goto failed;
113
114         state->result = find_domain_from_sid(service, sid);
115         if (state->result != NULL) {
116                 result->status = NT_STATUS_OK;
117                 if (!state->result->initialized) {
118                         ctx = wb_init_domain_send(service, state->result);
119                         if (ctx == NULL) goto failed;
120                         ctx->async.fn = sid2domain_recv_init;
121                         ctx->async.private_data = state;
122                         return result;
123                 }
124                 composite_trigger_done(result);
125                 return result;
126         }
127
128         state->my_domain = find_primary_domain(service);
129         if (state->my_domain == NULL) {
130                 result->status = NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
131                 composite_trigger_error(result);
132                 return result;
133         }
134
135         ctx = wb_cmd_lookupsid_send(state, service, state->sid);
136         if (ctx == NULL) goto failed;
137         ctx->async.fn = sid2domain_recv_name;
138         ctx->async.private_data = state;
139         return result;
140
141  failed:
142         talloc_free(result);
143         return NULL;
144 }
145
146 static void sid2domain_recv_name(struct composite_context *ctx)
147 {
148         struct sid2domain_state *state =
149                 talloc_get_type(ctx->async.private_data,
150                                 struct sid2domain_state);
151         struct rpc_request *req;
152         struct wb_sid_object *name;
153
154         state->ctx->status = wb_cmd_lookupsid_recv(ctx, state, &name);
155         if (!composite_is_ok(state->ctx)) return;
156
157         if (name->type == SID_NAME_UNKNOWN) {
158                 composite_error(state->ctx, NT_STATUS_NO_SUCH_DOMAIN);
159                 return;
160         }
161
162         state->domain_name = name->domain;
163         state->domain_sid = dom_sid_dup(state, state->sid);
164         if (composite_nomem(state->domain_sid, state->ctx)) return;
165
166         if (name->type != SID_NAME_DOMAIN) {
167                 state->domain_sid->num_auths -= 1;
168         }
169
170         state->dsr_getdcname.in.server_unc =
171                 talloc_asprintf(state, "\\\\%s", state->my_domain->dcname);
172         if (composite_nomem(state->dsr_getdcname.in.server_unc,
173                             state->ctx)) return;
174
175         state->dsr_getdcname.in.domain_name = state->domain_name;
176         state->dsr_getdcname.in.domain_guid = NULL;
177         state->dsr_getdcname.in.site_guid = NULL;
178         state->dsr_getdcname.in.flags = 0x40000000;
179
180         req = dcerpc_netr_DsRGetDCName_send(state->my_domain->netlogon_pipe,
181                                             state, &state->dsr_getdcname);
182         composite_continue_rpc(state->ctx, req, sid2domain_recv_dsr_dcname,
183                                state);
184 }
185
186 static void sid2domain_recv_dsr_dcname(struct rpc_request *req)
187 {
188         struct sid2domain_state *state =
189                 talloc_get_type(req->async.private,
190                                 struct sid2domain_state);
191         struct composite_context *ctx;
192
193         state->ctx->status = dcerpc_ndr_request_recv(req);
194         if (!NT_STATUS_IS_OK(state->ctx->status)) {
195                 DEBUG(9, ("dcerpc_ndr_request_recv returned %s\n",
196                           nt_errstr(state->ctx->status)));
197                 goto fallback;
198         }
199
200         state->ctx->status =
201                 werror_to_ntstatus(state->dsr_getdcname.out.result);
202         if (!NT_STATUS_IS_OK(state->ctx->status)) {
203                 DEBUG(9, ("dsrgetdcname returned %s\n",
204                           nt_errstr(state->ctx->status)));
205                 goto fallback;
206         }
207
208         DEBUG(0, ("unc: %s, addr: %s, addr_type: %d, domain_name: %s, "
209                   "forest_name: %s\n", 
210                   state->dsr_getdcname.out.info->dc_unc, 
211                   state->dsr_getdcname.out.info->dc_address, 
212                   state->dsr_getdcname.out.info->dc_address_type, 
213                   state->dsr_getdcname.out.info->domain_name,
214                   state->dsr_getdcname.out.info->forest_name));
215
216  fallback:
217
218         ctx = wb_cmd_getdcname_send(state, state->service, state->domain_name);
219         composite_continue(state->ctx, ctx, sid2domain_recv_dcname, state);
220 }
221
222 static void sid2domain_recv_dcname(struct composite_context *ctx)
223 {
224         struct sid2domain_state *state =
225                 talloc_get_type(ctx->async.private_data,
226                                 struct sid2domain_state);
227
228         state->ctx->status = wb_cmd_getdcname_recv(ctx, state,
229                                                    &state->dc_name);
230         if (!composite_is_ok(state->ctx)) return;
231
232         state->result = talloc_zero(state, struct wbsrv_domain);
233         if (composite_nomem(state->result, state->ctx)) return;
234
235         state->result->name = talloc_steal(state->result, state->domain_name);
236         state->result->sid = talloc_steal(state->result, state->domain_sid);
237         state->result->dcname = talloc_steal(state->result, state->dc_name);
238
239         state->result->schannel_creds = cli_credentials_init(state->result);
240         if (composite_nomem(state->result->schannel_creds, state->ctx)) return;
241         cli_credentials_set_conf(state->result->schannel_creds);
242         cli_credentials_set_machine_account(state->result->schannel_creds);
243
244         talloc_steal(state->service, state->result);
245         DLIST_ADD(state->service->domains, state->result);
246
247         ctx = wb_init_domain_send(state->service, state->result);
248         composite_continue(state->ctx, ctx, sid2domain_recv_init, state);
249 }
250
251 static void sid2domain_recv_init(struct composite_context *ctx)
252 {
253         struct sid2domain_state *state =
254                 talloc_get_type(ctx->async.private_data,
255                                 struct sid2domain_state);
256
257         state->ctx->status = wb_init_domain_recv(ctx);
258         if (!composite_is_ok(state->ctx)) {
259                 DEBUG(10, ("Could not init domain\n"));
260                 return;
261         }
262
263         composite_done(state->ctx);
264 }
265
266 NTSTATUS wb_sid2domain_recv(struct composite_context *ctx,
267                             struct wbsrv_domain **result)
268 {
269         NTSTATUS status = composite_wait(ctx);
270         if (NT_STATUS_IS_OK(status)) {
271                 struct sid2domain_state *state =
272                         talloc_get_type(ctx->private_data,
273                                         struct sid2domain_state);
274                 *result = state->result;
275         }
276         talloc_free(ctx);
277         return status;
278 }
279
280 NTSTATUS wb_sid2domain(TALLOC_CTX *mem_ctx, struct wbsrv_service *service,
281                        const struct dom_sid *sid,
282                        struct wbsrv_domain **result)
283 {
284         struct composite_context *c = wb_sid2domain_send(mem_ctx, service,
285                                                          sid);
286         return wb_sid2domain_recv(c, result);
287 }