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"
39 /*******************************************************************
40 Check if a directory exists.
41 ********************************************************************/
43 static bool directory_exist_stat(const char *dname
,SMB_STRUCT_STAT
*st
)
51 if (sys_stat(dname
, st
, false) != 0)
54 ret
= S_ISDIR(st
->st_ex_mode
);
60 /***********************************************
61 Here we do a set of 'hard coded' checks for bad
62 configuration settings.
63 ************************************************/
65 static int do_global_checks(void)
69 const char *socket_options
;
71 if (lp_security() >= SEC_DOMAIN
&& !lp_encrypt_passwords()) {
72 fprintf(stderr
, "ERROR: in 'security=domain' mode the "
73 "'encrypt passwords' parameter must always be "
74 "set to 'true'.\n\n");
78 if (lp_we_are_a_wins_server() && lp_wins_server_list()) {
79 fprintf(stderr
, "ERROR: both 'wins support = true' and "
80 "'wins server = <server list>' cannot be set in "
81 "the smb.conf file. nmbd will abort with this "
86 if (strequal(lp_workgroup(), lp_netbios_name())) {
87 fprintf(stderr
, "WARNING: 'workgroup' and 'netbios name' "
91 if (!directory_exist_stat(lp_lock_directory(), &st
)) {
92 fprintf(stderr
, "ERROR: lock directory %s does not exist\n\n",
95 } else if ((st
.st_ex_mode
& 0777) != 0755) {
96 fprintf(stderr
, "WARNING: lock directory %s should have "
97 "permissions 0755 for browsing to work\n\n",
101 if (!directory_exist_stat(lp_state_directory(), &st
)) {
102 fprintf(stderr
, "ERROR: state directory %s does not exist\n\n",
103 lp_state_directory());
105 } else if ((st
.st_ex_mode
& 0777) != 0755) {
106 fprintf(stderr
, "WARNING: state directory %s should have "
107 "permissions 0755 for browsing to work\n\n",
108 lp_state_directory());
111 if (!directory_exist_stat(lp_cache_directory(), &st
)) {
112 fprintf(stderr
, "ERROR: cache directory %s does not exist\n\n",
113 lp_cache_directory());
115 } else if ((st
.st_ex_mode
& 0777) != 0755) {
116 fprintf(stderr
, "WARNING: cache directory %s should have "
117 "permissions 0755 for browsing to work\n\n",
118 lp_cache_directory());
121 if (!directory_exist_stat(lp_pid_directory(), &st
)) {
122 fprintf(stderr
, "ERROR: pid directory %s does not exist\n\n",
127 if (lp_passdb_expand_explicit()) {
128 fprintf(stderr
, "WARNING: passdb expand explicit = yes is "
135 socket_options
= lp_socket_options();
136 if (socket_options
!= NULL
&&
137 (strstr(socket_options
, "SO_SNDBUF") ||
138 strstr(socket_options
, "SO_RCVBUF") ||
139 strstr(socket_options
, "SO_SNDLOWAT") ||
140 strstr(socket_options
, "SO_RCVLOWAT")))
143 "WARNING: socket options = %s\n"
144 "This warning is printed because you set one of the\n"
145 "following options: SO_SNDBUF, SO_RCVBUF, SO_SNDLOWAT,\n"
147 "Modern server operating systems are tuned for\n"
148 "high network performance in the majority of situations;\n"
149 "when you set 'socket options' you are overriding those\n"
151 "Linux in particular has an auto-tuning mechanism for\n"
152 "buffer sizes (SO_SNDBUF, SO_RCVBUF) that will be\n"
153 "disabled if you specify a socket buffer size. This can\n"
154 "potentially cripple your TCP/IP stack.\n\n"
155 "Getting the 'socket options' correct can make a big\n"
156 "difference to your performance, but getting them wrong\n"
157 "can degrade it by just as much. As with any other low\n"
158 "level setting, if you must make changes to it, make\n "
159 "small changes and test the effect before making any\n"
160 "large changes.\n\n",
165 * Password server sanity checks.
168 if((lp_security() >= SEC_DOMAIN
) && !*lp_password_server()) {
169 const char *sec_setting
;
170 if(lp_security() == SEC_DOMAIN
)
171 sec_setting
= "domain";
172 else if(lp_security() == SEC_ADS
)
177 fprintf(stderr
, "ERROR: The setting 'security=%s' requires the "
178 "'password server' parameter be set to the "
179 "default value * or a valid password server.\n\n",
184 if((lp_security() >= SEC_DOMAIN
) && (strcmp(lp_password_server(), "*") != 0)) {
185 const char *sec_setting
;
186 if(lp_security() == SEC_DOMAIN
)
187 sec_setting
= "domain";
188 else if(lp_security() == SEC_ADS
)
193 fprintf(stderr
, "WARNING: The setting 'security=%s' should NOT "
194 "be combined with the 'password server' "
196 "(by default Samba will discover the correct DC "
197 "to contact automatically).\n\n",
202 * Password chat sanity checks.
205 if(lp_security() == SEC_USER
&& lp_unix_password_sync()) {
208 * Check that we have a valid lp_passwd_program() if not using pam.
212 if (!lp_pam_password_change()) {
215 if((lp_passwd_program(talloc_tos()) == NULL
) ||
216 (strlen(lp_passwd_program(talloc_tos())) == 0))
219 "ERROR: the 'unix password sync' "
220 "parameter is set and there is no valid "
221 "'passwd program' parameter.\n\n");
224 const char *passwd_prog
;
225 char *truncated_prog
= NULL
;
228 passwd_prog
= lp_passwd_program(talloc_tos());
230 next_token_talloc(talloc_tos(),
232 &truncated_prog
, NULL
);
233 if (truncated_prog
&& access(truncated_prog
, F_OK
) == -1) {
235 "ERROR: the 'unix password sync' "
236 "parameter is set and the "
237 "'passwd program' (%s) cannot be "
238 "executed (error was %s).\n\n",
249 if(lp_passwd_chat(talloc_tos()) == NULL
) {
251 "ERROR: the 'unix password sync' parameter is "
252 "set and there is no valid 'passwd chat' "
257 if ((lp_passwd_program(talloc_tos()) != NULL
) &&
258 (strlen(lp_passwd_program(talloc_tos())) > 0))
260 /* check if there's a %u parameter present */
261 if(strstr_m(lp_passwd_program(talloc_tos()), "%u") == NULL
) {
263 "ERROR: the 'passwd program' (%s) "
264 "requires a '%%u' parameter.\n\n",
265 lp_passwd_program(talloc_tos()));
271 * Check that we have a valid script and that it hasn't
272 * been written to expect the old password.
275 if(lp_encrypt_passwords()) {
276 if(strstr_m( lp_passwd_chat(talloc_tos()), "%o")!=NULL
) {
278 "ERROR: the 'passwd chat' script [%s] "
279 "expects to use the old plaintext "
280 "password via the %%o substitution. With "
281 "encrypted passwords this is not "
283 lp_passwd_chat(talloc_tos()) );
289 if (strlen(lp_winbind_separator()) != 1) {
290 fprintf(stderr
, "ERROR: the 'winbind separator' parameter must "
291 "be a single character.\n\n");
295 if (*lp_winbind_separator() == '+') {
296 fprintf(stderr
, "'winbind separator = +' might cause problems "
297 "with group membership.\n\n");
300 if (lp_algorithmic_rid_base() < BASE_RID
) {
301 /* Try to prevent admin foot-shooting, we can't put algorithmic
302 rids below 1000, that's the 'well known RIDs' on NT */
303 fprintf(stderr
, "'algorithmic rid base' must be equal to or "
304 "above %lu\n\n", BASE_RID
);
307 if (lp_algorithmic_rid_base() & 1) {
308 fprintf(stderr
, "'algorithmic rid base' must be even.\n\n");
312 if (lp_preload_modules()) {
313 fprintf(stderr
, "WARNING: 'preload modules = ' set while loading "
314 "plugins not supported.\n\n");
318 if (!lp_passdb_backend()) {
319 fprintf(stderr
, "ERROR: passdb backend must have a value or be "
323 if (lp_os_level() > 255) {
324 fprintf(stderr
, "WARNING: Maximum value for 'os level' is "
328 if (strequal(lp_dos_charset(), "UTF8") || strequal(lp_dos_charset(), "UTF-8")) {
329 fprintf(stderr
, "ERROR: 'dos charset' must not be UTF8\n\n");
337 * per-share logic tests
339 static void do_per_share_checks(int s
)
341 const char **deny_list
= lp_hosts_deny(s
);
342 const char **allow_list
= lp_hosts_allow(s
);
346 for (i
=0; deny_list
[i
]; i
++) {
347 char *hasstar
= strchr_m(deny_list
[i
], '*');
348 char *hasquery
= strchr_m(deny_list
[i
], '?');
349 if(hasstar
|| hasquery
) {
351 "Invalid character %c in hosts deny list "
352 "(%s) for service %s.\n\n",
353 hasstar
? *hasstar
: *hasquery
,
355 lp_servicename(talloc_tos(), s
));
361 for (i
=0; allow_list
[i
]; i
++) {
362 char *hasstar
= strchr_m(allow_list
[i
], '*');
363 char *hasquery
= strchr_m(allow_list
[i
], '?');
364 if(hasstar
|| hasquery
) {
366 "Invalid character %c in hosts allow "
367 "list (%s) for service %s.\n\n",
368 hasstar
? *hasstar
: *hasquery
,
370 lp_servicename(talloc_tos(), s
));
375 if(lp_level2_oplocks(s
) && !lp_oplocks(s
)) {
376 fprintf(stderr
, "Invalid combination of parameters for service "
377 "%s. Level II oplocks can only be set if oplocks "
379 lp_servicename(talloc_tos(), s
));
382 if (!lp_store_dos_attributes(s
) && lp_map_hidden(s
)
383 && !(lp_create_mask(s
) & S_IXOTH
))
386 "Invalid combination of parameters for service %s. Map "
387 "hidden can only work if create mask includes octal "
389 lp_servicename(talloc_tos(), s
));
391 if (!lp_store_dos_attributes(s
) && lp_map_hidden(s
)
392 && (lp_force_create_mode(s
) & S_IXOTH
))
395 "Invalid combination of parameters for service "
396 "%s. Map hidden can only work if force create mode "
397 "excludes octal 01 (S_IXOTH).\n\n",
398 lp_servicename(talloc_tos(), s
));
400 if (!lp_store_dos_attributes(s
) && lp_map_system(s
)
401 && !(lp_create_mask(s
) & S_IXGRP
))
404 "Invalid combination of parameters for service "
405 "%s. Map system can only work if create mask includes "
406 "octal 010 (S_IXGRP).\n\n",
407 lp_servicename(talloc_tos(), s
));
409 if (!lp_store_dos_attributes(s
) && lp_map_system(s
)
410 && (lp_force_create_mode(s
) & S_IXGRP
))
413 "Invalid combination of parameters for service "
414 "%s. Map system can only work if force create mode "
415 "excludes octal 010 (S_IXGRP).\n\n",
416 lp_servicename(talloc_tos(), s
));
418 if (lp_printing(s
) == PRINT_CUPS
&& *(lp_print_command(talloc_tos(), s
)) != '\0') {
420 "Warning: Service %s defines a print command, but "
421 "parameter is ignored when using CUPS libraries.\n\n",
422 lp_servicename(talloc_tos(), s
));
426 int main(int argc
, const char *argv
[])
428 const char *config_file
= get_dyn_CONFIGFILE();
430 static int silent_mode
= False
;
431 static int show_all_parameters
= False
;
434 static char *parameter_name
= NULL
;
435 static const char *section_name
= NULL
;
438 static int show_defaults
;
439 static int skip_logic_checks
= 0;
441 struct poptOption long_options
[] = {
443 {"suppress-prompt", 's', POPT_ARG_VAL
, &silent_mode
, 1, "Suppress prompt for enter"},
444 {"verbose", 'v', POPT_ARG_NONE
, &show_defaults
, 1, "Show default options too"},
445 {"skip-logic-checks", 'l', POPT_ARG_NONE
, &skip_logic_checks
, 1, "Skip the global checks"},
446 {"show-all-parameters", '\0', POPT_ARG_VAL
, &show_all_parameters
, True
, "Show the parameters, type, possible values" },
447 {"parameter-name", '\0', POPT_ARG_STRING
, ¶meter_name
, 0, "Limit testparm to a named parameter" },
448 {"section-name", '\0', POPT_ARG_STRING
, §ion_name
, 0, "Limit testparm to a named section" },
450 POPT_COMMON_DEBUGLEVEL
455 TALLOC_CTX
*frame
= talloc_stackframe();
459 * Set the default debug level to 2.
460 * Allow it to be overridden by the command line,
463 lp_set_cmdline("log level", "2");
465 pc
= poptGetContext(NULL
, argc
, argv
, long_options
,
466 POPT_CONTEXT_KEEP_FIRST
);
467 poptSetOtherOptionHelp(pc
, "[OPTION...] <config-file> [host-name] [host-ip]");
469 while(poptGetNextOpt(pc
) != -1);
471 if (show_all_parameters
) {
472 show_parameter_list();
476 setup_logging(poptGetArg(pc
), DEBUG_STDERR
);
479 config_file
= poptGetArg(pc
);
481 cname
= poptGetArg(pc
);
482 caddr
= poptGetArg(pc
);
486 if ( cname
&& ! caddr
) {
487 printf ( "ERROR: You must specify both a machine name and an IP address.\n" );
492 fprintf(stderr
,"Load smb config files from %s\n",config_file
);
494 if (!lp_load_with_registry_shares(config_file
,False
,True
,False
,True
)) {
495 fprintf(stderr
,"Error loading services.\n");
500 fprintf(stderr
,"Loaded services file OK.\n");
502 if (skip_logic_checks
== 0) {
503 ret
= do_global_checks();
506 for (s
=0;s
<1000;s
++) {
508 if (strlen(lp_servicename(talloc_tos(), s
)) > 12) {
509 fprintf(stderr
, "WARNING: You have some share names that are longer than 12 characters.\n" );
510 fprintf(stderr
, "These may not be accessible to some older clients.\n" );
511 fprintf(stderr
, "(Eg. Windows9x, WindowsMe, and smbclient prior to Samba 3.0.)\n" );
516 for (s
=0;s
<1000;s
++) {
517 if (VALID_SNUM(s
) && (skip_logic_checks
== 0)) {
518 do_per_share_checks(s
);
523 if (!section_name
&& !parameter_name
) {
525 "Server role: %s\n\n",
526 server_role_str(lp_server_role()));
531 fprintf(stderr
,"Press enter to see a dump of your service definitions\n");
535 if (parameter_name
|| section_name
) {
536 bool isGlobal
= False
;
537 s
= GLOBAL_SECTION_SNUM
;
540 section_name
= GLOBAL_NAME
;
542 } else if ((isGlobal
=!strwicmp(section_name
, GLOBAL_NAME
)) == 0 &&
543 (s
=lp_servicenumber(section_name
)) == -1) {
544 fprintf(stderr
,"Unknown section %s\n",
549 if (parameter_name
) {
550 if (!dump_a_parameter( s
, parameter_name
, stdout
, isGlobal
)) {
551 fprintf(stderr
,"Parameter %s unknown for section %s\n",
552 parameter_name
, section_name
);
557 if (isGlobal
== True
)
558 lp_dump(stdout
, show_defaults
, 0);
560 lp_dump_one(stdout
, show_defaults
, s
);
565 lp_dump(stdout
, show_defaults
, lp_numservices());
569 /* this is totally ugly, a real `quick' hack */
570 for (s
=0;s
<1000;s
++) {
572 if (allow_access(lp_hosts_deny(-1), lp_hosts_allow(-1), cname
, caddr
)
573 && allow_access(lp_hosts_deny(s
), lp_hosts_allow(s
), cname
, caddr
)) {
574 fprintf(stderr
,"Allow connection from %s (%s) to %s\n",
575 cname
,caddr
,lp_servicename(talloc_tos(), s
));
577 fprintf(stderr
,"Deny connection from %s (%s) to %s\n",
578 cname
,caddr
,lp_servicename(talloc_tos(), s
));