9e62a1b10285c66feb82ad33e5e8894f2aa2e01b
[kai/samba.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
26 #undef DBGC_CLASS
27 #define DBGC_CLASS DBGC_WINBIND
28
29 /* Constants and helper functions for determining domain trust types */
30
31 enum trust_type {
32         EXTERNAL = 0,
33         FOREST,
34         IN_FOREST,
35         NONE,
36 };
37
38 const char *trust_type_strings[] = {"External", 
39                                     "Forest", 
40                                     "In Forest",
41                                     "None"};
42
43 static enum trust_type get_trust_type(struct winbindd_tdc_domain *domain)
44 {
45         if (domain->trust_attribs == NETR_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN)   
46                 return EXTERNAL;
47         else if (domain->trust_attribs == NETR_TRUST_ATTRIBUTE_FOREST_TRANSITIVE)
48                 return FOREST;
49         else if (((domain->trust_flags & NETR_TRUST_FLAG_IN_FOREST) == NETR_TRUST_FLAG_IN_FOREST) &&
50             ((domain->trust_flags & NETR_TRUST_FLAG_PRIMARY) == 0x0))
51                 return IN_FOREST;
52         return NONE;    
53 }
54
55 static const char *get_trust_type_string(struct winbindd_tdc_domain *domain)
56 {
57         return trust_type_strings[get_trust_type(domain)];
58 }
59
60 static bool trust_is_inbound(struct winbindd_tdc_domain *domain)
61 {
62         return (domain->trust_flags == 0x0) ||
63             ((domain->trust_flags & NETR_TRUST_FLAG_IN_FOREST) ==
64             NETR_TRUST_FLAG_IN_FOREST) ||                       
65             ((domain->trust_flags & NETR_TRUST_FLAG_INBOUND) ==
66             NETR_TRUST_FLAG_INBOUND);           
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         if ((domain->trust_attribs == NETR_TRUST_ATTRIBUTE_NON_TRANSITIVE) ||         
81             (domain->trust_attribs == NETR_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN) ||
82             (domain->trust_attribs == NETR_TRUST_ATTRIBUTE_TREAT_AS_EXTERNAL))
83                 return False;
84         return True;
85 }
86
87 void winbindd_list_trusted_domains(struct winbindd_cli_state *state)
88 {
89         struct winbindd_tdc_domain *dom_list = NULL;
90         struct winbindd_tdc_domain *d = NULL;
91         size_t num_domains = 0;
92         int extra_data_len = 0;
93         char *extra_data = NULL;
94         int i = 0;
95         
96         DEBUG(3, ("[%5lu]: list trusted domains\n",
97                   (unsigned long)state->pid));
98
99         if( !wcache_tdc_fetch_list( &dom_list, &num_domains )) {
100                 request_error(state);   
101                 goto done;
102         }
103
104         for ( i = 0; i < num_domains; i++ ) {
105                 struct winbindd_domain *domain;
106                 bool is_online = true;          
107
108                 d = &dom_list[i];
109                 domain = find_domain_from_name_noinit(d->domain_name);
110                 if (domain) {
111                         is_online = domain->online;
112                 }
113
114                 if ( !extra_data ) {
115                         extra_data = talloc_asprintf(state->mem_ctx, 
116                                                      "%s\\%s\\%s\\%s\\%s\\%s\\%s\\%s",
117                                                      d->domain_name,
118                                                      d->dns_name ? d->dns_name : d->domain_name,
119                                                      sid_string_talloc(state->mem_ctx, &d->sid),
120                                                      get_trust_type_string(d),
121                                                      trust_is_transitive(d) ? "Yes" : "No",
122                                                      trust_is_inbound(d) ? "Yes" : "No",
123                                                      trust_is_outbound(d) ? "Yes" : "No",
124                                                      is_online ? "Online" : "Offline" );
125                 } else {
126                         extra_data = talloc_asprintf(state->mem_ctx, 
127                                                      "%s\n%s\\%s\\%s\\%s\\%s\\%s\\%s\\%s",
128                                                      extra_data,
129                                                      d->domain_name,
130                                                      d->dns_name ? d->dns_name : d->domain_name,
131                                                      sid_string_talloc(state->mem_ctx, &d->sid),
132                                                      get_trust_type_string(d),
133                                                      trust_is_transitive(d) ? "Yes" : "No",
134                                                      trust_is_inbound(d) ? "Yes" : "No",
135                                                      trust_is_outbound(d) ? "Yes" : "No",
136                                                      is_online ? "Online" : "Offline" );
137                 }
138         }
139         
140         extra_data_len = 0;
141         if (extra_data != NULL) {
142                 extra_data_len = strlen(extra_data);
143         }
144
145         if (extra_data_len > 0) {
146                 state->response->extra_data.data = extra_data;
147                 state->response->length += extra_data_len+1;
148         }
149
150         request_ok(state);      
151 done:
152         TALLOC_FREE( dom_list );
153 }
154
155 enum winbindd_result winbindd_dual_list_trusted_domains(struct winbindd_domain *domain,
156                                                         struct winbindd_cli_state *state)
157 {
158         uint32 i, num_domains;
159         char **names, **alt_names;
160         DOM_SID *sids;
161         int extra_data_len = 0;
162         char *extra_data;
163         NTSTATUS result;
164         bool have_own_domain = False;
165
166         DEBUG(3, ("[%5lu]: list trusted domains\n",
167                   (unsigned long)state->pid));
168
169         result = domain->methods->trusted_domains(domain, state->mem_ctx,
170                                                   &num_domains, &names,
171                                                   &alt_names, &sids);
172
173         if (!NT_STATUS_IS_OK(result)) {
174                 DEBUG(3, ("winbindd_dual_list_trusted_domains: trusted_domains returned %s\n",
175                         nt_errstr(result) ));
176                 return WINBINDD_ERROR;
177         }
178
179         extra_data = talloc_strdup(state->mem_ctx, "");
180
181         if (num_domains > 0)
182                 extra_data = talloc_asprintf(
183                         state->mem_ctx, "%s\\%s\\%s",
184                         names[0], alt_names[0] ? alt_names[0] : names[0],
185                         sid_string_talloc(state->mem_ctx, &sids[0]));
186
187         for (i=1; i<num_domains; i++)
188                 extra_data = talloc_asprintf(
189                         state->mem_ctx, "%s\n%s\\%s\\%s",
190                         extra_data, names[i],
191                         alt_names[i] ? alt_names[i] : names[i],
192                         sid_string_talloc(state->mem_ctx, &sids[i]));
193
194         /* add our primary domain */
195         
196         for (i=0; i<num_domains; i++) {
197                 if (strequal(names[i], domain->name)) {
198                         have_own_domain = True;
199                         break;
200                 }
201         }
202
203         if (state->request->data.list_all_domains && !have_own_domain) {
204                 extra_data = talloc_asprintf(
205                         state->mem_ctx, "%s\n%s\\%s\\%s",
206                         extra_data, domain->name,
207                         domain->alt_name ? domain->alt_name : domain->name,
208                         sid_string_talloc(state->mem_ctx, &domain->sid));
209         }
210
211         /* This is a bit excessive, but the extra data sooner or later will be
212            talloc'ed */
213
214         extra_data_len = 0;
215         if (extra_data != NULL) {
216                 extra_data_len = strlen(extra_data);
217         }
218
219         if (extra_data_len > 0) {
220                 state->response->extra_data.data = extra_data;
221                 state->response->length += extra_data_len+1;
222         }
223
224         return WINBINDD_OK;
225 }
226
227 enum winbindd_result winbindd_dual_getdcname(struct winbindd_domain *domain,
228                                              struct winbindd_cli_state *state)
229 {
230         const char *dcname_slash = NULL;
231         const char *p;
232         struct rpc_pipe_client *netlogon_pipe;
233         NTSTATUS result;
234         WERROR werr;
235         unsigned int orig_timeout;
236         struct winbindd_domain *req_domain;
237
238         state->request->domain_name
239                 [sizeof(state->request->domain_name)-1] = '\0';
240
241         DEBUG(3, ("[%5lu]: Get DC name for %s\n", (unsigned long)state->pid,
242                   state->request->domain_name));
243
244         result = cm_connect_netlogon(domain, &netlogon_pipe);
245
246         if (!NT_STATUS_IS_OK(result)) {
247                 DEBUG(1, ("Can't contact the NETLOGON pipe\n"));
248                 return WINBINDD_ERROR;
249         }
250
251         /* This call can take a long time - allow the server to time out.
252            35 seconds should do it. */
253
254         orig_timeout = rpccli_set_timeout(netlogon_pipe, 35000);
255
256         req_domain = find_domain_from_name_noinit(state->request->domain_name);
257         if (req_domain == domain) {
258                 result = rpccli_netr_GetDcName(netlogon_pipe,
259                                                state->mem_ctx,
260                                                domain->dcname,
261                                                state->request->domain_name,
262                                                &dcname_slash,
263                                                &werr);
264         } else {
265                 result = rpccli_netr_GetAnyDCName(netlogon_pipe,
266                                                   state->mem_ctx,
267                                                   domain->dcname,
268                                                   state->request->domain_name,
269                                                   &dcname_slash,
270                                                   &werr);
271         }
272         /* And restore our original timeout. */
273         rpccli_set_timeout(netlogon_pipe, orig_timeout);
274
275         if (!NT_STATUS_IS_OK(result)) {
276                 DEBUG(5,("Error requesting DCname for domain %s: %s\n",
277                         state->request->domain_name, nt_errstr(result)));
278                 return WINBINDD_ERROR;
279         }
280
281         if (!W_ERROR_IS_OK(werr)) {
282                 DEBUG(5, ("Error requesting DCname for domain %s: %s\n",
283                         state->request->domain_name, win_errstr(werr)));
284                 return WINBINDD_ERROR;
285         }
286
287         p = dcname_slash;
288         if (*p == '\\') {
289                 p+=1;
290         }
291         if (*p == '\\') {
292                 p+=1;
293         }
294
295         fstrcpy(state->response->data.dc_name, p);
296         return WINBINDD_OK;
297 }
298
299 /* This is the child-only version of --sequence. It only allows for a single
300  * domain (ie "our" one) to be displayed. */
301
302 enum winbindd_result winbindd_dual_show_sequence(struct winbindd_domain *domain,
303                                                  struct winbindd_cli_state *state)
304 {
305         DEBUG(3, ("[%5lu]: show sequence\n", (unsigned long)state->pid));
306
307         /* Ensure null termination */
308         state->request->domain_name[sizeof(state->request->domain_name)-1]='\0';
309
310         domain->methods->sequence_number(domain, &domain->sequence_number);
311
312         state->response->data.sequence_number =
313                 domain->sequence_number;
314
315         return WINBINDD_OK;
316 }
317
318 struct domain_info_state {
319         struct winbindd_domain *domain;
320         struct winbindd_cli_state *cli;
321         struct winbindd_request ping_request;
322 };
323
324 static void domain_info_done(struct tevent_req *req);
325
326 void winbindd_domain_info(struct winbindd_cli_state *cli)
327 {
328         struct domain_info_state *state;
329         struct winbindd_domain *domain;
330         struct tevent_req *req;
331
332         DEBUG(3, ("[%5lu]: domain_info [%s]\n", (unsigned long)cli->pid,
333                   cli->request->domain_name));
334
335         domain = find_domain_from_name_noinit(cli->request->domain_name);
336
337         if (domain == NULL) {
338                 DEBUG(3, ("Did not find domain [%s]\n",
339                           cli->request->domain_name));
340                 request_error(cli);
341                 return;
342         }
343
344         if (domain->initialized) {
345                 fstrcpy(cli->response->data.domain_info.name,
346                         domain->name);
347                 fstrcpy(cli->response->data.domain_info.alt_name,
348                         domain->alt_name);
349                 sid_to_fstring(cli->response->data.domain_info.sid,
350                                &domain->sid);
351                 cli->response->data.domain_info.native_mode =
352                         domain->native_mode;
353                 cli->response->data.domain_info.active_directory =
354                         domain->active_directory;
355                 cli->response->data.domain_info.primary =
356                         domain->primary;
357                 request_ok(cli);
358                 return;
359         }
360
361         state = talloc_zero(cli->mem_ctx, struct domain_info_state);
362         if (state == NULL) {
363                 DEBUG(0, ("talloc failed\n"));
364                 request_error(cli);
365                 return;
366         }
367
368         state->cli = cli;
369         state->domain = domain;
370         state->ping_request.cmd = WINBINDD_PING;
371
372         /*
373          * Send a ping down. This implicitly initializes the domain.
374          */
375
376         req = wb_domain_request_send(state, winbind_event_context(),
377                                      domain, &state->ping_request);
378         if (req == NULL) {
379                 DEBUG(3, ("wb_domain_request_send failed\n"));
380                 request_error(cli);
381                 return;
382         }
383         tevent_req_set_callback(req, domain_info_done, state);
384 }
385
386 static void domain_info_done(struct tevent_req *req)
387 {
388         struct domain_info_state *state = tevent_req_callback_data(
389                 req, struct domain_info_state);
390         struct winbindd_response *response;
391         int ret, err;
392
393         ret = wb_domain_request_recv(req, req, &response, &err);
394         TALLOC_FREE(req);
395         if (ret == -1) {
396                 DEBUG(10, ("wb_domain_request failed: %s\n", strerror(errno)));
397                 request_error(state->cli);
398                 return;
399         }
400         if (!state->domain->initialized) {
401                 DEBUG(5, ("wb_domain_request did not initialize domain %s\n",
402                           state->domain->name));
403                 request_error(state->cli);
404                 return;
405         }
406
407         fstrcpy(state->cli->response->data.domain_info.name,
408                 state->domain->name);
409         fstrcpy(state->cli->response->data.domain_info.alt_name,
410                 state->domain->alt_name);
411         sid_to_fstring(state->cli->response->data.domain_info.sid,
412                        &state->domain->sid);
413
414         state->cli->response->data.domain_info.native_mode =
415                 state->domain->native_mode;
416         state->cli->response->data.domain_info.active_directory =
417                 state->domain->active_directory;
418         state->cli->response->data.domain_info.primary =
419                 state->domain->primary;
420
421         request_ok(state->cli);
422 }
423
424 /* List various tidbits of information */
425
426 void winbindd_info(struct winbindd_cli_state *state)
427 {
428
429         DEBUG(3, ("[%5lu]: request misc info\n", (unsigned long)state->pid));
430
431         state->response->data.info.winbind_separator = *lp_winbind_separator();
432         fstrcpy(state->response->data.info.samba_version, samba_version_string());
433         request_ok(state);
434 }
435
436 /* Tell the client the current interface version */
437
438 void winbindd_interface_version(struct winbindd_cli_state *state)
439 {
440         DEBUG(3, ("[%5lu]: request interface version\n",
441                   (unsigned long)state->pid));
442         
443         state->response->data.interface_version = WINBIND_INTERFACE_VERSION;
444         request_ok(state);
445 }
446
447 /* What domain are we a member of? */
448
449 void winbindd_domain_name(struct winbindd_cli_state *state)
450 {
451         DEBUG(3, ("[%5lu]: request domain name\n", (unsigned long)state->pid));
452         
453         fstrcpy(state->response->data.domain_name, lp_workgroup());
454         request_ok(state);
455 }
456
457 /* What's my name again? */
458
459 void winbindd_netbios_name(struct winbindd_cli_state *state)
460 {
461         DEBUG(3, ("[%5lu]: request netbios name\n",
462                   (unsigned long)state->pid));
463         
464         fstrcpy(state->response->data.netbios_name, global_myname());
465         request_ok(state);
466 }
467
468 /* Where can I find the privilaged pipe? */
469
470 void winbindd_priv_pipe_dir(struct winbindd_cli_state *state)
471 {
472         char *priv_dir;
473         DEBUG(3, ("[%5lu]: request location of privileged pipe\n",
474                   (unsigned long)state->pid));
475         
476         priv_dir = get_winbind_priv_pipe_dir();
477         state->response->extra_data.data = talloc_move(state->mem_ctx,
478                                                       &priv_dir);
479
480         /* must add one to length to copy the 0 for string termination */
481         state->response->length +=
482                 strlen((char *)state->response->extra_data.data) + 1;
483
484         request_ok(state);
485 }
486