log winbind version (when requested) in winbindd log
[sfrench/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 "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 == 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         extra_data = talloc_strdup(state->mem_ctx, "");
106         if (extra_data == NULL) {
107                 request_error(state);
108                 goto done;
109         }
110
111         for ( i = 0; i < num_domains; i++ ) {
112                 struct winbindd_domain *domain;
113                 bool is_online = true;          
114
115                 d = &dom_list[i];
116                 domain = find_domain_from_name_noinit(d->domain_name);
117                 if (domain) {
118                         is_online = domain->online;
119                 }
120                 extra_data = talloc_asprintf_append_buffer(
121                         extra_data,
122                         "%s\\%s\\%s\\%s\\%s\\%s\\%s\\%s\n",
123                         d->domain_name,
124                         d->dns_name ? d->dns_name : "",
125                         sid_string_talloc(state->mem_ctx, &d->sid),
126                         get_trust_type_string(d),
127                         trust_is_transitive(d) ? "Yes" : "No",
128                         trust_is_inbound(d) ? "Yes" : "No",
129                         trust_is_outbound(d) ? "Yes" : "No",
130                         is_online ? "Online" : "Offline" );
131         }
132
133         state->response->data.num_entries = num_domains;
134
135         extra_data_len = strlen(extra_data);
136         if (extra_data_len > 0) {
137
138                 /* Strip the last \n */
139                 extra_data[extra_data_len-1] = '\0';
140
141                 state->response->extra_data.data = extra_data;
142                 state->response->length += extra_data_len;
143         }
144
145         request_ok(state);      
146 done:
147         TALLOC_FREE( dom_list );
148 }
149
150 enum winbindd_result winbindd_dual_list_trusted_domains(struct winbindd_domain *domain,
151                                                         struct winbindd_cli_state *state)
152 {
153         int i;
154         int extra_data_len = 0;
155         char *extra_data;
156         NTSTATUS result;
157         bool have_own_domain = False;
158         struct netr_DomainTrustList trusts;
159
160         DEBUG(3, ("[%5lu]: list trusted domains\n",
161                   (unsigned long)state->pid));
162
163         result = domain->methods->trusted_domains(domain, state->mem_ctx,
164                                                   &trusts);
165
166         if (!NT_STATUS_IS_OK(result)) {
167                 DEBUG(3, ("winbindd_dual_list_trusted_domains: trusted_domains returned %s\n",
168                         nt_errstr(result) ));
169                 return WINBINDD_ERROR;
170         }
171
172         extra_data = talloc_strdup(state->mem_ctx, "");
173
174         for (i=0; i<trusts.count; i++) {
175
176                 if (trusts.array[i].sid == NULL) {
177                         continue;
178                 }
179                 if (dom_sid_equal(trusts.array[i].sid, &global_sid_NULL)) {
180                         continue;
181                 }
182
183                 extra_data = talloc_asprintf_append_buffer(
184                         extra_data, "%s\\%s\\%s\n",
185                         trusts.array[i].netbios_name,
186                         trusts.array[i].dns_name,
187                         sid_string_talloc(state->mem_ctx,
188                                           trusts.array[i].sid));
189         }
190
191         /* add our primary domain */
192
193         for (i=0; i<trusts.count; i++) {
194                 if (strequal(trusts.array[i].netbios_name, domain->name)) {
195                         have_own_domain = True;
196                         break;
197                 }
198         }
199
200         if (state->request->data.list_all_domains && !have_own_domain) {
201                 extra_data = talloc_asprintf_append_buffer(
202                         extra_data, "%s\\%s\\%s\n", domain->name,
203                         domain->alt_name != NULL ?
204                                 domain->alt_name :
205                                 domain->name,
206                         sid_string_talloc(state->mem_ctx, &domain->sid));
207         }
208
209         extra_data_len = strlen(extra_data);
210         if (extra_data_len > 0) {
211
212                 /* Strip the last \n */
213                 extra_data[extra_data_len-1] = '\0';
214
215                 state->response->extra_data.data = extra_data;
216                 state->response->length += extra_data_len+1;
217         }
218
219         return WINBINDD_OK;
220 }
221
222 struct domain_info_state {
223         struct winbindd_domain *domain;
224         struct winbindd_cli_state *cli;
225         struct winbindd_request ping_request;
226 };
227
228 static void domain_info_done(struct tevent_req *req);
229
230 void winbindd_domain_info(struct winbindd_cli_state *cli)
231 {
232         struct domain_info_state *state;
233         struct winbindd_domain *domain;
234         struct tevent_req *req;
235
236         DEBUG(3, ("[%5lu]: domain_info [%s]\n", (unsigned long)cli->pid,
237                   cli->request->domain_name));
238
239         domain = find_domain_from_name_noinit(cli->request->domain_name);
240
241         if (domain == NULL) {
242                 DEBUG(3, ("Did not find domain [%s]\n",
243                           cli->request->domain_name));
244                 request_error(cli);
245                 return;
246         }
247
248         if (domain->initialized) {
249                 fstrcpy(cli->response->data.domain_info.name,
250                         domain->name);
251                 fstrcpy(cli->response->data.domain_info.alt_name,
252                         domain->alt_name);
253                 sid_to_fstring(cli->response->data.domain_info.sid,
254                                &domain->sid);
255                 cli->response->data.domain_info.native_mode =
256                         domain->native_mode;
257                 cli->response->data.domain_info.active_directory =
258                         domain->active_directory;
259                 cli->response->data.domain_info.primary =
260                         domain->primary;
261                 request_ok(cli);
262                 return;
263         }
264
265         state = talloc_zero(cli->mem_ctx, struct domain_info_state);
266         if (state == NULL) {
267                 DEBUG(0, ("talloc failed\n"));
268                 request_error(cli);
269                 return;
270         }
271
272         state->cli = cli;
273         state->domain = domain;
274         state->ping_request.cmd = WINBINDD_PING;
275
276         /*
277          * Send a ping down. This implicitly initializes the domain.
278          */
279
280         req = wb_domain_request_send(state, winbind_event_context(),
281                                      domain, &state->ping_request);
282         if (req == NULL) {
283                 DEBUG(3, ("wb_domain_request_send failed\n"));
284                 request_error(cli);
285                 return;
286         }
287         tevent_req_set_callback(req, domain_info_done, state);
288 }
289
290 static void domain_info_done(struct tevent_req *req)
291 {
292         struct domain_info_state *state = tevent_req_callback_data(
293                 req, struct domain_info_state);
294         struct winbindd_response *response;
295         int ret, err;
296
297         ret = wb_domain_request_recv(req, req, &response, &err);
298         TALLOC_FREE(req);
299         if (ret == -1) {
300                 DEBUG(10, ("wb_domain_request failed: %s\n", strerror(errno)));
301                 request_error(state->cli);
302                 return;
303         }
304         if (!state->domain->initialized) {
305                 DEBUG(5, ("wb_domain_request did not initialize domain %s\n",
306                           state->domain->name));
307                 request_error(state->cli);
308                 return;
309         }
310
311         fstrcpy(state->cli->response->data.domain_info.name,
312                 state->domain->name);
313         fstrcpy(state->cli->response->data.domain_info.alt_name,
314                 state->domain->alt_name);
315         sid_to_fstring(state->cli->response->data.domain_info.sid,
316                        &state->domain->sid);
317
318         state->cli->response->data.domain_info.native_mode =
319                 state->domain->native_mode;
320         state->cli->response->data.domain_info.active_directory =
321                 state->domain->active_directory;
322         state->cli->response->data.domain_info.primary =
323                 state->domain->primary;
324
325         request_ok(state->cli);
326 }
327
328 void winbindd_dc_info(struct winbindd_cli_state *cli)
329 {
330         struct winbindd_domain *domain;
331         char *dc_name, *dc_ip;
332
333         cli->request->domain_name[sizeof(cli->request->domain_name)-1] = '\0';
334
335         DEBUG(3, ("[%5lu]: domain_info [%s]\n", (unsigned long)cli->pid,
336                   cli->request->domain_name));
337
338         if (cli->request->domain_name[0] != '\0') {
339                 domain = find_domain_from_name_noinit(
340                         cli->request->domain_name);
341                 DEBUG(10, ("Could not find domain %s\n",
342                            cli->request->domain_name));
343                 if (domain == NULL) {
344                         request_error(cli);
345                         return;
346                 }
347         } else {
348                 domain = find_our_domain();
349         }
350
351         if (!fetch_current_dc_from_gencache(
352                     talloc_tos(), domain->name, &dc_name, &dc_ip)) {
353                 DEBUG(10, ("fetch_current_dc_from_gencache(%s) failed\n",
354                            domain->name));
355                 request_error(cli);
356                 return;
357         }
358
359         cli->response->data.num_entries = 1;
360         cli->response->extra_data.data = talloc_asprintf(
361                 cli->mem_ctx, "%s\n%s\n", dc_name, dc_ip);
362
363         TALLOC_FREE(dc_name);
364         TALLOC_FREE(dc_ip);
365
366         if (cli->response->extra_data.data == NULL) {
367                 request_error(cli);
368                 return;
369         }
370
371         /* must add one to length to copy the 0 for string termination */
372         cli->response->length +=
373                 strlen((char *)cli->response->extra_data.data) + 1;
374
375         request_ok(cli);
376 }
377
378 /* List various tidbits of information */
379
380 void winbindd_info(struct winbindd_cli_state *state)
381 {
382
383         DEBUG(3, ("[%5lu]: request misc info\n", (unsigned long)state->pid));
384
385         state->response->data.info.winbind_separator = *lp_winbind_separator();
386         fstrcpy(state->response->data.info.samba_version, samba_version_string());
387         request_ok(state);
388 }
389
390 /* Tell the client the current interface version */
391
392 void winbindd_interface_version(struct winbindd_cli_state *state)
393 {
394         DEBUG(3, ("[%5lu]: request interface version (version = %d)\n",
395                   (unsigned long)state->pid, WINBIND_INTERFACE_VERSION));
396
397         state->response->data.interface_version = WINBIND_INTERFACE_VERSION;
398         request_ok(state);
399 }
400
401 /* What domain are we a member of? */
402
403 void winbindd_domain_name(struct winbindd_cli_state *state)
404 {
405         DEBUG(3, ("[%5lu]: request domain name\n", (unsigned long)state->pid));
406
407         fstrcpy(state->response->data.domain_name, lp_workgroup());
408         request_ok(state);
409 }
410
411 /* What's my name again? */
412
413 void winbindd_netbios_name(struct winbindd_cli_state *state)
414 {
415         DEBUG(3, ("[%5lu]: request netbios name\n",
416                   (unsigned long)state->pid));
417
418         fstrcpy(state->response->data.netbios_name, lp_netbios_name());
419         request_ok(state);
420 }
421
422 /* Where can I find the privileged pipe? */
423
424 void winbindd_priv_pipe_dir(struct winbindd_cli_state *state)
425 {
426         char *priv_dir;
427         DEBUG(3, ("[%5lu]: request location of privileged pipe\n",
428                   (unsigned long)state->pid));
429
430         priv_dir = get_winbind_priv_pipe_dir();
431         state->response->extra_data.data = talloc_move(state->mem_ctx,
432                                                       &priv_dir);
433
434         /* must add one to length to copy the 0 for string termination */
435         state->response->length +=
436                 strlen((char *)state->response->extra_data.data) + 1;
437
438         request_ok(state);
439 }
440