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"
41 /*******************************************************************
42 Check if a directory exists.
43 ********************************************************************/
45 static bool directory_exist_stat(const char *dname
,SMB_STRUCT_STAT
*st
)
53 if (sys_stat(dname
, st
, false) != 0)
56 ret
= S_ISDIR(st
->st_ex_mode
);
63 const char *domain_name
;
69 struct idmap_domains
{
70 struct idmap_config
*c
;
75 static bool lp_scan_idmap_found_domain(const char *string
,
81 if (matches
[1].rm_so
== -1) {
82 fprintf(stderr
, "Found match, but no name - invalid idmap config");
85 if (matches
[1].rm_eo
<= matches
[1].rm_so
) {
86 fprintf(stderr
, "Invalid match - invalid idmap config");
91 struct idmap_domains
*d
= private_data
;
92 struct idmap_config
*c
= &d
->c
[d
->count
];
93 regoff_t len
= matches
[1].rm_eo
- matches
[1].rm_so
;
94 char domname
[len
+ 1];
96 if (d
->count
>= d
->size
) {
100 memcpy(domname
, string
+ matches
[1].rm_so
, len
);
103 c
->domain_name
= talloc_strdup_upper(d
->c
, domname
);
104 if (c
->domain_name
== NULL
) {
107 c
->backend
= talloc_strdup(d
->c
, lp_idmap_backend(domname
));
108 if (c
->backend
== NULL
) {
112 if (lp_server_role() != ROLE_ACTIVE_DIRECTORY_DC
) {
113 ok
= lp_idmap_range(domname
, &c
->low
, &c
->high
);
116 "ERROR: Invalid idmap range for domain "
126 return false; /* Keep scanning */
129 static bool do_idmap_check(void)
131 struct idmap_domains
*d
;
136 d
= talloc_zero(talloc_tos(), struct idmap_domains
);
143 d
->c
= talloc_array(d
, struct idmap_config
, d
->size
);
148 rc
= lp_wi_scan_global_parametrics("idmapconfig\\(.*\\):backend",
150 lp_scan_idmap_found_domain
,
154 "FATAL: wi_scan_global_parametrics failed: %d",
158 for (i
= 0; i
< d
->count
; i
++) {
159 struct idmap_config
*c
= &d
->c
[i
];
162 for (j
= 0; j
< d
->count
&& j
!= i
; j
++) {
163 struct idmap_config
*x
= &d
->c
[j
];
165 if ((c
->low
>= x
->low
&& c
->low
<= x
->high
) ||
166 (c
->high
>= x
->low
&& c
->high
<= x
->high
)) {
167 /* Allow overlapping ranges for idmap_ad */
168 ok
= strequal(c
->backend
, x
->backend
);
170 ok
= strequal(c
->backend
, "ad");
173 "NOTE: The idmap_ad "
174 "range for the domain "
175 "%s overlaps with the "
184 "ERROR: The idmap range for the domain "
185 "%s (%s) overlaps with the range of "
203 /***********************************************
204 Here we do a set of 'hard coded' checks for bad
205 configuration settings.
206 ************************************************/
208 static int do_global_checks(void)
212 const char *socket_options
;
214 if (lp_security() >= SEC_DOMAIN
&& !lp_encrypt_passwords()) {
215 fprintf(stderr
, "ERROR: in 'security=domain' mode the "
216 "'encrypt passwords' parameter must always be "
217 "set to 'true'.\n\n");
221 if (lp_we_are_a_wins_server() && lp_wins_server_list()) {
222 fprintf(stderr
, "ERROR: both 'wins support = true' and "
223 "'wins server = <server list>' cannot be set in "
224 "the smb.conf file. nmbd will abort with this "
229 if (strequal(lp_workgroup(), lp_netbios_name())) {
230 fprintf(stderr
, "WARNING: 'workgroup' and 'netbios name' "
234 if (lp_client_ipc_signing() == SMB_SIGNING_IF_REQUIRED
235 || lp_client_ipc_signing() == SMB_SIGNING_OFF
) {
236 fprintf(stderr
, "WARNING: The 'client ipc signing' value "
237 "%s SMB signing is not used when contacting a "
238 "domain controller or other server. "
239 "This setting is not recommended; please be "
240 "aware of the security implications when using "
241 "this configuration setting.\n\n",
242 lp_client_ipc_signing() == SMB_SIGNING_OFF
?
243 "ensures" : "may mean");
246 if (strlen(lp_netbios_name()) > 15) {
247 fprintf(stderr
, "WARNING: The 'netbios name' is too long "
248 "(max. 15 chars).\n\n");
251 if (!directory_exist_stat(lp_lock_directory(), &st
)) {
252 fprintf(stderr
, "ERROR: lock directory %s does not exist\n\n",
253 lp_lock_directory());
255 } else if ((st
.st_ex_mode
& 0777) != 0755) {
256 fprintf(stderr
, "WARNING: lock directory %s should have "
257 "permissions 0755 for browsing to work\n\n",
258 lp_lock_directory());
261 if (!directory_exist_stat(lp_state_directory(), &st
)) {
262 fprintf(stderr
, "ERROR: state directory %s does not exist\n\n",
263 lp_state_directory());
265 } else if ((st
.st_ex_mode
& 0777) != 0755) {
266 fprintf(stderr
, "WARNING: state directory %s should have "
267 "permissions 0755 for browsing to work\n\n",
268 lp_state_directory());
271 if (!directory_exist_stat(lp_cache_directory(), &st
)) {
272 fprintf(stderr
, "ERROR: cache directory %s does not exist\n\n",
273 lp_cache_directory());
275 } else if ((st
.st_ex_mode
& 0777) != 0755) {
276 fprintf(stderr
, "WARNING: cache directory %s should have "
277 "permissions 0755 for browsing to work\n\n",
278 lp_cache_directory());
281 if (!directory_exist_stat(lp_pid_directory(), &st
)) {
282 fprintf(stderr
, "ERROR: pid directory %s does not exist\n\n",
287 if (lp_passdb_expand_explicit()) {
288 fprintf(stderr
, "WARNING: passdb expand explicit = yes is "
295 socket_options
= lp_socket_options();
296 if (socket_options
!= NULL
&&
297 (strstr(socket_options
, "SO_SNDBUF") ||
298 strstr(socket_options
, "SO_RCVBUF") ||
299 strstr(socket_options
, "SO_SNDLOWAT") ||
300 strstr(socket_options
, "SO_RCVLOWAT")))
303 "WARNING: socket options = %s\n"
304 "This warning is printed because you set one of the\n"
305 "following options: SO_SNDBUF, SO_RCVBUF, SO_SNDLOWAT,\n"
307 "Modern server operating systems are tuned for\n"
308 "high network performance in the majority of situations;\n"
309 "when you set 'socket options' you are overriding those\n"
311 "Linux in particular has an auto-tuning mechanism for\n"
312 "buffer sizes (SO_SNDBUF, SO_RCVBUF) that will be\n"
313 "disabled if you specify a socket buffer size. This can\n"
314 "potentially cripple your TCP/IP stack.\n\n"
315 "Getting the 'socket options' correct can make a big\n"
316 "difference to your performance, but getting them wrong\n"
317 "can degrade it by just as much. As with any other low\n"
318 "level setting, if you must make changes to it, make\n "
319 "small changes and test the effect before making any\n"
320 "large changes.\n\n",
325 * Password server sanity checks.
328 if((lp_security() >= SEC_DOMAIN
) && !*lp_password_server()) {
329 const char *sec_setting
;
330 if(lp_security() == SEC_DOMAIN
)
331 sec_setting
= "domain";
332 else if(lp_security() == SEC_ADS
)
337 fprintf(stderr
, "ERROR: The setting 'security=%s' requires the "
338 "'password server' parameter be set to the "
339 "default value * or a valid password server.\n\n",
344 if((lp_security() >= SEC_DOMAIN
) && (strcmp(lp_password_server(), "*") != 0)) {
345 const char *sec_setting
;
346 if(lp_security() == SEC_DOMAIN
)
347 sec_setting
= "domain";
348 else if(lp_security() == SEC_ADS
)
353 fprintf(stderr
, "WARNING: The setting 'security=%s' should NOT "
354 "be combined with the 'password server' "
356 "(by default Samba will discover the correct DC "
357 "to contact automatically).\n\n",
362 * Password chat sanity checks.
365 if(lp_security() == SEC_USER
&& lp_unix_password_sync()) {
368 * Check that we have a valid lp_passwd_program() if not using pam.
372 if (!lp_pam_password_change()) {
375 if((lp_passwd_program(talloc_tos()) == NULL
) ||
376 (strlen(lp_passwd_program(talloc_tos())) == 0))
379 "ERROR: the 'unix password sync' "
380 "parameter is set and there is no valid "
381 "'passwd program' parameter.\n\n");
384 const char *passwd_prog
;
385 char *truncated_prog
= NULL
;
388 passwd_prog
= lp_passwd_program(talloc_tos());
390 next_token_talloc(talloc_tos(),
392 &truncated_prog
, NULL
);
393 if (truncated_prog
&& access(truncated_prog
, F_OK
) == -1) {
395 "ERROR: the 'unix password sync' "
396 "parameter is set and the "
397 "'passwd program' (%s) cannot be "
398 "executed (error was %s).\n\n",
409 if(lp_passwd_chat(talloc_tos()) == NULL
) {
411 "ERROR: the 'unix password sync' parameter is "
412 "set and there is no valid 'passwd chat' "
417 if ((lp_passwd_program(talloc_tos()) != NULL
) &&
418 (strlen(lp_passwd_program(talloc_tos())) > 0))
420 /* check if there's a %u parameter present */
421 if(strstr_m(lp_passwd_program(talloc_tos()), "%u") == NULL
) {
423 "ERROR: the 'passwd program' (%s) "
424 "requires a '%%u' parameter.\n\n",
425 lp_passwd_program(talloc_tos()));
431 * Check that we have a valid script and that it hasn't
432 * been written to expect the old password.
435 if(lp_encrypt_passwords()) {
436 if(strstr_m( lp_passwd_chat(talloc_tos()), "%o")!=NULL
) {
438 "ERROR: the 'passwd chat' script [%s] "
439 "expects to use the old plaintext "
440 "password via the %%o substitution. With "
441 "encrypted passwords this is not "
443 lp_passwd_chat(talloc_tos()) );
449 if (strlen(lp_winbind_separator()) != 1) {
450 fprintf(stderr
, "ERROR: the 'winbind separator' parameter must "
451 "be a single character.\n\n");
455 if (*lp_winbind_separator() == '+') {
456 fprintf(stderr
, "'winbind separator = +' might cause problems "
457 "with group membership.\n\n");
460 if (lp_algorithmic_rid_base() < BASE_RID
) {
461 /* Try to prevent admin foot-shooting, we can't put algorithmic
462 rids below 1000, that's the 'well known RIDs' on NT */
463 fprintf(stderr
, "'algorithmic rid base' must be equal to or "
464 "above %lu\n\n", BASE_RID
);
467 if (lp_algorithmic_rid_base() & 1) {
468 fprintf(stderr
, "'algorithmic rid base' must be even.\n\n");
471 if (lp_server_role() != ROLE_STANDALONE
) {
472 const char *default_backends
[] = {
473 "tdb", "tdb2", "ldap", "autorid", "hash"
475 const char *idmap_backend
;
476 bool valid_backend
= false;
480 idmap_backend
= lp_idmap_default_backend();
482 for (i
= 0; i
< ARRAY_SIZE(default_backends
); i
++) {
483 ok
= strequal(idmap_backend
, default_backends
[i
]);
485 valid_backend
= true;
489 if (!valid_backend
) {
491 fprintf(stderr
, "ERROR: Do not use the '%s' backend "
492 "as the default idmap backend!\n\n",
496 ok
= do_idmap_check();
503 if (lp_preload_modules()) {
504 fprintf(stderr
, "WARNING: 'preload modules = ' set while loading "
505 "plugins not supported.\n\n");
509 if (!lp_passdb_backend()) {
510 fprintf(stderr
, "ERROR: passdb backend must have a value or be "
514 if (lp_os_level() > 255) {
515 fprintf(stderr
, "WARNING: Maximum value for 'os level' is "
519 if (strequal(lp_dos_charset(), "UTF8") || strequal(lp_dos_charset(), "UTF-8")) {
520 fprintf(stderr
, "ERROR: 'dos charset' must not be UTF8\n\n");
528 * per-share logic tests
530 static void do_per_share_checks(int s
)
532 const char **deny_list
= lp_hosts_deny(s
);
533 const char **allow_list
= lp_hosts_allow(s
);
534 const char **vfs_objects
= NULL
;
536 static bool uses_fruit
;
537 static bool doesnt_use_fruit
;
538 static bool fruit_mix_warned
;
541 for (i
=0; deny_list
[i
]; i
++) {
542 char *hasstar
= strchr_m(deny_list
[i
], '*');
543 char *hasquery
= strchr_m(deny_list
[i
], '?');
544 if(hasstar
|| hasquery
) {
546 "Invalid character %c in hosts deny list "
547 "(%s) for service %s.\n\n",
548 hasstar
? *hasstar
: *hasquery
,
550 lp_servicename(talloc_tos(), s
));
556 for (i
=0; allow_list
[i
]; i
++) {
557 char *hasstar
= strchr_m(allow_list
[i
], '*');
558 char *hasquery
= strchr_m(allow_list
[i
], '?');
559 if(hasstar
|| hasquery
) {
561 "Invalid character %c in hosts allow "
562 "list (%s) for service %s.\n\n",
563 hasstar
? *hasstar
: *hasquery
,
565 lp_servicename(talloc_tos(), s
));
570 if(lp_level2_oplocks(s
) && !lp_oplocks(s
)) {
571 fprintf(stderr
, "Invalid combination of parameters for service "
572 "%s. Level II oplocks can only be set if oplocks "
574 lp_servicename(talloc_tos(), s
));
577 if (!lp_store_dos_attributes(s
) && lp_map_hidden(s
)
578 && !(lp_create_mask(s
) & S_IXOTH
))
581 "Invalid combination of parameters for service %s. Map "
582 "hidden can only work if create mask includes octal "
584 lp_servicename(talloc_tos(), s
));
586 if (!lp_store_dos_attributes(s
) && lp_map_hidden(s
)
587 && (lp_force_create_mode(s
) & S_IXOTH
))
590 "Invalid combination of parameters for service "
591 "%s. Map hidden can only work if force create mode "
592 "excludes octal 01 (S_IXOTH).\n\n",
593 lp_servicename(talloc_tos(), s
));
595 if (!lp_store_dos_attributes(s
) && lp_map_system(s
)
596 && !(lp_create_mask(s
) & S_IXGRP
))
599 "Invalid combination of parameters for service "
600 "%s. Map system can only work if create mask includes "
601 "octal 010 (S_IXGRP).\n\n",
602 lp_servicename(talloc_tos(), s
));
604 if (!lp_store_dos_attributes(s
) && lp_map_system(s
)
605 && (lp_force_create_mode(s
) & S_IXGRP
))
608 "Invalid combination of parameters for service "
609 "%s. Map system can only work if force create mode "
610 "excludes octal 010 (S_IXGRP).\n\n",
611 lp_servicename(talloc_tos(), s
));
613 if (lp_printing(s
) == PRINT_CUPS
&& *(lp_print_command(talloc_tos(), s
)) != '\0') {
615 "Warning: Service %s defines a print command, but "
616 "parameter is ignored when using CUPS libraries.\n\n",
617 lp_servicename(talloc_tos(), s
));
620 vfs_objects
= lp_vfs_objects(s
);
621 if (vfs_objects
&& str_list_check(vfs_objects
, "fruit")) {
624 doesnt_use_fruit
= true;
627 if (uses_fruit
&& doesnt_use_fruit
&& !fruit_mix_warned
) {
628 fruit_mix_warned
= true;
630 "WARNING: some services use vfs_fruit, others don't. Mounting them "
631 "in conjunction on OS X clients results in undefined behaviour.\n\n");
635 int main(int argc
, const char *argv
[])
637 const char *config_file
= get_dyn_CONFIGFILE();
639 static int silent_mode
= False
;
640 static int show_all_parameters
= False
;
643 static char *parameter_name
= NULL
;
644 static const char *section_name
= NULL
;
647 static int show_defaults
;
648 static int skip_logic_checks
= 0;
650 struct poptOption long_options
[] = {
652 {"suppress-prompt", 's', POPT_ARG_VAL
, &silent_mode
, 1, "Suppress prompt for enter"},
653 {"verbose", 'v', POPT_ARG_NONE
, &show_defaults
, 1, "Show default options too"},
654 {"skip-logic-checks", 'l', POPT_ARG_NONE
, &skip_logic_checks
, 1, "Skip the global checks"},
655 {"show-all-parameters", '\0', POPT_ARG_VAL
, &show_all_parameters
, True
, "Show the parameters, type, possible values" },
656 {"parameter-name", '\0', POPT_ARG_STRING
, ¶meter_name
, 0, "Limit testparm to a named parameter" },
657 {"section-name", '\0', POPT_ARG_STRING
, §ion_name
, 0, "Limit testparm to a named section" },
659 POPT_COMMON_DEBUGLEVEL
664 TALLOC_CTX
*frame
= talloc_stackframe();
668 * Set the default debug level to 2.
669 * Allow it to be overridden by the command line,
672 lp_set_cmdline("log level", "2");
674 pc
= poptGetContext(NULL
, argc
, argv
, long_options
,
675 POPT_CONTEXT_KEEP_FIRST
);
676 poptSetOtherOptionHelp(pc
, "[OPTION...] <config-file> [host-name] [host-ip]");
678 while(poptGetNextOpt(pc
) != -1);
680 if (show_all_parameters
) {
681 show_parameter_list();
685 setup_logging(poptGetArg(pc
), DEBUG_STDERR
);
688 config_file
= poptGetArg(pc
);
690 cname
= poptGetArg(pc
);
691 caddr
= poptGetArg(pc
);
695 if ( cname
&& ! caddr
) {
696 printf ( "ERROR: You must specify both a machine name and an IP address.\n" );
701 fprintf(stderr
,"Load smb config files from %s\n",config_file
);
703 if (!lp_load_with_registry_shares(config_file
)) {
704 fprintf(stderr
,"Error loading services.\n");
709 fprintf(stderr
,"Loaded services file OK.\n");
711 if (skip_logic_checks
== 0) {
712 ret
= do_global_checks();
715 for (s
=0;s
<1000;s
++) {
717 if (strlen(lp_servicename(talloc_tos(), s
)) > 12) {
718 fprintf(stderr
, "WARNING: You have some share names that are longer than 12 characters.\n" );
719 fprintf(stderr
, "These may not be accessible to some older clients.\n" );
720 fprintf(stderr
, "(Eg. Windows9x, WindowsMe, and smbclient prior to Samba 3.0.)\n" );
725 for (s
=0;s
<1000;s
++) {
726 if (VALID_SNUM(s
) && (skip_logic_checks
== 0)) {
727 do_per_share_checks(s
);
732 if (!section_name
&& !parameter_name
) {
734 "Server role: %s\n\n",
735 server_role_str(lp_server_role()));
740 fprintf(stderr
,"Press enter to see a dump of your service definitions\n");
744 if (parameter_name
|| section_name
) {
745 bool isGlobal
= False
;
746 s
= GLOBAL_SECTION_SNUM
;
749 section_name
= GLOBAL_NAME
;
751 } else if ((isGlobal
=!strwicmp(section_name
, GLOBAL_NAME
)) == 0 &&
752 (s
=lp_servicenumber(section_name
)) == -1) {
753 fprintf(stderr
,"Unknown section %s\n",
758 if (parameter_name
) {
759 if (!dump_a_parameter( s
, parameter_name
, stdout
, isGlobal
)) {
760 fprintf(stderr
,"Parameter %s unknown for section %s\n",
761 parameter_name
, section_name
);
766 if (isGlobal
== True
)
767 lp_dump(stdout
, show_defaults
, 0);
769 lp_dump_one(stdout
, show_defaults
, s
);
774 lp_dump(stdout
, show_defaults
, lp_numservices());
778 /* this is totally ugly, a real `quick' hack */
779 for (s
=0;s
<1000;s
++) {
781 if (allow_access(lp_hosts_deny(-1), lp_hosts_allow(-1), cname
, caddr
)
782 && allow_access(lp_hosts_deny(s
), lp_hosts_allow(s
), cname
, caddr
)) {
783 fprintf(stderr
,"Allow connection from %s (%s) to %s\n",
784 cname
,caddr
,lp_servicename(talloc_tos(), s
));
786 fprintf(stderr
,"Deny connection from %s (%s) to %s\n",
787 cname
,caddr
,lp_servicename(talloc_tos(), s
));