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