samba-tool: Add new samba-tool gpo aclcheck and test
[Samba/gebeck_regimport.git] / source4 / scripting / python / samba / netcmd / testparm.py
blob92514694218a4b46b8dca9cc40303638cfbbfcea
1 # Unix SMB/CIFS implementation.
2 # Test validity of smb.conf
3 # Copyright (C) 2010-2011 Jelmer Vernooij <jelmer@samba.org>
5 # Based on the original in C:
6 # Copyright (C) Karl Auer 1993, 1994-1998
7 # Extensively modified by Andrew Tridgell, 1995
8 # Converted to popt by Jelmer Vernooij (jelmer@nl.linux.org), 2002
9 # Updated for Samba4 by Andrew Bartlett <abartlet@samba.org> 2006
11 # This program is free software; you can redistribute it and/or modify
12 # it under the terms of the GNU General Public License as published by
13 # the Free Software Foundation; either version 3 of the License, or
14 # (at your option) any later version.
16 # This program is distributed in the hope that it will be useful,
17 # but WITHOUT ANY WARRANTY; without even the implied warranty of
18 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 # GNU General Public License for more details.
21 # You should have received a copy of the GNU General Public License
22 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24 # Testbed for loadparm.c/params.c
26 # This module simply loads a specified configuration file and
27 # if successful, dumps it's contents to stdout. Note that the
28 # operation is performed with DEBUGLEVEL at 3.
30 # Useful for a quick 'syntax check' of a configuration file.
33 import os
34 import sys
36 import samba
37 import samba.getopt as options
38 from samba.netcmd import Command, CommandError, Option
40 class cmd_testparm(Command):
41 """Syntax check the configuration file."""
43 synopsis = "%prog [options]"
45 takes_optiongroups = {
46 "sambaopts": options.SambaOptions,
47 "versionopts": options.VersionOptions
50 takes_options = [
51 Option("--section-name", type=str,
52 help="Limit testparm to a named section"),
53 Option("--parameter-name", type=str,
54 help="Limit testparm to a named parameter"),
55 Option("--client-name", type=str,
56 help="Client DNS name for 'hosts allow' checking "
57 "(should match reverse lookup)"),
58 Option("--client-ip", type=str,
59 help="Client IP address for 'hosts allow' checking"),
60 Option("--suppress-prompt", action="store_true", default=False,
61 help="Suppress prompt for enter"),
62 Option("-v", "--verbose", action="store_true",
63 default=False, help="Show default options too"),
64 # We need support for smb.conf macros before this will work again
65 Option("--server", type=str, help="Set %L macro to servername"),
66 # These are harder to do with the new code structure
67 Option("--show-all-parameters", action="store_true", default=False,
68 help="Show the parameters, type, possible values")
71 takes_args = []
73 def run(self, sambaopts, versionopts, section_name=None,
74 parameter_name=None, client_ip=None, client_name=None,
75 verbose=False, suppress_prompt=None, show_all_parameters=False,
76 server=None):
77 if server:
78 raise NotImplementedError("--server not yet implemented")
79 if show_all_parameters:
80 raise NotImplementedError("--show-all-parameters not yet implemented")
81 if client_name is not None and client_ip is None:
82 raise CommandError("Both a DNS name and an IP address are "
83 "required for the host access check")
85 try:
86 lp = sambaopts.get_loadparm()
87 except RuntimeError, err:
88 raise CommandError(err)
90 # We need this to force the output
91 samba.set_debug_level(2)
93 logger = self.get_logger("testparm")
95 logger.info("Loaded smb config files from %s", lp.configfile)
96 logger.info("Loaded services file OK.")
98 valid = self.do_global_checks(lp, logger)
99 valid = valid and self.do_share_checks(lp, logger)
100 if client_name is not None and client_ip is not None:
101 self.check_client_access(lp, logger, client_name, client_ip)
102 else:
103 if section_name is not None or parameter_name is not None:
104 if parameter_name is None:
105 lp[section_name].dump(sys.stdout, lp.default_service,
106 verbose)
107 else:
108 self.outf.write(lp.get(parameter_name, section_name)+"\n")
109 else:
110 if not suppress_prompt:
111 self.outf.write("Press enter to see a dump of your service definitions\n")
112 sys.stdin.readline()
113 lp.dump(sys.stdout, verbose)
114 if valid:
115 return
116 else:
117 raise CommandError("Invalid smb.conf")
119 def do_global_checks(self, lp, logger):
120 valid = True
122 netbios_name = lp.get("netbios name")
123 if not samba.valid_netbios_name(netbios_name):
124 logger.error("netbios name %s is not a valid netbios name",
125 netbios_name)
126 valid = False
128 workgroup = lp.get("workgroup")
129 if not samba.valid_netbios_name(workgroup):
130 logger.error("workgroup name %s is not a valid netbios name",
131 workgroup)
132 valid = False
134 lockdir = lp.get("lockdir")
136 if not os.path.isdir(lockdir):
137 logger.error("lock directory %s does not exist", lockdir)
138 valid = False
140 piddir = lp.get("pid directory")
142 if not os.path.isdir(piddir):
143 logger.error("pid directory %s does not exist", piddir)
144 valid = False
146 winbind_separator = lp.get("winbind separator")
148 if len(winbind_separator) != 1:
149 logger.error("the 'winbind separator' parameter must be a single "
150 "character.")
151 valid = False
153 if winbind_separator == '+':
154 logger.error(
155 "'winbind separator = +' might cause problems with group "
156 "membership.")
157 valid = False
159 return valid
161 def allow_access(self, deny_list, allow_list, cname, caddr):
162 raise NotImplementedError(self.allow_access)
164 def do_share_checks(self, lp, logger):
165 valid = True
166 for s in lp.services():
167 if len(s) > 12:
168 logger.warning(
169 "You have some share names that are longer than 12 "
170 "characters. These may not be accessible to some older "
171 "clients. (Eg. Windows9x, WindowsMe, and not listed in "
172 "smbclient in Samba 3.0.)")
173 break
175 for s in lp.services():
176 deny_list = lp.get("hosts deny", s)
177 allow_list = lp.get("hosts allow", s)
178 if deny_list:
179 for entry in deny_list:
180 if "*" in entry or "?" in entry:
181 logger.error("Invalid character (* or ?) in hosts deny "
182 "list (%s) for service %s.", entry, s)
183 valid = False
185 if allow_list:
186 for entry in allow_list:
187 if "*" in entry or "?" in entry:
188 logger.error("Invalid character (* or ?) in hosts allow "
189 "list (%s) for service %s.", entry, s)
190 valid = False
191 return valid
193 def check_client_access(self, lp, logger, cname, caddr):
194 # this is totally ugly, a real `quick' hack
195 for s in lp.services():
196 if (self.allow_access(lp.get("hosts deny"), lp.get("hosts allow"), cname,
197 caddr) and
198 self.allow_access(lp.get("hosts deny", s), lp.get("hosts allow", s),
199 cname, caddr)):
200 logger.info("Allow connection from %s (%s) to %s", cname, caddr, s)
201 else:
202 logger.info("Deny connection from %s (%s) to %s", cname, caddr, s)
204 ## FIXME: We need support for smb.conf macros before this will work again
206 ## if (new_local_machine) {
207 ## set_local_machine_name(new_local_machine, True)
208 ## }