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 1874 : const char *check_pw_script = NULL;
269 :
270 1874 : fprintf(stderr, "\n");
271 :
272 1874 : if (lp_security() >= SEC_DOMAIN && !lp_encrypt_passwords()) {
273 0 : fprintf(stderr, "ERROR: in 'security=domain' mode the "
274 : "'encrypt passwords' parameter must always be "
275 : "set to 'true'.\n\n");
276 0 : ret = 1;
277 : }
278 :
279 1874 : if (lp_security() == SEC_ADS) {
280 2 : const char *workgroup = lp_workgroup();
281 2 : const char *realm = lp_realm();
282 :
283 2 : if (workgroup == NULL || strlen(workgroup) == 0) {
284 0 : fprintf(stderr,
285 : "ERROR: The 'security=ADS' mode requires "
286 : "'workgroup' parameter to be set!\n\n ");
287 0 : ret = 1;
288 : }
289 :
290 2 : if (realm == NULL || strlen(realm) == 0) {
291 0 : fprintf(stderr,
292 : "ERROR: The 'security=ADS' mode requires "
293 : "'realm' parameter to be set!\n\n ");
294 0 : ret = 1;
295 : }
296 : }
297 :
298 :
299 1874 : if (lp_we_are_a_wins_server() && lp_wins_server_list()) {
300 0 : fprintf(stderr, "ERROR: both 'wins support = true' and "
301 : "'wins server = <server list>' cannot be set in "
302 : "the smb.conf file. nmbd will abort with this "
303 : "setting.\n\n");
304 0 : ret = 1;
305 : }
306 :
307 1874 : if (strequal(lp_workgroup(), lp_netbios_name())) {
308 0 : fprintf(stderr, "WARNING: 'workgroup' and 'netbios name' "
309 : "must differ.\n\n");
310 : }
311 :
312 1874 : if (lp_client_ipc_signing() == SMB_SIGNING_IF_REQUIRED
313 1874 : || lp_client_ipc_signing() == SMB_SIGNING_OFF) {
314 0 : fprintf(stderr, "WARNING: The 'client ipc signing' value "
315 : "%s SMB signing is not used when contacting a "
316 : "domain controller or other server. "
317 : "This setting is not recommended; please be "
318 : "aware of the security implications when using "
319 : "this configuration setting.\n\n",
320 0 : lp_client_ipc_signing() == SMB_SIGNING_OFF ?
321 : "ensures" : "may mean");
322 : }
323 :
324 1874 : if (strlen(lp_netbios_name()) > 15) {
325 1869 : fprintf(stderr, "WARNING: The 'netbios name' is too long "
326 : "(max. 15 chars).\n\n");
327 : }
328 :
329 1874 : if (!directory_exist_stat(lp_lock_directory(), &st)) {
330 1872 : fprintf(stderr, "ERROR: lock directory %s does not exist\n\n",
331 : lp_lock_directory());
332 1872 : ret = 1;
333 2 : } else if ((st.st_ex_mode & 0777) != 0755) {
334 0 : fprintf(stderr, "WARNING: lock directory %s should have "
335 : "permissions 0755 for browsing to work\n\n",
336 : lp_lock_directory());
337 : }
338 :
339 1874 : if (!directory_exist_stat(lp_state_directory(), &st)) {
340 1872 : fprintf(stderr, "ERROR: state directory %s does not exist\n\n",
341 : lp_state_directory());
342 1872 : ret = 1;
343 2 : } else if ((st.st_ex_mode & 0777) != 0755) {
344 0 : fprintf(stderr, "WARNING: state directory %s should have "
345 : "permissions 0755 for browsing to work\n\n",
346 : lp_state_directory());
347 : }
348 :
349 1874 : if (!directory_exist_stat(lp_cache_directory(), &st)) {
350 1872 : fprintf(stderr, "ERROR: cache directory %s does not exist\n\n",
351 : lp_cache_directory());
352 1872 : ret = 1;
353 2 : } else if ((st.st_ex_mode & 0777) != 0755) {
354 0 : fprintf(stderr, "WARNING: cache directory %s should have "
355 : "permissions 0755 for browsing to work\n\n",
356 : lp_cache_directory());
357 : }
358 :
359 1874 : if (!directory_exist_stat(lp_pid_directory(), &st)) {
360 1872 : fprintf(stderr, "ERROR: pid directory %s does not exist\n\n",
361 : lp_pid_directory());
362 1872 : ret = 1;
363 : }
364 :
365 1874 : if (lp_passdb_expand_explicit()) {
366 2 : fprintf(stderr, "WARNING: passdb expand explicit = yes is "
367 : "deprecated\n\n");
368 : }
369 :
370 : /*
371 : * Socket options.
372 : */
373 1874 : socket_options = lp_socket_options();
374 3746 : if (socket_options != NULL &&
375 3746 : (strstr(socket_options, "SO_SNDBUF") ||
376 3746 : strstr(socket_options, "SO_RCVBUF") ||
377 3746 : strstr(socket_options, "SO_SNDLOWAT") ||
378 1874 : strstr(socket_options, "SO_RCVLOWAT")))
379 : {
380 0 : fprintf(stderr,
381 : "WARNING: socket options = %s\n"
382 : "This warning is printed because you set one of the\n"
383 : "following options: SO_SNDBUF, SO_RCVBUF, SO_SNDLOWAT,\n"
384 : "SO_RCVLOWAT\n"
385 : "Modern server operating systems are tuned for\n"
386 : "high network performance in the majority of situations;\n"
387 : "when you set 'socket options' you are overriding those\n"
388 : "settings.\n"
389 : "Linux in particular has an auto-tuning mechanism for\n"
390 : "buffer sizes (SO_SNDBUF, SO_RCVBUF) that will be\n"
391 : "disabled if you specify a socket buffer size. This can\n"
392 : "potentially cripple your TCP/IP stack.\n\n"
393 : "Getting the 'socket options' correct can make a big\n"
394 : "difference to your performance, but getting them wrong\n"
395 : "can degrade it by just as much. As with any other low\n"
396 : "level setting, if you must make changes to it, make\n "
397 : "small changes and test the effect before making any\n"
398 : "large changes.\n\n",
399 : socket_options);
400 : }
401 :
402 : /*
403 : * Password server sanity checks.
404 : */
405 :
406 1874 : if((lp_security() >= SEC_DOMAIN) && !*lp_password_server()) {
407 : const char *sec_setting;
408 0 : if(lp_security() == SEC_DOMAIN)
409 0 : sec_setting = "domain";
410 0 : else if(lp_security() == SEC_ADS)
411 0 : sec_setting = "ads";
412 : else
413 0 : sec_setting = "";
414 :
415 0 : fprintf(stderr, "ERROR: The setting 'security=%s' requires the "
416 : "'password server' parameter be set to the "
417 : "default value * or a valid password server.\n\n",
418 : sec_setting );
419 0 : ret = 1;
420 : }
421 :
422 1874 : if((lp_security() >= SEC_DOMAIN) && (strcmp(lp_password_server(), "*") != 0)) {
423 : const char *sec_setting;
424 2 : if(lp_security() == SEC_DOMAIN)
425 0 : sec_setting = "domain";
426 2 : else if(lp_security() == SEC_ADS)
427 2 : sec_setting = "ads";
428 : else
429 0 : sec_setting = "";
430 :
431 2 : fprintf(stderr, "WARNING: The setting 'security=%s' should NOT "
432 : "be combined with the 'password server' "
433 : "parameter.\n"
434 : "(by default Samba will discover the correct DC "
435 : "to contact automatically).\n\n",
436 : sec_setting );
437 : }
438 :
439 : /*
440 : * Password chat sanity checks.
441 : */
442 :
443 1874 : if(lp_security() == SEC_USER && lp_unix_password_sync()) {
444 :
445 : /*
446 : * Check that we have a valid lp_passwd_program() if not using pam.
447 : */
448 :
449 : #ifdef WITH_PAM
450 2 : if (!lp_pam_password_change()) {
451 : #endif
452 :
453 4 : if((lp_passwd_program(talloc_tos(), lp_sub) == NULL) ||
454 2 : (strlen(lp_passwd_program(talloc_tos(), lp_sub)) == 0))
455 : {
456 2 : fprintf(stderr,
457 : "ERROR: the 'unix password sync' "
458 : "parameter is set and there is no valid "
459 : "'passwd program' parameter.\n\n");
460 2 : ret = 1;
461 : } else {
462 : const char *passwd_prog;
463 0 : char *truncated_prog = NULL;
464 : const char *p;
465 :
466 0 : passwd_prog = lp_passwd_program(talloc_tos(), lp_sub);
467 0 : p = passwd_prog;
468 0 : next_token_talloc(talloc_tos(),
469 : &p,
470 : &truncated_prog, NULL);
471 0 : if (truncated_prog && access(truncated_prog, F_OK) == -1) {
472 0 : fprintf(stderr,
473 : "ERROR: the 'unix password sync' "
474 : "parameter is set and the "
475 : "'passwd program' (%s) cannot be "
476 : "executed (error was %s).\n\n",
477 : truncated_prog,
478 0 : strerror(errno));
479 0 : ret = 1;
480 : }
481 : }
482 :
483 : #ifdef WITH_PAM
484 : }
485 : #endif
486 :
487 2 : if(lp_passwd_chat(talloc_tos(), lp_sub) == NULL) {
488 0 : fprintf(stderr,
489 : "ERROR: the 'unix password sync' parameter is "
490 : "set and there is no valid 'passwd chat' "
491 : "parameter.\n\n");
492 0 : ret = 1;
493 : }
494 :
495 4 : if ((lp_passwd_program(talloc_tos(), lp_sub) != NULL) &&
496 2 : (strlen(lp_passwd_program(talloc_tos(), lp_sub)) > 0))
497 : {
498 : /* check if there's a %u parameter present */
499 0 : if(strstr_m(lp_passwd_program(talloc_tos(), lp_sub), "%u") == NULL) {
500 0 : fprintf(stderr,
501 : "ERROR: the 'passwd program' (%s) "
502 : "requires a '%%u' parameter.\n\n",
503 : lp_passwd_program(talloc_tos(), lp_sub));
504 0 : ret = 1;
505 : }
506 : }
507 :
508 : /*
509 : * Check that we have a valid script and that it hasn't
510 : * been written to expect the old password.
511 : */
512 :
513 2 : if(lp_encrypt_passwords()) {
514 2 : if(strstr_m( lp_passwd_chat(talloc_tos(), lp_sub), "%o")!=NULL) {
515 0 : fprintf(stderr,
516 : "ERROR: the 'passwd chat' script [%s] "
517 : "expects to use the old plaintext "
518 : "password via the %%o substitution. With "
519 : "encrypted passwords this is not "
520 : "possible.\n\n",
521 : lp_passwd_chat(talloc_tos(), lp_sub) );
522 0 : ret = 1;
523 : }
524 : }
525 : }
526 :
527 1874 : if (strlen(lp_winbind_separator()) != 1) {
528 2 : fprintf(stderr, "ERROR: the 'winbind separator' parameter must "
529 : "be a single character.\n\n");
530 2 : ret = 1;
531 : }
532 :
533 1874 : if (*lp_winbind_separator() == '+') {
534 0 : fprintf(stderr, "'winbind separator = +' might cause problems "
535 : "with group membership.\n\n");
536 : }
537 :
538 1874 : if (lp_algorithmic_rid_base() < BASE_RID) {
539 : /* Try to prevent admin foot-shooting, we can't put algorithmic
540 : rids below 1000, that's the 'well known RIDs' on NT */
541 2 : fprintf(stderr, "'algorithmic rid base' must be equal to or "
542 : "above %lu\n\n", BASE_RID);
543 : }
544 :
545 1874 : if (lp_algorithmic_rid_base() & 1) {
546 2 : fprintf(stderr, "'algorithmic rid base' must be even.\n\n");
547 : }
548 :
549 1874 : if (lp_server_role() != ROLE_STANDALONE) {
550 4 : const char *default_backends[] = {
551 : "tdb", "tdb2", "ldap", "autorid", "hash"
552 : };
553 : const char *idmap_backend;
554 4 : bool valid_backend = false;
555 : uint32_t i;
556 : bool ok;
557 :
558 4 : idmap_backend = lp_idmap_default_backend();
559 :
560 24 : for (i = 0; i < ARRAY_SIZE(default_backends); i++) {
561 20 : ok = strequal(idmap_backend, default_backends[i]);
562 20 : if (ok) {
563 4 : valid_backend = true;
564 : }
565 : }
566 :
567 4 : if (!valid_backend) {
568 0 : ret = 1;
569 0 : fprintf(stderr, "ERROR: Do not use the '%s' backend "
570 : "as the default idmap backend!\n\n",
571 : idmap_backend);
572 : }
573 :
574 4 : ok = do_idmap_check();
575 4 : if (!ok) {
576 0 : ret = 1;
577 : }
578 : }
579 :
580 : #ifndef HAVE_DLOPEN
581 : if (lp_preload_modules()) {
582 : fprintf(stderr, "WARNING: 'preload modules = ' set while loading "
583 : "plugins not supported.\n\n");
584 : }
585 : #endif
586 :
587 1874 : if (!lp_passdb_backend()) {
588 0 : fprintf(stderr, "ERROR: passdb backend must have a value or be "
589 : "left out\n\n");
590 : }
591 :
592 1874 : if (lp_os_level() > 255) {
593 0 : fprintf(stderr, "WARNING: Maximum value for 'os level' is "
594 : "255!\n\n");
595 : }
596 :
597 1874 : if (strequal(lp_dos_charset(), "UTF8") || strequal(lp_dos_charset(), "UTF-8")) {
598 0 : fprintf(stderr, "ERROR: 'dos charset' must not be UTF8\n\n");
599 0 : ret = 1;
600 : }
601 :
602 1874 : if (lp_server_schannel() != true) { /* can be 'auto' */
603 0 : fprintf(stderr,
604 : "WARNING: You have not configured "
605 : "'server schannel = yes' (the default). "
606 : "Your server is vulernable to \"ZeroLogon\" "
607 : "(CVE-2020-1472)\n"
608 : "If required use individual "
609 : "'server require schannel:COMPUTERACCOUNT$ = no' "
610 : "options\n\n");
611 : }
612 1874 : if (lp_allow_nt4_crypto()) {
613 2 : fprintf(stderr,
614 : "WARNING: You have not configured "
615 : "'allow nt4 crypto = no' (the default). "
616 : "Your server is vulernable to "
617 : "CVE-2022-38023 and others!\n"
618 : "If required use individual "
619 : "'allow nt4 crypto:COMPUTERACCOUNT$ = yes' "
620 : "options\n\n");
621 : }
622 1874 : if (!lp_reject_md5_clients()) {
623 0 : fprintf(stderr,
624 : "WARNING: You have not configured "
625 : "'reject md5 clients = yes' (the default). "
626 : "Your server is vulernable to "
627 : "CVE-2022-38023!\n"
628 : "If required use individual "
629 : "'server reject md5 schannel:COMPUTERACCOUNT$ = yes' "
630 : "options\n\n");
631 : }
632 1874 : if (!lp_server_schannel_require_seal()) {
633 0 : fprintf(stderr,
634 : "WARNING: You have not configured "
635 : "'server schannel require seal = yes' (the default). "
636 : "Your server is vulernable to "
637 : "CVE-2022-38023!\n"
638 : "If required use individual "
639 : "'server schannel require seal:COMPUTERACCOUNT$ = no' "
640 : "options\n\n");
641 : }
642 :
643 1874 : if (lp_client_schannel() != true) { /* can be 'auto' */
644 0 : fprintf(stderr,
645 : "WARNING: You have not configured "
646 : "'client schannel = yes' (the default). "
647 : "Your server is vulernable to \"ZeroLogon\" "
648 : "(CVE-2020-1472)\n"
649 : "If required use individual "
650 : "'client schannel:NETBIOSDOMAIN = no' "
651 : "options\n\n");
652 : }
653 1874 : if (!lp_reject_md5_servers()) {
654 0 : fprintf(stderr,
655 : "WARNING: You have not configured "
656 : "'reject md5 servers = yes' (the default). "
657 : "Your server is vulernable to "
658 : "CVE-2022-38023\n"
659 : "If required use individual "
660 : "'reject md5 servers:NETBIOSDOMAIN = no' "
661 : "options\n\n");
662 : }
663 1874 : if (!lp_require_strong_key()) {
664 0 : fprintf(stderr,
665 : "WARNING: You have not configured "
666 : "'require strong key = yes' (the default). "
667 : "Your server is vulernable to "
668 : "CVE-2022-38023\n"
669 : "If required use individual "
670 : "'require strong key:NETBIOSDOMAIN = no' "
671 : "options\n\n");
672 : }
673 1874 : if (!lp_winbind_sealed_pipes()) {
674 0 : fprintf(stderr,
675 : "WARNING: You have not configured "
676 : "'winbind sealed pipes = yes' (the default). "
677 : "Your server is vulernable to "
678 : "CVE-2022-38023\n"
679 : "If required use individual "
680 : "'winbind sealed pipes:NETBIOSDOMAIN = no' "
681 : "options\n\n");
682 : }
683 :
684 1874 : if (lp_kerberos_encryption_types() == KERBEROS_ETYPES_LEGACY) {
685 0 : fprintf(stderr,
686 : "WARNING: You have configured "
687 : "'kerberos encryption types = legacy'. "
688 : "Your server is vulernable to "
689 : "CVE-2022-37966\n\n");
690 : }
691 :
692 1874 : check_pw_script = lp_check_password_script(talloc_tos(), lp_sub);
693 1874 : if (talloc_string_sub_mixed_quoting(check_pw_script, 'u')) {
694 0 : fprintf(stderr,
695 : "WARNING: You are using 'check password script' "
696 : "with mixed quoting and %%u.\n"
697 : "CVE-2026-4408 changed the way %%u substitution works. \n"
698 : "You should use the SAMBA_CPS_ACCOUNT_NAME "
699 : "environment variable exported to the script, or\n"
700 : "at least use single quotes (directly) around '%%u'.\n\n");
701 : }
702 :
703 1874 : return ret;
704 : }
705 :
706 : /**
707 : * per-share logic tests
708 : */
709 1631 : static void do_per_share_checks(int s)
710 : {
711 1409 : const struct loadparm_substitution *lp_sub =
712 222 : loadparm_s3_global_substitution();
713 1631 : const char **deny_list = lp_hosts_deny(s);
714 1631 : const char **allow_list = lp_hosts_allow(s);
715 1631 : const char **vfs_objects = NULL;
716 : int i;
717 : static bool uses_fruit;
718 : static bool doesnt_use_fruit;
719 : static bool fruit_mix_warned;
720 :
721 1631 : if(deny_list) {
722 4 : for (i=0; deny_list[i]; i++) {
723 3 : char *hasstar = strchr_m(deny_list[i], '*');
724 3 : char *hasquery = strchr_m(deny_list[i], '?');
725 3 : if(hasstar || hasquery) {
726 0 : fprintf(stderr,
727 : "Invalid character %c in hosts deny list "
728 : "(%s) for service %s.\n\n",
729 0 : hasstar ? *hasstar : *hasquery,
730 0 : deny_list[i],
731 : lp_servicename(talloc_tos(), lp_sub, s));
732 : }
733 : }
734 : }
735 :
736 1631 : if(allow_list) {
737 4 : for (i=0; allow_list[i]; i++) {
738 3 : char *hasstar = strchr_m(allow_list[i], '*');
739 3 : char *hasquery = strchr_m(allow_list[i], '?');
740 3 : if(hasstar || hasquery) {
741 0 : fprintf(stderr,
742 : "Invalid character %c in hosts allow "
743 : "list (%s) for service %s.\n\n",
744 0 : hasstar ? *hasstar : *hasquery,
745 0 : allow_list[i],
746 : lp_servicename(talloc_tos(), lp_sub, s));
747 : }
748 : }
749 : }
750 :
751 1631 : if(lp_level2_oplocks(s) && !lp_oplocks(s)) {
752 0 : fprintf(stderr, "Invalid combination of parameters for service "
753 : "%s. Level II oplocks can only be set if oplocks "
754 : "are also set.\n\n",
755 : lp_servicename(talloc_tos(), lp_sub, s));
756 : }
757 :
758 1631 : if (!lp_store_dos_attributes(s) && lp_map_hidden(s)
759 0 : && !(lp_create_mask(s) & S_IXOTH))
760 : {
761 0 : fprintf(stderr,
762 : "Invalid combination of parameters for service %s. Map "
763 : "hidden can only work if create mask includes octal "
764 : "01 (S_IXOTH).\n\n",
765 : lp_servicename(talloc_tos(), lp_sub, s));
766 : }
767 1631 : if (!lp_store_dos_attributes(s) && lp_map_hidden(s)
768 0 : && (lp_force_create_mode(s) & S_IXOTH))
769 : {
770 0 : fprintf(stderr,
771 : "Invalid combination of parameters for service "
772 : "%s. Map hidden can only work if force create mode "
773 : "excludes octal 01 (S_IXOTH).\n\n",
774 : lp_servicename(talloc_tos(), lp_sub, s));
775 : }
776 1631 : if (!lp_store_dos_attributes(s) && lp_map_system(s)
777 0 : && !(lp_create_mask(s) & S_IXGRP))
778 : {
779 0 : fprintf(stderr,
780 : "Invalid combination of parameters for service "
781 : "%s. Map system can only work if create mask includes "
782 : "octal 010 (S_IXGRP).\n\n",
783 : lp_servicename(talloc_tos(), lp_sub, s));
784 : }
785 1631 : if (!lp_store_dos_attributes(s) && lp_map_system(s)
786 0 : && (lp_force_create_mode(s) & S_IXGRP))
787 : {
788 0 : fprintf(stderr,
789 : "Invalid combination of parameters for service "
790 : "%s. Map system can only work if force create mode "
791 : "excludes octal 010 (S_IXGRP).\n\n",
792 : lp_servicename(talloc_tos(), lp_sub, s));
793 : }
794 1631 : if (lp_printing(s) == PRINT_CUPS && *(lp_print_command(s)) != '\0') {
795 1 : fprintf(stderr,
796 : "Warning: Service %s defines a print command, but "
797 : "parameter is ignored when using CUPS libraries.\n\n",
798 : lp_servicename(talloc_tos(), lp_sub, s));
799 : }
800 1631 : if (talloc_string_sub_mixed_quoting(lp_print_command(s), 'J')) {
801 0 : fprintf(stderr,
802 : "WARNING: Service %s defines a 'print command' "
803 : "with mixed quoting and %%J.\n"
804 : "CVE-2026-4480 changed the way %%J substitution works.\n"
805 : "You should use single quotes (directly) around '%%J'.\n\n",
806 : lp_servicename(talloc_tos(), lp_sub, s));
807 : }
808 :
809 1631 : vfs_objects = lp_vfs_objects(s);
810 1631 : if (vfs_objects && str_list_check(vfs_objects, "fruit")) {
811 18 : uses_fruit = true;
812 : } else {
813 1613 : doesnt_use_fruit = true;
814 : }
815 :
816 1631 : if (uses_fruit && doesnt_use_fruit && !fruit_mix_warned) {
817 2 : fruit_mix_warned = true;
818 2 : fprintf(stderr,
819 : "WARNING: some services use vfs_fruit, others don't. Mounting them "
820 : "in conjunction on OS X clients results in undefined behaviour.\n\n");
821 : }
822 1631 : }
823 :
824 1875 : int main(int argc, const char *argv[])
825 : {
826 1875 : const char *config_file = NULL;
827 1873 : const struct loadparm_substitution *lp_sub =
828 2 : loadparm_s3_global_substitution();
829 : int opt;
830 : int s;
831 : static int silent_mode = False;
832 : static int show_all_parameters = False;
833 1875 : int ret = 0;
834 : poptContext pc;
835 : static char *parameter_name = NULL;
836 : static const char *section_name = NULL;
837 : const char *cname;
838 : const char *caddr;
839 : static int show_defaults;
840 : static int skip_logic_checks = 0;
841 : bool ok;
842 :
843 7500 : struct poptOption long_options[] = {
844 : POPT_AUTOHELP
845 : {
846 : .longName = "suppress-prompt",
847 : .shortName = 's',
848 : .argInfo = POPT_ARG_VAL,
849 : .arg = &silent_mode,
850 : .val = 1,
851 : .descrip = "Suppress prompt for enter",
852 : },
853 : {
854 : .longName = "verbose",
855 : .shortName = 'v',
856 : .argInfo = POPT_ARG_NONE,
857 : .arg = &show_defaults,
858 : .val = 1,
859 : .descrip = "Show default options too",
860 : },
861 : {
862 : .longName = "skip-logic-checks",
863 : .shortName = 'l',
864 : .argInfo = POPT_ARG_NONE,
865 : .arg = &skip_logic_checks,
866 : .val = 1,
867 : .descrip = "Skip the global checks",
868 : },
869 : {
870 : .longName = "show-all-parameters",
871 : .shortName = '\0',
872 : .argInfo = POPT_ARG_VAL,
873 : .arg = &show_all_parameters,
874 : .val = True,
875 : .descrip = "Show the parameters, type, possible "
876 : "values",
877 : },
878 : {
879 : .longName = "parameter-name",
880 : .shortName = '\0',
881 : .argInfo = POPT_ARG_STRING,
882 : .arg = ¶meter_name,
883 : .val = 0,
884 : .descrip = "Limit testparm to a named parameter",
885 : },
886 : {
887 : .longName = "section-name",
888 : .shortName = '\0',
889 : .argInfo = POPT_ARG_STRING,
890 : .arg = §ion_name,
891 : .val = 0,
892 : .descrip = "Limit testparm to a named section",
893 : },
894 1875 : POPT_COMMON_DEBUG_ONLY
895 1875 : POPT_COMMON_OPTION_ONLY
896 1875 : POPT_COMMON_VERSION
897 : POPT_TABLEEND
898 : };
899 :
900 1875 : TALLOC_CTX *frame = talloc_stackframe();
901 :
902 1875 : smb_init_locale();
903 :
904 1875 : ok = samba_cmdline_init(frame,
905 : SAMBA_CMDLINE_CONFIG_NONE,
906 : true /* require_smbconf */);
907 1875 : if (!ok) {
908 0 : DBG_ERR("Failed to init cmdline parser!\n");
909 0 : ret = 1;
910 0 : goto done;
911 : }
912 :
913 : /*
914 : * Set the default debug level to 1.
915 : * Allow it to be overridden by the command line,
916 : * not by smb.conf.
917 : */
918 1875 : lp_set_cmdline("log level", "1");
919 :
920 1875 : pc = samba_popt_get_context(getprogname(),
921 : argc,
922 : argv,
923 : long_options,
924 : 0);
925 1875 : if (pc == NULL) {
926 0 : DBG_ERR("Failed to setup popt context!\n");
927 0 : ret = 1;
928 0 : goto done;
929 : }
930 :
931 1875 : poptSetOtherOptionHelp(pc, "[OPTION...] <config-file> [host-name] [host-ip]");
932 :
933 1875 : while ((opt = poptGetNextOpt(pc)) != -1) {
934 0 : switch (opt) {
935 0 : case POPT_ERROR_BADOPT:
936 0 : fprintf(stderr, "\nInvalid option %s: %s\n\n",
937 : poptBadOption(pc, 0), poptStrerror(opt));
938 0 : poptPrintUsage(pc, stderr, 0);
939 0 : exit(1);
940 : }
941 : }
942 :
943 1874 : if (show_all_parameters) {
944 0 : show_parameter_list();
945 0 : exit(0);
946 : }
947 :
948 1874 : if (poptPeekArg(pc)) {
949 1874 : config_file = talloc_strdup(frame, poptGetArg(pc));
950 1874 : if (config_file == NULL) {
951 0 : DBG_ERR("out of memory\n");
952 0 : TALLOC_FREE(frame);
953 0 : exit(1);
954 : }
955 : } else {
956 0 : config_file = get_dyn_CONFIGFILE();
957 : }
958 :
959 1874 : cname = talloc_strdup(frame, poptGetArg(pc));
960 1874 : caddr = talloc_strdup(frame, poptGetArg(pc));
961 :
962 1874 : poptFreeContext(pc);
963 :
964 1874 : if ( cname && ! caddr ) {
965 0 : printf ( "ERROR: You must specify both a machine name and an IP address.\n" );
966 0 : ret = 1;
967 0 : goto done;
968 : }
969 :
970 1874 : fprintf(stderr,"Load smb config files from %s\n",config_file);
971 :
972 1874 : if (!lp_load_with_registry_shares(config_file)) {
973 0 : fprintf(stderr,"Error loading services.\n");
974 0 : ret = 1;
975 0 : goto done;
976 : }
977 :
978 1874 : fprintf(stderr,"Loaded services file OK.\n");
979 :
980 1874 : fprintf(stderr,
981 : "Weak crypto is %sallowed by GnuTLS "
982 : "(e.g. NTLM as a compatibility fallback)\n",
983 1874 : samba_gnutls_weak_crypto_allowed() ? "" : "dis");
984 :
985 1874 : if (skip_logic_checks == 0) {
986 1874 : ret = do_global_checks();
987 : }
988 :
989 1875874 : for (s=0;s<1000;s++) {
990 1874000 : if (VALID_SNUM(s) && (skip_logic_checks == 0)) {
991 1631 : do_per_share_checks(s);
992 : }
993 : }
994 :
995 :
996 1874 : if (!section_name && !parameter_name) {
997 464 : fprintf(stderr,
998 : "Server role: %s\n\n",
999 464 : server_role_str(lp_server_role()));
1000 : }
1001 :
1002 1874 : if (!cname) {
1003 1874 : if (!silent_mode) {
1004 0 : fprintf(stderr,"Press enter to see a dump of your service definitions\n");
1005 0 : fflush(stdout);
1006 0 : getc(stdin);
1007 : }
1008 1874 : if (parameter_name || section_name) {
1009 1410 : bool isGlobal = False;
1010 1410 : s = GLOBAL_SECTION_SNUM;
1011 :
1012 1410 : if (!section_name) {
1013 0 : section_name = GLOBAL_NAME;
1014 0 : isGlobal = True;
1015 1807 : } else if ((isGlobal=!strwicmp(section_name, GLOBAL_NAME)) == 0 &&
1016 397 : (s=lp_servicenumber(section_name)) == -1) {
1017 0 : fprintf(stderr,"Unknown section %s\n",
1018 : section_name);
1019 0 : ret = 1;
1020 0 : goto done;
1021 : }
1022 1410 : if (parameter_name) {
1023 1410 : if (!dump_a_parameter( s, parameter_name, stdout, isGlobal)) {
1024 0 : fprintf(stderr,"Parameter %s unknown for section %s\n",
1025 : parameter_name, section_name);
1026 0 : ret = 1;
1027 0 : goto done;
1028 : }
1029 : } else {
1030 0 : if (isGlobal == True)
1031 0 : lp_dump(stdout, show_defaults, 0);
1032 : else
1033 0 : lp_dump_one(stdout, show_defaults, s);
1034 : }
1035 1410 : goto done;
1036 : }
1037 :
1038 464 : lp_dump(stdout, show_defaults, lp_numservices());
1039 : }
1040 :
1041 464 : if(cname && caddr){
1042 : /* this is totally ugly, a real `quick' hack */
1043 0 : for (s=0;s<1000;s++) {
1044 0 : if (VALID_SNUM(s)) {
1045 0 : if (allow_access(lp_hosts_deny(-1), lp_hosts_allow(-1), cname, caddr)
1046 0 : && allow_access(lp_hosts_deny(s), lp_hosts_allow(s), cname, caddr)) {
1047 0 : fprintf(stderr,"Allow connection from %s (%s) to %s\n",
1048 : cname,caddr,lp_servicename(talloc_tos(), lp_sub, s));
1049 : } else {
1050 0 : fprintf(stderr,"Deny connection from %s (%s) to %s\n",
1051 : cname,caddr,lp_servicename(talloc_tos(), lp_sub, s));
1052 : }
1053 : }
1054 : }
1055 : }
1056 :
1057 464 : done:
1058 1874 : gfree_loadparm();
1059 1874 : TALLOC_FREE(frame);
1060 1874 : return ret;
1061 : }
|