CID 1416476: possibly dereferencing NULL in fruit_ftruncate_rsrc
[Samba.git] / source3 / torture / test_ntlm_auth.py
blob076019c539b925645880abfef7d8e017fd1c24d7
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 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()
49 return buf[:newline]
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")
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)
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")
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")
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")
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")
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.")
111 parser.add_option("-s", "--configfile", dest="config_file",\
112 help="Path to smb.conf file. [default:/etc/samba/smb.conf")
114 (opts, args) = parser.parse_args()
115 if len(args) != 1:
116 parser.error("Invalid number of arguments.")
118 if not os.access(args[0], os.X_OK):
119 parser.error("%s is not executable." % args[0])
121 return (opts, args[0])
124 def main():
125 """main() -> int
126 Run the test.
127 Returns 0 if test succeeded, <>0 otherwise.
129 (opts, ntlm_auth_path) = parseCommandLine()
131 (client_in_r, client_in_w) = os.pipe()
132 (client_out_r, client_out_w) = os.pipe()
134 client_pid = os.fork()
136 if not client_pid:
137 # We're in the client child
138 os.close(0)
139 os.close(1)
141 os.dup2(client_out_r, 0)
142 os.close(client_out_r)
143 os.close(client_out_w)
145 os.dup2(client_in_w, 1)
146 os.close(client_in_r)
147 os.close(client_in_w)
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)
163 os.execv(ntlm_auth_path, client_args)
165 client_in = client_in_r
166 os.close(client_in_w)
168 client_out = client_out_w
169 os.close(client_out_r)
171 (server_in_r, server_in_w) = os.pipe()
172 (server_out_r, server_out_w) = os.pipe()
174 server_pid = os.fork()
176 if not server_pid:
177 # We're in the server child
178 os.close(0)
179 os.close(1)
181 os.dup2(server_out_r, 0)
182 os.close(server_out_r)
183 os.close(server_out_w)
185 os.dup2(server_in_w, 1)
186 os.close(server_in_r)
187 os.close(server_in_w)
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)
201 server_args.append("--configfile=%s" % opts.config_file)
203 os.execv(ntlm_auth_path, server_args)
205 server_in = server_in_r
206 os.close(server_in_w)
208 server_out = server_out_w
209 os.close(server_out_r)
211 if opts.client_helper == "ntlmssp-client-1" and opts.server_helper == "squid-2.5-ntlmssp":
213 # We're in the parent
214 writeLine(client_out, "YR")
215 buf = readLine(client_in)
217 if buf.count("YR ", 0, 3) != 1:
218 sys.exit(1)
220 writeLine(server_out, buf)
221 buf = readLine(server_in)
223 if buf.count("TT ", 0, 3) != 1:
224 sys.exit(2)
226 writeLine(client_out, buf)
227 buf = readLine(client_in)
229 if buf.count("AF ", 0, 3) != 1:
230 sys.exit(3)
232 # Client sends 'AF <base64 blob>' but server expects 'KK <abse64 blob>'
233 buf = buf.replace("AF", "KK", 1)
235 writeLine(server_out, buf)
236 buf = readLine(server_in)
238 if buf.count("AF ", 0, 3) != 1:
239 sys.exit(4)
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)
247 if buf.count("YR ", 0, 3) != 1:
248 sys.exit(1)
250 writeLine(server_out, buf)
251 buf = readLine(server_in)
253 if buf.count("TT ", 0, 3) != 1:
254 sys.exit(2)
256 writeLine(client_out, buf)
257 buf = readLine(client_in)
259 if buf.count("AF ", 0, 3) != 1:
260 sys.exit(3)
262 # Client sends 'AF <base64 blob>' but server expects 'KK <abse64 blob>'
263 buf = buf.replace("AF", "KK", 1)
265 writeLine(server_out, buf)
266 buf = readLine(server_in)
268 if buf.count("AF * ", 0, 5) != 1:
269 sys.exit(4)
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)
277 while True:
278 if buf.count("AF ", 0, 3) != 1 and buf.count("TT ", 0, 3) != 1:
279 sys.exit(1)
281 writeLine(client_out, buf)
282 buf = readLine(client_in)
284 if buf.count("AF", 0, 2) == 1:
285 break
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)
290 writeLine(server_out, buf)
291 buf = readLine(server_in)
293 if buf.count("AF * ", 0, 5) == 1:
294 break
296 else:
297 sys.exit(5)
299 if opts.client_helper == "ntlmssp-client-1":
300 writeLine(client_out, "GK")
301 buf = readLine(client_in)
303 if buf.count("GK ", 0, 3) != 1:
304 sys.exit(4)
306 writeLine(client_out, "GF")
307 buf = readLine(client_in)
309 if buf.count("GF ", 0, 3) != 1:
310 sys.exit(4)
312 if opts.server_helper == "squid-2.5-ntlmssp":
313 writeLine(server_out, "GK")
314 buf = readLine(server_in)
316 if buf.count("GK ", 0, 3) != 1:
317 sys.exit(4)
319 writeLine(server_out, "GF")
320 buf = readLine(server_in)
322 if buf.count("GF ", 0, 3) != 1:
323 sys.exit(4)
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)
333 if __name__ == "__main__":
334 main()