r11193: Implement wbinfo -m
[jelmer/samba4-debian.git] / source / 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
84 static void sid2domain_recv_name(struct composite_context *ctx);
85 static void sid2domain_recv_dcname(struct composite_context *ctx);
86 static void sid2domain_recv_init(struct composite_context *ctx);
87
88 struct composite_context *wb_sid2domain_send(struct wbsrv_service *service,
89                                              const struct dom_sid *sid)
90 {
91         struct composite_context *result, *ctx;
92         struct sid2domain_state *state;
93
94         result = talloc_zero(NULL, struct composite_context);
95         if (result == NULL) goto failed;
96         result->state = COMPOSITE_STATE_IN_PROGRESS;
97         result->async.fn = NULL;
98         result->event_ctx = service->task->event_ctx;
99
100         state = talloc(result, struct sid2domain_state);
101         if (state == NULL) goto failed;
102         state->ctx = result;
103         result->private_data = state;
104
105         state->service = service;
106         state->sid = dom_sid_dup(state, sid);
107         if (state->sid == NULL) goto failed;
108
109         state->result = find_domain_from_sid(service, sid);
110         if (state->result != NULL) {
111                 result->status = NT_STATUS_OK;
112                 if (!state->result->initialized) {
113                         ctx = wb_init_domain_send(state->result,
114                                                   service->task->event_ctx,
115                                                   service->task->msg_ctx);
116                         if (ctx == NULL) goto failed;
117                         ctx->async.fn = sid2domain_recv_init;
118                         ctx->async.private_data = state;
119                         return result;
120                 }
121                 composite_trigger_done(result);
122                 return result;
123         }
124
125         state->my_domain = find_primary_domain(service);
126         if (state->my_domain == NULL) {
127                 result->status = NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
128                 composite_trigger_error(result);
129                 return result;
130         }
131
132         ctx = wb_cmd_lookupsid_send(service, state->my_domain, state->sid);
133         if (ctx == NULL) goto failed;
134         ctx->async.fn = sid2domain_recv_name;
135         ctx->async.private_data = state;
136         return result;
137
138  failed:
139         talloc_free(result);
140         return NULL;
141 }
142
143 static void sid2domain_recv_name(struct composite_context *ctx)
144 {
145         struct sid2domain_state *state =
146                 talloc_get_type(ctx->async.private_data,
147                                 struct sid2domain_state);
148         struct wb_sid_object *name;
149
150         state->ctx->status = wb_cmd_lookupsid_recv(ctx, state, &name);
151         if (!composite_is_ok(state->ctx)) return;
152
153         if (name->type == SID_NAME_UNKNOWN) {
154                 composite_error(state->ctx, NT_STATUS_NO_SUCH_DOMAIN);
155                 return;
156         }
157
158         state->domain_name = name->domain;
159         state->domain_sid = dom_sid_dup(state, state->sid);
160         if (name->type != SID_NAME_DOMAIN) {
161                 state->domain_sid->num_auths -= 1;
162         }
163         
164         ctx = wb_cmd_getdcname_send(state->service, state->my_domain,
165                                     state->domain_name);
166         composite_continue(state->ctx, ctx, sid2domain_recv_dcname, state);
167 }
168
169 static void sid2domain_recv_dcname(struct composite_context *ctx)
170 {
171         struct sid2domain_state *state =
172                 talloc_get_type(ctx->async.private_data,
173                                 struct sid2domain_state);
174
175         state->ctx->status = wb_cmd_getdcname_recv(ctx, state,
176                                                    &state->dc_name);
177         if (!composite_is_ok(state->ctx)) return;
178
179         state->result = talloc_zero(state, struct wbsrv_domain);
180         if (composite_nomem(state->result, state->ctx)) return;
181
182         state->result->name = talloc_steal(state->result, state->domain_name);
183         state->result->sid = talloc_steal(state->result, state->domain_sid);
184         state->result->dcname = talloc_steal(state->result, state->dc_name);
185
186         state->result->schannel_creds = cli_credentials_init(state->result);
187         if (composite_nomem(state->result->schannel_creds, state->ctx)) return;
188         cli_credentials_set_conf(state->result->schannel_creds);
189         cli_credentials_set_anonymous(state->result->schannel_creds);
190
191         talloc_steal(state->service, state->result);
192         DLIST_ADD(state->service->domains, state->result);
193
194         ctx = wb_init_domain_send(state->result,
195                                   state->service->task->event_ctx,
196                                   state->service->task->msg_ctx);
197         composite_continue(state->ctx, ctx, sid2domain_recv_init, state);
198 }
199
200 static void sid2domain_recv_init(struct composite_context *ctx)
201 {
202         struct sid2domain_state *state =
203                 talloc_get_type(ctx->async.private_data,
204                                 struct sid2domain_state);
205
206         state->ctx->status = wb_init_domain_recv(ctx);
207         if (!composite_is_ok(state->ctx)) return;
208
209         composite_done(state->ctx);
210 }
211
212 NTSTATUS wb_sid2domain_recv(struct composite_context *ctx,
213                             struct wbsrv_domain **result)
214 {
215         NTSTATUS status = composite_wait(ctx);
216         if (NT_STATUS_IS_OK(status)) {
217                 struct sid2domain_state *state =
218                         talloc_get_type(ctx->private_data,
219                                         struct sid2domain_state);
220                 *result = state->result;
221         }
222         talloc_free(ctx);
223         return status;
224 }
225
226 NTSTATUS wb_sid2domain(struct wbsrv_service *service,
227                        const struct dom_sid *sid,
228                        struct wbsrv_domain **result)
229 {
230         struct composite_context *c = wb_sid2domain_send(service, sid);
231         return wb_sid2domain_recv(c, result);
232 }