Fix bug #8953 - winbind can hang as nbt_getdc() has no timeout.
[Samba.git] / source3 / torture / test_ntlm_auth.py
blob12a4dae398c92938d7c3260b00ff65546292c500
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("--server-username", dest="server_username",\
85 help="User name server uses for local auth. [default: foo]")
86 parser.add_option("--server-password", dest="server_password",\
87 help="Password server uses for local auth. [default: secret]")
88 parser.add_option("--server-domain", dest="server_domain",\
89 help="Domain server uses for local auth. [default: FOO]")
90 parser.add_option("--server-helper", dest="server_helper",\
91 help="Helper mode for the ntlm_auth server. [default: squid-2.5-server]")
93 parser.add_option("-s", "--configfile", dest="config_file",\
94 help="Path to smb.conf file. [default:/etc/samba/smb.conf")
96 (opts, args) = parser.parse_args()
97 if len(args) != 1:
98 parser.error("Invalid number of arguments.")
100 if not os.access(args[0], os.X_OK):
101 parser.error("%s is not executable." % args[0])
103 return (opts, args[0])
106 def main():
107 """main() -> int
108 Run the test.
109 Returns 0 if test succeeded, <>0 otherwise.
111 (opts, ntlm_auth_path) = parseCommandLine()
113 (client_in_r, client_in_w) = os.pipe()
114 (client_out_r, client_out_w) = os.pipe()
116 client_pid = os.fork()
118 if not client_pid:
119 # We're in the client child
120 os.close(0)
121 os.close(1)
123 os.dup2(client_out_r, 0)
124 os.close(client_out_r)
125 os.close(client_out_w)
127 os.dup2(client_in_w, 1)
128 os.close(client_in_r)
129 os.close(client_in_w)
131 client_args = []
132 client_args.append("--helper-protocol=%s" % opts.client_helper)
133 client_args.append("--username=%s" % opts.client_username)
134 client_args.append("--password=%s" % opts.client_password)
135 client_args.append("--domain=%s" % opts.client_domain)
136 client_args.append("--configfile=%s" % opts.config_file)
138 os.execv(ntlm_auth_path, client_args)
140 client_in = client_in_r
141 os.close(client_in_w)
143 client_out = client_out_w
144 os.close(client_out_r)
146 (server_in_r, server_in_w) = os.pipe()
147 (server_out_r, server_out_w) = os.pipe()
149 server_pid = os.fork()
151 if not server_pid:
152 # We're in the server child
153 os.close(0)
154 os.close(1)
156 os.dup2(server_out_r, 0)
157 os.close(server_out_r)
158 os.close(server_out_w)
160 os.dup2(server_in_w, 1)
161 os.close(server_in_r)
162 os.close(server_in_w)
164 server_args = []
165 server_args.append("--helper-protocol=%s" % opts.server_helper)
166 server_args.append("--username=%s" % opts.server_username)
167 server_args.append("--password=%s" % opts.server_password)
168 server_args.append("--domain=%s" % opts.server_domain)
169 server_args.append("--configfile=%s" % opts.config_file)
171 os.execv(ntlm_auth_path, server_args)
173 server_in = server_in_r
174 os.close(server_in_w)
176 server_out = server_out_w
177 os.close(server_out_r)
179 # We're in the parent
180 writeLine(client_out, "YR")
181 buf = readLine(client_in)
183 if buf.count("YR ", 0, 3) != 1:
184 sys.exit(1)
186 writeLine(server_out, buf)
187 buf = readLine(server_in)
189 if buf.count("TT ", 0, 3) != 1:
190 sys.exit(2)
192 writeLine(client_out, buf)
193 buf = readLine(client_in)
195 if buf.count("AF ", 0, 3) != 1:
196 sys.exit(3)
198 # Client sends 'AF <base64 blob>' but server expects 'KK <abse64 blob>'
199 buf = buf.replace("AF", "KK", 1)
201 writeLine(server_out, buf)
202 buf = readLine(server_in)
204 if buf.count("AF ", 0, 3) != 1:
205 sys.exit(4)
207 os.close(server_in)
208 os.close(server_out)
209 os.close(client_in)
210 os.close(client_out)
211 os.waitpid(server_pid, 0)
212 os.waitpid(client_pid, 0)
213 sys.exit(0)
215 if __name__ == "__main__":
216 main()