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