051e9515f31676b1f158b0f9ed45c68cc00d3f76
[metze/samba/wip.git] / source3 / winbindd / winbindd_misc.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    Winbind daemon - miscellaneous other functions
5
6    Copyright (C) Tim Potter      2000
7    Copyright (C) Andrew Bartlett 2002
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.h"
25 #include "libcli/security/dom_sid.h"
26
27 #undef DBGC_CLASS
28 #define DBGC_CLASS DBGC_WINBIND
29
30 /* Constants and helper functions for determining domain trust types */
31
32 enum trust_type {
33         EXTERNAL = 0,
34         FOREST,
35         IN_FOREST,
36         NONE,
37 };
38
39 const char *trust_type_strings[] = {"External", 
40                                     "Forest", 
41                                     "In Forest",
42                                     "None"};
43
44 static enum trust_type get_trust_type(struct winbindd_tdc_domain *domain)
45 {
46         if (domain->trust_attribs == LSA_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN)
47                 return EXTERNAL;
48         else if (domain->trust_attribs == LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE)
49                 return FOREST;
50         else if (((domain->trust_flags & NETR_TRUST_FLAG_IN_FOREST) == NETR_TRUST_FLAG_IN_FOREST) &&
51             ((domain->trust_flags & NETR_TRUST_FLAG_PRIMARY) == 0x0))
52                 return IN_FOREST;
53         return NONE;    
54 }
55
56 static const char *get_trust_type_string(struct winbindd_tdc_domain *domain)
57 {
58         return trust_type_strings[get_trust_type(domain)];
59 }
60
61 static bool trust_is_inbound(struct winbindd_tdc_domain *domain)
62 {
63         if (domain->trust_flags & NETR_TRUST_FLAG_INBOUND) {
64                 return true;
65         }
66         return false;
67 }
68
69 static bool trust_is_outbound(struct winbindd_tdc_domain *domain)
70 {
71         return (domain->trust_flags == 0x0) ||
72             ((domain->trust_flags & NETR_TRUST_FLAG_IN_FOREST) ==
73             NETR_TRUST_FLAG_IN_FOREST) ||                       
74             ((domain->trust_flags & NETR_TRUST_FLAG_OUTBOUND) ==
75             NETR_TRUST_FLAG_OUTBOUND);          
76 }
77
78 static bool trust_is_transitive(struct winbindd_tdc_domain *domain)
79 {
80         bool transitive = false;
81
82         /*
83          * Beware: order matters
84          */
85
86         if (domain->trust_attribs & LSA_TRUST_ATTRIBUTE_WITHIN_FOREST) {
87                 transitive = true;
88         }
89
90         if (domain->trust_attribs & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) {
91                 transitive = true;
92         }
93
94         if (domain->trust_attribs & LSA_TRUST_ATTRIBUTE_NON_TRANSITIVE) {
95                 transitive = false;
96         }
97
98         if (domain->trust_attribs & LSA_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN) {
99                 transitive = false;
100         }
101
102         if (domain->trust_flags & NETR_TRUST_FLAG_PRIMARY) {
103                 transitive = true;
104         }
105
106         return transitive;
107 }
108
109 void winbindd_list_trusted_domains(struct winbindd_cli_state *state)
110 {
111         struct winbindd_tdc_domain *dom_list = NULL;
112         size_t num_domains = 0;
113         int extra_data_len = 0;
114         char *extra_data = NULL;
115         int i = 0;
116
117         DEBUG(3, ("[%5lu]: list trusted domains\n",
118                   (unsigned long)state->pid));
119
120         if( !wcache_tdc_fetch_list( &dom_list, &num_domains )) {
121                 request_error(state);   
122                 goto done;
123         }
124
125         extra_data = talloc_strdup(state->mem_ctx, "");
126         if (extra_data == NULL) {
127                 request_error(state);
128                 goto done;
129         }
130
131         for ( i = 0; i < num_domains; i++ ) {
132                 struct winbindd_domain *domain;
133                 bool is_online = true;          
134                 struct winbindd_tdc_domain *d = NULL;
135
136                 d = &dom_list[i];
137                 domain = find_domain_from_name_noinit(d->domain_name);
138                 if (domain) {
139                         is_online = domain->online;
140                 }
141                 extra_data = talloc_asprintf_append_buffer(
142                         extra_data,
143                         "%s\\%s\\%s\\%s\\%s\\%s\\%s\\%s\n",
144                         d->domain_name,
145                         d->dns_name ? d->dns_name : "",
146                         sid_string_talloc(state->mem_ctx, &d->sid),
147                         get_trust_type_string(d),
148                         trust_is_transitive(d) ? "Yes" : "No",
149                         trust_is_inbound(d) ? "Yes" : "No",
150                         trust_is_outbound(d) ? "Yes" : "No",
151                         is_online ? "Online" : "Offline" );
152         }
153
154         state->response->data.num_entries = num_domains;
155
156         extra_data_len = strlen(extra_data);
157         if (extra_data_len > 0) {
158
159                 /* Strip the last \n */
160                 extra_data[extra_data_len-1] = '\0';
161
162                 state->response->extra_data.data = extra_data;
163                 state->response->length += extra_data_len;
164         }
165
166         request_ok(state);      
167 done:
168         TALLOC_FREE( dom_list );
169 }
170
171 enum winbindd_result winbindd_dual_list_trusted_domains(struct winbindd_domain *domain,
172                                                         struct winbindd_cli_state *state)
173 {
174         int i;
175         int extra_data_len = 0;
176         char *extra_data;
177         NTSTATUS result;
178         bool have_own_domain = False;
179         struct netr_DomainTrustList trusts;
180
181         DEBUG(3, ("[%5lu]: list trusted domains\n",
182                   (unsigned long)state->pid));
183
184         result = wb_cache_trusted_domains(domain, state->mem_ctx, &trusts);
185
186         if (!NT_STATUS_IS_OK(result)) {
187                 DEBUG(3, ("winbindd_dual_list_trusted_domains: trusted_domains returned %s\n",
188                         nt_errstr(result) ));
189                 return WINBINDD_ERROR;
190         }
191
192         extra_data = talloc_strdup(state->mem_ctx, "");
193
194         for (i=0; i<trusts.count; i++) {
195
196                 if (trusts.array[i].sid == NULL) {
197                         continue;
198                 }
199                 if (dom_sid_equal(trusts.array[i].sid, &global_sid_NULL)) {
200                         continue;
201                 }
202
203                 extra_data = talloc_asprintf_append_buffer(
204                     extra_data, "%s\\%s\\%s\\%u\\%u\\%u\n",
205                     trusts.array[i].netbios_name, trusts.array[i].dns_name,
206                     sid_string_talloc(state->mem_ctx, trusts.array[i].sid),
207                     trusts.array[i].trust_flags,
208                     (uint32_t)trusts.array[i].trust_type,
209                     trusts.array[i].trust_attributes);
210         }
211
212         /* add our primary domain */
213
214         for (i=0; i<trusts.count; i++) {
215                 if (strequal(trusts.array[i].netbios_name, domain->name)) {
216                         have_own_domain = True;
217                         break;
218                 }
219         }
220
221         if (state->request->data.list_all_domains && !have_own_domain) {
222                 extra_data = talloc_asprintf_append_buffer(
223                         extra_data, "%s\\%s\\%s\n", domain->name,
224                         domain->alt_name != NULL ?
225                                 domain->alt_name :
226                                 domain->name,
227                         sid_string_talloc(state->mem_ctx, &domain->sid));
228         }
229
230         extra_data_len = strlen(extra_data);
231         if (extra_data_len > 0) {
232
233                 /* Strip the last \n */
234                 extra_data[extra_data_len-1] = '\0';
235
236                 state->response->extra_data.data = extra_data;
237                 state->response->length += extra_data_len;
238         }
239
240         return WINBINDD_OK;
241 }
242
243 struct domain_info_state {
244         struct winbindd_domain *domain;
245         struct winbindd_cli_state *cli;
246         struct winbindd_request ping_request;
247 };
248
249 static void domain_info_done(struct tevent_req *req);
250
251 void winbindd_domain_info(struct winbindd_cli_state *cli)
252 {
253         struct domain_info_state *state;
254         struct winbindd_domain *domain;
255         struct tevent_req *req;
256
257         DEBUG(3, ("[%5lu]: domain_info [%s]\n", (unsigned long)cli->pid,
258                   cli->request->domain_name));
259
260         domain = find_domain_from_name_noinit(cli->request->domain_name);
261
262         if (domain == NULL) {
263                 DEBUG(3, ("Did not find domain [%s]\n",
264                           cli->request->domain_name));
265                 request_error(cli);
266                 return;
267         }
268
269         if (domain->initialized) {
270                 fstrcpy(cli->response->data.domain_info.name,
271                         domain->name);
272                 fstrcpy(cli->response->data.domain_info.alt_name,
273                         domain->alt_name);
274                 sid_to_fstring(cli->response->data.domain_info.sid,
275                                &domain->sid);
276                 cli->response->data.domain_info.native_mode =
277                         domain->native_mode;
278                 cli->response->data.domain_info.active_directory =
279                         domain->active_directory;
280                 cli->response->data.domain_info.primary =
281                         domain->primary;
282                 request_ok(cli);
283                 return;
284         }
285
286         state = talloc_zero(cli->mem_ctx, struct domain_info_state);
287         if (state == NULL) {
288                 DEBUG(0, ("talloc failed\n"));
289                 request_error(cli);
290                 return;
291         }
292
293         state->cli = cli;
294         state->domain = domain;
295         state->ping_request.cmd = WINBINDD_PING;
296
297         /*
298          * Send a ping down. This implicitly initializes the domain.
299          */
300
301         req = wb_domain_request_send(state, server_event_context(),
302                                      domain, &state->ping_request);
303         if (req == NULL) {
304                 DEBUG(3, ("wb_domain_request_send failed\n"));
305                 request_error(cli);
306                 return;
307         }
308         tevent_req_set_callback(req, domain_info_done, state);
309 }
310
311 static void domain_info_done(struct tevent_req *req)
312 {
313         struct domain_info_state *state = tevent_req_callback_data(
314                 req, struct domain_info_state);
315         struct winbindd_response *response;
316         int ret, err;
317
318         ret = wb_domain_request_recv(req, req, &response, &err);
319         TALLOC_FREE(req);
320         if (ret == -1) {
321                 DEBUG(10, ("wb_domain_request failed: %s\n", strerror(errno)));
322                 request_error(state->cli);
323                 return;
324         }
325         if (!state->domain->initialized) {
326                 DEBUG(5, ("wb_domain_request did not initialize domain %s\n",
327                           state->domain->name));
328                 request_error(state->cli);
329                 return;
330         }
331
332         fstrcpy(state->cli->response->data.domain_info.name,
333                 state->domain->name);
334         fstrcpy(state->cli->response->data.domain_info.alt_name,
335                 state->domain->alt_name);
336         sid_to_fstring(state->cli->response->data.domain_info.sid,
337                        &state->domain->sid);
338
339         state->cli->response->data.domain_info.native_mode =
340                 state->domain->native_mode;
341         state->cli->response->data.domain_info.active_directory =
342                 state->domain->active_directory;
343         state->cli->response->data.domain_info.primary =
344                 state->domain->primary;
345
346         request_ok(state->cli);
347 }
348
349 void winbindd_dc_info(struct winbindd_cli_state *cli)
350 {
351         struct winbindd_domain *domain;
352         char *dc_name, *dc_ip;
353
354         cli->request->domain_name[sizeof(cli->request->domain_name)-1] = '\0';
355
356         DEBUG(3, ("[%5lu]: domain_info [%s]\n", (unsigned long)cli->pid,
357                   cli->request->domain_name));
358
359         if (cli->request->domain_name[0] != '\0') {
360                 domain = find_trust_from_name_noinit(
361                         cli->request->domain_name);
362                 if (domain == NULL) {
363                         DEBUG(10, ("Could not find domain %s\n",
364                                    cli->request->domain_name));
365                         request_error(cli);
366                         return;
367                 }
368         } else {
369                 domain = find_our_domain();
370         }
371
372         if (!fetch_current_dc_from_gencache(
373                     talloc_tos(), domain->name, &dc_name, &dc_ip)) {
374                 DEBUG(10, ("fetch_current_dc_from_gencache(%s) failed\n",
375                            domain->name));
376                 request_error(cli);
377                 return;
378         }
379
380         cli->response->data.num_entries = 1;
381         cli->response->extra_data.data = talloc_asprintf(
382                 cli->mem_ctx, "%s\n%s\n", dc_name, dc_ip);
383
384         TALLOC_FREE(dc_name);
385         TALLOC_FREE(dc_ip);
386
387         if (cli->response->extra_data.data == NULL) {
388                 request_error(cli);
389                 return;
390         }
391
392         /* must add one to length to copy the 0 for string termination */
393         cli->response->length +=
394                 strlen((char *)cli->response->extra_data.data) + 1;
395
396         request_ok(cli);
397 }
398
399 /* List various tidbits of information */
400
401 void winbindd_info(struct winbindd_cli_state *state)
402 {
403
404         DEBUG(3, ("[%5lu]: request misc info\n", (unsigned long)state->pid));
405
406         state->response->data.info.winbind_separator = *lp_winbind_separator();
407         fstrcpy(state->response->data.info.samba_version, samba_version_string());
408         request_ok(state);
409 }
410
411 /* Tell the client the current interface version */
412
413 void winbindd_interface_version(struct winbindd_cli_state *state)
414 {
415         DEBUG(3, ("[%5lu]: request interface version (version = %d)\n",
416                   (unsigned long)state->pid, WINBIND_INTERFACE_VERSION));
417
418         state->response->data.interface_version = WINBIND_INTERFACE_VERSION;
419         request_ok(state);
420 }
421
422 /* What domain are we a member of? */
423
424 void winbindd_domain_name(struct winbindd_cli_state *state)
425 {
426         DEBUG(3, ("[%5lu]: request domain name\n", (unsigned long)state->pid));
427
428         fstrcpy(state->response->data.domain_name, lp_workgroup());
429         request_ok(state);
430 }
431
432 /* What's my name again? */
433
434 void winbindd_netbios_name(struct winbindd_cli_state *state)
435 {
436         DEBUG(3, ("[%5lu]: request netbios name\n",
437                   (unsigned long)state->pid));
438
439         fstrcpy(state->response->data.netbios_name, lp_netbios_name());
440         request_ok(state);
441 }
442
443 /* Where can I find the privileged pipe? */
444
445 void winbindd_priv_pipe_dir(struct winbindd_cli_state *state)
446 {
447         char *priv_dir;
448         DEBUG(3, ("[%5lu]: request location of privileged pipe\n",
449                   (unsigned long)state->pid));
450
451         priv_dir = get_winbind_priv_pipe_dir();
452         state->response->extra_data.data = talloc_move(state->mem_ctx,
453                                                       &priv_dir);
454
455         /* must add one to length to copy the 0 for string termination */
456         state->response->length +=
457                 strlen((char *)state->response->extra_data.data) + 1;
458
459         request_ok(state);
460 }
461