CVE-2022-38023 testparm: warn about unsecure schannel related options
[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 "lib/cmdline/cmdline.h"
37 #include "lib/param/loadparm.h"
38 #include "lib/crypto/gnutls_helpers.h"
39 #include "cmdline_contexts.h"
40
41 #include <regex.h>
42
43 /*******************************************************************
44  Check if a directory exists.
45 ********************************************************************/
46
47 static bool directory_exist_stat(const char *dname,SMB_STRUCT_STAT *st)
48 {
49         SMB_STRUCT_STAT st2;
50         bool ret;
51
52         if (!st)
53                 st = &st2;
54
55         if (sys_stat(dname, st, false) != 0)
56                 return(False);
57
58         ret = S_ISDIR(st->st_ex_mode);
59         if(!ret)
60                 errno = ENOTDIR;
61         return ret;
62 }
63
64 struct idmap_config {
65         const char *domain_name;
66         const char *backend;
67         uint32_t high;
68         uint32_t low;
69 };
70
71 struct idmap_domains {
72         struct idmap_config *c;
73         uint32_t count;
74         uint32_t size;
75 };
76
77 static bool lp_scan_idmap_found_domain(const char *string,
78                                        regmatch_t matches[],
79                                        void *private_data)
80 {
81         bool ok = false;
82
83         if (matches[1].rm_so == -1) {
84                 fprintf(stderr, "Found match, but no name - invalid idmap config");
85                 return false;
86         }
87         if (matches[1].rm_eo <= matches[1].rm_so) {
88                 fprintf(stderr, "Invalid match - invalid idmap config");
89                 return false;
90         }
91
92         {
93                 struct idmap_domains *d = private_data;
94                 struct idmap_config *c = &d->c[d->count];
95                 regoff_t len = matches[1].rm_eo - matches[1].rm_so;
96                 char domname[len + 1];
97
98                 if (d->count >= d->size) {
99                         return false;
100                 }
101
102                 memcpy(domname, string + matches[1].rm_so, len);
103                 domname[len] = '\0';
104
105                 c->domain_name = talloc_strdup_upper(d->c, domname);
106                 if (c->domain_name == NULL) {
107                         return false;
108                 }
109                 c->backend = talloc_strdup(d->c, lp_idmap_backend(domname));
110                 if (c->backend == NULL) {
111                         return false;
112                 }
113
114                 if (lp_server_role() != ROLE_ACTIVE_DIRECTORY_DC) {
115                         ok = lp_idmap_range(domname, &c->low, &c->high);
116                         if (!ok) {
117                                 fprintf(stderr,
118                                         "ERROR: Invalid idmap range for domain "
119                                         "%s!\n\n",
120                                         c->domain_name);
121                                 return false;
122                         }
123                 }
124
125                 d->count++;
126         }
127
128         return false; /* Keep scanning */
129 }
130
131 static int idmap_config_int(const char *domname, const char *option, int def)
132 {
133         int len = snprintf(NULL, 0, "idmap config %s", domname);
134
135         if (len == -1) {
136                 return def;
137         }
138         {
139                 char config_option[len+1];
140                 snprintf(config_option, sizeof(config_option),
141                          "idmap config %s", domname);
142                 return lp_parm_int(-1, config_option, option, def);
143         }
144 }
145
146 static bool do_idmap_check(void)
147 {
148         struct idmap_domains *d;
149         uint32_t i;
150         bool ok = false;
151         int rc;
152
153         d = talloc_zero(talloc_tos(), struct idmap_domains);
154         if (d == NULL) {
155                 return false;
156         }
157         d->count = 0;
158         d->size = 32;
159
160         d->c = talloc_array(d, struct idmap_config, d->size);
161         if (d->c == NULL) {
162                 goto done;
163         }
164
165         rc = lp_wi_scan_global_parametrics("idmapconfig\\(.*\\):backend",
166                                            2,
167                                            lp_scan_idmap_found_domain,
168                                            d);
169         if (rc != 0) {
170                 fprintf(stderr,
171                         "FATAL: wi_scan_global_parametrics failed: %d",
172                         rc);
173         }
174
175         /* Check autorid backend */
176         if (strequal(lp_idmap_default_backend(), "autorid")) {
177                 struct idmap_config *c = NULL;
178                 bool found = false;
179
180                 for (i = 0; i < d->count; i++) {
181                         c = &d->c[i];
182
183                         if (strequal(c->backend, "autorid")) {
184                                 found = true;
185                                 break;
186                         }
187                 }
188
189                 if (found) {
190                         uint32_t rangesize =
191                                 idmap_config_int("*", "rangesize", 100000);
192                         uint32_t maxranges =
193                                 (c->high - c->low  + 1) / rangesize;
194
195                         if (maxranges < 2) {
196                                 fprintf(stderr,
197                                         "ERROR: The idmap autorid range "
198                                         "[%u-%u] needs to be at least twice as "
199                                         "big as the rangesize [%u]!"
200                                         "\n\n",
201                                         c->low,
202                                         c->high,
203                                         rangesize);
204                                 ok = false;
205                                 goto done;
206                         }
207                 }
208         }
209
210         /* Check for overlapping idmap ranges */
211         for (i = 0; i < d->count; i++) {
212                 struct idmap_config *c = &d->c[i];
213                 uint32_t j;
214
215                 for (j = 0; j < d->count && j != i; j++) {
216                         struct idmap_config *x = &d->c[j];
217
218                         if ((c->low >= x->low && c->low <= x->high) ||
219                             (c->high >= x->low && c->high <= x->high)) {
220                                 /* Allow overlapping ranges for idmap_ad */
221                                 ok = strequal(c->backend, x->backend);
222                                 if (ok) {
223                                         ok = strequal(c->backend, "ad");
224                                         if (ok) {
225                                                 fprintf(stderr,
226                                                         "NOTE: The idmap_ad "
227                                                         "range for the domain "
228                                                         "%s overlaps with the "
229                                                         "range of %s.\n\n",
230                                                         c->domain_name,
231                                                         x->domain_name);
232                                                 continue;
233                                         }
234                                 }
235
236                                 fprintf(stderr,
237                                         "ERROR: The idmap range for the domain "
238                                         "%s (%s) overlaps with the range of "
239                                         "%s (%s)!\n\n",
240                                         c->domain_name,
241                                         c->backend,
242                                         x->domain_name,
243                                         x->backend);
244                                 ok = false;
245                                 goto done;
246                         }
247                 }
248         }
249
250         ok = true;
251 done:
252         TALLOC_FREE(d);
253         return ok;
254 }
255
256 /***********************************************
257  Here we do a set of 'hard coded' checks for bad
258  configuration settings.
259 ************************************************/
260
261 static int do_global_checks(void)
262 {
263         int ret = 0;
264         SMB_STRUCT_STAT st;
265         const char *socket_options;
266         const struct loadparm_substitution *lp_sub =
267                 loadparm_s3_global_substitution();
268
269         fprintf(stderr, "\n");
270
271         if (lp_security() >= SEC_DOMAIN && !lp_encrypt_passwords()) {
272                 fprintf(stderr, "ERROR: in 'security=domain' mode the "
273                                 "'encrypt passwords' parameter must always be "
274                                 "set to 'true'.\n\n");
275                 ret = 1;
276         }
277
278         if (lp_security() == SEC_ADS) {
279                 const char *workgroup = lp_workgroup();
280                 const char *realm = lp_realm();
281
282                 if (workgroup == NULL || strlen(workgroup) == 0) {
283                         fprintf(stderr,
284                                 "ERROR: The 'security=ADS' mode requires "
285                                 "'workgroup' parameter to be set!\n\n ");
286                         ret = 1;
287                 }
288
289                 if (realm == NULL || strlen(realm) == 0) {
290                         fprintf(stderr,
291                                 "ERROR: The 'security=ADS' mode requires "
292                                 "'realm' parameter to be set!\n\n ");
293                         ret = 1;
294                 }
295         }
296
297
298         if (lp_we_are_a_wins_server() && lp_wins_server_list()) {
299                 fprintf(stderr, "ERROR: both 'wins support = true' and "
300                                 "'wins server = <server list>' cannot be set in "
301                                 "the smb.conf file. nmbd will abort with this "
302                                 "setting.\n\n");
303                 ret = 1;
304         }
305
306         if (strequal(lp_workgroup(), lp_netbios_name())) {
307                 fprintf(stderr, "WARNING: 'workgroup' and 'netbios name' "
308                                 "must differ.\n\n");
309         }
310
311         if (lp_client_ipc_signing() == SMB_SIGNING_IF_REQUIRED
312          || lp_client_ipc_signing() == SMB_SIGNING_OFF) {
313                 fprintf(stderr, "WARNING: The 'client ipc signing' value "
314                         "%s SMB signing is not used when contacting a "
315                         "domain controller or other server. "
316                         "This setting is not recommended; please be "
317                         "aware of the security implications when using "
318                         "this configuration setting.\n\n",
319                         lp_client_ipc_signing() == SMB_SIGNING_OFF ?
320                         "ensures" : "may mean");
321         }
322
323         if (strlen(lp_netbios_name()) > 15) {
324                 fprintf(stderr, "WARNING: The 'netbios name' is too long "
325                                 "(max. 15 chars).\n\n");
326         }
327
328         if (!directory_exist_stat(lp_lock_directory(), &st)) {
329                 fprintf(stderr, "ERROR: lock directory %s does not exist\n\n",
330                        lp_lock_directory());
331                 ret = 1;
332         } else if ((st.st_ex_mode & 0777) != 0755) {
333                 fprintf(stderr, "WARNING: lock directory %s should have "
334                                 "permissions 0755 for browsing to work\n\n",
335                        lp_lock_directory());
336         }
337
338         if (!directory_exist_stat(lp_state_directory(), &st)) {
339                 fprintf(stderr, "ERROR: state directory %s does not exist\n\n",
340                        lp_state_directory());
341                 ret = 1;
342         } else if ((st.st_ex_mode & 0777) != 0755) {
343                 fprintf(stderr, "WARNING: state directory %s should have "
344                                 "permissions 0755 for browsing to work\n\n",
345                        lp_state_directory());
346         }
347
348         if (!directory_exist_stat(lp_cache_directory(), &st)) {
349                 fprintf(stderr, "ERROR: cache directory %s does not exist\n\n",
350                        lp_cache_directory());
351                 ret = 1;
352         } else if ((st.st_ex_mode & 0777) != 0755) {
353                 fprintf(stderr, "WARNING: cache directory %s should have "
354                                 "permissions 0755 for browsing to work\n\n",
355                        lp_cache_directory());
356         }
357
358         if (!directory_exist_stat(lp_pid_directory(), &st)) {
359                 fprintf(stderr, "ERROR: pid directory %s does not exist\n\n",
360                        lp_pid_directory());
361                 ret = 1;
362         }
363
364         if (lp_passdb_expand_explicit()) {
365                 fprintf(stderr, "WARNING: passdb expand explicit = yes is "
366                                 "deprecated\n\n");
367         }
368
369         /*
370          * Socket options.
371          */
372         socket_options = lp_socket_options();
373         if (socket_options != NULL &&
374             (strstr(socket_options, "SO_SNDBUF") ||
375              strstr(socket_options, "SO_RCVBUF") ||
376              strstr(socket_options, "SO_SNDLOWAT") ||
377              strstr(socket_options, "SO_RCVLOWAT")))
378         {
379                 fprintf(stderr,
380                         "WARNING: socket options = %s\n"
381                         "This warning is printed because you set one of the\n"
382                         "following options: SO_SNDBUF, SO_RCVBUF, SO_SNDLOWAT,\n"
383                         "SO_RCVLOWAT\n"
384                         "Modern server operating systems are tuned for\n"
385                         "high network performance in the majority of situations;\n"
386                         "when you set 'socket options' you are overriding those\n"
387                         "settings.\n"
388                         "Linux in particular has an auto-tuning mechanism for\n"
389                         "buffer sizes (SO_SNDBUF, SO_RCVBUF) that will be\n"
390                         "disabled if you specify a socket buffer size. This can\n"
391                         "potentially cripple your TCP/IP stack.\n\n"
392                         "Getting the 'socket options' correct can make a big\n"
393                         "difference to your performance, but getting them wrong\n"
394                         "can degrade it by just as much. As with any other low\n"
395                         "level setting, if you must make changes to it, make\n "
396                         "small changes and test the effect before making any\n"
397                         "large changes.\n\n",
398                         socket_options);
399         }
400
401         /*
402          * Password server sanity checks.
403          */
404
405         if((lp_security() >= SEC_DOMAIN) && !*lp_password_server()) {
406                 const char *sec_setting;
407                 if(lp_security() == SEC_DOMAIN)
408                         sec_setting = "domain";
409                 else if(lp_security() == SEC_ADS)
410                         sec_setting = "ads";
411                 else
412                         sec_setting = "";
413
414                 fprintf(stderr, "ERROR: The setting 'security=%s' requires the "
415                                 "'password server' parameter be set to the "
416                                 "default value * or a valid password server.\n\n",
417                                 sec_setting );
418                 ret = 1;
419         }
420
421         if((lp_security() >= SEC_DOMAIN) && (strcmp(lp_password_server(), "*") != 0)) {
422                 const char *sec_setting;
423                 if(lp_security() == SEC_DOMAIN)
424                         sec_setting = "domain";
425                 else if(lp_security() == SEC_ADS)
426                         sec_setting = "ads";
427                 else
428                         sec_setting = "";
429
430                 fprintf(stderr, "WARNING: The setting 'security=%s' should NOT "
431                                 "be combined with the 'password server' "
432                                 "parameter.\n"
433                                 "(by default Samba will discover the correct DC "
434                                 "to contact automatically).\n\n",
435                                 sec_setting );
436         }
437
438         /*
439          * Password chat sanity checks.
440          */
441
442         if(lp_security() == SEC_USER && lp_unix_password_sync()) {
443
444                 /*
445                  * Check that we have a valid lp_passwd_program() if not using pam.
446                  */
447
448 #ifdef WITH_PAM
449                 if (!lp_pam_password_change()) {
450 #endif
451
452                         if((lp_passwd_program(talloc_tos(), lp_sub) == NULL) ||
453                            (strlen(lp_passwd_program(talloc_tos(), lp_sub)) == 0))
454                         {
455                                 fprintf(stderr,
456                                         "ERROR: the 'unix password sync' "
457                                         "parameter is set and there is no valid "
458                                         "'passwd program' parameter.\n\n");
459                                 ret = 1;
460                         } else {
461                                 const char *passwd_prog;
462                                 char *truncated_prog = NULL;
463                                 const char *p;
464
465                                 passwd_prog = lp_passwd_program(talloc_tos(), lp_sub);
466                                 p = passwd_prog;
467                                 next_token_talloc(talloc_tos(),
468                                                 &p,
469                                                 &truncated_prog, NULL);
470                                 if (truncated_prog && access(truncated_prog, F_OK) == -1) {
471                                         fprintf(stderr,
472                                                 "ERROR: the 'unix password sync' "
473                                                 "parameter is set and the "
474                                                 "'passwd program' (%s) cannot be "
475                                                 "executed (error was %s).\n\n",
476                                                 truncated_prog,
477                                                 strerror(errno));
478                                         ret = 1;
479                                 }
480                         }
481
482 #ifdef WITH_PAM
483                 }
484 #endif
485
486                 if(lp_passwd_chat(talloc_tos(), lp_sub) == NULL) {
487                         fprintf(stderr,
488                                 "ERROR: the 'unix password sync' parameter is "
489                                 "set and there is no valid 'passwd chat' "
490                                 "parameter.\n\n");
491                         ret = 1;
492                 }
493
494                 if ((lp_passwd_program(talloc_tos(), lp_sub) != NULL) &&
495                     (strlen(lp_passwd_program(talloc_tos(), lp_sub)) > 0))
496                 {
497                         /* check if there's a %u parameter present */
498                         if(strstr_m(lp_passwd_program(talloc_tos(), lp_sub), "%u") == NULL) {
499                                 fprintf(stderr,
500                                         "ERROR: the 'passwd program' (%s) "
501                                         "requires a '%%u' parameter.\n\n",
502                                         lp_passwd_program(talloc_tos(), lp_sub));
503                                 ret = 1;
504                         }
505                 }
506
507                 /*
508                  * Check that we have a valid script and that it hasn't
509                  * been written to expect the old password.
510                  */
511
512                 if(lp_encrypt_passwords()) {
513                         if(strstr_m( lp_passwd_chat(talloc_tos(), lp_sub), "%o")!=NULL) {
514                                 fprintf(stderr,
515                                         "ERROR: the 'passwd chat' script [%s] "
516                                         "expects to use the old plaintext "
517                                         "password via the %%o substitution. With "
518                                         "encrypted passwords this is not "
519                                         "possible.\n\n",
520                                         lp_passwd_chat(talloc_tos(), lp_sub) );
521                                 ret = 1;
522                         }
523                 }
524         }
525
526         if (strlen(lp_winbind_separator()) != 1) {
527                 fprintf(stderr, "ERROR: the 'winbind separator' parameter must "
528                                 "be a single character.\n\n");
529                 ret = 1;
530         }
531
532         if (*lp_winbind_separator() == '+') {
533                 fprintf(stderr, "'winbind separator = +' might cause problems "
534                                 "with group membership.\n\n");
535         }
536
537         if (lp_algorithmic_rid_base() < BASE_RID) {
538                 /* Try to prevent admin foot-shooting, we can't put algorithmic
539                    rids below 1000, that's the 'well known RIDs' on NT */
540                 fprintf(stderr, "'algorithmic rid base' must be equal to or "
541                                 "above %lu\n\n", BASE_RID);
542         }
543
544         if (lp_algorithmic_rid_base() & 1) {
545                 fprintf(stderr, "'algorithmic rid base' must be even.\n\n");
546         }
547
548         if (lp_server_role() != ROLE_STANDALONE) {
549                 const char *default_backends[] = {
550                         "tdb", "tdb2", "ldap", "autorid", "hash"
551                 };
552                 const char *idmap_backend;
553                 bool valid_backend = false;
554                 uint32_t i;
555                 bool ok;
556
557                 idmap_backend = lp_idmap_default_backend();
558
559                 for (i = 0; i < ARRAY_SIZE(default_backends); i++) {
560                         ok = strequal(idmap_backend, default_backends[i]);
561                         if (ok) {
562                                 valid_backend = true;
563                         }
564                 }
565
566                 if (!valid_backend) {
567                         ret = 1;
568                         fprintf(stderr, "ERROR: Do not use the '%s' backend "
569                                         "as the default idmap backend!\n\n",
570                                         idmap_backend);
571                 }
572
573                 ok = do_idmap_check();
574                 if (!ok) {
575                         ret = 1;
576                 }
577         }
578
579 #ifndef HAVE_DLOPEN
580         if (lp_preload_modules()) {
581                 fprintf(stderr, "WARNING: 'preload modules = ' set while loading "
582                                 "plugins not supported.\n\n");
583         }
584 #endif
585
586         if (!lp_passdb_backend()) {
587                 fprintf(stderr, "ERROR: passdb backend must have a value or be "
588                                 "left out\n\n");
589         }
590
591         if (lp_os_level() > 255) {
592                 fprintf(stderr, "WARNING: Maximum value for 'os level' is "
593                                 "255!\n\n");
594         }
595
596         if (strequal(lp_dos_charset(), "UTF8") || strequal(lp_dos_charset(), "UTF-8")) {
597                 fprintf(stderr, "ERROR: 'dos charset' must not be UTF8\n\n");
598                 ret = 1;
599         }
600
601         if (lp_server_schannel() != true) { /* can be 'auto' */
602                 fprintf(stderr,
603                         "WARNING: You have not configured "
604                         "'server schannel = yes' (the default). "
605                         "Your server is vulernable to \"ZeroLogon\" "
606                         "(CVE-2020-1472)\n"
607                         "If required use individual "
608                         "'server require schannel:COMPUTERACCOUNT$ = no' "
609                         "options\n\n");
610         }
611         if (lp_allow_nt4_crypto()) {
612                 fprintf(stderr,
613                         "WARNING: You have not configured "
614                         "'allow nt4 crypto = no' (the default). "
615                         "Your server is vulernable to "
616                         "CVE-2022-38023 and others!\n"
617                         "If required use individual "
618                         "'allow nt4 crypto:COMPUTERACCOUNT$ = yes' "
619                         "options\n\n");
620         }
621         if (!lp_reject_md5_clients()) {
622                 fprintf(stderr,
623                         "WARNING: You have not configured "
624                         "'reject md5 clients = yes' (the default). "
625                         "Your server is vulernable to "
626                         "CVE-2022-38023!\n"
627                         "If required use individual "
628                         "'server reject md5 schannel:COMPUTERACCOUNT$ = yes' "
629                         "options\n\n");
630         }
631         if (!lp_server_schannel_require_seal()) {
632                 fprintf(stderr,
633                         "WARNING: You have not configured "
634                         "'server schannel require seal = yes' (the default). "
635                         "Your server is vulernable to "
636                         "CVE-2022-38023!\n"
637                         "If required use individual "
638                         "'server schannel require seal:COMPUTERACCOUNT$ = no' "
639                         "options\n\n");
640         }
641
642         if (lp_client_schannel() != true) { /* can be 'auto' */
643                 fprintf(stderr,
644                         "WARNING: You have not configured "
645                         "'client schannel = yes' (the default). "
646                         "Your server is vulernable to \"ZeroLogon\" "
647                         "(CVE-2020-1472)\n"
648                         "If required use individual "
649                         "'client schannel:NETBIOSDOMAIN = no' "
650                         "options\n\n");
651         }
652         if (!lp_reject_md5_servers()) {
653                 fprintf(stderr,
654                         "WARNING: You have not configured "
655                         "'reject md5 servers = yes' (the default). "
656                         "Your server is vulernable to "
657                         "CVE-2022-38023\n"
658                         "If required use individual "
659                         "'reject md5 servers:NETBIOSDOMAIN = no' "
660                         "options\n\n");
661         }
662         if (!lp_require_strong_key()) {
663                 fprintf(stderr,
664                         "WARNING: You have not configured "
665                         "'require strong key = yes' (the default). "
666                         "Your server is vulernable to "
667                         "CVE-2022-38023\n"
668                         "If required use individual "
669                         "'require strong key:NETBIOSDOMAIN = no' "
670                         "options\n\n");
671         }
672         if (!lp_winbind_sealed_pipes()) {
673                 fprintf(stderr,
674                         "WARNING: You have not configured "
675                         "'winbind sealed pipes = yes' (the default). "
676                         "Your server is vulernable to "
677                         "CVE-2022-38023\n"
678                         "If required use individual "
679                         "'winbind sealed pipes:NETBIOSDOMAIN = no' "
680                         "options\n\n");
681         }
682
683         return ret;
684 }
685
686 /**
687  * per-share logic tests
688  */
689 static void do_per_share_checks(int s)
690 {
691         const struct loadparm_substitution *lp_sub =
692                 loadparm_s3_global_substitution();
693         const char **deny_list = lp_hosts_deny(s);
694         const char **allow_list = lp_hosts_allow(s);
695         const char **vfs_objects = NULL;
696         int i;
697         static bool uses_fruit;
698         static bool doesnt_use_fruit;
699         static bool fruit_mix_warned;
700
701         if(deny_list) {
702                 for (i=0; deny_list[i]; i++) {
703                         char *hasstar = strchr_m(deny_list[i], '*');
704                         char *hasquery = strchr_m(deny_list[i], '?');
705                         if(hasstar || hasquery) {
706                                 fprintf(stderr,
707                                         "Invalid character %c in hosts deny list "
708                                         "(%s) for service %s.\n\n",
709                                         hasstar ? *hasstar : *hasquery,
710                                         deny_list[i],
711                                         lp_servicename(talloc_tos(), lp_sub, s));
712                         }
713                 }
714         }
715
716         if(allow_list) {
717                 for (i=0; allow_list[i]; i++) {
718                         char *hasstar = strchr_m(allow_list[i], '*');
719                         char *hasquery = strchr_m(allow_list[i], '?');
720                         if(hasstar || hasquery) {
721                                 fprintf(stderr,
722                                         "Invalid character %c in hosts allow "
723                                         "list (%s) for service %s.\n\n",
724                                         hasstar ? *hasstar : *hasquery,
725                                         allow_list[i],
726                                         lp_servicename(talloc_tos(), lp_sub, s));
727                         }
728                 }
729         }
730
731         if(lp_level2_oplocks(s) && !lp_oplocks(s)) {
732                 fprintf(stderr, "Invalid combination of parameters for service "
733                                 "%s. Level II oplocks can only be set if oplocks "
734                                 "are also set.\n\n",
735                                 lp_servicename(talloc_tos(), lp_sub, s));
736         }
737
738         if (!lp_store_dos_attributes(s) && lp_map_hidden(s)
739             && !(lp_create_mask(s) & S_IXOTH))
740         {
741                 fprintf(stderr,
742                         "Invalid combination of parameters for service %s. Map "
743                         "hidden can only work if create mask includes octal "
744                         "01 (S_IXOTH).\n\n",
745                         lp_servicename(talloc_tos(), lp_sub, s));
746         }
747         if (!lp_store_dos_attributes(s) && lp_map_hidden(s)
748             && (lp_force_create_mode(s) & S_IXOTH))
749         {
750                 fprintf(stderr,
751                         "Invalid combination of parameters for service "
752                         "%s. Map hidden can only work if force create mode "
753                         "excludes octal 01 (S_IXOTH).\n\n",
754                         lp_servicename(talloc_tos(), lp_sub, s));
755         }
756         if (!lp_store_dos_attributes(s) && lp_map_system(s)
757             && !(lp_create_mask(s) & S_IXGRP))
758         {
759                 fprintf(stderr,
760                         "Invalid combination of parameters for service "
761                         "%s. Map system can only work if create mask includes "
762                         "octal 010 (S_IXGRP).\n\n",
763                         lp_servicename(talloc_tos(), lp_sub, s));
764         }
765         if (!lp_store_dos_attributes(s) && lp_map_system(s)
766             && (lp_force_create_mode(s) & S_IXGRP))
767         {
768                 fprintf(stderr,
769                         "Invalid combination of parameters for service "
770                         "%s. Map system can only work if force create mode "
771                         "excludes octal 010 (S_IXGRP).\n\n",
772                         lp_servicename(talloc_tos(), lp_sub, s));
773         }
774         if (lp_printing(s) == PRINT_CUPS && *(lp_print_command(s)) != '\0') {
775                 fprintf(stderr,
776                         "Warning: Service %s defines a print command, but "
777                         "parameter is ignored when using CUPS libraries.\n\n",
778                         lp_servicename(talloc_tos(), lp_sub, s));
779         }
780
781         vfs_objects = lp_vfs_objects(s);
782         if (vfs_objects && str_list_check(vfs_objects, "fruit")) {
783                 uses_fruit = true;
784         } else {
785                 doesnt_use_fruit = true;
786         }
787
788         if (uses_fruit && doesnt_use_fruit && !fruit_mix_warned) {
789                 fruit_mix_warned = true;
790                 fprintf(stderr,
791                         "WARNING: some services use vfs_fruit, others don't. Mounting them "
792                         "in conjunction on OS X clients results in undefined behaviour.\n\n");
793         }
794 }
795
796  int main(int argc, const char *argv[])
797 {
798         const char *config_file = NULL;
799         const struct loadparm_substitution *lp_sub =
800                 loadparm_s3_global_substitution();
801         int opt;
802         int s;
803         static int silent_mode = False;
804         static int show_all_parameters = False;
805         int ret = 0;
806         poptContext pc;
807         static char *parameter_name = NULL;
808         static const char *section_name = NULL;
809         const char *cname;
810         const char *caddr;
811         static int show_defaults;
812         static int skip_logic_checks = 0;
813         bool ok;
814
815         struct poptOption long_options[] = {
816                 POPT_AUTOHELP
817                 {
818                         .longName   = "suppress-prompt",
819                         .shortName  = 's',
820                         .argInfo    = POPT_ARG_VAL,
821                         .arg        = &silent_mode,
822                         .val        = 1,
823                         .descrip    = "Suppress prompt for enter",
824                 },
825                 {
826                         .longName   = "verbose",
827                         .shortName  = 'v',
828                         .argInfo    = POPT_ARG_NONE,
829                         .arg        = &show_defaults,
830                         .val        = 1,
831                         .descrip    = "Show default options too",
832                 },
833                 {
834                         .longName   = "skip-logic-checks",
835                         .shortName  = 'l',
836                         .argInfo    = POPT_ARG_NONE,
837                         .arg        = &skip_logic_checks,
838                         .val        = 1,
839                         .descrip    = "Skip the global checks",
840                 },
841                 {
842                         .longName   = "show-all-parameters",
843                         .shortName  = '\0',
844                         .argInfo    = POPT_ARG_VAL,
845                         .arg        = &show_all_parameters,
846                         .val        = True,
847                         .descrip    = "Show the parameters, type, possible "
848                                       "values",
849                 },
850                 {
851                         .longName   = "parameter-name",
852                         .shortName  = '\0',
853                         .argInfo    = POPT_ARG_STRING,
854                         .arg        = &parameter_name,
855                         .val        = 0,
856                         .descrip    = "Limit testparm to a named parameter",
857                 },
858                 {
859                         .longName   = "section-name",
860                         .shortName  = '\0',
861                         .argInfo    = POPT_ARG_STRING,
862                         .arg        = &section_name,
863                         .val        = 0,
864                         .descrip    = "Limit testparm to a named section",
865                 },
866                 POPT_COMMON_DEBUG_ONLY
867                 POPT_COMMON_OPTION_ONLY
868                 POPT_COMMON_VERSION
869                 POPT_TABLEEND
870         };
871
872         TALLOC_CTX *frame = talloc_stackframe();
873
874         smb_init_locale();
875
876         ok = samba_cmdline_init(frame,
877                                 SAMBA_CMDLINE_CONFIG_NONE,
878                                 true /* require_smbconf */);
879         if (!ok) {
880                 DBG_ERR("Failed to init cmdline parser!\n");
881                 ret = 1;
882                 goto done;
883         }
884
885         /*
886          * Set the default debug level to 1.
887          * Allow it to be overridden by the command line,
888          * not by smb.conf.
889          */
890         lp_set_cmdline("log level", "1");
891
892         pc = samba_popt_get_context(getprogname(),
893                                     argc,
894                                     argv,
895                                     long_options,
896                                     0);
897         if (pc == NULL) {
898                 DBG_ERR("Failed to setup popt context!\n");
899                 ret = 1;
900                 goto done;
901         }
902
903         poptSetOtherOptionHelp(pc, "[OPTION...] <config-file> [host-name] [host-ip]");
904
905         while ((opt = poptGetNextOpt(pc)) != -1) {
906                 switch (opt) {
907                 case POPT_ERROR_BADOPT:
908                         fprintf(stderr, "\nInvalid option %s: %s\n\n",
909                                 poptBadOption(pc, 0), poptStrerror(opt));
910                         poptPrintUsage(pc, stderr, 0);
911                         exit(1);
912                 }
913         }
914
915         if (show_all_parameters) {
916                 show_parameter_list();
917                 exit(0);
918         }
919
920         if (poptPeekArg(pc)) {
921                 config_file = talloc_strdup(frame, poptGetArg(pc));
922                 if (config_file == NULL) {
923                         DBG_ERR("out of memory\n");
924                         TALLOC_FREE(frame);
925                         exit(1);
926                 }
927         } else {
928                 config_file = get_dyn_CONFIGFILE();
929         }
930
931         cname = talloc_strdup(frame, poptGetArg(pc));
932         caddr = talloc_strdup(frame, poptGetArg(pc));
933
934         poptFreeContext(pc);
935
936         if ( cname && ! caddr ) {
937                 printf ( "ERROR: You must specify both a machine name and an IP address.\n" );
938                 ret = 1;
939                 goto done;
940         }
941
942         fprintf(stderr,"Load smb config files from %s\n",config_file);
943
944         if (!lp_load_with_registry_shares(config_file)) {
945                 fprintf(stderr,"Error loading services.\n");
946                 ret = 1;
947                 goto done;
948         }
949
950         fprintf(stderr,"Loaded services file OK.\n");
951
952         fprintf(stderr,
953                 "Weak crypto is %sallowed by GnuTLS "
954                 "(e.g. NTLM as a compatibility fallback)\n",
955                 samba_gnutls_weak_crypto_allowed() ? "" : "dis");
956
957         if (skip_logic_checks == 0) {
958                 ret = do_global_checks();
959         }
960
961         for (s=0;s<1000;s++) {
962                 if (VALID_SNUM(s) && (skip_logic_checks == 0)) {
963                         do_per_share_checks(s);
964                 }
965         }
966
967
968         if (!section_name && !parameter_name) {
969                 fprintf(stderr,
970                         "Server role: %s\n\n",
971                         server_role_str(lp_server_role()));
972         }
973
974         if (!cname) {
975                 if (!silent_mode) {
976                         fprintf(stderr,"Press enter to see a dump of your service definitions\n");
977                         fflush(stdout);
978                         getc(stdin);
979                 }
980                 if (parameter_name || section_name) {
981                         bool isGlobal = False;
982                         s = GLOBAL_SECTION_SNUM;
983
984                         if (!section_name) {
985                                 section_name = GLOBAL_NAME;
986                                 isGlobal = True;
987                         } else if ((isGlobal=!strwicmp(section_name, GLOBAL_NAME)) == 0 &&
988                                  (s=lp_servicenumber(section_name)) == -1) {
989                                         fprintf(stderr,"Unknown section %s\n",
990                                                 section_name);
991                                         ret = 1;
992                                         goto done;
993                         }
994                         if (parameter_name) {
995                                 if (!dump_a_parameter( s, parameter_name, stdout, isGlobal)) {
996                                         fprintf(stderr,"Parameter %s unknown for section %s\n",
997                                                 parameter_name, section_name);
998                                         ret = 1;
999                                         goto done;
1000                                 }
1001                         } else {
1002                                 if (isGlobal == True)
1003                                         lp_dump(stdout, show_defaults, 0);
1004                                 else
1005                                         lp_dump_one(stdout, show_defaults, s);
1006                         }
1007                         goto done;
1008                 }
1009
1010                 lp_dump(stdout, show_defaults, lp_numservices());
1011         }
1012
1013         if(cname && caddr){
1014                 /* this is totally ugly, a real `quick' hack */
1015                 for (s=0;s<1000;s++) {
1016                         if (VALID_SNUM(s)) {
1017                                 if (allow_access(lp_hosts_deny(-1), lp_hosts_allow(-1), cname, caddr)
1018                                     && allow_access(lp_hosts_deny(s), lp_hosts_allow(s), cname, caddr)) {
1019                                         fprintf(stderr,"Allow connection from %s (%s) to %s\n",
1020                                                    cname,caddr,lp_servicename(talloc_tos(), lp_sub, s));
1021                                 } else {
1022                                         fprintf(stderr,"Deny connection from %s (%s) to %s\n",
1023                                                    cname,caddr,lp_servicename(talloc_tos(), lp_sub, s));
1024                                 }
1025                         }
1026                 }
1027         }
1028
1029 done:
1030         gfree_loadparm();
1031         TALLOC_FREE(frame);
1032         return ret;
1033 }