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 "cmdline_contexts.h"
42 /*******************************************************************
43 Check if a directory exists.
44 ********************************************************************/
46 static bool directory_exist_stat(const char *dname
,SMB_STRUCT_STAT
*st
)
54 if (sys_stat(dname
, st
, false) != 0)
57 ret
= S_ISDIR(st
->st_ex_mode
);
64 const char *domain_name
;
70 struct idmap_domains
{
71 struct idmap_config
*c
;
76 static bool lp_scan_idmap_found_domain(const char *string
,
82 if (matches
[1].rm_so
== -1) {
83 fprintf(stderr
, "Found match, but no name - invalid idmap config");
86 if (matches
[1].rm_eo
<= matches
[1].rm_so
) {
87 fprintf(stderr
, "Invalid match - invalid idmap config");
92 struct idmap_domains
*d
= private_data
;
93 struct idmap_config
*c
= &d
->c
[d
->count
];
94 regoff_t len
= matches
[1].rm_eo
- matches
[1].rm_so
;
95 char domname
[len
+ 1];
97 if (d
->count
>= d
->size
) {
101 memcpy(domname
, string
+ matches
[1].rm_so
, len
);
104 c
->domain_name
= talloc_strdup_upper(d
->c
, domname
);
105 if (c
->domain_name
== NULL
) {
108 c
->backend
= talloc_strdup(d
->c
, lp_idmap_backend(domname
));
109 if (c
->backend
== NULL
) {
113 if (lp_server_role() != ROLE_ACTIVE_DIRECTORY_DC
) {
114 ok
= lp_idmap_range(domname
, &c
->low
, &c
->high
);
117 "ERROR: Invalid idmap range for domain "
127 return false; /* Keep scanning */
130 static bool do_idmap_check(void)
132 struct idmap_domains
*d
;
137 d
= talloc_zero(talloc_tos(), struct idmap_domains
);
144 d
->c
= talloc_array(d
, struct idmap_config
, d
->size
);
149 rc
= lp_wi_scan_global_parametrics("idmapconfig\\(.*\\):backend",
151 lp_scan_idmap_found_domain
,
155 "FATAL: wi_scan_global_parametrics failed: %d",
159 for (i
= 0; i
< d
->count
; i
++) {
160 struct idmap_config
*c
= &d
->c
[i
];
163 for (j
= 0; j
< d
->count
&& j
!= i
; j
++) {
164 struct idmap_config
*x
= &d
->c
[j
];
166 if ((c
->low
>= x
->low
&& c
->low
<= x
->high
) ||
167 (c
->high
>= x
->low
&& c
->high
<= x
->high
)) {
168 /* Allow overlapping ranges for idmap_ad */
169 ok
= strequal(c
->backend
, x
->backend
);
171 ok
= strequal(c
->backend
, "ad");
174 "NOTE: The idmap_ad "
175 "range for the domain "
176 "%s overlaps with the "
185 "ERROR: The idmap range for the domain "
186 "%s (%s) overlaps with the range of "
204 /***********************************************
205 Here we do a set of 'hard coded' checks for bad
206 configuration settings.
207 ************************************************/
209 static int do_global_checks(void)
213 const char *socket_options
;
214 const struct loadparm_substitution
*lp_sub
=
215 loadparm_s3_global_substitution();
217 if (lp_security() >= SEC_DOMAIN
&& !lp_encrypt_passwords()) {
218 fprintf(stderr
, "ERROR: in 'security=domain' mode the "
219 "'encrypt passwords' parameter must always be "
220 "set to 'true'.\n\n");
224 if (lp_we_are_a_wins_server() && lp_wins_server_list()) {
225 fprintf(stderr
, "ERROR: both 'wins support = true' and "
226 "'wins server = <server list>' cannot be set in "
227 "the smb.conf file. nmbd will abort with this "
232 if (strequal(lp_workgroup(), lp_netbios_name())) {
233 fprintf(stderr
, "WARNING: 'workgroup' and 'netbios name' "
237 if (lp_client_ipc_signing() == SMB_SIGNING_IF_REQUIRED
238 || lp_client_ipc_signing() == SMB_SIGNING_OFF
) {
239 fprintf(stderr
, "WARNING: The 'client ipc signing' value "
240 "%s SMB signing is not used when contacting a "
241 "domain controller or other server. "
242 "This setting is not recommended; please be "
243 "aware of the security implications when using "
244 "this configuration setting.\n\n",
245 lp_client_ipc_signing() == SMB_SIGNING_OFF
?
246 "ensures" : "may mean");
249 if (strlen(lp_netbios_name()) > 15) {
250 fprintf(stderr
, "WARNING: The 'netbios name' is too long "
251 "(max. 15 chars).\n\n");
254 if (!directory_exist_stat(lp_lock_directory(), &st
)) {
255 fprintf(stderr
, "ERROR: lock directory %s does not exist\n\n",
256 lp_lock_directory());
258 } else if ((st
.st_ex_mode
& 0777) != 0755) {
259 fprintf(stderr
, "WARNING: lock directory %s should have "
260 "permissions 0755 for browsing to work\n\n",
261 lp_lock_directory());
264 if (!directory_exist_stat(lp_state_directory(), &st
)) {
265 fprintf(stderr
, "ERROR: state directory %s does not exist\n\n",
266 lp_state_directory());
268 } else if ((st
.st_ex_mode
& 0777) != 0755) {
269 fprintf(stderr
, "WARNING: state directory %s should have "
270 "permissions 0755 for browsing to work\n\n",
271 lp_state_directory());
274 if (!directory_exist_stat(lp_cache_directory(), &st
)) {
275 fprintf(stderr
, "ERROR: cache directory %s does not exist\n\n",
276 lp_cache_directory());
278 } else if ((st
.st_ex_mode
& 0777) != 0755) {
279 fprintf(stderr
, "WARNING: cache directory %s should have "
280 "permissions 0755 for browsing to work\n\n",
281 lp_cache_directory());
284 if (!directory_exist_stat(lp_pid_directory(), &st
)) {
285 fprintf(stderr
, "ERROR: pid directory %s does not exist\n\n",
290 if (lp_passdb_expand_explicit()) {
291 fprintf(stderr
, "WARNING: passdb expand explicit = yes is "
298 socket_options
= lp_socket_options();
299 if (socket_options
!= NULL
&&
300 (strstr(socket_options
, "SO_SNDBUF") ||
301 strstr(socket_options
, "SO_RCVBUF") ||
302 strstr(socket_options
, "SO_SNDLOWAT") ||
303 strstr(socket_options
, "SO_RCVLOWAT")))
306 "WARNING: socket options = %s\n"
307 "This warning is printed because you set one of the\n"
308 "following options: SO_SNDBUF, SO_RCVBUF, SO_SNDLOWAT,\n"
310 "Modern server operating systems are tuned for\n"
311 "high network performance in the majority of situations;\n"
312 "when you set 'socket options' you are overriding those\n"
314 "Linux in particular has an auto-tuning mechanism for\n"
315 "buffer sizes (SO_SNDBUF, SO_RCVBUF) that will be\n"
316 "disabled if you specify a socket buffer size. This can\n"
317 "potentially cripple your TCP/IP stack.\n\n"
318 "Getting the 'socket options' correct can make a big\n"
319 "difference to your performance, but getting them wrong\n"
320 "can degrade it by just as much. As with any other low\n"
321 "level setting, if you must make changes to it, make\n "
322 "small changes and test the effect before making any\n"
323 "large changes.\n\n",
328 * Password server sanity checks.
331 if((lp_security() >= SEC_DOMAIN
) && !*lp_password_server()) {
332 const char *sec_setting
;
333 if(lp_security() == SEC_DOMAIN
)
334 sec_setting
= "domain";
335 else if(lp_security() == SEC_ADS
)
340 fprintf(stderr
, "ERROR: The setting 'security=%s' requires the "
341 "'password server' parameter be set to the "
342 "default value * or a valid password server.\n\n",
347 if((lp_security() >= SEC_DOMAIN
) && (strcmp(lp_password_server(), "*") != 0)) {
348 const char *sec_setting
;
349 if(lp_security() == SEC_DOMAIN
)
350 sec_setting
= "domain";
351 else if(lp_security() == SEC_ADS
)
356 fprintf(stderr
, "WARNING: The setting 'security=%s' should NOT "
357 "be combined with the 'password server' "
359 "(by default Samba will discover the correct DC "
360 "to contact automatically).\n\n",
365 * Password chat sanity checks.
368 if(lp_security() == SEC_USER
&& lp_unix_password_sync()) {
371 * Check that we have a valid lp_passwd_program() if not using pam.
375 if (!lp_pam_password_change()) {
378 if((lp_passwd_program(talloc_tos(), lp_sub
) == NULL
) ||
379 (strlen(lp_passwd_program(talloc_tos(), lp_sub
)) == 0))
382 "ERROR: the 'unix password sync' "
383 "parameter is set and there is no valid "
384 "'passwd program' parameter.\n\n");
387 const char *passwd_prog
;
388 char *truncated_prog
= NULL
;
391 passwd_prog
= lp_passwd_program(talloc_tos(), lp_sub
);
393 next_token_talloc(talloc_tos(),
395 &truncated_prog
, NULL
);
396 if (truncated_prog
&& access(truncated_prog
, F_OK
) == -1) {
398 "ERROR: the 'unix password sync' "
399 "parameter is set and the "
400 "'passwd program' (%s) cannot be "
401 "executed (error was %s).\n\n",
412 if(lp_passwd_chat(talloc_tos(), lp_sub
) == NULL
) {
414 "ERROR: the 'unix password sync' parameter is "
415 "set and there is no valid 'passwd chat' "
420 if ((lp_passwd_program(talloc_tos(), lp_sub
) != NULL
) &&
421 (strlen(lp_passwd_program(talloc_tos(), lp_sub
)) > 0))
423 /* check if there's a %u parameter present */
424 if(strstr_m(lp_passwd_program(talloc_tos(), lp_sub
), "%u") == NULL
) {
426 "ERROR: the 'passwd program' (%s) "
427 "requires a '%%u' parameter.\n\n",
428 lp_passwd_program(talloc_tos(), lp_sub
));
434 * Check that we have a valid script and that it hasn't
435 * been written to expect the old password.
438 if(lp_encrypt_passwords()) {
439 if(strstr_m( lp_passwd_chat(talloc_tos(), lp_sub
), "%o")!=NULL
) {
441 "ERROR: the 'passwd chat' script [%s] "
442 "expects to use the old plaintext "
443 "password via the %%o substitution. With "
444 "encrypted passwords this is not "
446 lp_passwd_chat(talloc_tos(), lp_sub
) );
452 if (strlen(lp_winbind_separator()) != 1) {
453 fprintf(stderr
, "ERROR: the 'winbind separator' parameter must "
454 "be a single character.\n\n");
458 if (*lp_winbind_separator() == '+') {
459 fprintf(stderr
, "'winbind separator = +' might cause problems "
460 "with group membership.\n\n");
463 if (lp_algorithmic_rid_base() < BASE_RID
) {
464 /* Try to prevent admin foot-shooting, we can't put algorithmic
465 rids below 1000, that's the 'well known RIDs' on NT */
466 fprintf(stderr
, "'algorithmic rid base' must be equal to or "
467 "above %lu\n\n", BASE_RID
);
470 if (lp_algorithmic_rid_base() & 1) {
471 fprintf(stderr
, "'algorithmic rid base' must be even.\n\n");
474 if (lp_server_role() != ROLE_STANDALONE
) {
475 const char *default_backends
[] = {
476 "tdb", "tdb2", "ldap", "autorid", "hash"
478 const char *idmap_backend
;
479 bool valid_backend
= false;
483 idmap_backend
= lp_idmap_default_backend();
485 for (i
= 0; i
< ARRAY_SIZE(default_backends
); i
++) {
486 ok
= strequal(idmap_backend
, default_backends
[i
]);
488 valid_backend
= true;
492 if (!valid_backend
) {
494 fprintf(stderr
, "ERROR: Do not use the '%s' backend "
495 "as the default idmap backend!\n\n",
499 ok
= do_idmap_check();
506 if (lp_preload_modules()) {
507 fprintf(stderr
, "WARNING: 'preload modules = ' set while loading "
508 "plugins not supported.\n\n");
512 if (!lp_passdb_backend()) {
513 fprintf(stderr
, "ERROR: passdb backend must have a value or be "
517 if (lp_os_level() > 255) {
518 fprintf(stderr
, "WARNING: Maximum value for 'os level' is "
522 if (strequal(lp_dos_charset(), "UTF8") || strequal(lp_dos_charset(), "UTF-8")) {
523 fprintf(stderr
, "ERROR: 'dos charset' must not be UTF8\n\n");
531 * per-share logic tests
533 static void do_per_share_checks(int s
)
535 const struct loadparm_substitution
*lp_sub
=
536 loadparm_s3_global_substitution();
537 const char **deny_list
= lp_hosts_deny(s
);
538 const char **allow_list
= lp_hosts_allow(s
);
539 const char **vfs_objects
= NULL
;
541 static bool uses_fruit
;
542 static bool doesnt_use_fruit
;
543 static bool fruit_mix_warned
;
546 for (i
=0; deny_list
[i
]; i
++) {
547 char *hasstar
= strchr_m(deny_list
[i
], '*');
548 char *hasquery
= strchr_m(deny_list
[i
], '?');
549 if(hasstar
|| hasquery
) {
551 "Invalid character %c in hosts deny list "
552 "(%s) for service %s.\n\n",
553 hasstar
? *hasstar
: *hasquery
,
555 lp_servicename(talloc_tos(), lp_sub
, s
));
561 for (i
=0; allow_list
[i
]; i
++) {
562 char *hasstar
= strchr_m(allow_list
[i
], '*');
563 char *hasquery
= strchr_m(allow_list
[i
], '?');
564 if(hasstar
|| hasquery
) {
566 "Invalid character %c in hosts allow "
567 "list (%s) for service %s.\n\n",
568 hasstar
? *hasstar
: *hasquery
,
570 lp_servicename(talloc_tos(), lp_sub
, s
));
575 if(lp_level2_oplocks(s
) && !lp_oplocks(s
)) {
576 fprintf(stderr
, "Invalid combination of parameters for service "
577 "%s. Level II oplocks can only be set if oplocks "
579 lp_servicename(talloc_tos(), lp_sub
, s
));
582 if (!lp_store_dos_attributes(s
) && lp_map_hidden(s
)
583 && !(lp_create_mask(s
) & S_IXOTH
))
586 "Invalid combination of parameters for service %s. Map "
587 "hidden can only work if create mask includes octal "
589 lp_servicename(talloc_tos(), lp_sub
, s
));
591 if (!lp_store_dos_attributes(s
) && lp_map_hidden(s
)
592 && (lp_force_create_mode(s
) & S_IXOTH
))
595 "Invalid combination of parameters for service "
596 "%s. Map hidden can only work if force create mode "
597 "excludes octal 01 (S_IXOTH).\n\n",
598 lp_servicename(talloc_tos(), lp_sub
, s
));
600 if (!lp_store_dos_attributes(s
) && lp_map_system(s
)
601 && !(lp_create_mask(s
) & S_IXGRP
))
604 "Invalid combination of parameters for service "
605 "%s. Map system can only work if create mask includes "
606 "octal 010 (S_IXGRP).\n\n",
607 lp_servicename(talloc_tos(), lp_sub
, s
));
609 if (!lp_store_dos_attributes(s
) && lp_map_system(s
)
610 && (lp_force_create_mode(s
) & S_IXGRP
))
613 "Invalid combination of parameters for service "
614 "%s. Map system can only work if force create mode "
615 "excludes octal 010 (S_IXGRP).\n\n",
616 lp_servicename(talloc_tos(), lp_sub
, s
));
618 if (lp_printing(s
) == PRINT_CUPS
&& *(lp_print_command(s
)) != '\0') {
620 "Warning: Service %s defines a print command, but "
621 "parameter is ignored when using CUPS libraries.\n\n",
622 lp_servicename(talloc_tos(), lp_sub
, s
));
625 vfs_objects
= lp_vfs_objects(s
);
626 if (vfs_objects
&& str_list_check(vfs_objects
, "fruit")) {
629 doesnt_use_fruit
= true;
632 if (uses_fruit
&& doesnt_use_fruit
&& !fruit_mix_warned
) {
633 fruit_mix_warned
= true;
635 "WARNING: some services use vfs_fruit, others don't. Mounting them "
636 "in conjunction on OS X clients results in undefined behaviour.\n\n");
640 int main(int argc
, const char *argv
[])
642 const char *config_file
= get_dyn_CONFIGFILE();
643 const struct loadparm_substitution
*lp_sub
=
644 loadparm_s3_global_substitution();
646 static int silent_mode
= False
;
647 static int show_all_parameters
= False
;
650 static char *parameter_name
= NULL
;
651 static const char *section_name
= NULL
;
654 static int show_defaults
;
655 static int skip_logic_checks
= 0;
657 struct poptOption long_options
[] = {
660 .longName
= "suppress-prompt",
662 .argInfo
= POPT_ARG_VAL
,
665 .descrip
= "Suppress prompt for enter",
668 .longName
= "verbose",
670 .argInfo
= POPT_ARG_NONE
,
671 .arg
= &show_defaults
,
673 .descrip
= "Show default options too",
676 .longName
= "skip-logic-checks",
678 .argInfo
= POPT_ARG_NONE
,
679 .arg
= &skip_logic_checks
,
681 .descrip
= "Skip the global checks",
684 .longName
= "show-all-parameters",
686 .argInfo
= POPT_ARG_VAL
,
687 .arg
= &show_all_parameters
,
689 .descrip
= "Show the parameters, type, possible "
693 .longName
= "parameter-name",
695 .argInfo
= POPT_ARG_STRING
,
696 .arg
= ¶meter_name
,
698 .descrip
= "Limit testparm to a named parameter",
701 .longName
= "section-name",
703 .argInfo
= POPT_ARG_STRING
,
704 .arg
= §ion_name
,
706 .descrip
= "Limit testparm to a named section",
709 POPT_COMMON_DEBUGLEVEL
714 TALLOC_CTX
*frame
= talloc_stackframe();
718 * Set the default debug level to 1.
719 * Allow it to be overridden by the command line,
722 lp_set_cmdline("log level", "1");
724 pc
= poptGetContext(NULL
, argc
, argv
, long_options
,
725 POPT_CONTEXT_KEEP_FIRST
);
726 poptSetOtherOptionHelp(pc
, "[OPTION...] <config-file> [host-name] [host-ip]");
728 while(poptGetNextOpt(pc
) != -1);
730 if (show_all_parameters
) {
731 show_parameter_list();
735 setup_logging(poptGetArg(pc
), DEBUG_STDERR
);
738 config_file
= poptGetArg(pc
);
740 cname
= poptGetArg(pc
);
741 caddr
= poptGetArg(pc
);
745 if ( cname
&& ! caddr
) {
746 printf ( "ERROR: You must specify both a machine name and an IP address.\n" );
751 fprintf(stderr
,"Load smb config files from %s\n",config_file
);
753 if (!lp_load_with_registry_shares(config_file
)) {
754 fprintf(stderr
,"Error loading services.\n");
759 fprintf(stderr
,"Loaded services file OK.\n");
761 if (skip_logic_checks
== 0) {
762 ret
= do_global_checks();
765 for (s
=0;s
<1000;s
++) {
766 if (VALID_SNUM(s
) && (skip_logic_checks
== 0)) {
767 do_per_share_checks(s
);
772 if (!section_name
&& !parameter_name
) {
774 "Server role: %s\n\n",
775 server_role_str(lp_server_role()));
780 fprintf(stderr
,"Press enter to see a dump of your service definitions\n");
784 if (parameter_name
|| section_name
) {
785 bool isGlobal
= False
;
786 s
= GLOBAL_SECTION_SNUM
;
789 section_name
= GLOBAL_NAME
;
791 } else if ((isGlobal
=!strwicmp(section_name
, GLOBAL_NAME
)) == 0 &&
792 (s
=lp_servicenumber(section_name
)) == -1) {
793 fprintf(stderr
,"Unknown section %s\n",
798 if (parameter_name
) {
799 if (!dump_a_parameter( s
, parameter_name
, stdout
, isGlobal
)) {
800 fprintf(stderr
,"Parameter %s unknown for section %s\n",
801 parameter_name
, section_name
);
806 if (isGlobal
== True
)
807 lp_dump(stdout
, show_defaults
, 0);
809 lp_dump_one(stdout
, show_defaults
, s
);
814 lp_dump(stdout
, show_defaults
, lp_numservices());
818 /* this is totally ugly, a real `quick' hack */
819 for (s
=0;s
<1000;s
++) {
821 if (allow_access(lp_hosts_deny(-1), lp_hosts_allow(-1), cname
, caddr
)
822 && allow_access(lp_hosts_deny(s
), lp_hosts_allow(s
), cname
, caddr
)) {
823 fprintf(stderr
,"Allow connection from %s (%s) to %s\n",
824 cname
,caddr
,lp_servicename(talloc_tos(), lp_sub
, s
));
826 fprintf(stderr
,"Deny connection from %s (%s) to %s\n",
827 cname
,caddr
,lp_servicename(talloc_tos(), lp_sub
, s
));