python/samba/tests/krb5: Allow PkInitTests.test_pkinit_ntlm_from_pac_must_change_now...
[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 #include "libcli/security/dom_sid.h"
26 #include "lib/util/string_wrappers.h"
27
28 #undef DBGC_CLASS
29 #define DBGC_CLASS DBGC_WINBIND
30
31 static char *get_trust_type_string(TALLOC_CTX *mem_ctx,
32                                    struct winbindd_tdc_domain *tdc,
33                                    struct winbindd_domain *domain)
34 {
35         enum netr_SchannelType secure_channel_type = SEC_CHAN_NULL;
36         char *s = NULL;
37
38         if (domain != NULL) {
39                 secure_channel_type = domain->secure_channel_type;
40         }
41
42         switch (secure_channel_type) {
43         case SEC_CHAN_NULL: {
44                 if (domain == NULL) {
45                         DBG_ERR("Missing domain [%s]\n",
46                                 tdc->domain_name);
47                         return NULL;
48                 }
49                 if (domain->routing_domain == NULL) {
50                         DBG_ERR("Missing routing for domain [%s]\n",
51                                 tdc->domain_name);
52                         return NULL;
53                 }
54                 s = talloc_asprintf(mem_ctx, "Routed (via %s)",
55                                     domain->routing_domain->name);
56                 if (s == NULL) {
57                         return NULL;
58                 }
59                 break;
60         }
61
62         case SEC_CHAN_LOCAL:
63                 s = talloc_strdup(mem_ctx, "Local");
64                 if (s == NULL) {
65                         return NULL;
66                 }
67                 break;
68
69         case SEC_CHAN_WKSTA:
70                 s = talloc_strdup(mem_ctx, "Workstation");
71                 if (s == NULL) {
72                         return NULL;
73                 }
74                 break;
75
76         case SEC_CHAN_BDC: {
77                 int role = lp_server_role();
78
79                 if (role == ROLE_DOMAIN_PDC || role == ROLE_IPA_DC) {
80                         s = talloc_strdup(mem_ctx, "PDC");
81                         if (s == NULL) {
82                                 return NULL;
83                         }
84                         break;
85                 }
86
87                 if (role == ROLE_DOMAIN_BDC) {
88                         s = talloc_strdup(mem_ctx, "BDC");
89                         if (s == NULL) {
90                                 return NULL;
91                         }
92                         break;
93                 }
94
95                 s = talloc_strdup(mem_ctx, "RWDC");
96                 if (s == NULL) {
97                         return NULL;
98                 }
99                 break;
100         }
101
102         case SEC_CHAN_RODC:
103                 s = talloc_strdup(mem_ctx, "RODC");
104                 if (s == NULL) {
105                         return NULL;
106                 }
107                 break;
108
109         case SEC_CHAN_DNS_DOMAIN:
110                 if (tdc->trust_attribs & LSA_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN) {
111                         s = talloc_strdup(mem_ctx, "External");
112                         if (s == NULL) {
113                                 return NULL;
114                         }
115                         break;
116                 }
117                 if (tdc->trust_attribs & LSA_TRUST_ATTRIBUTE_WITHIN_FOREST) {
118                         s = talloc_strdup(mem_ctx, "In Forest");
119                         if (s == NULL) {
120                                 return NULL;
121                         }
122                         break;
123                 }
124                 if (tdc->trust_attribs & LSA_TRUST_ATTRIBUTE_TREAT_AS_EXTERNAL) {
125                         s = talloc_strdup(mem_ctx, "External");
126                         if (s == NULL) {
127                                 return NULL;
128                         }
129                         break;
130                 }
131                 if (tdc->trust_attribs & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) {
132                         s = talloc_strdup(mem_ctx, "Forest");
133                         if (s == NULL) {
134                                 return NULL;
135                         }
136                         break;
137                 }
138                 s = talloc_strdup(mem_ctx, "External");
139                 if (s == NULL) {
140                         return NULL;
141                 }
142                 break;
143
144         case SEC_CHAN_DOMAIN:
145                 s = talloc_strdup(mem_ctx, "External");
146                 if (s == NULL) {
147                         return NULL;
148                 }
149                 break;
150
151         default:
152                 DBG_ERR("Unhandled secure_channel_type %d for domain[%s]\n",
153                         secure_channel_type, tdc->domain_name);
154                 return NULL;
155         }
156
157         return s;
158 }
159
160 static bool trust_is_inbound(struct winbindd_tdc_domain *domain)
161 {
162         if (domain->trust_flags & NETR_TRUST_FLAG_INBOUND) {
163                 return true;
164         }
165         return false;
166 }
167
168 static bool trust_is_outbound(struct winbindd_tdc_domain *domain)
169 {
170         if (domain->trust_flags & NETR_TRUST_FLAG_OUTBOUND) {
171                 return true;
172         }
173         return false;
174 }
175
176 static bool trust_is_transitive(struct winbindd_tdc_domain *domain)
177 {
178         bool transitive = false;
179
180         /*
181          * Beware: order matters
182          */
183
184         if (domain->trust_attribs & LSA_TRUST_ATTRIBUTE_WITHIN_FOREST) {
185                 transitive = true;
186         }
187
188         if (domain->trust_attribs & LSA_TRUST_ATTRIBUTE_FOREST_TRANSITIVE) {
189                 transitive = true;
190         }
191
192         if (domain->trust_attribs & LSA_TRUST_ATTRIBUTE_NON_TRANSITIVE) {
193                 transitive = false;
194         }
195
196         if (domain->trust_attribs & LSA_TRUST_ATTRIBUTE_QUARANTINED_DOMAIN) {
197                 transitive = false;
198         }
199
200         if (domain->trust_flags & NETR_TRUST_FLAG_PRIMARY) {
201                 transitive = true;
202         }
203
204         return transitive;
205 }
206
207 bool winbindd_list_trusted_domains(struct winbindd_cli_state *state)
208 {
209         struct winbindd_tdc_domain *dom_list = NULL;
210         size_t num_domains = 0;
211         int extra_data_len = 0;
212         char *extra_data = NULL;
213         size_t i = 0;
214         bool ret = false;
215
216         DBG_NOTICE("[%s (%u)]: list trusted domains\n",
217                    state->client_name,
218                    (unsigned int)state->pid);
219
220         if( !wcache_tdc_fetch_list( &dom_list, &num_domains )) {
221                 goto done;
222         }
223
224         extra_data = talloc_strdup(state->mem_ctx, "");
225         if (extra_data == NULL) {
226                 goto done;
227         }
228
229         for ( i = 0; i < num_domains; i++ ) {
230                 struct winbindd_domain *domain;
231                 bool is_online = true;
232                 struct winbindd_tdc_domain *d = NULL;
233                 char *trust_type = NULL;
234                 struct dom_sid_buf buf;
235
236                 d = &dom_list[i];
237                 domain = find_domain_from_name_noinit(d->domain_name);
238                 if (domain) {
239                         is_online = domain->online;
240                 }
241
242                 trust_type = get_trust_type_string(talloc_tos(), d, domain);
243                 if (trust_type == NULL) {
244                         continue;
245                 }
246
247                 extra_data = talloc_asprintf_append_buffer(
248                         extra_data,
249                         "%s\\%s\\%s\\%s\\%s\\%s\\%s\\%s\n",
250                         d->domain_name,
251                         d->dns_name ? d->dns_name : "",
252                         dom_sid_str_buf(&d->sid, &buf),
253                         trust_type,
254                         trust_is_transitive(d) ? "Yes" : "No",
255                         trust_is_inbound(d) ? "Yes" : "No",
256                         trust_is_outbound(d) ? "Yes" : "No",
257                         is_online ? "Online" : "Offline" );
258
259                 TALLOC_FREE(trust_type);
260         }
261
262         state->response->data.num_entries = num_domains;
263
264         extra_data_len = strlen(extra_data);
265         if (extra_data_len > 0) {
266
267                 /* Strip the last \n */
268                 extra_data[extra_data_len-1] = '\0';
269
270                 state->response->extra_data.data = extra_data;
271                 state->response->length += extra_data_len;
272         }
273
274         ret = true;
275 done:
276         TALLOC_FREE( dom_list );
277         return ret;
278 }
279
280 bool winbindd_dc_info(struct winbindd_cli_state *cli)
281 {
282         struct winbindd_domain *domain;
283         char *dc_name, *dc_ip;
284
285         cli->request->domain_name[sizeof(cli->request->domain_name)-1] = '\0';
286
287         DBG_NOTICE("[%s (%u)]: domain_info [%s]\n",
288                    cli->client_name,
289                    (unsigned int)cli->pid,
290                    cli->request->domain_name);
291
292         if (cli->request->domain_name[0] != '\0') {
293                 domain = find_trust_from_name_noinit(
294                         cli->request->domain_name);
295                 if (domain == NULL) {
296                         DEBUG(10, ("Could not find domain %s\n",
297                                    cli->request->domain_name));
298                         return false;
299                 }
300         } else {
301                 domain = find_our_domain();
302         }
303
304         if (!fetch_current_dc_from_gencache(
305                     talloc_tos(), domain->name, &dc_name, &dc_ip)) {
306                 DEBUG(10, ("fetch_current_dc_from_gencache(%s) failed\n",
307                            domain->name));
308                 return false;
309         }
310
311         cli->response->data.num_entries = 1;
312         cli->response->extra_data.data = talloc_asprintf(
313                 cli->mem_ctx, "%s\n%s\n", dc_name, dc_ip);
314
315         TALLOC_FREE(dc_name);
316         TALLOC_FREE(dc_ip);
317
318         if (cli->response->extra_data.data == NULL) {
319                 return false;
320         }
321
322         /* must add one to length to copy the 0 for string termination */
323         cli->response->length +=
324                 strlen((char *)cli->response->extra_data.data) + 1;
325
326         return true;
327 }
328
329 bool winbindd_ping(struct winbindd_cli_state *state)
330 {
331         DBG_NOTICE("[%s (%u)]: ping\n",
332                    state->client_name,
333                    (unsigned int)state->pid);
334         return true;
335 }
336
337 /* List various tidbits of information */
338
339 bool winbindd_info(struct winbindd_cli_state *state)
340 {
341
342         DBG_NOTICE("[%s (%u)]: request misc info\n",
343                    state->client_name,
344                    (unsigned int)state->pid);
345
346         state->response->data.info.winbind_separator = *lp_winbind_separator();
347         fstrcpy(state->response->data.info.samba_version, samba_version_string());
348         return true;
349 }
350
351 /* Tell the client the current interface version */
352
353 bool winbindd_interface_version(struct winbindd_cli_state *state)
354 {
355         DBG_NOTICE("[%s (%u)]: request interface version (version = %d)\n",
356                    state->client_name,
357                    (unsigned int)state->pid,
358                    WINBIND_INTERFACE_VERSION);
359
360         state->response->data.interface_version = WINBIND_INTERFACE_VERSION;
361         return true;
362 }
363
364 /* What domain are we a member of? */
365
366 bool winbindd_domain_name(struct winbindd_cli_state *state)
367 {
368         DBG_NOTICE("[%s (%u)]: request domain name\n",
369                    state->client_name,
370                    (unsigned int)state->pid);
371
372         fstrcpy(state->response->data.domain_name, lp_workgroup());
373         return true;
374 }
375
376 /* What's my name again? */
377
378 bool winbindd_netbios_name(struct winbindd_cli_state *state)
379 {
380         DBG_NOTICE("[%s (%u)]: request netbios name\n",
381                    state->client_name,
382                    (unsigned int)state->pid);
383
384         fstrcpy(state->response->data.netbios_name, lp_netbios_name());
385         return true;
386 }
387
388 /* Where can I find the privileged pipe? */
389
390 char *get_winbind_priv_pipe_dir(void)
391 {
392         return state_path(talloc_tos(), WINBINDD_PRIV_SOCKET_SUBDIR);
393 }
394
395 bool winbindd_priv_pipe_dir(struct winbindd_cli_state *state)
396 {
397         char *priv_dir;
398
399         DBG_NOTICE("[%s (%u)]: request location of privileged pipe\n",
400                    state->client_name,
401                    (unsigned int)state->pid);
402
403         priv_dir = get_winbind_priv_pipe_dir();
404         state->response->extra_data.data = talloc_move(state->mem_ctx,
405                                                       &priv_dir);
406
407         /* must add one to length to copy the 0 for string termination */
408         state->response->length +=
409                 strlen((char *)state->response->extra_data.data) + 1;
410
411         DBG_NOTICE("[%s (%u)]: response location of privileged pipe: %s\n",
412                    state->client_name,
413                    (unsigned int)state->pid,
414                    priv_dir);
415
416         return true;
417 }
418
419 static void winbindd_setup_max_fds(void)
420 {
421         int num_fds = MAX_OPEN_FUDGEFACTOR;
422         int actual_fds;
423
424         num_fds += lp_winbind_max_clients();
425         /* Add some more to account for 2 sockets open
426            when the client transitions from unprivileged
427            to privileged socket
428         */
429         num_fds += lp_winbind_max_clients() / 10;
430
431         /* Add one socket per child process
432            (yeah there are child processes other than the
433            domain children but only domain children can vary
434            with configuration
435         */
436         num_fds += lp_winbind_max_domain_connections() *
437                    (lp_allow_trusted_domains() ? WINBIND_MAX_DOMAINS_HINT : 1);
438
439         actual_fds = set_maxfiles(num_fds);
440
441         if (actual_fds < num_fds) {
442                 DEBUG(1, ("winbindd_setup_max_fds: Information only: "
443                           "requested %d open files, %d are available.\n",
444                           num_fds, actual_fds));
445         }
446 }
447
448 bool winbindd_reload_services_file(const char *lfile)
449 {
450         const struct loadparm_substitution *lp_sub =
451                 loadparm_s3_global_substitution();
452         bool ret;
453
454         if (lp_loaded()) {
455                 char *fname = lp_next_configfile(talloc_tos(), lp_sub);
456
457                 if (file_exist(fname) && !strcsequal(fname,get_dyn_CONFIGFILE())) {
458                         set_dyn_CONFIGFILE(fname);
459                 }
460                 TALLOC_FREE(fname);
461         }
462
463         reopen_logs();
464         ret = lp_load_global(get_dyn_CONFIGFILE());
465
466         /* if this is a child, restore the logfile to the special
467            name - <domain>, idmap, etc. */
468         if (lfile && *lfile) {
469                 lp_set_logfile(lfile);
470         }
471
472         reopen_logs();
473         load_interfaces();
474         winbindd_setup_max_fds();
475
476         return(ret);
477 }
478
479 static size_t *debug_call_depth = NULL;
480
481 void winbind_debug_call_depth_setup(size_t *depth)
482 {
483         debug_call_depth = depth;
484 }
485
486 void winbind_call_flow(void *private_data,
487                        enum tevent_thread_call_depth_cmd cmd,
488                        struct tevent_req *req,
489                        size_t depth,
490                        const char *fname)
491 {
492         switch (cmd) {
493         case TEVENT_CALL_FLOW_REQ_CREATE:
494                 *debug_call_depth = depth;
495                 DEBUG(20, ("flow: -> %s\n", fname));
496                 break;
497         case TEVENT_CALL_FLOW_REQ_NOTIFY_CB:
498                 *debug_call_depth = depth;
499                 DEBUG(20, ("flow: <- %s\n", fname));
500                 break;
501         case TEVENT_CALL_FLOW_REQ_QUEUE_TRIGGER:
502                 *debug_call_depth = depth;
503                 break;
504         case TEVENT_CALL_FLOW_REQ_RESET:
505                 *debug_call_depth = depth;
506                 break;
507         case TEVENT_CALL_FLOW_REQ_CANCEL:
508         case TEVENT_CALL_FLOW_REQ_CLEANUP:
509         case TEVENT_CALL_FLOW_REQ_QUEUE_ENTER:
510         case TEVENT_CALL_FLOW_REQ_QUEUE_LEAVE:
511                 break;
512         }
513 }