selftest: Use scripted testparm.
[idra/samba.git] / source4 / scripting / bin / testparm
1 #!/usr/bin/python
2 # vim: expandtab ft=python
3 #
4 #   Unix SMB/CIFS implementation.
5 #   Test validity of smb.conf
6 #   Copyright (C) Karl Auer 1993, 1994-1998
7 #
8 #   Extensively modified by Andrew Tridgell, 1995
9 #   Converted to popt by Jelmer Vernooij (jelmer@nl.linux.org), 2002
10 #   Updated for Samba4 by Andrew Bartlett <abartlet@samba.org> 2006
11 #   Converted to Python by Jelmer Vernooij <jelmer@samba.org> 2010
12 #   
13 #   This program is free software; you can redistribute it and/or modify
14 #   it under the terms of the GNU General Public License as published by
15 #   the Free Software Foundation; either version 3 of the License, or
16 #   (at your option) any later version.
17 #   
18 #   This program is distributed in the hope that it will be useful,
19 #   but WITHOUT ANY WARRANTY; without even the implied warranty of
20 #   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21 #   GNU General Public License for more details.
22 #   
23 #   You should have received a copy of the GNU General Public License
24 #   along with this program.  If not, see <http://www.gnu.org/licenses/>.
25 #
26 # Testbed for loadparm.c/params.c
27 #
28 # This module simply loads a specified configuration file and
29 # if successful, dumps it's contents to stdout. Note that the
30 # operation is performed with DEBUGLEVEL at 3.
31 #
32 # Useful for a quick 'syntax check' of a configuration file.
33 #
34
35 import logging
36 import optparse
37 import os
38 import sys
39
40 # Find right directory when running from source tree
41 sys.path.insert(0, "bin/python")
42
43 import samba
44 from samba import getopt as options
45
46 # Here we do a set of 'hard coded' checks for bad
47 # configuration settings.
48
49 def do_global_checks(lp, logger):
50     valid = True
51
52     lockdir = lp.get("lockdir")
53
54     if not os.path.isdir(lockdir):
55         logger.error("lock directory %s does not exist", lockdir)
56         valid = False
57
58     piddir = lp.get("pid directory")
59
60     if not os.path.isdir(piddir):
61         logger.error("pid directory %s does not exist", piddir)
62         valid = False
63
64     winbind_separator = lp.get("winbind separator")
65
66     if len(winbind_separator) != 1:
67         logger.error("the 'winbind separator' parameter must be a single character.")
68         valid = False
69
70     if winbind_separator == '+':
71         logger.error("'winbind separator = +' might cause problems with group membership.")
72         valid = False
73
74     return valid
75
76
77 def allow_access(deny_list, allow_list, cname, caddr):
78     raise NotImplementedError(allow_access)
79
80
81 def do_share_checks(lp, logger):
82     valid = True
83     for s in lp.services():
84         if len(s) > 12:
85             logger.warning("You have some share names that are longer than 12 characters. These may not be accessible to some older clients. (Eg. Windows9x, WindowsMe, and not listed in smbclient in Samba 3.0.)")
86             break
87
88     for s in lp.services():
89         deny_list = lp.get("hosts deny", s)
90         allow_list = lp.get("hosts allow", s)
91         if deny_list:
92             for entry in deny_list:
93                 if "*" in entry or "?" in entry:
94                     logger.error("Invalid character (* or ?) in hosts deny list (%s) for service %s.", entry, s)
95                     valid = False
96
97         if allow_list:
98             for entry in allow_list:
99                 if "*" in entry or "?" in entry:
100                     logger.error("Invalid character (* or ?) in hosts allow list (%s) for service %s.", entry, s)
101                     valid = False
102     return valid
103
104 def check_client_access(lp, cname, caddr):
105     # this is totally ugly, a real `quick' hack
106     for s in lp.services():
107         if (allow_access(lp.get("hosts deny"), lp.get("hosts allow"), cname, caddr) and
108             allow_access(lp.get("hosts deny", s), lp.get("hosts allow", s), cname, caddr)):
109             logger.info("Allow connection from %s (%s) to %s",
110                    cname, caddr, s)
111         else:
112             logger.info("Deny connection from %s (%s) to %s",
113                    cname, caddr, s)
114
115
116 if __name__ == '__main__':
117     parser = optparse.OptionParser("testparm [OPTION...] [host-name] [host-ip]")
118     parser.add_option("--section-name", type="string", metavar="SECTION",
119             help="Limit testparm to a named section")
120     parser.add_option("--parameter-name", type="string", metavar="PARAMETER",
121             help="Limit testparm to a named parameter")
122     parser.add_option("--client-name", type="string", metavar="HOSTNAME",
123             help="Client DNS name for 'hosts allow' checking (should match reverse lookup)")
124     parser.add_option("--client-ip", type="string", metavar="IP",
125             help="Client IP address for 'hosts allow' checking")
126     parser.add_option("--suppress-prompt", action="store_true", default=False,
127             help="Suppress prompt for enter")
128     parser.add_option("-v", "--verbose", action="store_true", 
129             default=False, help="Show default options too")
130     parser.add_option_group(options.VersionOptions(parser))
131     # We need support for smb.conf macros before this will work again 
132     parser.add_option("--server", type="string",
133             help="Set %%L macro to servername")
134     # These are harder to do with the new code structure
135     parser.add_option("--show-all-parameters", action="store_true",
136             default=False, help="Show the parameters, type, possible values")
137
138     sambaopts = options.SambaOptions(parser)
139     parser.add_option_group(sambaopts)
140
141     opts, args = parser.parse_args()
142
143
144 #    if (show_all_parameters) {
145 #        show_parameter_list()
146 #        exit(0)
147 #    }
148
149     if len(args) > 0:
150         cname = args[0]
151     else:
152         cname = None
153     if len(args) > 1:
154         caddr = args[1]
155     else:
156         caddr = None
157
158     if cname is not None and caddr is None:
159         print "ERROR: For 'hosts allow' check you must specify both a DNS name and an IP address.\n"
160         sys.exit(1)
161
162 #   FIXME: We need support for smb.conf macros before this will work again 
163 #
164 #    if (new_local_machine) {
165 #        set_local_machine_name(new_local_machine, True)
166 #    }
167
168     lp = sambaopts.get_loadparm()
169
170     # We need this to force the output
171     samba.set_debug_level(2)
172
173     logger = logging.getLogger("testparm")
174     logger.addHandler(logging.StreamHandler(sys.stdout))
175
176     logger.info("Loaded smb config files from %s", lp.configfile)
177     logger.info("Loaded services file OK.")
178
179     valid = do_global_checks(lp, logger)
180     valid = valid and do_share_checks(lp, logger)
181     if cname is not None:
182         check_client_access(lp, cname, caddr)
183     else:
184         if opts.section_name is not None or opts.parameter_name is not None:
185             if opts.parameter_name is None:
186                 lp[opts.section_name].dump(sys.stdout, lp.default_service, opts.verbose)
187             else:
188                 print lp.get(opts.parameter_name, opts.section_name)
189         else:
190             if not opts.suppress_prompt:
191                 print "Press enter to see a dump of your service definitions\n"
192                 sys.stdin.readline()
193             lp.dump(sys.stdout, opts.verbose)
194     if valid:
195         sys.exit(0)
196     else:
197         sys.exit(1)