testparm: Reformat text and add a newline.
[amitay/samba.git] / source3 / utils / testparm.c
1 /* 
2    Unix SMB/CIFS implementation.
3    Test validity of smb.conf
4    Copyright (C) Karl Auer 1993, 1994-1998
5
6    Extensively modified by Andrew Tridgell, 1995
7    Converted to popt by Jelmer Vernooij (jelmer@nl.linux.org), 2002
8    
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.
13    
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.
18    
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/>.
21 */
22
23 /*
24  * Testbed for loadparm.c/params.c
25  *
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.
29  *
30  * Useful for a quick 'syntax check' of a configuration file.
31  *
32  */
33
34 #include "includes.h"
35 #include "system/filesys.h"
36 #include "popt_common.h"
37 #include "lib/param/loadparm.h"
38
39 /*******************************************************************
40  Check if a directory exists.
41 ********************************************************************/
42
43 static bool directory_exist_stat(const char *dname,SMB_STRUCT_STAT *st)
44 {
45         SMB_STRUCT_STAT st2;
46         bool ret;
47
48         if (!st)
49                 st = &st2;
50
51         if (sys_stat(dname, st, false) != 0)
52                 return(False);
53
54         ret = S_ISDIR(st->st_ex_mode);
55         if(!ret)
56                 errno = ENOTDIR;
57         return ret;
58 }
59
60 /***********************************************
61  Here we do a set of 'hard coded' checks for bad
62  configuration settings.
63 ************************************************/
64
65 static int do_global_checks(void)
66 {
67         int ret = 0;
68         SMB_STRUCT_STAT st;
69
70         if (lp_security() >= SEC_DOMAIN && !lp_encrypted_passwords()) {
71                 fprintf(stderr, "ERROR: in 'security=domain' mode the "
72                                 "'encrypt passwords' parameter must always be "
73                                 "set to 'true'.\n\n");
74                 ret = 1;
75         }
76
77         if (lp_we_are_a_wins_server() && lp_wins_server_list()) {
78                 fprintf(stderr, "ERROR: both 'wins support = true' and "
79                                 "'wins server = <server list>' cannot be set in "
80                                 "the smb.conf file. nmbd will abort with this "
81                                 "setting.\n\n");
82                 ret = 1;
83         }
84
85         if (strequal(lp_workgroup(), lp_netbios_name())) {
86                 fprintf(stderr, "WARNING: 'workgroup' and 'netbios name' "
87                                 "must differ.\n\n");
88                 ret = 1;
89         }
90
91         if (!directory_exist_stat(lp_lockdir(), &st)) {
92                 fprintf(stderr, "ERROR: lock directory %s does not exist\n\n",
93                        lp_lockdir());
94                 ret = 1;
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",
98                        lp_lockdir());
99                 ret = 1;
100         }
101
102         if (!directory_exist_stat(lp_statedir(), &st)) {
103                 fprintf(stderr, "ERROR: state directory %s does not exist\n\n",
104                        lp_statedir());
105                 ret = 1;
106         } else if ((st.st_ex_mode & 0777) != 0755) {
107                 fprintf(stderr, "WARNING: state directory %s should have "
108                                 "permissions 0755 for browsing to work\n\n",
109                        lp_statedir());
110                 ret = 1;
111         }
112
113         if (!directory_exist_stat(lp_cachedir(), &st)) {
114                 fprintf(stderr, "ERROR: cache directory %s does not exist\n\n",
115                        lp_cachedir());
116                 ret = 1;
117         } else if ((st.st_ex_mode & 0777) != 0755) {
118                 fprintf(stderr, "WARNING: cache directory %s should have "
119                                 "permissions 0755 for browsing to work\n\n",
120                        lp_cachedir());
121                 ret = 1;
122         }
123
124         if (!directory_exist_stat(lp_piddir(), &st)) {
125                 fprintf(stderr, "ERROR: pid directory %s does not exist\n\n",
126                        lp_piddir());
127                 ret = 1;
128         }
129
130         if (lp_passdb_expand_explicit()) {
131                 fprintf(stderr, "WARNING: passdb expand explicit = yes is "
132                                 "deprecated\n\n");
133         }
134
135         /*
136          * Password server sanity checks.
137          */
138
139         if((lp_security() >= SEC_DOMAIN) && !*lp_passwordserver()) {
140                 const char *sec_setting;
141                 if(lp_security() == SEC_DOMAIN)
142                         sec_setting = "domain";
143                 else if(lp_security() == SEC_ADS)
144                         sec_setting = "ads";
145                 else
146                         sec_setting = "";
147
148                 fprintf(stderr, "ERROR: The setting 'security=%s' requires the "
149                                 "'password server' parameter be set to the "
150                                 "default value * or a valid password server.\n\n",
151                                 sec_setting );
152                 ret = 1;
153         }
154
155         if((lp_security() >= SEC_DOMAIN) && (strcmp(lp_passwordserver(), "*") != 0)) {
156                 const char *sec_setting;
157                 if(lp_security() == SEC_DOMAIN)
158                         sec_setting = "domain";
159                 else if(lp_security() == SEC_ADS)
160                         sec_setting = "ads";
161                 else
162                         sec_setting = "";
163
164                 fprintf(stderr, "WARNING: The setting 'security=%s' should NOT "
165                                 "be combined with the 'password server' "
166                                 "parameter.\n"
167                                 "(by default Samba will discover the correct DC "
168                                 "to contact automatically).\n\n",
169                                 sec_setting );
170         }
171
172         /*
173          * Password chat sanity checks.
174          */
175
176         if(lp_security() == SEC_USER && lp_unix_password_sync()) {
177
178                 /*
179                  * Check that we have a valid lp_passwd_program() if not using pam.
180                  */
181
182 #ifdef WITH_PAM
183                 if (!lp_pam_password_change()) {
184 #endif
185
186                         if((lp_passwd_program(talloc_tos()) == NULL) ||
187                            (strlen(lp_passwd_program(talloc_tos())) == 0))
188                         {
189                                 fprintf(stderr,
190                                         "ERROR: the 'unix password sync' "
191                                         "parameter is set and there is no valid "
192                                         "'passwd program' parameter.\n\n");
193                                 ret = 1;
194                         } else {
195                                 const char *passwd_prog;
196                                 char *truncated_prog = NULL;
197                                 const char *p;
198
199                                 passwd_prog = lp_passwd_program(talloc_tos());
200                                 p = passwd_prog;
201                                 next_token_talloc(talloc_tos(),
202                                                 &p,
203                                                 &truncated_prog, NULL);
204                                 if (truncated_prog && access(truncated_prog, F_OK) == -1) {
205                                         fprintf(stderr,
206                                                 "ERROR: the 'unix password sync' "
207                                                 "parameter is set and the "
208                                                 "'passwd program' (%s) cannot be "
209                                                 "executed (error was %s).\n\n",
210                                                 truncated_prog,
211                                                 strerror(errno));
212                                         ret = 1;
213                                 }
214                         }
215
216 #ifdef WITH_PAM
217                 }
218 #endif
219
220                 if(lp_passwd_chat(talloc_tos()) == NULL) {
221                         fprintf(stderr,
222                                 "ERROR: the 'unix password sync' parameter is "
223                                 "set and there is no valid 'passwd chat' "
224                                 "parameter.\n\n");
225                         ret = 1;
226                 }
227
228                 if ((lp_passwd_program(talloc_tos()) != NULL) &&
229                     (strlen(lp_passwd_program(talloc_tos())) > 0))
230                 {
231                         /* check if there's a %u parameter present */
232                         if(strstr_m(lp_passwd_program(talloc_tos()), "%u") == NULL) {
233                                 fprintf(stderr,
234                                         "ERROR: the 'passwd program' (%s) "
235                                         "requires a '%%u' parameter.\n\n",
236                                         lp_passwd_program(talloc_tos()));
237                                 ret = 1;
238                         }
239                 }
240
241                 /*
242                  * Check that we have a valid script and that it hasn't
243                  * been written to expect the old password.
244                  */
245
246                 if(lp_encrypted_passwords()) {
247                         if(strstr_m( lp_passwd_chat(talloc_tos()), "%o")!=NULL) {
248                                 fprintf(stderr,
249                                         "ERROR: the 'passwd chat' script [%s] "
250                                         "expects to use the old plaintext "
251                                         "password via the %%o substitution. With "
252                                         "encrypted passwords this is not "
253                                         "possible.\n\n",
254                                         lp_passwd_chat(talloc_tos()) );
255                                 ret = 1;
256                         }
257                 }
258         }
259
260         if (strlen(lp_winbind_separator()) != 1) {
261                 fprintf(stderr, "ERROR: the 'winbind separator' parameter must "
262                                 "be a single character.\n\n");
263                 ret = 1;
264         }
265
266         if (*lp_winbind_separator() == '+') {
267                 fprintf(stderr, "'winbind separator = +' might cause problems "
268                                 "with group membership.\n\n");
269         }
270
271         if (lp_algorithmic_rid_base() < BASE_RID) {
272                 /* Try to prevent admin foot-shooting, we can't put algorithmic
273                    rids below 1000, that's the 'well known RIDs' on NT */
274                 fprintf(stderr, "'algorithmic rid base' must be equal to or "
275                                 "above %lu\n\n", BASE_RID);
276         }
277
278         if (lp_algorithmic_rid_base() & 1) {
279                 fprintf(stderr, "'algorithmic rid base' must be even.\n\n");
280         }
281
282 #ifndef HAVE_DLOPEN
283         if (lp_preload_modules()) {
284                 fprintf(stderr, "WARNING: 'preload modules = ' set while loading "
285                                 "plugins not supported.\n\n");
286         }
287 #endif
288
289         if (!lp_passdb_backend()) {
290                 fprintf(stderr, "ERROR: passdb backend must have a value or be "
291                                 "left out\n\n");
292         }
293         
294         if (lp_os_level() > 255) {
295                 fprintf(stderr, "WARNING: Maximum value for 'os level' is "
296                                 "255!\n\n");
297         }
298
299         if (strequal(lp_dos_charset(), "UTF8") || strequal(lp_dos_charset(), "UTF-8")) {
300                 fprintf(stderr, "ERROR: 'dos charset' must not be UTF8\n\n");
301                 ret = 1;
302         }
303
304         return ret;
305 }   
306
307 /**
308  * per-share logic tests
309  */
310 static void do_per_share_checks(int s)
311 {
312         const char **deny_list = lp_hostsdeny(s);
313         const char **allow_list = lp_hostsallow(s);
314         int i;
315
316         if(deny_list) {
317                 for (i=0; deny_list[i]; i++) {
318                         char *hasstar = strchr_m(deny_list[i], '*');
319                         char *hasquery = strchr_m(deny_list[i], '?');
320                         if(hasstar || hasquery) {
321                                 fprintf(stderr,
322                                         "Invalid character %c in hosts deny list "
323                                         "(%s) for service %s.\n\n",
324                                         hasstar ? *hasstar : *hasquery,
325                                         deny_list[i],
326                                         lp_servicename(talloc_tos(), s));
327                         }
328                 }
329         }
330
331         if(allow_list) {
332                 for (i=0; allow_list[i]; i++) {
333                         char *hasstar = strchr_m(allow_list[i], '*');
334                         char *hasquery = strchr_m(allow_list[i], '?');
335                         if(hasstar || hasquery) {
336                                 fprintf(stderr,
337                                         "Invalid character %c in hosts allow "
338                                         "list (%s) for service %s.\n\n",
339                                         hasstar ? *hasstar : *hasquery,
340                                         allow_list[i],
341                                         lp_servicename(talloc_tos(), s));
342                         }
343                 }
344         }
345
346         if(lp_level2_oplocks(s) && !lp_oplocks(s)) {
347                 fprintf(stderr, "Invalid combination of parameters for service "
348                                 "%s. Level II oplocks can only be set if oplocks "
349                                 "are also set.\n\n",
350                                 lp_servicename(talloc_tos(), s));
351         }
352
353         if (!lp_store_dos_attributes(s) && lp_map_hidden(s)
354             && !(lp_create_mask(s) & S_IXOTH))
355         {
356                 fprintf(stderr,
357                         "Invalid combination of parameters for service %s. Map "
358                         "hidden can only work if create mask includes octal "
359                         "01 (S_IXOTH).\n\n",
360                         lp_servicename(talloc_tos(), s));
361         }
362         if (!lp_store_dos_attributes(s) && lp_map_hidden(s)
363             && (lp_force_create_mode(s) & S_IXOTH))
364         {
365                 fprintf(stderr,
366                         "Invalid combination of parameters for service "
367                         "%s. Map hidden can only work if force create mode "
368                         "excludes octal 01 (S_IXOTH).\n\n",
369                         lp_servicename(talloc_tos(), s));
370         }
371         if (!lp_store_dos_attributes(s) && lp_map_system(s)
372             && !(lp_create_mask(s) & S_IXGRP))
373         {
374                 fprintf(stderr,
375                         "Invalid combination of parameters for service "
376                         "%s. Map system can only work if create mask includes "
377                         "octal 010 (S_IXGRP).\n\n",
378                         lp_servicename(talloc_tos(), s));
379         }
380         if (!lp_store_dos_attributes(s) && lp_map_system(s)
381             && (lp_force_create_mode(s) & S_IXGRP))
382         {
383                 fprintf(stderr,
384                         "Invalid combination of parameters for service "
385                         "%s. Map system can only work if force create mode "
386                         "excludes octal 010 (S_IXGRP).\n\n",
387                         lp_servicename(talloc_tos(), s));
388         }
389         if (lp_printing(s) == PRINT_CUPS && *(lp_printcommand(talloc_tos(), s)) != '\0') {
390                 fprintf(stderr,
391                         "Warning: Service %s defines a print command, but "
392                         "parameter is ignored when using CUPS libraries.\n\n",
393                         lp_servicename(talloc_tos(), s));
394         }
395 }
396
397  int main(int argc, const char *argv[])
398 {
399         const char *config_file = get_dyn_CONFIGFILE();
400         int s;
401         static int silent_mode = False;
402         static int show_all_parameters = False;
403         int ret = 0;
404         poptContext pc;
405         static char *parameter_name = NULL;
406         static const char *section_name = NULL;
407         const char *cname;
408         const char *caddr;
409         static int show_defaults;
410         static int skip_logic_checks = 0;
411
412         struct poptOption long_options[] = {
413                 POPT_AUTOHELP
414                 {"suppress-prompt", 's', POPT_ARG_VAL, &silent_mode, 1, "Suppress prompt for enter"},
415                 {"verbose", 'v', POPT_ARG_NONE, &show_defaults, 1, "Show default options too"},
416                 {"skip-logic-checks", 'l', POPT_ARG_NONE, &skip_logic_checks, 1, "Skip the global checks"},
417                 {"show-all-parameters", '\0', POPT_ARG_VAL, &show_all_parameters, True, "Show the parameters, type, possible values" },
418                 {"parameter-name", '\0', POPT_ARG_STRING, &parameter_name, 0, "Limit testparm to a named parameter" },
419                 {"section-name", '\0', POPT_ARG_STRING, &section_name, 0, "Limit testparm to a named section" },
420                 POPT_COMMON_VERSION
421                 POPT_COMMON_DEBUGLEVEL
422                 POPT_COMMON_OPTION
423                 POPT_TABLEEND
424         };
425
426         TALLOC_CTX *frame = talloc_stackframe();
427
428         load_case_tables();
429         /*
430          * Set the default debug level to 2.
431          * Allow it to be overridden by the command line,
432          * not by smb.conf.
433          */
434         lp_set_cmdline("log level", "2");
435
436         pc = poptGetContext(NULL, argc, argv, long_options, 
437                             POPT_CONTEXT_KEEP_FIRST);
438         poptSetOtherOptionHelp(pc, "[OPTION...] <config-file> [host-name] [host-ip]");
439
440         while(poptGetNextOpt(pc) != -1);
441
442         if (show_all_parameters) {
443                 show_parameter_list();
444                 exit(0);
445         }
446
447         setup_logging(poptGetArg(pc), DEBUG_STDERR);
448
449         if (poptPeekArg(pc)) 
450                 config_file = poptGetArg(pc);
451
452         cname = poptGetArg(pc);
453         caddr = poptGetArg(pc);
454
455         poptFreeContext(pc);
456
457         if ( cname && ! caddr ) {
458                 printf ( "ERROR: You must specify both a machine name and an IP address.\n" );
459                 ret = 1;
460                 goto done;
461         }
462
463         fprintf(stderr,"Load smb config files from %s\n",config_file);
464
465         if (!lp_load_with_registry_shares(config_file,False,True,False,True)) {
466                 fprintf(stderr,"Error loading services.\n");
467                 ret = 1;
468                 goto done;
469         }
470
471         fprintf(stderr,"Loaded services file OK.\n");
472
473         if (skip_logic_checks == 0) {
474                 ret = do_global_checks();
475         }
476
477         for (s=0;s<1000;s++) {
478                 if (VALID_SNUM(s))
479                         if (strlen(lp_servicename(talloc_tos(), s)) > 12) {
480                                 fprintf(stderr, "WARNING: You have some share names that are longer than 12 characters.\n" );
481                                 fprintf(stderr, "These may not be accessible to some older clients.\n" );
482                                 fprintf(stderr, "(Eg. Windows9x, WindowsMe, and smbclient prior to Samba 3.0.)\n" );
483                                 break;
484                         }
485         }
486
487         for (s=0;s<1000;s++) {
488                 if (VALID_SNUM(s) && (skip_logic_checks == 0)) {
489                         do_per_share_checks(s);
490                 }
491         }
492
493
494         if (!section_name && !parameter_name) {
495                 fprintf(stderr,
496                         "Server role: %s\n\n",
497                         server_role_str(lp_server_role()));
498         }
499
500         if (!cname) {
501                 if (!silent_mode) {
502                         fprintf(stderr,"Press enter to see a dump of your service definitions\n");
503                         fflush(stdout);
504                         getc(stdin);
505                 }
506                 if (parameter_name || section_name) {
507                         bool isGlobal = False;
508                         s = GLOBAL_SECTION_SNUM;
509
510                         if (!section_name) {
511                                 section_name = GLOBAL_NAME;
512                                 isGlobal = True;
513                         } else if ((isGlobal=!strwicmp(section_name, GLOBAL_NAME)) == 0 &&
514                                  (s=lp_servicenumber(section_name)) == -1) {
515                                         fprintf(stderr,"Unknown section %s\n",
516                                                 section_name);
517                                         ret = 1;
518                                         goto done;
519                         }
520                         if (parameter_name) {
521                                 if (!dump_a_parameter( s, parameter_name, stdout, isGlobal)) {
522                                         fprintf(stderr,"Parameter %s unknown for section %s\n",
523                                                 parameter_name, section_name);
524                                         ret = 1;
525                                         goto done;
526                                 }
527                         } else {
528                                 if (isGlobal == True)
529                                         lp_dump(stdout, show_defaults, 0);
530                                 else
531                                         lp_dump_one(stdout, show_defaults, s);
532                         }
533                         goto done;
534                 }
535
536                 lp_dump(stdout, show_defaults, lp_numservices());
537         }
538
539         if(cname && caddr){
540                 /* this is totally ugly, a real `quick' hack */
541                 for (s=0;s<1000;s++) {
542                         if (VALID_SNUM(s)) {
543                                 if (allow_access(lp_hostsdeny(-1), lp_hostsallow(-1), cname, caddr)
544                                     && allow_access(lp_hostsdeny(s), lp_hostsallow(s), cname, caddr)) {
545                                         fprintf(stderr,"Allow connection from %s (%s) to %s\n",
546                                                    cname,caddr,lp_servicename(talloc_tos(), s));
547                                 } else {
548                                         fprintf(stderr,"Deny connection from %s (%s) to %s\n",
549                                                    cname,caddr,lp_servicename(talloc_tos(), s));
550                                 }
551                         }
552                 }
553         }
554
555 done:
556         gfree_loadparm();
557         TALLOC_FREE(frame);
558         return ret;
559 }
560