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 7576 : 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 7576 : if (!st)
54 0 : st = &st2;
55 :
56 7576 : if (sys_stat(dname, st, false) != 0)
57 7560 : 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 1894 : static int do_global_checks(void)
279 : {
280 1894 : int ret = 0;
281 0 : SMB_STRUCT_STAT st;
282 0 : const char *socket_options;
283 0 : const struct loadparm_substitution *lp_sub =
284 1894 : loadparm_s3_global_substitution();
285 :
286 1894 : fprintf(stderr, "\n");
287 :
288 1894 : 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 1894 : 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 1894 : 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 1894 : if (strequal(lp_workgroup(), lp_netbios_name())) {
324 0 : fprintf(stderr, "WARNING: 'workgroup' and 'netbios name' "
325 : "must differ.\n\n");
326 : }
327 :
328 1894 : if (lp_client_ipc_signing() == SMB_SIGNING_IF_REQUIRED
329 1894 : || 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 1894 : if (strlen(lp_netbios_name()) > 15) {
341 1887 : fprintf(stderr, "WARNING: The 'netbios name' is too long "
342 : "(max. 15 chars).\n\n");
343 : }
344 :
345 1894 : if (!directory_exist_stat(lp_lock_directory(), &st)) {
346 1890 : fprintf(stderr, "ERROR: lock directory %s does not exist\n\n",
347 : lp_lock_directory());
348 1890 : 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 1894 : if (!directory_exist_stat(lp_state_directory(), &st)) {
356 1890 : fprintf(stderr, "ERROR: state directory %s does not exist\n\n",
357 : lp_state_directory());
358 1890 : 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 1894 : if (!directory_exist_stat(lp_cache_directory(), &st)) {
366 1890 : fprintf(stderr, "ERROR: cache directory %s does not exist\n\n",
367 : lp_cache_directory());
368 1890 : 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 1894 : if (!directory_exist_stat(lp_pid_directory(), &st)) {
376 1890 : fprintf(stderr, "ERROR: pid directory %s does not exist\n\n",
377 : lp_pid_directory());
378 1890 : ret = 1;
379 : }
380 :
381 1894 : 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 1894 : socket_options = lp_socket_options();
390 1894 : if (socket_options != NULL &&
391 1894 : (strstr(socket_options, "SO_SNDBUF") ||
392 1894 : strstr(socket_options, "SO_RCVBUF") ||
393 1894 : strstr(socket_options, "SO_SNDLOWAT") ||
394 1894 : 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 1894 : 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 1894 : 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 1894 : 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 1894 : 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 1894 : if (*lp_winbind_separator() == '+') {
550 0 : fprintf(stderr, "'winbind separator = +' might cause problems "
551 : "with group membership.\n\n");
552 : }
553 :
554 1894 : 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 1894 : if (lp_algorithmic_rid_base() & 1) {
562 2 : fprintf(stderr, "'algorithmic rid base' must be even.\n\n");
563 : }
564 :
565 1894 : 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 1894 : 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 1894 : if (lp_os_level() > 255) {
609 0 : fprintf(stderr, "WARNING: Maximum value for 'os level' is "
610 : "255!\n\n");
611 : }
612 :
613 1894 : 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 1894 : if (lp_server_schannel() != true) { /* can be 'auto' */
619 0 : fprintf(stderr,
620 : "WARNING: You have not configured "
621 : "'server schannel = yes' (the default). "
622 : "Your server is vulnerable to \"ZeroLogon\" "
623 : "(CVE-2020-1472)\n"
624 : "If required use individual "
625 : "'server require schannel:COMPUTERACCOUNT$ = no' "
626 : "options\n\n");
627 : }
628 1894 : if (lp_allow_nt4_crypto()) {
629 2 : fprintf(stderr,
630 : "WARNING: You have not configured "
631 : "'allow nt4 crypto = no' (the default). "
632 : "Your server is vulnerable to "
633 : "CVE-2022-38023 and others!\n"
634 : "If required use individual "
635 : "'allow nt4 crypto:COMPUTERACCOUNT$ = yes' "
636 : "options\n\n");
637 : }
638 1894 : if (!lp_reject_md5_clients()) {
639 0 : fprintf(stderr,
640 : "WARNING: You have not configured "
641 : "'reject md5 clients = yes' (the default). "
642 : "Your server is vulnerable to "
643 : "CVE-2022-38023!\n"
644 : "If required use individual "
645 : "'server reject md5 schannel:COMPUTERACCOUNT$ = yes' "
646 : "options\n\n");
647 : }
648 1894 : if (!lp_server_schannel_require_seal()) {
649 0 : fprintf(stderr,
650 : "WARNING: You have not configured "
651 : "'server schannel require seal = yes' (the default). "
652 : "Your server is vulnerable to "
653 : "CVE-2022-38023!\n"
654 : "If required use individual "
655 : "'server schannel require seal:COMPUTERACCOUNT$ = no' "
656 : "options\n\n");
657 : }
658 :
659 1894 : if (lp_client_schannel() != true) { /* can be 'auto' */
660 0 : fprintf(stderr,
661 : "WARNING: You have not configured "
662 : "'client schannel = yes' (the default). "
663 : "Your server is vulnerable to \"ZeroLogon\" "
664 : "(CVE-2020-1472)\n"
665 : "If required use individual "
666 : "'client schannel:NETBIOSDOMAIN = no' "
667 : "options\n\n");
668 : }
669 1894 : if (!lp_reject_md5_servers()) {
670 0 : fprintf(stderr,
671 : "WARNING: You have not configured "
672 : "'reject md5 servers = yes' (the default). "
673 : "Your server is vulnerable to "
674 : "CVE-2022-38023\n"
675 : "If required use individual "
676 : "'reject md5 servers:NETBIOSDOMAIN = no' "
677 : "options\n\n");
678 : }
679 1894 : if (!lp_require_strong_key()) {
680 0 : fprintf(stderr,
681 : "WARNING: You have not configured "
682 : "'require strong key = yes' (the default). "
683 : "Your server is vulnerable to "
684 : "CVE-2022-38023\n"
685 : "If required use individual "
686 : "'require strong key:NETBIOSDOMAIN = no' "
687 : "options\n\n");
688 : }
689 1894 : if (!lp_winbind_sealed_pipes()) {
690 0 : fprintf(stderr,
691 : "WARNING: You have not configured "
692 : "'winbind sealed pipes = yes' (the default). "
693 : "Your server is vulnerable to "
694 : "CVE-2022-38023\n"
695 : "If required use individual "
696 : "'winbind sealed pipes:NETBIOSDOMAIN = no' "
697 : "options\n\n");
698 : }
699 :
700 1894 : if (lp_kerberos_encryption_types() == KERBEROS_ETYPES_LEGACY) {
701 0 : fprintf(stderr,
702 : "WARNING: You have configured "
703 : "'kerberos encryption types = legacy'. "
704 : "Your server is vulnerable to "
705 : "CVE-2022-37966\n\n");
706 : }
707 :
708 1894 : return ret;
709 : }
710 :
711 : /**
712 : * per-share logic tests
713 : */
714 1664 : static void do_per_share_checks(int s)
715 : {
716 0 : const struct loadparm_substitution *lp_sub =
717 1664 : loadparm_s3_global_substitution();
718 1664 : const char **deny_list = lp_hosts_deny(s);
719 1664 : const char **allow_list = lp_hosts_allow(s);
720 1664 : const char **vfs_objects = NULL;
721 0 : int i;
722 0 : static bool uses_fruit;
723 0 : static bool doesnt_use_fruit;
724 0 : static bool fruit_mix_warned;
725 :
726 1664 : if(deny_list) {
727 4 : for (i=0; deny_list[i]; i++) {
728 3 : char *hasstar = strchr_m(deny_list[i], '*');
729 3 : char *hasquery = strchr_m(deny_list[i], '?');
730 3 : if(hasstar || hasquery) {
731 0 : fprintf(stderr,
732 : "Invalid character %c in hosts deny list "
733 : "(%s) for service %s.\n\n",
734 0 : hasstar ? *hasstar : *hasquery,
735 0 : deny_list[i],
736 : lp_servicename(talloc_tos(), lp_sub, s));
737 : }
738 : }
739 : }
740 :
741 1664 : if(allow_list) {
742 4 : for (i=0; allow_list[i]; i++) {
743 3 : char *hasstar = strchr_m(allow_list[i], '*');
744 3 : char *hasquery = strchr_m(allow_list[i], '?');
745 3 : if(hasstar || hasquery) {
746 0 : fprintf(stderr,
747 : "Invalid character %c in hosts allow "
748 : "list (%s) for service %s.\n\n",
749 0 : hasstar ? *hasstar : *hasquery,
750 0 : allow_list[i],
751 : lp_servicename(talloc_tos(), lp_sub, s));
752 : }
753 : }
754 : }
755 :
756 1664 : if(lp_level2_oplocks(s) && !lp_oplocks(s)) {
757 0 : fprintf(stderr, "Invalid combination of parameters for service "
758 : "%s. Level II oplocks can only be set if oplocks "
759 : "are also set.\n\n",
760 : lp_servicename(talloc_tos(), lp_sub, s));
761 : }
762 :
763 1664 : if (!lp_store_dos_attributes(s) && lp_map_hidden(s)
764 0 : && !(lp_create_mask(s) & S_IXOTH))
765 : {
766 0 : fprintf(stderr,
767 : "Invalid combination of parameters for service %s. Map "
768 : "hidden can only work if create mask includes octal "
769 : "01 (S_IXOTH).\n\n",
770 : lp_servicename(talloc_tos(), lp_sub, s));
771 : }
772 1664 : if (!lp_store_dos_attributes(s) && lp_map_hidden(s)
773 0 : && (lp_force_create_mode(s) & S_IXOTH))
774 : {
775 0 : fprintf(stderr,
776 : "Invalid combination of parameters for service "
777 : "%s. Map hidden can only work if force create mode "
778 : "excludes octal 01 (S_IXOTH).\n\n",
779 : lp_servicename(talloc_tos(), lp_sub, s));
780 : }
781 1664 : if (!lp_store_dos_attributes(s) && lp_map_system(s)
782 0 : && !(lp_create_mask(s) & S_IXGRP))
783 : {
784 0 : fprintf(stderr,
785 : "Invalid combination of parameters for service "
786 : "%s. Map system can only work if create mask includes "
787 : "octal 010 (S_IXGRP).\n\n",
788 : lp_servicename(talloc_tos(), lp_sub, s));
789 : }
790 1664 : if (!lp_store_dos_attributes(s) && lp_map_system(s)
791 0 : && (lp_force_create_mode(s) & S_IXGRP))
792 : {
793 0 : fprintf(stderr,
794 : "Invalid combination of parameters for service "
795 : "%s. Map system can only work if force create mode "
796 : "excludes octal 010 (S_IXGRP).\n\n",
797 : lp_servicename(talloc_tos(), lp_sub, s));
798 : }
799 1664 : if (lp_printing(s) == PRINT_CUPS && *(lp_print_command(s)) != '\0') {
800 1 : fprintf(stderr,
801 : "Warning: Service %s defines a print command, but "
802 : "parameter is ignored when using CUPS libraries.\n\n",
803 : lp_servicename(talloc_tos(), lp_sub, s));
804 : }
805 :
806 1664 : vfs_objects = lp_vfs_objects(s);
807 1664 : if (vfs_objects && str_list_check(vfs_objects, "fruit")) {
808 18 : uses_fruit = true;
809 : } else {
810 1646 : doesnt_use_fruit = true;
811 : }
812 :
813 1664 : if (uses_fruit && doesnt_use_fruit && !fruit_mix_warned) {
814 2 : fruit_mix_warned = true;
815 2 : fprintf(stderr,
816 : "WARNING: some services use vfs_fruit, others don't. Mounting them "
817 : "in conjunction on OS X clients results in undefined behaviour.\n\n");
818 : }
819 1664 : }
820 :
821 1961 : int main(int argc, const char *argv[])
822 : {
823 1961 : const char *config_file = NULL;
824 4 : const struct loadparm_substitution *lp_sub =
825 1961 : loadparm_s3_global_substitution();
826 4 : int opt;
827 4 : int s;
828 4 : static int silent_mode = False;
829 4 : static int show_all_parameters = False;
830 1961 : int ret = 0;
831 4 : poptContext pc;
832 4 : static char *parameter_name = NULL;
833 4 : static const char *section_name = NULL;
834 4 : const char *cname;
835 4 : const char *caddr;
836 4 : static int show_defaults;
837 4 : static int skip_logic_checks = 0;
838 4 : bool ok;
839 :
840 7844 : struct poptOption long_options[] = {
841 : POPT_AUTOHELP
842 : {
843 : .longName = "suppress-prompt",
844 : .shortName = 's',
845 : .argInfo = POPT_ARG_VAL,
846 : .arg = &silent_mode,
847 : .val = 1,
848 : .descrip = "Suppress prompt for enter",
849 : },
850 : {
851 : .longName = "verbose",
852 : .shortName = 'v',
853 : .argInfo = POPT_ARG_NONE,
854 : .arg = &show_defaults,
855 : .val = 1,
856 : .descrip = "Show default options too",
857 : },
858 : {
859 : .longName = "skip-logic-checks",
860 : .shortName = 'l',
861 : .argInfo = POPT_ARG_NONE,
862 : .arg = &skip_logic_checks,
863 : .val = 1,
864 : .descrip = "Skip the global checks",
865 : },
866 : {
867 : .longName = "show-all-parameters",
868 : .shortName = '\0',
869 : .argInfo = POPT_ARG_VAL,
870 : .arg = &show_all_parameters,
871 : .val = True,
872 : .descrip = "Show the parameters, type, possible "
873 : "values",
874 : },
875 : {
876 : .longName = "parameter-name",
877 : .shortName = '\0',
878 : .argInfo = POPT_ARG_STRING,
879 : .arg = ¶meter_name,
880 : .val = 0,
881 : .descrip = "Limit testparm to a named parameter",
882 : },
883 : {
884 : .longName = "section-name",
885 : .shortName = '\0',
886 : .argInfo = POPT_ARG_STRING,
887 : .arg = §ion_name,
888 : .val = 0,
889 : .descrip = "Limit testparm to a named section",
890 : },
891 1961 : POPT_COMMON_DEBUG_ONLY
892 1961 : POPT_COMMON_OPTION_ONLY
893 1961 : POPT_COMMON_VERSION
894 : POPT_TABLEEND
895 : };
896 :
897 1961 : TALLOC_CTX *frame = talloc_stackframe();
898 1961 : struct loadparm_context *lp_ctx = NULL;
899 :
900 1961 : smb_init_locale();
901 :
902 1961 : ok = samba_cmdline_init(frame,
903 : SAMBA_CMDLINE_CONFIG_NONE,
904 : true /* require_smbconf */);
905 1961 : if (!ok) {
906 0 : DBG_ERR("Failed to init cmdline parser!\n");
907 0 : ret = 1;
908 0 : goto done;
909 : }
910 1961 : lp_ctx = samba_cmdline_get_lp_ctx();
911 :
912 : /*
913 : * Set the default debug level to 1.
914 : * Allow it to be overridden by the command line,
915 : * not by smb.conf.
916 : */
917 1961 : lpcfg_set_cmdline(lp_ctx, "log level", "1");
918 :
919 1961 : pc = samba_popt_get_context(getprogname(),
920 : argc,
921 : argv,
922 : long_options,
923 : 0);
924 1961 : if (pc == NULL) {
925 0 : DBG_ERR("Failed to setup popt context!\n");
926 0 : ret = 1;
927 0 : goto done;
928 : }
929 :
930 1961 : poptSetOtherOptionHelp(pc, "[OPTION...] <config-file> [host-name] [host-ip]");
931 :
932 2027 : while ((opt = poptGetNextOpt(pc)) != -1) {
933 66 : switch (opt) {
934 0 : case POPT_ERROR_BADOPT:
935 0 : fprintf(stderr, "\nInvalid option %s: %s\n\n",
936 : poptBadOption(pc, 0), poptStrerror(opt));
937 0 : poptPrintUsage(pc, stderr, 0);
938 0 : exit(1);
939 : }
940 : }
941 :
942 1960 : if (show_all_parameters) {
943 0 : show_parameter_list();
944 0 : exit(0);
945 : }
946 :
947 1960 : if (poptPeekArg(pc)) {
948 1960 : config_file = talloc_strdup(frame, poptGetArg(pc));
949 1960 : if (config_file == NULL) {
950 0 : DBG_ERR("out of memory\n");
951 0 : TALLOC_FREE(frame);
952 0 : exit(1);
953 : }
954 : } else {
955 0 : config_file = get_dyn_CONFIGFILE();
956 : }
957 :
958 1960 : cname = talloc_strdup(frame, poptGetArg(pc));
959 1960 : caddr = talloc_strdup(frame, poptGetArg(pc));
960 :
961 1960 : poptFreeContext(pc);
962 :
963 1960 : if ( cname && ! caddr ) {
964 0 : printf ( "ERROR: You must specify both a machine name and an IP address.\n" );
965 0 : ret = 1;
966 0 : goto done;
967 : }
968 :
969 1960 : fprintf(stderr,"Load smb config files from %s\n",config_file);
970 :
971 1960 : if (!lp_load_with_registry_shares(config_file)) {
972 8 : fprintf(stderr,"Error loading services.\n");
973 8 : ret = 1;
974 8 : goto done;
975 : }
976 :
977 1952 : fprintf(stderr,"Loaded services file OK.\n");
978 :
979 1952 : fprintf(stderr,
980 : "Weak crypto is %sallowed by GnuTLS "
981 : "(e.g. NTLM as a compatibility fallback)\n",
982 1952 : samba_gnutls_weak_crypto_allowed() ? "" : "dis");
983 :
984 1952 : if (skip_logic_checks == 0) {
985 1894 : ret = do_global_checks();
986 : }
987 :
988 1953952 : for (s=0;s<1000;s++) {
989 1952000 : if (VALID_SNUM(s) && (skip_logic_checks == 0)) {
990 1664 : do_per_share_checks(s);
991 : }
992 : }
993 :
994 :
995 1952 : if (!section_name && !parameter_name) {
996 525 : fprintf(stderr,
997 : "Server role: %s\n\n",
998 525 : server_role_str(lp_server_role()));
999 : }
1000 :
1001 1952 : if (!cname) {
1002 1952 : if (!silent_mode) {
1003 0 : fprintf(stderr,"Press enter to see a dump of your service definitions\n");
1004 0 : fflush(stdout);
1005 0 : getc(stdin);
1006 : }
1007 1952 : if (parameter_name || section_name) {
1008 1427 : bool isGlobal = False;
1009 1427 : s = GLOBAL_SECTION_SNUM;
1010 :
1011 1427 : if (!section_name) {
1012 4 : section_name = GLOBAL_NAME;
1013 4 : isGlobal = True;
1014 1827 : } else if ((isGlobal=!strwicmp(section_name, GLOBAL_NAME)) == 0 &&
1015 404 : (s=lp_servicenumber(section_name)) == -1) {
1016 0 : fprintf(stderr,"Unknown section %s\n",
1017 : section_name);
1018 0 : ret = 1;
1019 0 : goto done;
1020 : }
1021 1427 : if (parameter_name) {
1022 1427 : if (!dump_a_parameter( s, parameter_name, stdout, isGlobal)) {
1023 0 : fprintf(stderr,"Parameter %s unknown for section %s\n",
1024 : parameter_name, section_name);
1025 0 : ret = 1;
1026 0 : goto done;
1027 : }
1028 : } else {
1029 0 : if (isGlobal == True)
1030 0 : lp_dump(stdout, show_defaults, 0);
1031 : else
1032 0 : lp_dump_one(stdout, show_defaults, s);
1033 : }
1034 1427 : goto done;
1035 : }
1036 :
1037 525 : lp_dump(stdout, show_defaults, lp_numservices());
1038 : }
1039 :
1040 525 : if(cname && caddr){
1041 : /* this is totally ugly, a real `quick' hack */
1042 0 : for (s=0;s<1000;s++) {
1043 0 : if (VALID_SNUM(s)) {
1044 0 : if (allow_access(lp_hosts_deny(-1), lp_hosts_allow(-1), cname, caddr)
1045 0 : && allow_access(lp_hosts_deny(s), lp_hosts_allow(s), cname, caddr)) {
1046 0 : fprintf(stderr,"Allow connection from %s (%s) to %s\n",
1047 : cname,caddr,lp_servicename(talloc_tos(), lp_sub, s));
1048 : } else {
1049 0 : fprintf(stderr,"Deny connection from %s (%s) to %s\n",
1050 : cname,caddr,lp_servicename(talloc_tos(), lp_sub, s));
1051 : }
1052 : }
1053 : }
1054 : }
1055 :
1056 525 : done:
1057 1960 : gfree_loadparm();
1058 1960 : TALLOC_FREE(frame);
1059 1960 : return ret;
1060 : }
|