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.
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
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")
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,
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")
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
)
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
,
108 lp
.dump_a_parameter(sys
.stdout
, parameter_name
, section_name
)
110 if not suppress_prompt
:
111 self
.outf
.write("Press enter to see a dump of your service definitions\n")
113 lp
.dump(sys
.stdout
, verbose
)
117 raise CommandError("Invalid smb.conf")
119 def do_global_checks(self
, lp
, logger
):
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",
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",
134 lockdir
= lp
.get("lockdir")
136 if not os
.path
.isdir(lockdir
):
137 logger
.error("lock directory %s does not exist", lockdir
)
140 piddir
= lp
.get("pid directory")
142 if not os
.path
.isdir(piddir
):
143 logger
.error("pid directory %s does not exist", piddir
)
146 winbind_separator
= lp
.get("winbind separator")
148 if len(winbind_separator
) != 1:
149 logger
.error("the 'winbind separator' parameter must be a single "
153 if winbind_separator
== '+':
155 "'winbind separator = +' might cause problems with group "
159 role
= lp
.get("server role")
160 charset
= lp
.get("unix charset").upper()
162 if role
in ["active directory domain controller", "domain controller", "dc"] and charset
not in ["UTF-8", "UTF8"]:
164 "When acting as Active Directory domain controller, "
165 "unix charset is expected to be UTF-8.")
169 def allow_access(self
, deny_list
, allow_list
, cname
, caddr
):
170 raise NotImplementedError(self
.allow_access
)
172 def do_share_checks(self
, lp
, logger
):
174 for s
in lp
.services():
177 "You have some share names that are longer than 12 "
178 "characters. These may not be accessible to some older "
179 "clients. (Eg. Windows9x, WindowsMe, and not listed in "
180 "smbclient in Samba 3.0.)")
183 for s
in lp
.services():
184 deny_list
= lp
.get("hosts deny", s
)
185 allow_list
= lp
.get("hosts allow", s
)
187 for entry
in deny_list
:
188 if "*" in entry
or "?" in entry
:
189 logger
.error("Invalid character (* or ?) in hosts deny "
190 "list (%s) for service %s.", entry
, s
)
194 for entry
in allow_list
:
195 if "*" in entry
or "?" in entry
:
196 logger
.error("Invalid character (* or ?) in hosts allow "
197 "list (%s) for service %s.", entry
, s
)
201 def check_client_access(self
, lp
, logger
, cname
, caddr
):
202 # this is totally ugly, a real `quick' hack
203 for s
in lp
.services():
204 if (self
.allow_access(lp
.get("hosts deny"), lp
.get("hosts allow"), cname
,
206 self
.allow_access(lp
.get("hosts deny", s
), lp
.get("hosts allow", s
),
208 logger
.info("Allow connection from %s (%s) to %s", cname
, caddr
, s
)
210 logger
.info("Deny connection from %s (%s) to %s", cname
, caddr
, s
)
212 ## FIXME: We need support for smb.conf macros before this will work again
214 ## if (new_local_machine) {
215 ## set_local_machine_name(new_local_machine, True)