2 Unix SMB/CIFS implementation.
3 Test validity of smb.conf
4 Copyright (C) Karl Auer 1993, 1994-1998
6 Extensively modified by Andrew Tridgell, 1995
7 Converted to popt by Jelmer Vernooij (jelmer@nl.linux.org), 2002
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.
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.
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/>.
24 * Testbed for loadparm.c/params.c
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.
30 * Useful for a quick 'syntax check' of a configuration file.
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"
43 /*******************************************************************
44 Check if a directory exists.
45 ********************************************************************/
47 static bool directory_exist_stat(const char *dname
,SMB_STRUCT_STAT
*st
)
55 if (sys_stat(dname
, st
, false) != 0)
58 ret
= S_ISDIR(st
->st_ex_mode
);
65 const char *domain_name
;
71 struct idmap_domains
{
72 struct idmap_config
*c
;
77 static bool lp_scan_idmap_found_domain(const char *string
,
83 if (matches
[1].rm_so
== -1) {
84 fprintf(stderr
, "Found match, but no name - invalid idmap config");
87 if (matches
[1].rm_eo
<= matches
[1].rm_so
) {
88 fprintf(stderr
, "Invalid match - invalid idmap config");
93 struct idmap_domains
*d
= private_data
;
94 struct idmap_config
*c
= &d
->c
[d
->count
];
95 regoff_t len
= matches
[1].rm_eo
- matches
[1].rm_so
;
96 char domname
[len
+ 1];
98 if (d
->count
>= d
->size
) {
102 memcpy(domname
, string
+ matches
[1].rm_so
, len
);
105 c
->domain_name
= talloc_strdup_upper(d
->c
, domname
);
106 if (c
->domain_name
== NULL
) {
109 c
->backend
= talloc_strdup(d
->c
, lp_idmap_backend(domname
));
110 if (c
->backend
== NULL
) {
114 if (lp_server_role() != ROLE_ACTIVE_DIRECTORY_DC
) {
115 ok
= lp_idmap_range(domname
, &c
->low
, &c
->high
);
118 "ERROR: Invalid idmap range for domain "
128 return false; /* Keep scanning */
131 static int idmap_config_int(const char *domname
, const char *option
, int def
)
133 int len
= snprintf(NULL
, 0, "idmap config %s", domname
);
139 char config_option
[len
+1];
140 snprintf(config_option
, sizeof(config_option
),
141 "idmap config %s", domname
);
142 return lp_parm_int(-1, config_option
, option
, def
);
146 static bool do_idmap_check(void)
148 struct idmap_domains
*d
;
153 d
= talloc_zero(talloc_tos(), struct idmap_domains
);
160 d
->c
= talloc_array(d
, struct idmap_config
, d
->size
);
165 rc
= lp_wi_scan_global_parametrics("idmapconfig\\(.*\\):backend",
167 lp_scan_idmap_found_domain
,
171 "FATAL: wi_scan_global_parametrics failed: %d",
175 /* Check autorid backend */
176 if (strequal(lp_idmap_default_backend(), "autorid")) {
177 struct idmap_config
*c
= NULL
;
180 for (i
= 0; i
< d
->count
; i
++) {
183 if (strequal(c
->backend
, "autorid")) {
191 idmap_config_int("*", "rangesize", 100000);
193 (c
->high
- c
->low
+ 1) / rangesize
;
197 "ERROR: The idmap autorid range "
198 "[%u-%u] needs to be at least twice as "
199 "big as the rangesize [%u]!"
210 /* Check for overlapping idmap ranges */
211 for (i
= 0; i
< d
->count
; i
++) {
212 struct idmap_config
*c
= &d
->c
[i
];
215 for (j
= 0; j
< d
->count
&& j
!= i
; j
++) {
216 struct idmap_config
*x
= &d
->c
[j
];
218 if ((c
->low
>= x
->low
&& c
->low
<= x
->high
) ||
219 (c
->high
>= x
->low
&& c
->high
<= x
->high
)) {
220 /* Allow overlapping ranges for idmap_ad */
221 ok
= strequal(c
->backend
, x
->backend
);
223 ok
= strequal(c
->backend
, "ad");
226 "NOTE: The idmap_ad "
227 "range for the domain "
228 "%s overlaps with the "
237 "ERROR: The idmap range for the domain "
238 "%s (%s) overlaps with the range of "
256 /***********************************************
257 Here we do a set of 'hard coded' checks for bad
258 configuration settings.
259 ************************************************/
261 static int do_global_checks(void)
265 const char *socket_options
;
266 const struct loadparm_substitution
*lp_sub
=
267 loadparm_s3_global_substitution();
269 fprintf(stderr
, "\n");
271 if (lp_security() >= SEC_DOMAIN
&& !lp_encrypt_passwords()) {
272 fprintf(stderr
, "ERROR: in 'security=domain' mode the "
273 "'encrypt passwords' parameter must always be "
274 "set to 'true'.\n\n");
278 if (lp_security() == SEC_ADS
) {
279 const char *workgroup
= lp_workgroup();
280 const char *realm
= lp_realm();
282 if (workgroup
== NULL
|| strlen(workgroup
) == 0) {
284 "ERROR: The 'security=ADS' mode requires "
285 "'workgroup' parameter to be set!\n\n ");
289 if (realm
== NULL
|| strlen(realm
) == 0) {
291 "ERROR: The 'security=ADS' mode requires "
292 "'realm' parameter to be set!\n\n ");
298 if (lp_we_are_a_wins_server() && lp_wins_server_list()) {
299 fprintf(stderr
, "ERROR: both 'wins support = true' and "
300 "'wins server = <server list>' cannot be set in "
301 "the smb.conf file. nmbd will abort with this "
306 if (strequal(lp_workgroup(), lp_netbios_name())) {
307 fprintf(stderr
, "WARNING: 'workgroup' and 'netbios name' "
311 if (lp_client_ipc_signing() == SMB_SIGNING_IF_REQUIRED
312 || lp_client_ipc_signing() == SMB_SIGNING_OFF
) {
313 fprintf(stderr
, "WARNING: The 'client ipc signing' value "
314 "%s SMB signing is not used when contacting a "
315 "domain controller or other server. "
316 "This setting is not recommended; please be "
317 "aware of the security implications when using "
318 "this configuration setting.\n\n",
319 lp_client_ipc_signing() == SMB_SIGNING_OFF
?
320 "ensures" : "may mean");
323 if (strlen(lp_netbios_name()) > 15) {
324 fprintf(stderr
, "WARNING: The 'netbios name' is too long "
325 "(max. 15 chars).\n\n");
328 if (!directory_exist_stat(lp_lock_directory(), &st
)) {
329 fprintf(stderr
, "ERROR: lock directory %s does not exist\n\n",
330 lp_lock_directory());
332 } else if ((st
.st_ex_mode
& 0777) != 0755) {
333 fprintf(stderr
, "WARNING: lock directory %s should have "
334 "permissions 0755 for browsing to work\n\n",
335 lp_lock_directory());
338 if (!directory_exist_stat(lp_state_directory(), &st
)) {
339 fprintf(stderr
, "ERROR: state directory %s does not exist\n\n",
340 lp_state_directory());
342 } else if ((st
.st_ex_mode
& 0777) != 0755) {
343 fprintf(stderr
, "WARNING: state directory %s should have "
344 "permissions 0755 for browsing to work\n\n",
345 lp_state_directory());
348 if (!directory_exist_stat(lp_cache_directory(), &st
)) {
349 fprintf(stderr
, "ERROR: cache directory %s does not exist\n\n",
350 lp_cache_directory());
352 } else if ((st
.st_ex_mode
& 0777) != 0755) {
353 fprintf(stderr
, "WARNING: cache directory %s should have "
354 "permissions 0755 for browsing to work\n\n",
355 lp_cache_directory());
358 if (!directory_exist_stat(lp_pid_directory(), &st
)) {
359 fprintf(stderr
, "ERROR: pid directory %s does not exist\n\n",
364 if (lp_passdb_expand_explicit()) {
365 fprintf(stderr
, "WARNING: passdb expand explicit = yes is "
372 socket_options
= lp_socket_options();
373 if (socket_options
!= NULL
&&
374 (strstr(socket_options
, "SO_SNDBUF") ||
375 strstr(socket_options
, "SO_RCVBUF") ||
376 strstr(socket_options
, "SO_SNDLOWAT") ||
377 strstr(socket_options
, "SO_RCVLOWAT")))
380 "WARNING: socket options = %s\n"
381 "This warning is printed because you set one of the\n"
382 "following options: SO_SNDBUF, SO_RCVBUF, SO_SNDLOWAT,\n"
384 "Modern server operating systems are tuned for\n"
385 "high network performance in the majority of situations;\n"
386 "when you set 'socket options' you are overriding those\n"
388 "Linux in particular has an auto-tuning mechanism for\n"
389 "buffer sizes (SO_SNDBUF, SO_RCVBUF) that will be\n"
390 "disabled if you specify a socket buffer size. This can\n"
391 "potentially cripple your TCP/IP stack.\n\n"
392 "Getting the 'socket options' correct can make a big\n"
393 "difference to your performance, but getting them wrong\n"
394 "can degrade it by just as much. As with any other low\n"
395 "level setting, if you must make changes to it, make\n "
396 "small changes and test the effect before making any\n"
397 "large changes.\n\n",
402 * Password server sanity checks.
405 if((lp_security() >= SEC_DOMAIN
) && !*lp_password_server()) {
406 const char *sec_setting
;
407 if(lp_security() == SEC_DOMAIN
)
408 sec_setting
= "domain";
409 else if(lp_security() == SEC_ADS
)
414 fprintf(stderr
, "ERROR: The setting 'security=%s' requires the "
415 "'password server' parameter be set to the "
416 "default value * or a valid password server.\n\n",
421 if((lp_security() >= SEC_DOMAIN
) && (strcmp(lp_password_server(), "*") != 0)) {
422 const char *sec_setting
;
423 if(lp_security() == SEC_DOMAIN
)
424 sec_setting
= "domain";
425 else if(lp_security() == SEC_ADS
)
430 fprintf(stderr
, "WARNING: The setting 'security=%s' should NOT "
431 "be combined with the 'password server' "
433 "(by default Samba will discover the correct DC "
434 "to contact automatically).\n\n",
439 * Password chat sanity checks.
442 if(lp_security() == SEC_USER
&& lp_unix_password_sync()) {
445 * Check that we have a valid lp_passwd_program() if not using pam.
449 if (!lp_pam_password_change()) {
452 if((lp_passwd_program(talloc_tos(), lp_sub
) == NULL
) ||
453 (strlen(lp_passwd_program(talloc_tos(), lp_sub
)) == 0))
456 "ERROR: the 'unix password sync' "
457 "parameter is set and there is no valid "
458 "'passwd program' parameter.\n\n");
461 const char *passwd_prog
;
462 char *truncated_prog
= NULL
;
465 passwd_prog
= lp_passwd_program(talloc_tos(), lp_sub
);
467 next_token_talloc(talloc_tos(),
469 &truncated_prog
, NULL
);
470 if (truncated_prog
&& access(truncated_prog
, F_OK
) == -1) {
472 "ERROR: the 'unix password sync' "
473 "parameter is set and the "
474 "'passwd program' (%s) cannot be "
475 "executed (error was %s).\n\n",
486 if(lp_passwd_chat(talloc_tos(), lp_sub
) == NULL
) {
488 "ERROR: the 'unix password sync' parameter is "
489 "set and there is no valid 'passwd chat' "
494 if ((lp_passwd_program(talloc_tos(), lp_sub
) != NULL
) &&
495 (strlen(lp_passwd_program(talloc_tos(), lp_sub
)) > 0))
497 /* check if there's a %u parameter present */
498 if(strstr_m(lp_passwd_program(talloc_tos(), lp_sub
), "%u") == NULL
) {
500 "ERROR: the 'passwd program' (%s) "
501 "requires a '%%u' parameter.\n\n",
502 lp_passwd_program(talloc_tos(), lp_sub
));
508 * Check that we have a valid script and that it hasn't
509 * been written to expect the old password.
512 if(lp_encrypt_passwords()) {
513 if(strstr_m( lp_passwd_chat(talloc_tos(), lp_sub
), "%o")!=NULL
) {
515 "ERROR: the 'passwd chat' script [%s] "
516 "expects to use the old plaintext "
517 "password via the %%o substitution. With "
518 "encrypted passwords this is not "
520 lp_passwd_chat(talloc_tos(), lp_sub
) );
526 if (strlen(lp_winbind_separator()) != 1) {
527 fprintf(stderr
, "ERROR: the 'winbind separator' parameter must "
528 "be a single character.\n\n");
532 if (*lp_winbind_separator() == '+') {
533 fprintf(stderr
, "'winbind separator = +' might cause problems "
534 "with group membership.\n\n");
537 if (lp_algorithmic_rid_base() < BASE_RID
) {
538 /* Try to prevent admin foot-shooting, we can't put algorithmic
539 rids below 1000, that's the 'well known RIDs' on NT */
540 fprintf(stderr
, "'algorithmic rid base' must be equal to or "
541 "above %lu\n\n", BASE_RID
);
544 if (lp_algorithmic_rid_base() & 1) {
545 fprintf(stderr
, "'algorithmic rid base' must be even.\n\n");
548 if (lp_server_role() != ROLE_STANDALONE
) {
549 const char *default_backends
[] = {
550 "tdb", "tdb2", "ldap", "autorid", "hash"
552 const char *idmap_backend
;
553 bool valid_backend
= false;
557 idmap_backend
= lp_idmap_default_backend();
559 for (i
= 0; i
< ARRAY_SIZE(default_backends
); i
++) {
560 ok
= strequal(idmap_backend
, default_backends
[i
]);
562 valid_backend
= true;
566 if (!valid_backend
) {
568 fprintf(stderr
, "ERROR: Do not use the '%s' backend "
569 "as the default idmap backend!\n\n",
573 ok
= do_idmap_check();
580 if (lp_preload_modules()) {
581 fprintf(stderr
, "WARNING: 'preload modules = ' set while loading "
582 "plugins not supported.\n\n");
586 if (!lp_passdb_backend()) {
587 fprintf(stderr
, "ERROR: passdb backend must have a value or be "
591 if (lp_os_level() > 255) {
592 fprintf(stderr
, "WARNING: Maximum value for 'os level' is "
596 if (strequal(lp_dos_charset(), "UTF8") || strequal(lp_dos_charset(), "UTF-8")) {
597 fprintf(stderr
, "ERROR: 'dos charset' must not be UTF8\n\n");
601 if (!lp_server_schannel()) {
603 "WARNING: You have configured 'server schannel = no'. "
604 "Your server is vulernable to \"ZeroLogon\" "
605 "(CVE-2020-1472)\n\n");
612 * per-share logic tests
614 static void do_per_share_checks(int s
)
616 const struct loadparm_substitution
*lp_sub
=
617 loadparm_s3_global_substitution();
618 const char **deny_list
= lp_hosts_deny(s
);
619 const char **allow_list
= lp_hosts_allow(s
);
620 const char **vfs_objects
= NULL
;
622 static bool uses_fruit
;
623 static bool doesnt_use_fruit
;
624 static bool fruit_mix_warned
;
627 for (i
=0; deny_list
[i
]; i
++) {
628 char *hasstar
= strchr_m(deny_list
[i
], '*');
629 char *hasquery
= strchr_m(deny_list
[i
], '?');
630 if(hasstar
|| hasquery
) {
632 "Invalid character %c in hosts deny list "
633 "(%s) for service %s.\n\n",
634 hasstar
? *hasstar
: *hasquery
,
636 lp_servicename(talloc_tos(), lp_sub
, s
));
642 for (i
=0; allow_list
[i
]; i
++) {
643 char *hasstar
= strchr_m(allow_list
[i
], '*');
644 char *hasquery
= strchr_m(allow_list
[i
], '?');
645 if(hasstar
|| hasquery
) {
647 "Invalid character %c in hosts allow "
648 "list (%s) for service %s.\n\n",
649 hasstar
? *hasstar
: *hasquery
,
651 lp_servicename(talloc_tos(), lp_sub
, s
));
656 if(lp_level2_oplocks(s
) && !lp_oplocks(s
)) {
657 fprintf(stderr
, "Invalid combination of parameters for service "
658 "%s. Level II oplocks can only be set if oplocks "
660 lp_servicename(talloc_tos(), lp_sub
, s
));
663 if (!lp_store_dos_attributes(s
) && lp_map_hidden(s
)
664 && !(lp_create_mask(s
) & S_IXOTH
))
667 "Invalid combination of parameters for service %s. Map "
668 "hidden can only work if create mask includes octal "
670 lp_servicename(talloc_tos(), lp_sub
, s
));
672 if (!lp_store_dos_attributes(s
) && lp_map_hidden(s
)
673 && (lp_force_create_mode(s
) & S_IXOTH
))
676 "Invalid combination of parameters for service "
677 "%s. Map hidden can only work if force create mode "
678 "excludes octal 01 (S_IXOTH).\n\n",
679 lp_servicename(talloc_tos(), lp_sub
, s
));
681 if (!lp_store_dos_attributes(s
) && lp_map_system(s
)
682 && !(lp_create_mask(s
) & S_IXGRP
))
685 "Invalid combination of parameters for service "
686 "%s. Map system can only work if create mask includes "
687 "octal 010 (S_IXGRP).\n\n",
688 lp_servicename(talloc_tos(), lp_sub
, s
));
690 if (!lp_store_dos_attributes(s
) && lp_map_system(s
)
691 && (lp_force_create_mode(s
) & S_IXGRP
))
694 "Invalid combination of parameters for service "
695 "%s. Map system can only work if force create mode "
696 "excludes octal 010 (S_IXGRP).\n\n",
697 lp_servicename(talloc_tos(), lp_sub
, s
));
699 if (lp_printing(s
) == PRINT_CUPS
&& *(lp_print_command(s
)) != '\0') {
701 "Warning: Service %s defines a print command, but "
702 "parameter is ignored when using CUPS libraries.\n\n",
703 lp_servicename(talloc_tos(), lp_sub
, s
));
706 vfs_objects
= lp_vfs_objects(s
);
707 if (vfs_objects
&& str_list_check(vfs_objects
, "fruit")) {
710 doesnt_use_fruit
= true;
713 if (uses_fruit
&& doesnt_use_fruit
&& !fruit_mix_warned
) {
714 fruit_mix_warned
= true;
716 "WARNING: some services use vfs_fruit, others don't. Mounting them "
717 "in conjunction on OS X clients results in undefined behaviour.\n\n");
721 int main(int argc
, const char *argv
[])
723 const char *config_file
= NULL
;
724 const struct loadparm_substitution
*lp_sub
=
725 loadparm_s3_global_substitution();
728 static int silent_mode
= False
;
729 static int show_all_parameters
= False
;
732 static char *parameter_name
= NULL
;
733 static const char *section_name
= NULL
;
736 static int show_defaults
;
737 static int skip_logic_checks
= 0;
740 struct poptOption long_options
[] = {
743 .longName
= "suppress-prompt",
745 .argInfo
= POPT_ARG_VAL
,
748 .descrip
= "Suppress prompt for enter",
751 .longName
= "verbose",
753 .argInfo
= POPT_ARG_NONE
,
754 .arg
= &show_defaults
,
756 .descrip
= "Show default options too",
759 .longName
= "skip-logic-checks",
761 .argInfo
= POPT_ARG_NONE
,
762 .arg
= &skip_logic_checks
,
764 .descrip
= "Skip the global checks",
767 .longName
= "show-all-parameters",
769 .argInfo
= POPT_ARG_VAL
,
770 .arg
= &show_all_parameters
,
772 .descrip
= "Show the parameters, type, possible "
776 .longName
= "parameter-name",
778 .argInfo
= POPT_ARG_STRING
,
779 .arg
= ¶meter_name
,
781 .descrip
= "Limit testparm to a named parameter",
784 .longName
= "section-name",
786 .argInfo
= POPT_ARG_STRING
,
787 .arg
= §ion_name
,
789 .descrip
= "Limit testparm to a named section",
791 POPT_COMMON_DEBUG_ONLY
792 POPT_COMMON_OPTION_ONLY
797 TALLOC_CTX
*frame
= talloc_stackframe();
801 ok
= samba_cmdline_init(frame
,
802 SAMBA_CMDLINE_CONFIG_NONE
,
803 true /* require_smbconf */);
805 DBG_ERR("Failed to init cmdline parser!\n");
811 * Set the default debug level to 1.
812 * Allow it to be overridden by the command line,
815 lp_set_cmdline("log level", "1");
817 pc
= samba_popt_get_context(getprogname(),
823 DBG_ERR("Failed to setup popt context!\n");
828 poptSetOtherOptionHelp(pc
, "[OPTION...] <config-file> [host-name] [host-ip]");
830 while ((opt
= poptGetNextOpt(pc
)) != -1) {
832 case POPT_ERROR_BADOPT
:
833 fprintf(stderr
, "\nInvalid option %s: %s\n\n",
834 poptBadOption(pc
, 0), poptStrerror(opt
));
835 poptPrintUsage(pc
, stderr
, 0);
840 if (show_all_parameters
) {
841 show_parameter_list();
845 if (poptPeekArg(pc
)) {
846 config_file
= poptGetArg(pc
);
848 config_file
= get_dyn_CONFIGFILE();
851 cname
= poptGetArg(pc
);
852 caddr
= poptGetArg(pc
);
856 if ( cname
&& ! caddr
) {
857 printf ( "ERROR: You must specify both a machine name and an IP address.\n" );
862 fprintf(stderr
,"Load smb config files from %s\n",config_file
);
864 if (!lp_load_with_registry_shares(config_file
)) {
865 fprintf(stderr
,"Error loading services.\n");
870 fprintf(stderr
,"Loaded services file OK.\n");
873 "Weak crypto is %sallowed by GnuTLS "
874 "(e.g. NTLM as a compatibility fallback)\n",
875 samba_gnutls_weak_crypto_allowed() ? "" : "dis");
877 if (skip_logic_checks
== 0) {
878 ret
= do_global_checks();
881 for (s
=0;s
<1000;s
++) {
882 if (VALID_SNUM(s
) && (skip_logic_checks
== 0)) {
883 do_per_share_checks(s
);
888 if (!section_name
&& !parameter_name
) {
890 "Server role: %s\n\n",
891 server_role_str(lp_server_role()));
896 fprintf(stderr
,"Press enter to see a dump of your service definitions\n");
900 if (parameter_name
|| section_name
) {
901 bool isGlobal
= False
;
902 s
= GLOBAL_SECTION_SNUM
;
905 section_name
= GLOBAL_NAME
;
907 } else if ((isGlobal
=!strwicmp(section_name
, GLOBAL_NAME
)) == 0 &&
908 (s
=lp_servicenumber(section_name
)) == -1) {
909 fprintf(stderr
,"Unknown section %s\n",
914 if (parameter_name
) {
915 if (!dump_a_parameter( s
, parameter_name
, stdout
, isGlobal
)) {
916 fprintf(stderr
,"Parameter %s unknown for section %s\n",
917 parameter_name
, section_name
);
922 if (isGlobal
== True
)
923 lp_dump(stdout
, show_defaults
, 0);
925 lp_dump_one(stdout
, show_defaults
, s
);
930 lp_dump(stdout
, show_defaults
, lp_numservices());
934 /* this is totally ugly, a real `quick' hack */
935 for (s
=0;s
<1000;s
++) {
937 if (allow_access(lp_hosts_deny(-1), lp_hosts_allow(-1), cname
, caddr
)
938 && allow_access(lp_hosts_deny(s
), lp_hosts_allow(s
), cname
, caddr
)) {
939 fprintf(stderr
,"Allow connection from %s (%s) to %s\n",
940 cname
,caddr
,lp_servicename(talloc_tos(), lp_sub
, s
));
942 fprintf(stderr
,"Deny connection from %s (%s) to %s\n",
943 cname
,caddr
,lp_servicename(talloc_tos(), lp_sub
, s
));