Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : Test validity of smb.conf
4 : Copyright (C) Karl Auer 1993, 1994-1998
5 :
6 : Extensively modified by Andrew Tridgell, 1995
7 : Converted to popt by Jelmer Vernooij (jelmer@nl.linux.org), 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 : /*
24 : * Testbed for loadparm.c/params.c
25 : *
26 : * This module simply loads a specified configuration file and
27 : * if successful, dumps it's contents to stdout. Note that the
28 : * operation is performed with DEBUGLEVEL at 3.
29 : *
30 : * Useful for a quick 'syntax check' of a configuration file.
31 : *
32 : */
33 :
34 : #include "includes.h"
35 : #include "system/filesys.h"
36 : #include "lib/cmdline/cmdline.h"
37 : #include "lib/param/loadparm.h"
38 : #include "lib/crypto/gnutls_helpers.h"
39 : #include "cmdline_contexts.h"
40 :
41 : #include <regex.h>
42 :
43 : /*******************************************************************
44 : Check if a directory exists.
45 : ********************************************************************/
46 :
47 7496 : static bool directory_exist_stat(const char *dname,SMB_STRUCT_STAT *st)
48 : {
49 : SMB_STRUCT_STAT st2;
50 : bool ret;
51 :
52 7496 : if (!st)
53 0 : st = &st2;
54 :
55 7496 : if (sys_stat(dname, st, false) != 0)
56 7488 : return(False);
57 :
58 8 : ret = S_ISDIR(st->st_ex_mode);
59 8 : if(!ret)
60 0 : errno = ENOTDIR;
61 8 : return ret;
62 : }
63 :
64 : struct idmap_config {
65 : const char *domain_name;
66 : const char *backend;
67 : uint32_t high;
68 : uint32_t low;
69 : };
70 :
71 : struct idmap_domains {
72 : struct idmap_config *c;
73 : uint32_t count;
74 : uint32_t size;
75 : };
76 :
77 4 : static bool lp_scan_idmap_found_domain(const char *string,
78 : regmatch_t matches[],
79 : void *private_data)
80 : {
81 4 : bool ok = false;
82 :
83 4 : if (matches[1].rm_so == -1) {
84 0 : fprintf(stderr, "Found match, but no name - invalid idmap config");
85 0 : return false;
86 : }
87 4 : if (matches[1].rm_eo <= matches[1].rm_so) {
88 0 : fprintf(stderr, "Invalid match - invalid idmap config");
89 0 : return false;
90 : }
91 :
92 4 : {
93 4 : struct idmap_domains *d = private_data;
94 4 : struct idmap_config *c = &d->c[d->count];
95 4 : regoff_t len = matches[1].rm_eo - matches[1].rm_so;
96 4 : char domname[len + 1];
97 :
98 4 : if (d->count >= d->size) {
99 0 : return false;
100 : }
101 :
102 4 : memcpy(domname, string + matches[1].rm_so, len);
103 4 : domname[len] = '\0';
104 :
105 4 : c->domain_name = talloc_strdup_upper(d->c, domname);
106 4 : if (c->domain_name == NULL) {
107 0 : return false;
108 : }
109 4 : c->backend = talloc_strdup(d->c, lp_idmap_backend(domname));
110 4 : if (c->backend == NULL) {
111 0 : return false;
112 : }
113 :
114 4 : if (lp_server_role() != ROLE_ACTIVE_DIRECTORY_DC) {
115 4 : ok = lp_idmap_range(domname, &c->low, &c->high);
116 4 : if (!ok) {
117 2 : fprintf(stderr,
118 : "ERROR: Invalid idmap range for domain "
119 : "%s!\n\n",
120 : c->domain_name);
121 2 : return false;
122 : }
123 : }
124 :
125 2 : d->count++;
126 : }
127 :
128 2 : return false; /* Keep scanning */
129 : }
130 :
131 0 : static int idmap_config_int(const char *domname, const char *option, int def)
132 : {
133 0 : int len = snprintf(NULL, 0, "idmap config %s", domname);
134 :
135 0 : if (len == -1) {
136 0 : return def;
137 : }
138 0 : {
139 0 : char config_option[len+1];
140 0 : snprintf(config_option, sizeof(config_option),
141 : "idmap config %s", domname);
142 0 : return lp_parm_int(-1, config_option, option, def);
143 : }
144 : }
145 :
146 4 : static bool do_idmap_check(void)
147 : {
148 : struct idmap_domains *d;
149 : uint32_t i;
150 4 : bool ok = false;
151 : int rc;
152 :
153 4 : d = talloc_zero(talloc_tos(), struct idmap_domains);
154 4 : if (d == NULL) {
155 0 : return false;
156 : }
157 4 : d->count = 0;
158 4 : d->size = 32;
159 :
160 4 : d->c = talloc_array(d, struct idmap_config, d->size);
161 4 : if (d->c == NULL) {
162 0 : goto done;
163 : }
164 :
165 4 : rc = lp_wi_scan_global_parametrics("idmapconfig\\(.*\\):backend",
166 : 2,
167 : lp_scan_idmap_found_domain,
168 : d);
169 4 : if (rc != 0) {
170 0 : fprintf(stderr,
171 : "FATAL: wi_scan_global_parametrics failed: %d",
172 : rc);
173 : }
174 :
175 : /* Check autorid backend */
176 4 : if (strequal(lp_idmap_default_backend(), "autorid")) {
177 0 : struct idmap_config *c = NULL;
178 0 : bool found = false;
179 :
180 0 : for (i = 0; i < d->count; i++) {
181 0 : c = &d->c[i];
182 :
183 0 : if (strequal(c->backend, "autorid")) {
184 0 : found = true;
185 0 : break;
186 : }
187 : }
188 :
189 0 : if (found) {
190 0 : uint32_t rangesize =
191 0 : idmap_config_int("*", "rangesize", 100000);
192 0 : uint32_t maxranges =
193 0 : (c->high - c->low + 1) / rangesize;
194 :
195 0 : if (maxranges < 2) {
196 0 : fprintf(stderr,
197 : "ERROR: The idmap autorid range "
198 : "[%u-%u] needs to be at least twice as "
199 : "big as the rangesize [%u]!"
200 : "\n\n",
201 : c->low,
202 : c->high,
203 : rangesize);
204 0 : ok = false;
205 0 : goto done;
206 : }
207 : }
208 : }
209 :
210 : /* Check for overlapping idmap ranges */
211 6 : for (i = 0; i < d->count; i++) {
212 2 : struct idmap_config *c = &d->c[i];
213 : uint32_t j;
214 :
215 2 : for (j = 0; j < d->count && j != i; j++) {
216 0 : struct idmap_config *x = &d->c[j];
217 :
218 0 : if ((c->low >= x->low && c->low <= x->high) ||
219 0 : (c->high >= x->low && c->high <= x->high)) {
220 : /* Allow overlapping ranges for idmap_ad */
221 0 : ok = strequal(c->backend, x->backend);
222 0 : if (ok) {
223 0 : ok = strequal(c->backend, "ad");
224 0 : if (ok) {
225 0 : fprintf(stderr,
226 : "NOTE: The idmap_ad "
227 : "range for the domain "
228 : "%s overlaps with the "
229 : "range of %s.\n\n",
230 : c->domain_name,
231 : x->domain_name);
232 0 : continue;
233 : }
234 : }
235 :
236 0 : fprintf(stderr,
237 : "ERROR: The idmap range for the domain "
238 : "%s (%s) overlaps with the range of "
239 : "%s (%s)!\n\n",
240 : c->domain_name,
241 : c->backend,
242 : x->domain_name,
243 : x->backend);
244 0 : ok = false;
245 0 : goto done;
246 : }
247 : }
248 : }
249 :
250 4 : ok = true;
251 4 : done:
252 4 : TALLOC_FREE(d);
253 4 : return ok;
254 : }
255 :
256 : /***********************************************
257 : Here we do a set of 'hard coded' checks for bad
258 : configuration settings.
259 : ************************************************/
260 :
261 1874 : static int do_global_checks(void)
262 : {
263 1874 : int ret = 0;
264 : SMB_STRUCT_STAT st;
265 : const char *socket_options;
266 1872 : const struct loadparm_substitution *lp_sub =
267 2 : loadparm_s3_global_substitution();
268 :
269 1874 : fprintf(stderr, "\n");
270 :
271 1874 : if (lp_security() >= SEC_DOMAIN && !lp_encrypt_passwords()) {
272 0 : fprintf(stderr, "ERROR: in 'security=domain' mode the "
273 : "'encrypt passwords' parameter must always be "
274 : "set to 'true'.\n\n");
275 0 : ret = 1;
276 : }
277 :
278 1874 : if (lp_security() == SEC_ADS) {
279 2 : const char *workgroup = lp_workgroup();
280 2 : const char *realm = lp_realm();
281 :
282 2 : if (workgroup == NULL || strlen(workgroup) == 0) {
283 0 : fprintf(stderr,
284 : "ERROR: The 'security=ADS' mode requires "
285 : "'workgroup' parameter to be set!\n\n ");
286 0 : ret = 1;
287 : }
288 :
289 2 : if (realm == NULL || strlen(realm) == 0) {
290 0 : fprintf(stderr,
291 : "ERROR: The 'security=ADS' mode requires "
292 : "'realm' parameter to be set!\n\n ");
293 0 : ret = 1;
294 : }
295 : }
296 :
297 :
298 1874 : if (lp_we_are_a_wins_server() && lp_wins_server_list()) {
299 0 : fprintf(stderr, "ERROR: both 'wins support = true' and "
300 : "'wins server = <server list>' cannot be set in "
301 : "the smb.conf file. nmbd will abort with this "
302 : "setting.\n\n");
303 0 : ret = 1;
304 : }
305 :
306 1874 : if (strequal(lp_workgroup(), lp_netbios_name())) {
307 0 : fprintf(stderr, "WARNING: 'workgroup' and 'netbios name' "
308 : "must differ.\n\n");
309 : }
310 :
311 1874 : if (lp_client_ipc_signing() == SMB_SIGNING_IF_REQUIRED
312 1874 : || lp_client_ipc_signing() == SMB_SIGNING_OFF) {
313 0 : fprintf(stderr, "WARNING: The 'client ipc signing' value "
314 : "%s SMB signing is not used when contacting a "
315 : "domain controller or other server. "
316 : "This setting is not recommended; please be "
317 : "aware of the security implications when using "
318 : "this configuration setting.\n\n",
319 0 : lp_client_ipc_signing() == SMB_SIGNING_OFF ?
320 : "ensures" : "may mean");
321 : }
322 :
323 1874 : if (strlen(lp_netbios_name()) > 15) {
324 1869 : fprintf(stderr, "WARNING: The 'netbios name' is too long "
325 : "(max. 15 chars).\n\n");
326 : }
327 :
328 1874 : if (!directory_exist_stat(lp_lock_directory(), &st)) {
329 1872 : fprintf(stderr, "ERROR: lock directory %s does not exist\n\n",
330 : lp_lock_directory());
331 1872 : ret = 1;
332 2 : } else if ((st.st_ex_mode & 0777) != 0755) {
333 0 : fprintf(stderr, "WARNING: lock directory %s should have "
334 : "permissions 0755 for browsing to work\n\n",
335 : lp_lock_directory());
336 : }
337 :
338 1874 : if (!directory_exist_stat(lp_state_directory(), &st)) {
339 1872 : fprintf(stderr, "ERROR: state directory %s does not exist\n\n",
340 : lp_state_directory());
341 1872 : ret = 1;
342 2 : } else if ((st.st_ex_mode & 0777) != 0755) {
343 0 : fprintf(stderr, "WARNING: state directory %s should have "
344 : "permissions 0755 for browsing to work\n\n",
345 : lp_state_directory());
346 : }
347 :
348 1874 : if (!directory_exist_stat(lp_cache_directory(), &st)) {
349 1872 : fprintf(stderr, "ERROR: cache directory %s does not exist\n\n",
350 : lp_cache_directory());
351 1872 : ret = 1;
352 2 : } else if ((st.st_ex_mode & 0777) != 0755) {
353 0 : fprintf(stderr, "WARNING: cache directory %s should have "
354 : "permissions 0755 for browsing to work\n\n",
355 : lp_cache_directory());
356 : }
357 :
358 1874 : if (!directory_exist_stat(lp_pid_directory(), &st)) {
359 1872 : fprintf(stderr, "ERROR: pid directory %s does not exist\n\n",
360 : lp_pid_directory());
361 1872 : ret = 1;
362 : }
363 :
364 1874 : if (lp_passdb_expand_explicit()) {
365 2 : fprintf(stderr, "WARNING: passdb expand explicit = yes is "
366 : "deprecated\n\n");
367 : }
368 :
369 : /*
370 : * Socket options.
371 : */
372 1874 : socket_options = lp_socket_options();
373 3746 : if (socket_options != NULL &&
374 3746 : (strstr(socket_options, "SO_SNDBUF") ||
375 3746 : strstr(socket_options, "SO_RCVBUF") ||
376 3746 : strstr(socket_options, "SO_SNDLOWAT") ||
377 1874 : strstr(socket_options, "SO_RCVLOWAT")))
378 : {
379 0 : fprintf(stderr,
380 : "WARNING: socket options = %s\n"
381 : "This warning is printed because you set one of the\n"
382 : "following options: SO_SNDBUF, SO_RCVBUF, SO_SNDLOWAT,\n"
383 : "SO_RCVLOWAT\n"
384 : "Modern server operating systems are tuned for\n"
385 : "high network performance in the majority of situations;\n"
386 : "when you set 'socket options' you are overriding those\n"
387 : "settings.\n"
388 : "Linux in particular has an auto-tuning mechanism for\n"
389 : "buffer sizes (SO_SNDBUF, SO_RCVBUF) that will be\n"
390 : "disabled if you specify a socket buffer size. This can\n"
391 : "potentially cripple your TCP/IP stack.\n\n"
392 : "Getting the 'socket options' correct can make a big\n"
393 : "difference to your performance, but getting them wrong\n"
394 : "can degrade it by just as much. As with any other low\n"
395 : "level setting, if you must make changes to it, make\n "
396 : "small changes and test the effect before making any\n"
397 : "large changes.\n\n",
398 : socket_options);
399 : }
400 :
401 : /*
402 : * Password server sanity checks.
403 : */
404 :
405 1874 : if((lp_security() >= SEC_DOMAIN) && !*lp_password_server()) {
406 : const char *sec_setting;
407 0 : if(lp_security() == SEC_DOMAIN)
408 0 : sec_setting = "domain";
409 0 : else if(lp_security() == SEC_ADS)
410 0 : sec_setting = "ads";
411 : else
412 0 : sec_setting = "";
413 :
414 0 : fprintf(stderr, "ERROR: The setting 'security=%s' requires the "
415 : "'password server' parameter be set to the "
416 : "default value * or a valid password server.\n\n",
417 : sec_setting );
418 0 : ret = 1;
419 : }
420 :
421 1874 : if((lp_security() >= SEC_DOMAIN) && (strcmp(lp_password_server(), "*") != 0)) {
422 : const char *sec_setting;
423 2 : if(lp_security() == SEC_DOMAIN)
424 0 : sec_setting = "domain";
425 2 : else if(lp_security() == SEC_ADS)
426 2 : sec_setting = "ads";
427 : else
428 0 : sec_setting = "";
429 :
430 2 : fprintf(stderr, "WARNING: The setting 'security=%s' should NOT "
431 : "be combined with the 'password server' "
432 : "parameter.\n"
433 : "(by default Samba will discover the correct DC "
434 : "to contact automatically).\n\n",
435 : sec_setting );
436 : }
437 :
438 : /*
439 : * Password chat sanity checks.
440 : */
441 :
442 1874 : if(lp_security() == SEC_USER && lp_unix_password_sync()) {
443 :
444 : /*
445 : * Check that we have a valid lp_passwd_program() if not using pam.
446 : */
447 :
448 : #ifdef WITH_PAM
449 2 : if (!lp_pam_password_change()) {
450 : #endif
451 :
452 4 : if((lp_passwd_program(talloc_tos(), lp_sub) == NULL) ||
453 2 : (strlen(lp_passwd_program(talloc_tos(), lp_sub)) == 0))
454 : {
455 2 : fprintf(stderr,
456 : "ERROR: the 'unix password sync' "
457 : "parameter is set and there is no valid "
458 : "'passwd program' parameter.\n\n");
459 2 : ret = 1;
460 : } else {
461 : const char *passwd_prog;
462 0 : char *truncated_prog = NULL;
463 : const char *p;
464 :
465 0 : passwd_prog = lp_passwd_program(talloc_tos(), lp_sub);
466 0 : p = passwd_prog;
467 0 : next_token_talloc(talloc_tos(),
468 : &p,
469 : &truncated_prog, NULL);
470 0 : if (truncated_prog && access(truncated_prog, F_OK) == -1) {
471 0 : fprintf(stderr,
472 : "ERROR: the 'unix password sync' "
473 : "parameter is set and the "
474 : "'passwd program' (%s) cannot be "
475 : "executed (error was %s).\n\n",
476 : truncated_prog,
477 0 : strerror(errno));
478 0 : ret = 1;
479 : }
480 : }
481 :
482 : #ifdef WITH_PAM
483 : }
484 : #endif
485 :
486 2 : if(lp_passwd_chat(talloc_tos(), lp_sub) == NULL) {
487 0 : fprintf(stderr,
488 : "ERROR: the 'unix password sync' parameter is "
489 : "set and there is no valid 'passwd chat' "
490 : "parameter.\n\n");
491 0 : ret = 1;
492 : }
493 :
494 4 : if ((lp_passwd_program(talloc_tos(), lp_sub) != NULL) &&
495 2 : (strlen(lp_passwd_program(talloc_tos(), lp_sub)) > 0))
496 : {
497 : /* check if there's a %u parameter present */
498 0 : if(strstr_m(lp_passwd_program(talloc_tos(), lp_sub), "%u") == NULL) {
499 0 : fprintf(stderr,
500 : "ERROR: the 'passwd program' (%s) "
501 : "requires a '%%u' parameter.\n\n",
502 : lp_passwd_program(talloc_tos(), lp_sub));
503 0 : ret = 1;
504 : }
505 : }
506 :
507 : /*
508 : * Check that we have a valid script and that it hasn't
509 : * been written to expect the old password.
510 : */
511 :
512 2 : if(lp_encrypt_passwords()) {
513 2 : if(strstr_m( lp_passwd_chat(talloc_tos(), lp_sub), "%o")!=NULL) {
514 0 : fprintf(stderr,
515 : "ERROR: the 'passwd chat' script [%s] "
516 : "expects to use the old plaintext "
517 : "password via the %%o substitution. With "
518 : "encrypted passwords this is not "
519 : "possible.\n\n",
520 : lp_passwd_chat(talloc_tos(), lp_sub) );
521 0 : ret = 1;
522 : }
523 : }
524 : }
525 :
526 1874 : if (strlen(lp_winbind_separator()) != 1) {
527 2 : fprintf(stderr, "ERROR: the 'winbind separator' parameter must "
528 : "be a single character.\n\n");
529 2 : ret = 1;
530 : }
531 :
532 1874 : if (*lp_winbind_separator() == '+') {
533 0 : fprintf(stderr, "'winbind separator = +' might cause problems "
534 : "with group membership.\n\n");
535 : }
536 :
537 1874 : if (lp_algorithmic_rid_base() < BASE_RID) {
538 : /* Try to prevent admin foot-shooting, we can't put algorithmic
539 : rids below 1000, that's the 'well known RIDs' on NT */
540 2 : fprintf(stderr, "'algorithmic rid base' must be equal to or "
541 : "above %lu\n\n", BASE_RID);
542 : }
543 :
544 1874 : if (lp_algorithmic_rid_base() & 1) {
545 2 : fprintf(stderr, "'algorithmic rid base' must be even.\n\n");
546 : }
547 :
548 1874 : if (lp_server_role() != ROLE_STANDALONE) {
549 4 : const char *default_backends[] = {
550 : "tdb", "tdb2", "ldap", "autorid", "hash"
551 : };
552 : const char *idmap_backend;
553 4 : bool valid_backend = false;
554 : uint32_t i;
555 : bool ok;
556 :
557 4 : idmap_backend = lp_idmap_default_backend();
558 :
559 24 : for (i = 0; i < ARRAY_SIZE(default_backends); i++) {
560 20 : ok = strequal(idmap_backend, default_backends[i]);
561 20 : if (ok) {
562 4 : valid_backend = true;
563 : }
564 : }
565 :
566 4 : if (!valid_backend) {
567 0 : ret = 1;
568 0 : fprintf(stderr, "ERROR: Do not use the '%s' backend "
569 : "as the default idmap backend!\n\n",
570 : idmap_backend);
571 : }
572 :
573 4 : ok = do_idmap_check();
574 4 : if (!ok) {
575 0 : ret = 1;
576 : }
577 : }
578 :
579 : #ifndef HAVE_DLOPEN
580 : if (lp_preload_modules()) {
581 : fprintf(stderr, "WARNING: 'preload modules = ' set while loading "
582 : "plugins not supported.\n\n");
583 : }
584 : #endif
585 :
586 1874 : if (!lp_passdb_backend()) {
587 0 : fprintf(stderr, "ERROR: passdb backend must have a value or be "
588 : "left out\n\n");
589 : }
590 :
591 1874 : if (lp_os_level() > 255) {
592 0 : fprintf(stderr, "WARNING: Maximum value for 'os level' is "
593 : "255!\n\n");
594 : }
595 :
596 1874 : if (strequal(lp_dos_charset(), "UTF8") || strequal(lp_dos_charset(), "UTF-8")) {
597 0 : fprintf(stderr, "ERROR: 'dos charset' must not be UTF8\n\n");
598 0 : ret = 1;
599 : }
600 :
601 1874 : if (lp_server_schannel() != true) { /* can be 'auto' */
602 0 : fprintf(stderr,
603 : "WARNING: You have not configured "
604 : "'server schannel = yes' (the default). "
605 : "Your server is vulernable to \"ZeroLogon\" "
606 : "(CVE-2020-1472)\n"
607 : "If required use individual "
608 : "'server require schannel:COMPUTERACCOUNT$ = no' "
609 : "options\n\n");
610 : }
611 1874 : if (lp_allow_nt4_crypto()) {
612 2 : fprintf(stderr,
613 : "WARNING: You have not configured "
614 : "'allow nt4 crypto = no' (the default). "
615 : "Your server is vulernable to "
616 : "CVE-2022-38023 and others!\n"
617 : "If required use individual "
618 : "'allow nt4 crypto:COMPUTERACCOUNT$ = yes' "
619 : "options\n\n");
620 : }
621 1874 : if (!lp_reject_md5_clients()) {
622 0 : fprintf(stderr,
623 : "WARNING: You have not configured "
624 : "'reject md5 clients = yes' (the default). "
625 : "Your server is vulernable to "
626 : "CVE-2022-38023!\n"
627 : "If required use individual "
628 : "'server reject md5 schannel:COMPUTERACCOUNT$ = yes' "
629 : "options\n\n");
630 : }
631 1874 : if (!lp_server_schannel_require_seal()) {
632 0 : fprintf(stderr,
633 : "WARNING: You have not configured "
634 : "'server schannel require seal = yes' (the default). "
635 : "Your server is vulernable to "
636 : "CVE-2022-38023!\n"
637 : "If required use individual "
638 : "'server schannel require seal:COMPUTERACCOUNT$ = no' "
639 : "options\n\n");
640 : }
641 :
642 1874 : if (lp_client_schannel() != true) { /* can be 'auto' */
643 0 : fprintf(stderr,
644 : "WARNING: You have not configured "
645 : "'client schannel = yes' (the default). "
646 : "Your server is vulernable to \"ZeroLogon\" "
647 : "(CVE-2020-1472)\n"
648 : "If required use individual "
649 : "'client schannel:NETBIOSDOMAIN = no' "
650 : "options\n\n");
651 : }
652 1874 : if (!lp_reject_md5_servers()) {
653 0 : fprintf(stderr,
654 : "WARNING: You have not configured "
655 : "'reject md5 servers = yes' (the default). "
656 : "Your server is vulernable to "
657 : "CVE-2022-38023\n"
658 : "If required use individual "
659 : "'reject md5 servers:NETBIOSDOMAIN = no' "
660 : "options\n\n");
661 : }
662 1874 : if (!lp_require_strong_key()) {
663 0 : fprintf(stderr,
664 : "WARNING: You have not configured "
665 : "'require strong key = yes' (the default). "
666 : "Your server is vulernable to "
667 : "CVE-2022-38023\n"
668 : "If required use individual "
669 : "'require strong key:NETBIOSDOMAIN = no' "
670 : "options\n\n");
671 : }
672 1874 : if (!lp_winbind_sealed_pipes()) {
673 0 : fprintf(stderr,
674 : "WARNING: You have not configured "
675 : "'winbind sealed pipes = yes' (the default). "
676 : "Your server is vulernable to "
677 : "CVE-2022-38023\n"
678 : "If required use individual "
679 : "'winbind sealed pipes:NETBIOSDOMAIN = no' "
680 : "options\n\n");
681 : }
682 :
683 1874 : if (lp_kerberos_encryption_types() == KERBEROS_ETYPES_LEGACY) {
684 0 : fprintf(stderr,
685 : "WARNING: You have configured "
686 : "'kerberos encryption types = legacy'. "
687 : "Your server is vulernable to "
688 : "CVE-2022-37966\n\n");
689 : }
690 :
691 1874 : return ret;
692 : }
693 :
694 : /**
695 : * per-share logic tests
696 : */
697 1629 : static void do_per_share_checks(int s)
698 : {
699 1409 : const struct loadparm_substitution *lp_sub =
700 220 : loadparm_s3_global_substitution();
701 1629 : const char **deny_list = lp_hosts_deny(s);
702 1629 : const char **allow_list = lp_hosts_allow(s);
703 1629 : const char **vfs_objects = NULL;
704 : int i;
705 : static bool uses_fruit;
706 : static bool doesnt_use_fruit;
707 : static bool fruit_mix_warned;
708 :
709 1629 : if(deny_list) {
710 4 : for (i=0; deny_list[i]; i++) {
711 3 : char *hasstar = strchr_m(deny_list[i], '*');
712 3 : char *hasquery = strchr_m(deny_list[i], '?');
713 3 : if(hasstar || hasquery) {
714 0 : fprintf(stderr,
715 : "Invalid character %c in hosts deny list "
716 : "(%s) for service %s.\n\n",
717 0 : hasstar ? *hasstar : *hasquery,
718 0 : deny_list[i],
719 : lp_servicename(talloc_tos(), lp_sub, s));
720 : }
721 : }
722 : }
723 :
724 1629 : if(allow_list) {
725 4 : for (i=0; allow_list[i]; i++) {
726 3 : char *hasstar = strchr_m(allow_list[i], '*');
727 3 : char *hasquery = strchr_m(allow_list[i], '?');
728 3 : if(hasstar || hasquery) {
729 0 : fprintf(stderr,
730 : "Invalid character %c in hosts allow "
731 : "list (%s) for service %s.\n\n",
732 0 : hasstar ? *hasstar : *hasquery,
733 0 : allow_list[i],
734 : lp_servicename(talloc_tos(), lp_sub, s));
735 : }
736 : }
737 : }
738 :
739 1629 : if(lp_level2_oplocks(s) && !lp_oplocks(s)) {
740 0 : fprintf(stderr, "Invalid combination of parameters for service "
741 : "%s. Level II oplocks can only be set if oplocks "
742 : "are also set.\n\n",
743 : lp_servicename(talloc_tos(), lp_sub, s));
744 : }
745 :
746 1629 : if (!lp_store_dos_attributes(s) && lp_map_hidden(s)
747 0 : && !(lp_create_mask(s) & S_IXOTH))
748 : {
749 0 : fprintf(stderr,
750 : "Invalid combination of parameters for service %s. Map "
751 : "hidden can only work if create mask includes octal "
752 : "01 (S_IXOTH).\n\n",
753 : lp_servicename(talloc_tos(), lp_sub, s));
754 : }
755 1629 : if (!lp_store_dos_attributes(s) && lp_map_hidden(s)
756 0 : && (lp_force_create_mode(s) & S_IXOTH))
757 : {
758 0 : fprintf(stderr,
759 : "Invalid combination of parameters for service "
760 : "%s. Map hidden can only work if force create mode "
761 : "excludes octal 01 (S_IXOTH).\n\n",
762 : lp_servicename(talloc_tos(), lp_sub, s));
763 : }
764 1629 : if (!lp_store_dos_attributes(s) && lp_map_system(s)
765 0 : && !(lp_create_mask(s) & S_IXGRP))
766 : {
767 0 : fprintf(stderr,
768 : "Invalid combination of parameters for service "
769 : "%s. Map system can only work if create mask includes "
770 : "octal 010 (S_IXGRP).\n\n",
771 : lp_servicename(talloc_tos(), lp_sub, s));
772 : }
773 1629 : if (!lp_store_dos_attributes(s) && lp_map_system(s)
774 0 : && (lp_force_create_mode(s) & S_IXGRP))
775 : {
776 0 : fprintf(stderr,
777 : "Invalid combination of parameters for service "
778 : "%s. Map system can only work if force create mode "
779 : "excludes octal 010 (S_IXGRP).\n\n",
780 : lp_servicename(talloc_tos(), lp_sub, s));
781 : }
782 1629 : if (lp_printing(s) == PRINT_CUPS && *(lp_print_command(s)) != '\0') {
783 1 : fprintf(stderr,
784 : "Warning: Service %s defines a print command, but "
785 : "parameter is ignored when using CUPS libraries.\n\n",
786 : lp_servicename(talloc_tos(), lp_sub, s));
787 : }
788 :
789 1629 : vfs_objects = lp_vfs_objects(s);
790 1629 : if (vfs_objects && str_list_check(vfs_objects, "fruit")) {
791 18 : uses_fruit = true;
792 : } else {
793 1611 : doesnt_use_fruit = true;
794 : }
795 :
796 1629 : if (uses_fruit && doesnt_use_fruit && !fruit_mix_warned) {
797 2 : fruit_mix_warned = true;
798 2 : fprintf(stderr,
799 : "WARNING: some services use vfs_fruit, others don't. Mounting them "
800 : "in conjunction on OS X clients results in undefined behaviour.\n\n");
801 : }
802 1629 : }
803 :
804 1875 : int main(int argc, const char *argv[])
805 : {
806 1875 : const char *config_file = NULL;
807 1873 : const struct loadparm_substitution *lp_sub =
808 2 : loadparm_s3_global_substitution();
809 : int opt;
810 : int s;
811 : static int silent_mode = False;
812 : static int show_all_parameters = False;
813 1875 : int ret = 0;
814 : poptContext pc;
815 : static char *parameter_name = NULL;
816 : static const char *section_name = NULL;
817 : const char *cname;
818 : const char *caddr;
819 : static int show_defaults;
820 : static int skip_logic_checks = 0;
821 : bool ok;
822 :
823 7500 : struct poptOption long_options[] = {
824 : POPT_AUTOHELP
825 : {
826 : .longName = "suppress-prompt",
827 : .shortName = 's',
828 : .argInfo = POPT_ARG_VAL,
829 : .arg = &silent_mode,
830 : .val = 1,
831 : .descrip = "Suppress prompt for enter",
832 : },
833 : {
834 : .longName = "verbose",
835 : .shortName = 'v',
836 : .argInfo = POPT_ARG_NONE,
837 : .arg = &show_defaults,
838 : .val = 1,
839 : .descrip = "Show default options too",
840 : },
841 : {
842 : .longName = "skip-logic-checks",
843 : .shortName = 'l',
844 : .argInfo = POPT_ARG_NONE,
845 : .arg = &skip_logic_checks,
846 : .val = 1,
847 : .descrip = "Skip the global checks",
848 : },
849 : {
850 : .longName = "show-all-parameters",
851 : .shortName = '\0',
852 : .argInfo = POPT_ARG_VAL,
853 : .arg = &show_all_parameters,
854 : .val = True,
855 : .descrip = "Show the parameters, type, possible "
856 : "values",
857 : },
858 : {
859 : .longName = "parameter-name",
860 : .shortName = '\0',
861 : .argInfo = POPT_ARG_STRING,
862 : .arg = ¶meter_name,
863 : .val = 0,
864 : .descrip = "Limit testparm to a named parameter",
865 : },
866 : {
867 : .longName = "section-name",
868 : .shortName = '\0',
869 : .argInfo = POPT_ARG_STRING,
870 : .arg = §ion_name,
871 : .val = 0,
872 : .descrip = "Limit testparm to a named section",
873 : },
874 1875 : POPT_COMMON_DEBUG_ONLY
875 1875 : POPT_COMMON_OPTION_ONLY
876 1875 : POPT_COMMON_VERSION
877 : POPT_TABLEEND
878 : };
879 :
880 1875 : TALLOC_CTX *frame = talloc_stackframe();
881 :
882 1875 : smb_init_locale();
883 :
884 1875 : ok = samba_cmdline_init(frame,
885 : SAMBA_CMDLINE_CONFIG_NONE,
886 : true /* require_smbconf */);
887 1875 : if (!ok) {
888 0 : DBG_ERR("Failed to init cmdline parser!\n");
889 0 : ret = 1;
890 0 : goto done;
891 : }
892 :
893 : /*
894 : * Set the default debug level to 1.
895 : * Allow it to be overridden by the command line,
896 : * not by smb.conf.
897 : */
898 1875 : lp_set_cmdline("log level", "1");
899 :
900 1875 : pc = samba_popt_get_context(getprogname(),
901 : argc,
902 : argv,
903 : long_options,
904 : 0);
905 1875 : if (pc == NULL) {
906 0 : DBG_ERR("Failed to setup popt context!\n");
907 0 : ret = 1;
908 0 : goto done;
909 : }
910 :
911 1875 : poptSetOtherOptionHelp(pc, "[OPTION...] <config-file> [host-name] [host-ip]");
912 :
913 1875 : while ((opt = poptGetNextOpt(pc)) != -1) {
914 0 : switch (opt) {
915 0 : case POPT_ERROR_BADOPT:
916 0 : fprintf(stderr, "\nInvalid option %s: %s\n\n",
917 : poptBadOption(pc, 0), poptStrerror(opt));
918 0 : poptPrintUsage(pc, stderr, 0);
919 0 : exit(1);
920 : }
921 : }
922 :
923 1874 : if (show_all_parameters) {
924 0 : show_parameter_list();
925 0 : exit(0);
926 : }
927 :
928 1874 : if (poptPeekArg(pc)) {
929 1874 : config_file = talloc_strdup(frame, poptGetArg(pc));
930 1874 : if (config_file == NULL) {
931 0 : DBG_ERR("out of memory\n");
932 0 : TALLOC_FREE(frame);
933 0 : exit(1);
934 : }
935 : } else {
936 0 : config_file = get_dyn_CONFIGFILE();
937 : }
938 :
939 1874 : cname = talloc_strdup(frame, poptGetArg(pc));
940 1874 : caddr = talloc_strdup(frame, poptGetArg(pc));
941 :
942 1874 : poptFreeContext(pc);
943 :
944 1874 : if ( cname && ! caddr ) {
945 0 : printf ( "ERROR: You must specify both a machine name and an IP address.\n" );
946 0 : ret = 1;
947 0 : goto done;
948 : }
949 :
950 1874 : fprintf(stderr,"Load smb config files from %s\n",config_file);
951 :
952 1874 : if (!lp_load_with_registry_shares(config_file)) {
953 0 : fprintf(stderr,"Error loading services.\n");
954 0 : ret = 1;
955 0 : goto done;
956 : }
957 :
958 1874 : fprintf(stderr,"Loaded services file OK.\n");
959 :
960 1874 : fprintf(stderr,
961 : "Weak crypto is %sallowed by GnuTLS "
962 : "(e.g. NTLM as a compatibility fallback)\n",
963 1874 : samba_gnutls_weak_crypto_allowed() ? "" : "dis");
964 :
965 1874 : if (skip_logic_checks == 0) {
966 1874 : ret = do_global_checks();
967 : }
968 :
969 1875874 : for (s=0;s<1000;s++) {
970 1874000 : if (VALID_SNUM(s) && (skip_logic_checks == 0)) {
971 1629 : do_per_share_checks(s);
972 : }
973 : }
974 :
975 :
976 1874 : if (!section_name && !parameter_name) {
977 464 : fprintf(stderr,
978 : "Server role: %s\n\n",
979 464 : server_role_str(lp_server_role()));
980 : }
981 :
982 1874 : if (!cname) {
983 1874 : if (!silent_mode) {
984 0 : fprintf(stderr,"Press enter to see a dump of your service definitions\n");
985 0 : fflush(stdout);
986 0 : getc(stdin);
987 : }
988 1874 : if (parameter_name || section_name) {
989 1410 : bool isGlobal = False;
990 1410 : s = GLOBAL_SECTION_SNUM;
991 :
992 1410 : if (!section_name) {
993 0 : section_name = GLOBAL_NAME;
994 0 : isGlobal = True;
995 1807 : } else if ((isGlobal=!strwicmp(section_name, GLOBAL_NAME)) == 0 &&
996 397 : (s=lp_servicenumber(section_name)) == -1) {
997 0 : fprintf(stderr,"Unknown section %s\n",
998 : section_name);
999 0 : ret = 1;
1000 0 : goto done;
1001 : }
1002 1410 : if (parameter_name) {
1003 1410 : if (!dump_a_parameter( s, parameter_name, stdout, isGlobal)) {
1004 0 : fprintf(stderr,"Parameter %s unknown for section %s\n",
1005 : parameter_name, section_name);
1006 0 : ret = 1;
1007 0 : goto done;
1008 : }
1009 : } else {
1010 0 : if (isGlobal == True)
1011 0 : lp_dump(stdout, show_defaults, 0);
1012 : else
1013 0 : lp_dump_one(stdout, show_defaults, s);
1014 : }
1015 1410 : goto done;
1016 : }
1017 :
1018 464 : lp_dump(stdout, show_defaults, lp_numservices());
1019 : }
1020 :
1021 464 : if(cname && caddr){
1022 : /* this is totally ugly, a real `quick' hack */
1023 0 : for (s=0;s<1000;s++) {
1024 0 : if (VALID_SNUM(s)) {
1025 0 : if (allow_access(lp_hosts_deny(-1), lp_hosts_allow(-1), cname, caddr)
1026 0 : && allow_access(lp_hosts_deny(s), lp_hosts_allow(s), cname, caddr)) {
1027 0 : fprintf(stderr,"Allow connection from %s (%s) to %s\n",
1028 : cname,caddr,lp_servicename(talloc_tos(), lp_sub, s));
1029 : } else {
1030 0 : fprintf(stderr,"Deny connection from %s (%s) to %s\n",
1031 : cname,caddr,lp_servicename(talloc_tos(), lp_sub, s));
1032 : }
1033 : }
1034 : }
1035 : }
1036 :
1037 464 : done:
1038 1874 : gfree_loadparm();
1039 1874 : TALLOC_FREE(frame);
1040 1874 : return ret;
1041 : }
|