ctdb-ipalloc: Fix a memory leak
[obnox/samba/samba-obnox.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         const char *socket_options;
70
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");
75                 ret = 1;
76         }
77
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 "
82                                 "setting.\n\n");
83                 ret = 1;
84         }
85
86         if (strequal(lp_workgroup(), lp_netbios_name())) {
87                 fprintf(stderr, "WARNING: 'workgroup' and 'netbios name' "
88                                 "must differ.\n\n");
89         }
90
91         if (strlen(lp_netbios_name()) > 15) {
92                 fprintf(stderr, "WARNING: The 'netbios name' is too long "
93                                 "(max. 15 chars).\n\n");
94         }
95
96         if (!directory_exist_stat(lp_lock_directory(), &st)) {
97                 fprintf(stderr, "ERROR: lock directory %s does not exist\n\n",
98                        lp_lock_directory());
99                 ret = 1;
100         } else if ((st.st_ex_mode & 0777) != 0755) {
101                 fprintf(stderr, "WARNING: lock directory %s should have "
102                                 "permissions 0755 for browsing to work\n\n",
103                        lp_lock_directory());
104         }
105
106         if (!directory_exist_stat(lp_state_directory(), &st)) {
107                 fprintf(stderr, "ERROR: state directory %s does not exist\n\n",
108                        lp_state_directory());
109                 ret = 1;
110         } else if ((st.st_ex_mode & 0777) != 0755) {
111                 fprintf(stderr, "WARNING: state directory %s should have "
112                                 "permissions 0755 for browsing to work\n\n",
113                        lp_state_directory());
114         }
115
116         if (!directory_exist_stat(lp_cache_directory(), &st)) {
117                 fprintf(stderr, "ERROR: cache directory %s does not exist\n\n",
118                        lp_cache_directory());
119                 ret = 1;
120         } else if ((st.st_ex_mode & 0777) != 0755) {
121                 fprintf(stderr, "WARNING: cache directory %s should have "
122                                 "permissions 0755 for browsing to work\n\n",
123                        lp_cache_directory());
124         }
125
126         if (!directory_exist_stat(lp_pid_directory(), &st)) {
127                 fprintf(stderr, "ERROR: pid directory %s does not exist\n\n",
128                        lp_pid_directory());
129                 ret = 1;
130         }
131
132         if (lp_passdb_expand_explicit()) {
133                 fprintf(stderr, "WARNING: passdb expand explicit = yes is "
134                                 "deprecated\n\n");
135         }
136
137         /*
138          * Socket options.
139          */
140         socket_options = lp_socket_options();
141         if (socket_options != NULL &&
142             (strstr(socket_options, "SO_SNDBUF") ||
143              strstr(socket_options, "SO_RCVBUF") ||
144              strstr(socket_options, "SO_SNDLOWAT") ||
145              strstr(socket_options, "SO_RCVLOWAT")))
146         {
147                 fprintf(stderr,
148                         "WARNING: socket options = %s\n"
149                         "This warning is printed because you set one of the\n"
150                         "following options: SO_SNDBUF, SO_RCVBUF, SO_SNDLOWAT,\n"
151                         "SO_RCVLOWAT\n"
152                         "Modern server operating systems are tuned for\n"
153                         "high network performance in the majority of situations;\n"
154                         "when you set 'socket options' you are overriding those\n"
155                         "settings.\n"
156                         "Linux in particular has an auto-tuning mechanism for\n"
157                         "buffer sizes (SO_SNDBUF, SO_RCVBUF) that will be\n"
158                         "disabled if you specify a socket buffer size. This can\n"
159                         "potentially cripple your TCP/IP stack.\n\n"
160                         "Getting the 'socket options' correct can make a big\n"
161                         "difference to your performance, but getting them wrong\n"
162                         "can degrade it by just as much. As with any other low\n"
163                         "level setting, if you must make changes to it, make\n "
164                         "small changes and test the effect before making any\n"
165                         "large changes.\n\n",
166                         socket_options);
167         }
168
169         /*
170          * Password server sanity checks.
171          */
172
173         if((lp_security() >= SEC_DOMAIN) && !*lp_password_server()) {
174                 const char *sec_setting;
175                 if(lp_security() == SEC_DOMAIN)
176                         sec_setting = "domain";
177                 else if(lp_security() == SEC_ADS)
178                         sec_setting = "ads";
179                 else
180                         sec_setting = "";
181
182                 fprintf(stderr, "ERROR: The setting 'security=%s' requires the "
183                                 "'password server' parameter be set to the "
184                                 "default value * or a valid password server.\n\n",
185                                 sec_setting );
186                 ret = 1;
187         }
188
189         if((lp_security() >= SEC_DOMAIN) && (strcmp(lp_password_server(), "*") != 0)) {
190                 const char *sec_setting;
191                 if(lp_security() == SEC_DOMAIN)
192                         sec_setting = "domain";
193                 else if(lp_security() == SEC_ADS)
194                         sec_setting = "ads";
195                 else
196                         sec_setting = "";
197
198                 fprintf(stderr, "WARNING: The setting 'security=%s' should NOT "
199                                 "be combined with the 'password server' "
200                                 "parameter.\n"
201                                 "(by default Samba will discover the correct DC "
202                                 "to contact automatically).\n\n",
203                                 sec_setting );
204         }
205
206         /*
207          * Password chat sanity checks.
208          */
209
210         if(lp_security() == SEC_USER && lp_unix_password_sync()) {
211
212                 /*
213                  * Check that we have a valid lp_passwd_program() if not using pam.
214                  */
215
216 #ifdef WITH_PAM
217                 if (!lp_pam_password_change()) {
218 #endif
219
220                         if((lp_passwd_program(talloc_tos()) == NULL) ||
221                            (strlen(lp_passwd_program(talloc_tos())) == 0))
222                         {
223                                 fprintf(stderr,
224                                         "ERROR: the 'unix password sync' "
225                                         "parameter is set and there is no valid "
226                                         "'passwd program' parameter.\n\n");
227                                 ret = 1;
228                         } else {
229                                 const char *passwd_prog;
230                                 char *truncated_prog = NULL;
231                                 const char *p;
232
233                                 passwd_prog = lp_passwd_program(talloc_tos());
234                                 p = passwd_prog;
235                                 next_token_talloc(talloc_tos(),
236                                                 &p,
237                                                 &truncated_prog, NULL);
238                                 if (truncated_prog && access(truncated_prog, F_OK) == -1) {
239                                         fprintf(stderr,
240                                                 "ERROR: the 'unix password sync' "
241                                                 "parameter is set and the "
242                                                 "'passwd program' (%s) cannot be "
243                                                 "executed (error was %s).\n\n",
244                                                 truncated_prog,
245                                                 strerror(errno));
246                                         ret = 1;
247                                 }
248                         }
249
250 #ifdef WITH_PAM
251                 }
252 #endif
253
254                 if(lp_passwd_chat(talloc_tos()) == NULL) {
255                         fprintf(stderr,
256                                 "ERROR: the 'unix password sync' parameter is "
257                                 "set and there is no valid 'passwd chat' "
258                                 "parameter.\n\n");
259                         ret = 1;
260                 }
261
262                 if ((lp_passwd_program(talloc_tos()) != NULL) &&
263                     (strlen(lp_passwd_program(talloc_tos())) > 0))
264                 {
265                         /* check if there's a %u parameter present */
266                         if(strstr_m(lp_passwd_program(talloc_tos()), "%u") == NULL) {
267                                 fprintf(stderr,
268                                         "ERROR: the 'passwd program' (%s) "
269                                         "requires a '%%u' parameter.\n\n",
270                                         lp_passwd_program(talloc_tos()));
271                                 ret = 1;
272                         }
273                 }
274
275                 /*
276                  * Check that we have a valid script and that it hasn't
277                  * been written to expect the old password.
278                  */
279
280                 if(lp_encrypt_passwords()) {
281                         if(strstr_m( lp_passwd_chat(talloc_tos()), "%o")!=NULL) {
282                                 fprintf(stderr,
283                                         "ERROR: the 'passwd chat' script [%s] "
284                                         "expects to use the old plaintext "
285                                         "password via the %%o substitution. With "
286                                         "encrypted passwords this is not "
287                                         "possible.\n\n",
288                                         lp_passwd_chat(talloc_tos()) );
289                                 ret = 1;
290                         }
291                 }
292         }
293
294         if (strlen(lp_winbind_separator()) != 1) {
295                 fprintf(stderr, "ERROR: the 'winbind separator' parameter must "
296                                 "be a single character.\n\n");
297                 ret = 1;
298         }
299
300         if (*lp_winbind_separator() == '+') {
301                 fprintf(stderr, "'winbind separator = +' might cause problems "
302                                 "with group membership.\n\n");
303         }
304
305         if (lp_algorithmic_rid_base() < BASE_RID) {
306                 /* Try to prevent admin foot-shooting, we can't put algorithmic
307                    rids below 1000, that's the 'well known RIDs' on NT */
308                 fprintf(stderr, "'algorithmic rid base' must be equal to or "
309                                 "above %lu\n\n", BASE_RID);
310         }
311
312         if (lp_algorithmic_rid_base() & 1) {
313                 fprintf(stderr, "'algorithmic rid base' must be even.\n\n");
314         }
315
316 #ifndef HAVE_DLOPEN
317         if (lp_preload_modules()) {
318                 fprintf(stderr, "WARNING: 'preload modules = ' set while loading "
319                                 "plugins not supported.\n\n");
320         }
321 #endif
322
323         if (!lp_passdb_backend()) {
324                 fprintf(stderr, "ERROR: passdb backend must have a value or be "
325                                 "left out\n\n");
326         }
327         
328         if (lp_os_level() > 255) {
329                 fprintf(stderr, "WARNING: Maximum value for 'os level' is "
330                                 "255!\n\n");
331         }
332
333         if (strequal(lp_dos_charset(), "UTF8") || strequal(lp_dos_charset(), "UTF-8")) {
334                 fprintf(stderr, "ERROR: 'dos charset' must not be UTF8\n\n");
335                 ret = 1;
336         }
337
338         return ret;
339 }   
340
341 /**
342  * per-share logic tests
343  */
344 static void do_per_share_checks(int s)
345 {
346         const char **deny_list = lp_hosts_deny(s);
347         const char **allow_list = lp_hosts_allow(s);
348         int i;
349
350         if(deny_list) {
351                 for (i=0; deny_list[i]; i++) {
352                         char *hasstar = strchr_m(deny_list[i], '*');
353                         char *hasquery = strchr_m(deny_list[i], '?');
354                         if(hasstar || hasquery) {
355                                 fprintf(stderr,
356                                         "Invalid character %c in hosts deny list "
357                                         "(%s) for service %s.\n\n",
358                                         hasstar ? *hasstar : *hasquery,
359                                         deny_list[i],
360                                         lp_servicename(talloc_tos(), s));
361                         }
362                 }
363         }
364
365         if(allow_list) {
366                 for (i=0; allow_list[i]; i++) {
367                         char *hasstar = strchr_m(allow_list[i], '*');
368                         char *hasquery = strchr_m(allow_list[i], '?');
369                         if(hasstar || hasquery) {
370                                 fprintf(stderr,
371                                         "Invalid character %c in hosts allow "
372                                         "list (%s) for service %s.\n\n",
373                                         hasstar ? *hasstar : *hasquery,
374                                         allow_list[i],
375                                         lp_servicename(talloc_tos(), s));
376                         }
377                 }
378         }
379
380         if(lp_level2_oplocks(s) && !lp_oplocks(s)) {
381                 fprintf(stderr, "Invalid combination of parameters for service "
382                                 "%s. Level II oplocks can only be set if oplocks "
383                                 "are also set.\n\n",
384                                 lp_servicename(talloc_tos(), s));
385         }
386
387         if (!lp_store_dos_attributes(s) && lp_map_hidden(s)
388             && !(lp_create_mask(s) & S_IXOTH))
389         {
390                 fprintf(stderr,
391                         "Invalid combination of parameters for service %s. Map "
392                         "hidden can only work if create mask includes octal "
393                         "01 (S_IXOTH).\n\n",
394                         lp_servicename(talloc_tos(), s));
395         }
396         if (!lp_store_dos_attributes(s) && lp_map_hidden(s)
397             && (lp_force_create_mode(s) & S_IXOTH))
398         {
399                 fprintf(stderr,
400                         "Invalid combination of parameters for service "
401                         "%s. Map hidden can only work if force create mode "
402                         "excludes octal 01 (S_IXOTH).\n\n",
403                         lp_servicename(talloc_tos(), s));
404         }
405         if (!lp_store_dos_attributes(s) && lp_map_system(s)
406             && !(lp_create_mask(s) & S_IXGRP))
407         {
408                 fprintf(stderr,
409                         "Invalid combination of parameters for service "
410                         "%s. Map system can only work if create mask includes "
411                         "octal 010 (S_IXGRP).\n\n",
412                         lp_servicename(talloc_tos(), s));
413         }
414         if (!lp_store_dos_attributes(s) && lp_map_system(s)
415             && (lp_force_create_mode(s) & S_IXGRP))
416         {
417                 fprintf(stderr,
418                         "Invalid combination of parameters for service "
419                         "%s. Map system can only work if force create mode "
420                         "excludes octal 010 (S_IXGRP).\n\n",
421                         lp_servicename(talloc_tos(), s));
422         }
423         if (lp_printing(s) == PRINT_CUPS && *(lp_print_command(talloc_tos(), s)) != '\0') {
424                 fprintf(stderr,
425                         "Warning: Service %s defines a print command, but "
426                         "parameter is ignored when using CUPS libraries.\n\n",
427                         lp_servicename(talloc_tos(), s));
428         }
429 }
430
431  int main(int argc, const char *argv[])
432 {
433         const char *config_file = get_dyn_CONFIGFILE();
434         int s;
435         static int silent_mode = False;
436         static int show_all_parameters = False;
437         int ret = 0;
438         poptContext pc;
439         static char *parameter_name = NULL;
440         static const char *section_name = NULL;
441         const char *cname;
442         const char *caddr;
443         static int show_defaults;
444         static int skip_logic_checks = 0;
445
446         struct poptOption long_options[] = {
447                 POPT_AUTOHELP
448                 {"suppress-prompt", 's', POPT_ARG_VAL, &silent_mode, 1, "Suppress prompt for enter"},
449                 {"verbose", 'v', POPT_ARG_NONE, &show_defaults, 1, "Show default options too"},
450                 {"skip-logic-checks", 'l', POPT_ARG_NONE, &skip_logic_checks, 1, "Skip the global checks"},
451                 {"show-all-parameters", '\0', POPT_ARG_VAL, &show_all_parameters, True, "Show the parameters, type, possible values" },
452                 {"parameter-name", '\0', POPT_ARG_STRING, &parameter_name, 0, "Limit testparm to a named parameter" },
453                 {"section-name", '\0', POPT_ARG_STRING, &section_name, 0, "Limit testparm to a named section" },
454                 POPT_COMMON_VERSION
455                 POPT_COMMON_DEBUGLEVEL
456                 POPT_COMMON_OPTION
457                 POPT_TABLEEND
458         };
459
460         TALLOC_CTX *frame = talloc_stackframe();
461
462         smb_init_locale();
463         /*
464          * Set the default debug level to 2.
465          * Allow it to be overridden by the command line,
466          * not by smb.conf.
467          */
468         lp_set_cmdline("log level", "2");
469
470         pc = poptGetContext(NULL, argc, argv, long_options, 
471                             POPT_CONTEXT_KEEP_FIRST);
472         poptSetOtherOptionHelp(pc, "[OPTION...] <config-file> [host-name] [host-ip]");
473
474         while(poptGetNextOpt(pc) != -1);
475
476         if (show_all_parameters) {
477                 show_parameter_list();
478                 exit(0);
479         }
480
481         setup_logging(poptGetArg(pc), DEBUG_STDERR);
482
483         if (poptPeekArg(pc)) 
484                 config_file = poptGetArg(pc);
485
486         cname = poptGetArg(pc);
487         caddr = poptGetArg(pc);
488
489         poptFreeContext(pc);
490
491         if ( cname && ! caddr ) {
492                 printf ( "ERROR: You must specify both a machine name and an IP address.\n" );
493                 ret = 1;
494                 goto done;
495         }
496
497         fprintf(stderr,"Load smb config files from %s\n",config_file);
498
499         if (!lp_load_with_registry_shares(config_file)) {
500                 fprintf(stderr,"Error loading services.\n");
501                 ret = 1;
502                 goto done;
503         }
504
505         fprintf(stderr,"Loaded services file OK.\n");
506
507         if (skip_logic_checks == 0) {
508                 ret = do_global_checks();
509         }
510
511         for (s=0;s<1000;s++) {
512                 if (VALID_SNUM(s))
513                         if (strlen(lp_servicename(talloc_tos(), s)) > 12) {
514                                 fprintf(stderr, "WARNING: You have some share names that are longer than 12 characters.\n" );
515                                 fprintf(stderr, "These may not be accessible to some older clients.\n" );
516                                 fprintf(stderr, "(Eg. Windows9x, WindowsMe, and smbclient prior to Samba 3.0.)\n" );
517                                 break;
518                         }
519         }
520
521         for (s=0;s<1000;s++) {
522                 if (VALID_SNUM(s) && (skip_logic_checks == 0)) {
523                         do_per_share_checks(s);
524                 }
525         }
526
527
528         if (!section_name && !parameter_name) {
529                 fprintf(stderr,
530                         "Server role: %s\n\n",
531                         server_role_str(lp_server_role()));
532         }
533
534         if (!cname) {
535                 if (!silent_mode) {
536                         fprintf(stderr,"Press enter to see a dump of your service definitions\n");
537                         fflush(stdout);
538                         getc(stdin);
539                 }
540                 if (parameter_name || section_name) {
541                         bool isGlobal = False;
542                         s = GLOBAL_SECTION_SNUM;
543
544                         if (!section_name) {
545                                 section_name = GLOBAL_NAME;
546                                 isGlobal = True;
547                         } else if ((isGlobal=!strwicmp(section_name, GLOBAL_NAME)) == 0 &&
548                                  (s=lp_servicenumber(section_name)) == -1) {
549                                         fprintf(stderr,"Unknown section %s\n",
550                                                 section_name);
551                                         ret = 1;
552                                         goto done;
553                         }
554                         if (parameter_name) {
555                                 if (!dump_a_parameter( s, parameter_name, stdout, isGlobal)) {
556                                         fprintf(stderr,"Parameter %s unknown for section %s\n",
557                                                 parameter_name, section_name);
558                                         ret = 1;
559                                         goto done;
560                                 }
561                         } else {
562                                 if (isGlobal == True)
563                                         lp_dump(stdout, show_defaults, 0);
564                                 else
565                                         lp_dump_one(stdout, show_defaults, s);
566                         }
567                         goto done;
568                 }
569
570                 lp_dump(stdout, show_defaults, lp_numservices());
571         }
572
573         if(cname && caddr){
574                 /* this is totally ugly, a real `quick' hack */
575                 for (s=0;s<1000;s++) {
576                         if (VALID_SNUM(s)) {
577                                 if (allow_access(lp_hosts_deny(-1), lp_hosts_allow(-1), cname, caddr)
578                                     && allow_access(lp_hosts_deny(s), lp_hosts_allow(s), cname, caddr)) {
579                                         fprintf(stderr,"Allow connection from %s (%s) to %s\n",
580                                                    cname,caddr,lp_servicename(talloc_tos(), s));
581                                 } else {
582                                         fprintf(stderr,"Deny connection from %s (%s) to %s\n",
583                                                    cname,caddr,lp_servicename(talloc_tos(), s));
584                                 }
585                         }
586                 }
587         }
588
589 done:
590         gfree_loadparm();
591         TALLOC_FREE(frame);
592         return ret;
593 }
594