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