s3-selftest: Add tests for ntlm_auth gss-spnego client and server
[Samba/gebeck_regimport.git] / source3 / torture / test_ntlm_auth.py
blobcb181be243b1d18bae7d5fffcb720f329b73958e
1 #!/usr/bin/env python
3 # Unix SMB/CIFS implementation.
4 # A test for the ntlm_auth tool
5 # Copyright (C) Kai Blin <kai@samba.org> 2008
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.
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.
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/>.
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 """
25 import os
26 import sys
27 from optparse import OptionParser
29 class ReadChildError(Exception):
30 pass
32 class WriteChildError(Exception):
33 pass
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 buf = os.read(pipe, 2047)
41 newline = buf.find('\n')
42 if newline == -1:
43 raise ReadChildError()
44 return buf[:newline]
46 def writeLine(pipe, buf):
47 """writeLine(pipe, buf) -> nul
48 Write a line to the child's pipe.
49 Raises WriteChildError if the write fails.
50 """
51 written = os.write(pipe, buf)
52 if written != len(buf):
53 raise WriteChildError()
54 os.write(pipe, "\n")
56 def parseCommandLine():
57 """parseCommandLine() -> (opts, ntlm_auth_path)
58 Parse the command line.
59 Return a tuple consisting of the options and the path to ntlm_auth.
60 """
61 usage = "usage: %prog [options] path/to/ntlm_auth"
62 parser = OptionParser(usage)
64 parser.set_defaults(client_username="foo")
65 parser.set_defaults(client_password="secret")
66 parser.set_defaults(client_domain="FOO")
67 parser.set_defaults(client_helper="ntlmssp-client-1")
69 parser.set_defaults(server_username="foo")
70 parser.set_defaults(server_password="secret")
71 parser.set_defaults(server_domain="FOO")
72 parser.set_defaults(server_helper="squid-2.5-ntlmssp")
73 parser.set_defaults(config_file="/etc/samba/smb.conf")
75 parser.add_option("--client-username", dest="client_username",\
76 help="User name for the client. [default: foo]")
77 parser.add_option("--client-password", dest="client_password",\
78 help="Password the client will send. [default: secret]")
79 parser.add_option("--client-domain", dest="client_domain",\
80 help="Domain the client authenticates for. [default: FOO]")
81 parser.add_option("--client-helper", dest="client_helper",\
82 help="Helper mode for the ntlm_auth client. [default: ntlmssp-client-1]")
84 parser.add_option("--target-hostname", dest="target_hostname",\
85 help="Target hostname for kerberos")
86 parser.add_option("--target-service", dest="target_service",\
87 help="Target service for kerberos")
90 parser.add_option("--server-username", dest="server_username",\
91 help="User name server uses for local auth. [default: foo]")
92 parser.add_option("--server-password", dest="server_password",\
93 help="Password server uses for local auth. [default: secret]")
94 parser.add_option("--server-domain", dest="server_domain",\
95 help="Domain server uses for local auth. [default: FOO]")
96 parser.add_option("--server-helper", dest="server_helper",\
97 help="Helper mode for the ntlm_auth server. [default: squid-2.5-server]")
98 parser.add_option("--server-use-winbindd", dest="server_use_winbindd",\
99 help="Use winbindd to check the password (rather than default username/pw)", action="store_true")
102 parser.add_option("-s", "--configfile", dest="config_file",\
103 help="Path to smb.conf file. [default:/etc/samba/smb.conf")
105 (opts, args) = parser.parse_args()
106 if len(args) != 1:
107 parser.error("Invalid number of arguments.")
109 if not os.access(args[0], os.X_OK):
110 parser.error("%s is not executable." % args[0])
112 return (opts, args[0])
115 def main():
116 """main() -> int
117 Run the test.
118 Returns 0 if test succeeded, <>0 otherwise.
120 (opts, ntlm_auth_path) = parseCommandLine()
122 (client_in_r, client_in_w) = os.pipe()
123 (client_out_r, client_out_w) = os.pipe()
125 client_pid = os.fork()
127 if not client_pid:
128 # We're in the client child
129 os.close(0)
130 os.close(1)
132 os.dup2(client_out_r, 0)
133 os.close(client_out_r)
134 os.close(client_out_w)
136 os.dup2(client_in_w, 1)
137 os.close(client_in_r)
138 os.close(client_in_w)
140 client_args = []
141 client_args.append("--helper-protocol=%s" % opts.client_helper)
142 client_args.append("--username=%s" % opts.client_username)
143 client_args.append("--password=%s" % opts.client_password)
144 client_args.append("--domain=%s" % opts.client_domain)
145 client_args.append("--configfile=%s" % opts.config_file)
146 if opts.target_service:
147 client_args.append("--target-service=%s" % opts.target_service)
148 if opts.target_hostname:
149 client_args.append("--target-hostname=%s" % opts.target_hostname)
151 os.execv(ntlm_auth_path, client_args)
153 client_in = client_in_r
154 os.close(client_in_w)
156 client_out = client_out_w
157 os.close(client_out_r)
159 (server_in_r, server_in_w) = os.pipe()
160 (server_out_r, server_out_w) = os.pipe()
162 server_pid = os.fork()
164 if not server_pid:
165 # We're in the server child
166 os.close(0)
167 os.close(1)
169 os.dup2(server_out_r, 0)
170 os.close(server_out_r)
171 os.close(server_out_w)
173 os.dup2(server_in_w, 1)
174 os.close(server_in_r)
175 os.close(server_in_w)
177 server_args = []
178 server_args.append("--helper-protocol=%s" % opts.server_helper)
179 if not opts.server_use_winbindd:
180 server_args.append("--username=%s" % opts.server_username)
181 server_args.append("--password=%s" % opts.server_password)
182 server_args.append("--domain=%s" % opts.server_domain)
184 server_args.append("--configfile=%s" % opts.config_file)
186 os.execv(ntlm_auth_path, server_args)
188 server_in = server_in_r
189 os.close(server_in_w)
191 server_out = server_out_w
192 os.close(server_out_r)
194 if opts.client_helper == "ntlmssp-client-1" and opts.server_helper == "squid-2.5-ntlmssp":
196 # We're in the parent
197 writeLine(client_out, "YR")
198 buf = readLine(client_in)
200 if buf.count("YR ", 0, 3) != 1:
201 sys.exit(1)
203 writeLine(server_out, buf)
204 buf = readLine(server_in)
206 if buf.count("TT ", 0, 3) != 1:
207 sys.exit(2)
209 writeLine(client_out, buf)
210 buf = readLine(client_in)
212 if buf.count("AF ", 0, 3) != 1:
213 sys.exit(3)
215 # Client sends 'AF <base64 blob>' but server expects 'KK <abse64 blob>'
216 buf = buf.replace("AF", "KK", 1)
218 writeLine(server_out, buf)
219 buf = readLine(server_in)
221 if buf.count("AF ", 0, 3) != 1:
222 sys.exit(4)
225 elif opts.client_helper == "ntlmssp-client-1" and opts.server_helper == "gss-spnego":
226 # We're in the parent
227 writeLine(client_out, "YR")
228 buf = readLine(client_in)
230 if buf.count("YR ", 0, 3) != 1:
231 sys.exit(1)
233 writeLine(server_out, buf)
234 buf = readLine(server_in)
236 if buf.count("TT ", 0, 3) != 1:
237 sys.exit(2)
239 writeLine(client_out, buf)
240 buf = readLine(client_in)
242 if buf.count("AF ", 0, 3) != 1:
243 sys.exit(3)
245 # Client sends 'AF <base64 blob>' but server expects 'KK <abse64 blob>'
246 buf = buf.replace("AF", "KK", 1)
248 writeLine(server_out, buf)
249 buf = readLine(server_in)
251 if buf.count("AF * ", 0, 5) != 1:
252 sys.exit(4)
255 elif opts.client_helper == "gss-spnego-client" and opts.server_helper == "gss-spnego":
256 # We're in the parent
257 writeLine(server_out, "YR")
258 buf = readLine(server_in)
260 while True:
261 if buf.count("AF ", 0, 3) != 1 and buf.count("TT ", 0, 3) != 1:
262 sys.exit(1)
264 writeLine(client_out, buf)
265 buf = readLine(client_in)
267 if buf.count("AF", 0, 2) == 1:
268 break
270 if buf.count("AF ", 0, 5) != 1 and buf.count("KK ", 0, 3) != 1 and buf.count("TT ", 0, 3) != 1:
271 sys.exit(2)
273 writeLine(server_out, buf)
274 buf = readLine(server_in)
276 if buf.count("AF * ", 0, 5) == 1:
277 break
279 else:
280 sys.exit(5)
282 if opts.client_helper == "ntlmssp-client-1":
283 writeLine(client_out, "GK")
284 buf = readLine(client_in)
286 if buf.count("GK ", 0, 3) != 1:
287 sys.exit(4)
289 writeLine(client_out, "GF")
290 buf = readLine(client_in)
292 if buf.count("GF ", 0, 3) != 1:
293 sys.exit(4)
295 if opts.server_helper == "squid-2.5-ntlmssp":
296 writeLine(server_out, "GK")
297 buf = readLine(server_in)
299 if buf.count("GK ", 0, 3) != 1:
300 sys.exit(4)
302 writeLine(server_out, "GF")
303 buf = readLine(server_in)
305 if buf.count("GF ", 0, 3) != 1:
306 sys.exit(4)
308 os.close(server_in)
309 os.close(server_out)
310 os.close(client_in)
311 os.close(client_out)
312 os.waitpid(server_pid, 0)
313 os.waitpid(client_pid, 0)
314 sys.exit(0)
316 if __name__ == "__main__":
317 main()