testparm: Convert to Python.
[metze/samba/wip.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 #/***********************************************
36 # Here we do a set of 'hard coded' checks for bad
37 # configuration settings.
38 #************************************************/
39 #
40
41 import logging
42 import optparse
43 import os
44 import sys
45
46 # Find right directory when running from source tree
47 sys.path.insert(0, "bin/python")
48
49 import samba
50 from samba import getopt as options
51
52 def do_global_checks(lp, logger):
53     ret = False
54
55     lockdir = lp.get("lockdir")
56
57     if not os.path.isdir(lockdir):
58         logger.error("lock directory %s does not exist", lockdir)
59         ret = True
60
61     piddir = lp.get("pid directory")
62
63     if os.path.isdir(piddir):
64         logger.error("pid directory %s does not exist", piddir)
65         ret = True
66
67     winbind_separator = lp.get("winbind separator")
68
69     if len(winbind_separator) != 1:
70         logger.error("the 'winbind separator' parameter must be a single character.")
71         ret = True
72
73     if winbind_separator == '+':
74         logger.error("'winbind separator = +' might cause problems with group membership.")
75
76     return ret
77
78
79 def allow_access(deny_list, allow_list, cname, caddr):
80     raise NotImplementedError(allow_access)
81
82
83 def do_share_checks(lp, cname, caddr, silent_mode, show_defaults, section_name,
84         parameter_name, logger):
85     ret = False
86
87     for s in lp.services():
88         if len(s) > 12:
89             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.)")
90             break
91
92     for s in lp.services():
93         deny_list = lp.get("hosts deny", s)
94         allow_list = lp.get("hosts allow", s)
95         if deny_list:
96             for entry in deny_list:
97                 if "*" in entry or "?" in entry:
98                     logger.error("Invalid character (* or ?) in hosts deny list (%s) for service %s.", entry, s)
99
100         if allow_list:
101             for entry in allow_list:
102                 if "*" in entry or "?" in entry:
103                     logger.error("Invalid character (* or ?) in hosts allow list (%s) for service %s.", entry, s)
104
105     if cname is not None:
106         if not silent_mode:
107             print "Press enter to see a dump of your service definitions\n"
108             sys.stdin.readline()
109         if section_name is not None or parameter_name is not None:
110             if parameter_name is None:
111                 lp.dump_service(sys.stdout, section_name, show_defaults)
112             else:
113                 lp.dump_parameter(sys.stdout, section_name, parameter_name)
114         else:
115             lp.dump(sys.stdout, show_defaults)
116         return ret
117
118     if cname is not None and caddr is not None:
119         # this is totally ugly, a real `quick' hack
120         for s in lp.services():
121             if (allow_access(lp.get("hosts deny"), lp.get("hosts allow"), cname, caddr) and
122                 allow_access(lp.get("hosts deny", s), lp.get("hosts allow", s), cname, caddr)):
123                 logger.info("Allow connection from %s (%s) to %s",
124                        cname, caddr, s)
125             else:
126                 logger.info("Deny connection from %s (%s) to %s",
127                        cname, caddr, s)
128
129     return ret
130
131
132 if __name__ == '__main__':
133     section_name = None
134     parameter_name = None
135     silent_mode = False
136     show_defaults = False
137
138     parser = optparse.OptionParser("testparm [OPTION...] [host-name] [host-ip]")
139     parser.add_option("--section-name", type="string", metavar="SECTION",
140             help="Limit testparm to a named section")
141     parser.add_option("--parameter-name", type="string", metavar="PARAMETER",
142             help="Limit testparm to a named parameter")
143     parser.add_option("--client-name", type="string", metavar="HOSTNAME",
144             help="Client DNS name for 'hosts allow' checking (should match reverse lookup)")
145     parser.add_option("--client-ip", type="string", metavar="IP",
146             help="Client IP address for 'hosts allow' checking")
147     parser.add_option("--suppress-prompt", action="store_true", 
148             help="Suppress prompt for enter")
149     parser.add_option("--verbose", action="store_true", 
150             help="Show default options too")
151     parser.add_option_group(options.VersionOptions(parser))
152     # We need support for smb.conf macros before this will work again 
153     parser.add_option("--server", type="string",
154             help="Set %%L macro to servername")
155     # These are harder to do with the new code structure
156     parser.add_option("--show-all-parameters", action="store_true", 
157             help="Show the parameters, type, possible values")
158
159     sambaopts = options.SambaOptions(parser)
160     parser.add_option_group(sambaopts)
161
162     opts, args = parser.parse_args()
163
164
165 #    if (show_all_parameters) {
166 #        show_parameter_list()
167 #        exit(0)
168 #    }
169
170     if len(args) > 0:
171         cname = args[0]
172     else:
173         cname = None
174     if len(args) > 1:
175         caddr = args[1]
176     else:
177         caddr = None
178
179     if cname is not None and caddr is None:
180         print "ERROR: For 'hosts allow' check you must specify both a DNS name and an IP address.\n"
181         sys.exit(1)
182
183 #   FIXME: We need support for smb.conf macros before this will work again 
184 #
185 #    if (new_local_machine) {
186 #        set_local_machine_name(new_local_machine, True)
187 #    }
188
189     lp = sambaopts.get_loadparm()
190
191     # We need this to force the output
192     samba.set_debug_level(2)
193
194     logger = logging.getLogger("testparm")
195
196     print "Loaded smb config files from %s\n" % lp.configfile
197
198     logger.info("Loaded services file OK.")
199
200     do_global_checks(lp, logger)
201     do_share_checks(lp, cname, caddr, silent_mode, show_defaults,
202             section_name, parameter_name, logger)
203
204     sys.exit(0)