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 "popt_common.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 bool do_idmap_check(void)
133 struct idmap_domains
*d
;
138 d
= talloc_zero(talloc_tos(), struct idmap_domains
);
145 d
->c
= talloc_array(d
, struct idmap_config
, d
->size
);
150 rc
= lp_wi_scan_global_parametrics("idmapconfig\\(.*\\):backend",
152 lp_scan_idmap_found_domain
,
156 "FATAL: wi_scan_global_parametrics failed: %d",
160 for (i
= 0; i
< d
->count
; i
++) {
161 struct idmap_config
*c
= &d
->c
[i
];
164 for (j
= 0; j
< d
->count
&& j
!= i
; j
++) {
165 struct idmap_config
*x
= &d
->c
[j
];
167 if ((c
->low
>= x
->low
&& c
->low
<= x
->high
) ||
168 (c
->high
>= x
->low
&& c
->high
<= x
->high
)) {
169 /* Allow overlapping ranges for idmap_ad */
170 ok
= strequal(c
->backend
, x
->backend
);
172 ok
= strequal(c
->backend
, "ad");
175 "NOTE: The idmap_ad "
176 "range for the domain "
177 "%s overlaps with the "
186 "ERROR: The idmap range for the domain "
187 "%s (%s) overlaps with the range of "
205 /***********************************************
206 Here we do a set of 'hard coded' checks for bad
207 configuration settings.
208 ************************************************/
210 static int do_global_checks(void)
214 const char *socket_options
;
215 const struct loadparm_substitution
*lp_sub
=
216 loadparm_s3_global_substitution();
218 if (lp_security() >= SEC_DOMAIN
&& !lp_encrypt_passwords()) {
219 fprintf(stderr
, "ERROR: in 'security=domain' mode the "
220 "'encrypt passwords' parameter must always be "
221 "set to 'true'.\n\n");
225 if (lp_we_are_a_wins_server() && lp_wins_server_list()) {
226 fprintf(stderr
, "ERROR: both 'wins support = true' and "
227 "'wins server = <server list>' cannot be set in "
228 "the smb.conf file. nmbd will abort with this "
233 if (strequal(lp_workgroup(), lp_netbios_name())) {
234 fprintf(stderr
, "WARNING: 'workgroup' and 'netbios name' "
238 if (lp_client_ipc_signing() == SMB_SIGNING_IF_REQUIRED
239 || lp_client_ipc_signing() == SMB_SIGNING_OFF
) {
240 fprintf(stderr
, "WARNING: The 'client ipc signing' value "
241 "%s SMB signing is not used when contacting a "
242 "domain controller or other server. "
243 "This setting is not recommended; please be "
244 "aware of the security implications when using "
245 "this configuration setting.\n\n",
246 lp_client_ipc_signing() == SMB_SIGNING_OFF
?
247 "ensures" : "may mean");
250 if (strlen(lp_netbios_name()) > 15) {
251 fprintf(stderr
, "WARNING: The 'netbios name' is too long "
252 "(max. 15 chars).\n\n");
255 if (!directory_exist_stat(lp_lock_directory(), &st
)) {
256 fprintf(stderr
, "ERROR: lock directory %s does not exist\n\n",
257 lp_lock_directory());
259 } else if ((st
.st_ex_mode
& 0777) != 0755) {
260 fprintf(stderr
, "WARNING: lock directory %s should have "
261 "permissions 0755 for browsing to work\n\n",
262 lp_lock_directory());
265 if (!directory_exist_stat(lp_state_directory(), &st
)) {
266 fprintf(stderr
, "ERROR: state directory %s does not exist\n\n",
267 lp_state_directory());
269 } else if ((st
.st_ex_mode
& 0777) != 0755) {
270 fprintf(stderr
, "WARNING: state directory %s should have "
271 "permissions 0755 for browsing to work\n\n",
272 lp_state_directory());
275 if (!directory_exist_stat(lp_cache_directory(), &st
)) {
276 fprintf(stderr
, "ERROR: cache directory %s does not exist\n\n",
277 lp_cache_directory());
279 } else if ((st
.st_ex_mode
& 0777) != 0755) {
280 fprintf(stderr
, "WARNING: cache directory %s should have "
281 "permissions 0755 for browsing to work\n\n",
282 lp_cache_directory());
285 if (!directory_exist_stat(lp_pid_directory(), &st
)) {
286 fprintf(stderr
, "ERROR: pid directory %s does not exist\n\n",
291 if (lp_passdb_expand_explicit()) {
292 fprintf(stderr
, "WARNING: passdb expand explicit = yes is "
299 socket_options
= lp_socket_options();
300 if (socket_options
!= NULL
&&
301 (strstr(socket_options
, "SO_SNDBUF") ||
302 strstr(socket_options
, "SO_RCVBUF") ||
303 strstr(socket_options
, "SO_SNDLOWAT") ||
304 strstr(socket_options
, "SO_RCVLOWAT")))
307 "WARNING: socket options = %s\n"
308 "This warning is printed because you set one of the\n"
309 "following options: SO_SNDBUF, SO_RCVBUF, SO_SNDLOWAT,\n"
311 "Modern server operating systems are tuned for\n"
312 "high network performance in the majority of situations;\n"
313 "when you set 'socket options' you are overriding those\n"
315 "Linux in particular has an auto-tuning mechanism for\n"
316 "buffer sizes (SO_SNDBUF, SO_RCVBUF) that will be\n"
317 "disabled if you specify a socket buffer size. This can\n"
318 "potentially cripple your TCP/IP stack.\n\n"
319 "Getting the 'socket options' correct can make a big\n"
320 "difference to your performance, but getting them wrong\n"
321 "can degrade it by just as much. As with any other low\n"
322 "level setting, if you must make changes to it, make\n "
323 "small changes and test the effect before making any\n"
324 "large changes.\n\n",
329 * Password server sanity checks.
332 if((lp_security() >= SEC_DOMAIN
) && !*lp_password_server()) {
333 const char *sec_setting
;
334 if(lp_security() == SEC_DOMAIN
)
335 sec_setting
= "domain";
336 else if(lp_security() == SEC_ADS
)
341 fprintf(stderr
, "ERROR: The setting 'security=%s' requires the "
342 "'password server' parameter be set to the "
343 "default value * or a valid password server.\n\n",
348 if((lp_security() >= SEC_DOMAIN
) && (strcmp(lp_password_server(), "*") != 0)) {
349 const char *sec_setting
;
350 if(lp_security() == SEC_DOMAIN
)
351 sec_setting
= "domain";
352 else if(lp_security() == SEC_ADS
)
357 fprintf(stderr
, "WARNING: The setting 'security=%s' should NOT "
358 "be combined with the 'password server' "
360 "(by default Samba will discover the correct DC "
361 "to contact automatically).\n\n",
366 * Password chat sanity checks.
369 if(lp_security() == SEC_USER
&& lp_unix_password_sync()) {
372 * Check that we have a valid lp_passwd_program() if not using pam.
376 if (!lp_pam_password_change()) {
379 if((lp_passwd_program(talloc_tos(), lp_sub
) == NULL
) ||
380 (strlen(lp_passwd_program(talloc_tos(), lp_sub
)) == 0))
383 "ERROR: the 'unix password sync' "
384 "parameter is set and there is no valid "
385 "'passwd program' parameter.\n\n");
388 const char *passwd_prog
;
389 char *truncated_prog
= NULL
;
392 passwd_prog
= lp_passwd_program(talloc_tos(), lp_sub
);
394 next_token_talloc(talloc_tos(),
396 &truncated_prog
, NULL
);
397 if (truncated_prog
&& access(truncated_prog
, F_OK
) == -1) {
399 "ERROR: the 'unix password sync' "
400 "parameter is set and the "
401 "'passwd program' (%s) cannot be "
402 "executed (error was %s).\n\n",
413 if(lp_passwd_chat(talloc_tos(), lp_sub
) == NULL
) {
415 "ERROR: the 'unix password sync' parameter is "
416 "set and there is no valid 'passwd chat' "
421 if ((lp_passwd_program(talloc_tos(), lp_sub
) != NULL
) &&
422 (strlen(lp_passwd_program(talloc_tos(), lp_sub
)) > 0))
424 /* check if there's a %u parameter present */
425 if(strstr_m(lp_passwd_program(talloc_tos(), lp_sub
), "%u") == NULL
) {
427 "ERROR: the 'passwd program' (%s) "
428 "requires a '%%u' parameter.\n\n",
429 lp_passwd_program(talloc_tos(), lp_sub
));
435 * Check that we have a valid script and that it hasn't
436 * been written to expect the old password.
439 if(lp_encrypt_passwords()) {
440 if(strstr_m( lp_passwd_chat(talloc_tos(), lp_sub
), "%o")!=NULL
) {
442 "ERROR: the 'passwd chat' script [%s] "
443 "expects to use the old plaintext "
444 "password via the %%o substitution. With "
445 "encrypted passwords this is not "
447 lp_passwd_chat(talloc_tos(), lp_sub
) );
453 if (strlen(lp_winbind_separator()) != 1) {
454 fprintf(stderr
, "ERROR: the 'winbind separator' parameter must "
455 "be a single character.\n\n");
459 if (*lp_winbind_separator() == '+') {
460 fprintf(stderr
, "'winbind separator = +' might cause problems "
461 "with group membership.\n\n");
464 if (lp_algorithmic_rid_base() < BASE_RID
) {
465 /* Try to prevent admin foot-shooting, we can't put algorithmic
466 rids below 1000, that's the 'well known RIDs' on NT */
467 fprintf(stderr
, "'algorithmic rid base' must be equal to or "
468 "above %lu\n\n", BASE_RID
);
471 if (lp_algorithmic_rid_base() & 1) {
472 fprintf(stderr
, "'algorithmic rid base' must be even.\n\n");
475 if (lp_server_role() != ROLE_STANDALONE
) {
476 const char *default_backends
[] = {
477 "tdb", "tdb2", "ldap", "autorid", "hash"
479 const char *idmap_backend
;
480 bool valid_backend
= false;
484 idmap_backend
= lp_idmap_default_backend();
486 for (i
= 0; i
< ARRAY_SIZE(default_backends
); i
++) {
487 ok
= strequal(idmap_backend
, default_backends
[i
]);
489 valid_backend
= true;
493 if (!valid_backend
) {
495 fprintf(stderr
, "ERROR: Do not use the '%s' backend "
496 "as the default idmap backend!\n\n",
500 ok
= do_idmap_check();
507 if (lp_preload_modules()) {
508 fprintf(stderr
, "WARNING: 'preload modules = ' set while loading "
509 "plugins not supported.\n\n");
513 if (!lp_passdb_backend()) {
514 fprintf(stderr
, "ERROR: passdb backend must have a value or be "
518 if (lp_os_level() > 255) {
519 fprintf(stderr
, "WARNING: Maximum value for 'os level' is "
523 if (strequal(lp_dos_charset(), "UTF8") || strequal(lp_dos_charset(), "UTF-8")) {
524 fprintf(stderr
, "ERROR: 'dos charset' must not be UTF8\n\n");
532 * per-share logic tests
534 static void do_per_share_checks(int s
)
536 const struct loadparm_substitution
*lp_sub
=
537 loadparm_s3_global_substitution();
538 const char **deny_list
= lp_hosts_deny(s
);
539 const char **allow_list
= lp_hosts_allow(s
);
540 const char **vfs_objects
= NULL
;
542 static bool uses_fruit
;
543 static bool doesnt_use_fruit
;
544 static bool fruit_mix_warned
;
547 for (i
=0; deny_list
[i
]; i
++) {
548 char *hasstar
= strchr_m(deny_list
[i
], '*');
549 char *hasquery
= strchr_m(deny_list
[i
], '?');
550 if(hasstar
|| hasquery
) {
552 "Invalid character %c in hosts deny list "
553 "(%s) for service %s.\n\n",
554 hasstar
? *hasstar
: *hasquery
,
556 lp_servicename(talloc_tos(), lp_sub
, s
));
562 for (i
=0; allow_list
[i
]; i
++) {
563 char *hasstar
= strchr_m(allow_list
[i
], '*');
564 char *hasquery
= strchr_m(allow_list
[i
], '?');
565 if(hasstar
|| hasquery
) {
567 "Invalid character %c in hosts allow "
568 "list (%s) for service %s.\n\n",
569 hasstar
? *hasstar
: *hasquery
,
571 lp_servicename(talloc_tos(), lp_sub
, s
));
576 if(lp_level2_oplocks(s
) && !lp_oplocks(s
)) {
577 fprintf(stderr
, "Invalid combination of parameters for service "
578 "%s. Level II oplocks can only be set if oplocks "
580 lp_servicename(talloc_tos(), lp_sub
, s
));
583 if (!lp_store_dos_attributes(s
) && lp_map_hidden(s
)
584 && !(lp_create_mask(s
) & S_IXOTH
))
587 "Invalid combination of parameters for service %s. Map "
588 "hidden can only work if create mask includes octal "
590 lp_servicename(talloc_tos(), lp_sub
, s
));
592 if (!lp_store_dos_attributes(s
) && lp_map_hidden(s
)
593 && (lp_force_create_mode(s
) & S_IXOTH
))
596 "Invalid combination of parameters for service "
597 "%s. Map hidden can only work if force create mode "
598 "excludes octal 01 (S_IXOTH).\n\n",
599 lp_servicename(talloc_tos(), lp_sub
, s
));
601 if (!lp_store_dos_attributes(s
) && lp_map_system(s
)
602 && !(lp_create_mask(s
) & S_IXGRP
))
605 "Invalid combination of parameters for service "
606 "%s. Map system can only work if create mask includes "
607 "octal 010 (S_IXGRP).\n\n",
608 lp_servicename(talloc_tos(), lp_sub
, s
));
610 if (!lp_store_dos_attributes(s
) && lp_map_system(s
)
611 && (lp_force_create_mode(s
) & S_IXGRP
))
614 "Invalid combination of parameters for service "
615 "%s. Map system can only work if force create mode "
616 "excludes octal 010 (S_IXGRP).\n\n",
617 lp_servicename(talloc_tos(), lp_sub
, s
));
619 if (lp_printing(s
) == PRINT_CUPS
&& *(lp_print_command(s
)) != '\0') {
621 "Warning: Service %s defines a print command, but "
622 "parameter is ignored when using CUPS libraries.\n\n",
623 lp_servicename(talloc_tos(), lp_sub
, s
));
626 vfs_objects
= lp_vfs_objects(s
);
627 if (vfs_objects
&& str_list_check(vfs_objects
, "fruit")) {
630 doesnt_use_fruit
= true;
633 if (uses_fruit
&& doesnt_use_fruit
&& !fruit_mix_warned
) {
634 fruit_mix_warned
= true;
636 "WARNING: some services use vfs_fruit, others don't. Mounting them "
637 "in conjunction on OS X clients results in undefined behaviour.\n\n");
641 int main(int argc
, const char *argv
[])
643 const char *config_file
= get_dyn_CONFIGFILE();
644 const struct loadparm_substitution
*lp_sub
=
645 loadparm_s3_global_substitution();
647 static int silent_mode
= False
;
648 static int show_all_parameters
= False
;
651 static char *parameter_name
= NULL
;
652 static const char *section_name
= NULL
;
655 static int show_defaults
;
656 static int skip_logic_checks
= 0;
657 const char *weak_crypo_str
= "";
659 struct poptOption long_options
[] = {
662 .longName
= "suppress-prompt",
664 .argInfo
= POPT_ARG_VAL
,
667 .descrip
= "Suppress prompt for enter",
670 .longName
= "verbose",
672 .argInfo
= POPT_ARG_NONE
,
673 .arg
= &show_defaults
,
675 .descrip
= "Show default options too",
678 .longName
= "skip-logic-checks",
680 .argInfo
= POPT_ARG_NONE
,
681 .arg
= &skip_logic_checks
,
683 .descrip
= "Skip the global checks",
686 .longName
= "show-all-parameters",
688 .argInfo
= POPT_ARG_VAL
,
689 .arg
= &show_all_parameters
,
691 .descrip
= "Show the parameters, type, possible "
695 .longName
= "parameter-name",
697 .argInfo
= POPT_ARG_STRING
,
698 .arg
= ¶meter_name
,
700 .descrip
= "Limit testparm to a named parameter",
703 .longName
= "section-name",
705 .argInfo
= POPT_ARG_STRING
,
706 .arg
= §ion_name
,
708 .descrip
= "Limit testparm to a named section",
711 POPT_COMMON_DEBUGLEVEL
716 TALLOC_CTX
*frame
= talloc_stackframe();
720 * Set the default debug level to 1.
721 * Allow it to be overridden by the command line,
724 lp_set_cmdline("log level", "1");
726 pc
= poptGetContext(NULL
, argc
, argv
, long_options
,
727 POPT_CONTEXT_KEEP_FIRST
);
728 poptSetOtherOptionHelp(pc
, "[OPTION...] <config-file> [host-name] [host-ip]");
730 while(poptGetNextOpt(pc
) != -1);
732 if (show_all_parameters
) {
733 show_parameter_list();
737 setup_logging(poptGetArg(pc
), DEBUG_STDERR
);
740 config_file
= poptGetArg(pc
);
742 cname
= poptGetArg(pc
);
743 caddr
= poptGetArg(pc
);
747 if ( cname
&& ! caddr
) {
748 printf ( "ERROR: You must specify both a machine name and an IP address.\n" );
753 fprintf(stderr
,"Load smb config files from %s\n",config_file
);
755 if (!lp_load_with_registry_shares(config_file
)) {
756 fprintf(stderr
,"Error loading services.\n");
761 fprintf(stderr
,"Loaded services file OK.\n");
763 if (samba_gnutls_weak_crypto_allowed()) {
764 weak_crypo_str
= "allowed";
766 weak_crypo_str
= "disallowed";
768 fprintf(stderr
, "Weak crypto is %s\n", weak_crypo_str
);
770 if (skip_logic_checks
== 0) {
771 ret
= do_global_checks();
774 for (s
=0;s
<1000;s
++) {
775 if (VALID_SNUM(s
) && (skip_logic_checks
== 0)) {
776 do_per_share_checks(s
);
781 if (!section_name
&& !parameter_name
) {
783 "Server role: %s\n\n",
784 server_role_str(lp_server_role()));
789 fprintf(stderr
,"Press enter to see a dump of your service definitions\n");
793 if (parameter_name
|| section_name
) {
794 bool isGlobal
= False
;
795 s
= GLOBAL_SECTION_SNUM
;
798 section_name
= GLOBAL_NAME
;
800 } else if ((isGlobal
=!strwicmp(section_name
, GLOBAL_NAME
)) == 0 &&
801 (s
=lp_servicenumber(section_name
)) == -1) {
802 fprintf(stderr
,"Unknown section %s\n",
807 if (parameter_name
) {
808 if (!dump_a_parameter( s
, parameter_name
, stdout
, isGlobal
)) {
809 fprintf(stderr
,"Parameter %s unknown for section %s\n",
810 parameter_name
, section_name
);
815 if (isGlobal
== True
)
816 lp_dump(stdout
, show_defaults
, 0);
818 lp_dump_one(stdout
, show_defaults
, s
);
823 lp_dump(stdout
, show_defaults
, lp_numservices());
827 /* this is totally ugly, a real `quick' hack */
828 for (s
=0;s
<1000;s
++) {
830 if (allow_access(lp_hosts_deny(-1), lp_hosts_allow(-1), cname
, caddr
)
831 && allow_access(lp_hosts_deny(s
), lp_hosts_allow(s
), cname
, caddr
)) {
832 fprintf(stderr
,"Allow connection from %s (%s) to %s\n",
833 cname
,caddr
,lp_servicename(talloc_tos(), lp_sub
, s
));
835 fprintf(stderr
,"Deny connection from %s (%s) to %s\n",
836 cname
,caddr
,lp_servicename(talloc_tos(), lp_sub
, s
));