wscript: Add check for --wrap linker flag
[vlendec/samba-autobuild/.git] / source3 / torture / test_ntlm_auth.py
1 #!/usr/bin/env python
2
3 # Unix SMB/CIFS implementation.
4 # A test for the ntlm_auth tool
5 # Copyright (C) Kai Blin <kai@samba.org> 2008
6 #
7 # This program is free software; you can redistribute it and/or modify
8 # it under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 3 of the License, or
10 # (at your option) any later version.
11 #
12 # This program is distributed in the hope that it will be useful,
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 # GNU General Public License for more details.
16 #
17 # You should have received a copy of the GNU General Public License
18 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 #
20 """Test ntlm_auth
21 This test program will start ntlm_auth with the given command line switches and
22 see if it will get the expected results.
23 """
24
25 import os
26 import sys
27 from optparse import OptionParser
28
29 class ReadChildError(Exception):
30     pass
31
32 class WriteChildError(Exception):
33     pass
34
35 def readLine(pipe):
36     """readLine(pipe) -> str
37     Read a line from the child's pipe, returns the string read.
38     Throws ReadChildError if the read fails.
39     """
40     newline = -1
41     buf = ""
42     while newline == -1:
43         more = os.read(pipe, 2047)
44         buf = buf + more
45         newline = buf.find('\n')
46         if more == "":
47             raise ReadChildError()
48
49     return buf[:newline]
50
51 def writeLine(pipe, buf):
52     """writeLine(pipe, buf) -> nul
53     Write a line to the child's pipe.
54     Raises WriteChildError if the write fails.
55     """
56     written = os.write(pipe, buf)
57     if written != len(buf):
58         raise WriteChildError()
59     os.write(pipe, "\n")
60
61 def parseCommandLine():
62     """parseCommandLine() -> (opts, ntlm_auth_path)
63     Parse the command line.
64     Return a tuple consisting of the options and the path to ntlm_auth.
65     """
66     usage = "usage: %prog [options] path/to/ntlm_auth"
67     parser = OptionParser(usage)
68
69     parser.set_defaults(client_username="foo")
70     parser.set_defaults(client_password="secret")
71     parser.set_defaults(client_domain="FOO")
72     parser.set_defaults(client_helper="ntlmssp-client-1")
73
74     parser.set_defaults(server_username="foo")
75     parser.set_defaults(server_password="secret")
76     parser.set_defaults(server_domain="FOO")
77     parser.set_defaults(server_helper="squid-2.5-ntlmssp")
78     parser.set_defaults(config_file="/etc/samba/smb.conf")
79
80     parser.add_option("--client-username", dest="client_username",\
81                 help="User name for the client. [default: foo]")
82     parser.add_option("--client-password", dest="client_password",\
83                 help="Password the client will send. [default: secret]")
84     parser.add_option("--client-domain", dest="client_domain",\
85                 help="Domain the client authenticates for. [default: FOO]")
86     parser.add_option("--client-helper", dest="client_helper",\
87                 help="Helper mode for the ntlm_auth client. [default: ntlmssp-client-1]")
88     parser.add_option("--client-use-cached-creds", dest="client_use_cached_creds",\
89                 help="Use winbindd credentials cache (rather than default username/pw)", action="store_true")
90
91     parser.add_option("--target-hostname", dest="target_hostname",\
92                 help="Target hostname for kerberos")
93     parser.add_option("--target-service", dest="target_service",\
94                 help="Target service for kerberos")
95
96
97     parser.add_option("--server-username", dest="server_username",\
98                 help="User name server uses for local auth. [default: foo]")
99     parser.add_option("--server-password", dest="server_password",\
100                 help="Password server uses for local auth. [default: secret]")
101     parser.add_option("--server-domain", dest="server_domain",\
102                 help="Domain server uses for local auth. [default: FOO]")
103     parser.add_option("--server-helper", dest="server_helper",\
104                 help="Helper mode for the ntlm_auth server. [default: squid-2.5-server]")
105     parser.add_option("--server-use-winbindd", dest="server_use_winbindd",\
106                 help="Use winbindd to check the password (rather than default username/pw)", action="store_true")
107     parser.add_option("--require-membership-of", dest="sid",\
108                 help="Require that the user is a member of this group to authenticate.")
109
110
111     parser.add_option("-s", "--configfile", dest="config_file",\
112                 help="Path to smb.conf file. [default:/etc/samba/smb.conf")
113
114     (opts, args) = parser.parse_args()
115     if len(args) != 1:
116         parser.error("Invalid number of arguments.")
117
118     if not os.access(args[0], os.X_OK):
119         parser.error("%s is not executable." % args[0])
120
121     return (opts, args[0])
122
123
124 def main():
125     """main() -> int
126     Run the test.
127     Returns 0 if test succeeded, <>0 otherwise.
128     """
129     (opts, ntlm_auth_path) = parseCommandLine()
130
131     (client_in_r,  client_in_w)  = os.pipe()
132     (client_out_r, client_out_w) = os.pipe()
133
134     client_pid = os.fork()
135
136     if not client_pid:
137         # We're in the client child
138         os.close(0)
139         os.close(1)
140
141         os.dup2(client_out_r, 0)
142         os.close(client_out_r)
143         os.close(client_out_w)
144
145         os.dup2(client_in_w, 1)
146         os.close(client_in_r)
147         os.close(client_in_w)
148
149         client_args = []
150         client_args.append("--helper-protocol=%s" % opts.client_helper)
151         client_args.append("--username=%s" % opts.client_username)
152         if opts.client_use_cached_creds:
153             client_args.append("--use-cached-creds")
154         else:
155             client_args.append("--password=%s" % opts.client_password)
156         client_args.append("--domain=%s" % opts.client_domain)
157         client_args.append("--configfile=%s" % opts.config_file)
158         if opts.target_service:
159             client_args.append("--target-service=%s" % opts.target_service)
160         if opts.target_hostname:
161             client_args.append("--target-hostname=%s" % opts.target_hostname)
162
163         os.execv(ntlm_auth_path, client_args)
164
165     client_in = client_in_r
166     os.close(client_in_w)
167
168     client_out = client_out_w
169     os.close(client_out_r)
170
171     (server_in_r,  server_in_w)  = os.pipe()
172     (server_out_r, server_out_w) = os.pipe()
173
174     server_pid = os.fork()
175
176     if not server_pid:
177         # We're in the server child
178         os.close(0)
179         os.close(1)
180
181         os.dup2(server_out_r, 0)
182         os.close(server_out_r)
183         os.close(server_out_w)
184
185         os.dup2(server_in_w, 1)
186         os.close(server_in_r)
187         os.close(server_in_w)
188
189         server_args = []
190         server_args.append("--helper-protocol=%s" % opts.server_helper)
191         if not opts.server_use_winbindd:
192             server_args.append("--username=%s" % opts.server_username)
193             server_args.append("--password=%s" % opts.server_password)
194             server_args.append("--domain=%s" % opts.server_domain)
195             if opts.sid:
196                 raise Exception("Server must be using winbindd for require-membership-of.")
197         else:
198             if opts.sid:
199                 server_args.append("--require-membership-of=%s" % opts.sid)
200
201         server_args.append("--configfile=%s" % opts.config_file)
202
203         os.execv(ntlm_auth_path, server_args)
204
205     server_in = server_in_r
206     os.close(server_in_w)
207
208     server_out = server_out_w
209     os.close(server_out_r)
210
211     if opts.client_helper == "ntlmssp-client-1" and opts.server_helper == "squid-2.5-ntlmssp":
212
213         # We're in the parent
214         writeLine(client_out, "YR")
215         buf = readLine(client_in)
216
217         if buf.count("YR ", 0, 3) != 1:
218             sys.exit(1)
219
220         writeLine(server_out, buf)
221         buf = readLine(server_in)
222
223         if buf.count("TT ", 0, 3) != 1:
224             sys.exit(2)
225
226         writeLine(client_out, buf)
227         buf = readLine(client_in)
228
229         if buf.count("AF ", 0, 3) != 1:
230             sys.exit(3)
231
232         # Client sends 'AF <base64 blob>' but server expects 'KK <abse64 blob>'
233         buf = buf.replace("AF", "KK", 1)
234
235         writeLine(server_out, buf)
236         buf = readLine(server_in)
237
238         if buf.count("AF ", 0, 3) != 1:
239             sys.exit(4)
240
241
242     elif opts.client_helper == "ntlmssp-client-1" and opts.server_helper == "gss-spnego":
243         # We're in the parent
244         writeLine(client_out, "YR")
245         buf = readLine(client_in)
246
247         if buf.count("YR ", 0, 3) != 1:
248             sys.exit(1)
249
250         writeLine(server_out, buf)
251         buf = readLine(server_in)
252
253         if buf.count("TT ", 0, 3) != 1:
254             sys.exit(2)
255
256         writeLine(client_out, buf)
257         buf = readLine(client_in)
258
259         if buf.count("AF ", 0, 3) != 1:
260             sys.exit(3)
261
262         # Client sends 'AF <base64 blob>' but server expects 'KK <abse64 blob>'
263         buf = buf.replace("AF", "KK", 1)
264
265         writeLine(server_out, buf)
266         buf = readLine(server_in)
267
268         if buf.count("AF * ", 0, 5) != 1:
269             sys.exit(4)
270
271
272     elif opts.client_helper == "gss-spnego-client" and opts.server_helper == "gss-spnego":
273         # We're in the parent
274         writeLine(server_out, "YR")
275         buf = readLine(server_in)
276
277         while True:
278             if buf.count("AF ", 0, 3) != 1 and buf.count("TT ", 0, 3) != 1:
279                 sys.exit(1)
280
281             writeLine(client_out, buf)
282             buf = readLine(client_in)
283
284             if buf.count("AF", 0, 2) == 1:
285                 break
286
287             if buf.count("AF ", 0, 5) != 1 and buf.count("KK ", 0, 3) != 1 and buf.count("TT ", 0, 3) != 1:
288                 sys.exit(2)
289
290             writeLine(server_out, buf)
291             buf = readLine(server_in)
292
293             if buf.count("AF * ", 0, 5) == 1:
294                 break
295
296     else:
297         sys.exit(5)
298
299     if opts.client_helper == "ntlmssp-client-1":
300         writeLine(client_out, "GK")
301         buf = readLine(client_in)
302
303         if buf.count("GK ", 0, 3) != 1:
304             sys.exit(4)
305
306         writeLine(client_out, "GF")
307         buf = readLine(client_in)
308
309         if buf.count("GF ", 0, 3) != 1:
310             sys.exit(4)
311
312     if opts.server_helper == "squid-2.5-ntlmssp":
313         writeLine(server_out, "GK")
314         buf = readLine(server_in)
315
316         if buf.count("GK ", 0, 3) != 1:
317             sys.exit(4)
318
319         writeLine(server_out, "GF")
320         buf = readLine(server_in)
321
322         if buf.count("GF ", 0, 3) != 1:
323             sys.exit(4)
324
325     os.close(server_in)
326     os.close(server_out)
327     os.close(client_in)
328     os.close(client_out)
329     os.waitpid(server_pid, 0)
330     os.waitpid(client_pid, 0)
331     sys.exit(0)
332
333 if __name__ == "__main__":
334     main()
335
336