s3-selftest: Verify GK and GF flag behaviour
[Samba/bjacke.git] / source3 / torture / test_ntlm_auth.py
blobbe725485a0ce4762cd11d91e8ca8cf2e0846644e
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]")
92 parser.add_option("--server-use-winbindd", dest="server_use_winbindd",\
93 help="Use winbindd to check the password (rather than default username/pw)", action="store_true")
96 parser.add_option("-s", "--configfile", dest="config_file",\
97 help="Path to smb.conf file. [default:/etc/samba/smb.conf")
99 (opts, args) = parser.parse_args()
100 if len(args) != 1:
101 parser.error("Invalid number of arguments.")
103 if not os.access(args[0], os.X_OK):
104 parser.error("%s is not executable." % args[0])
106 return (opts, args[0])
109 def main():
110 """main() -> int
111 Run the test.
112 Returns 0 if test succeeded, <>0 otherwise.
114 (opts, ntlm_auth_path) = parseCommandLine()
116 (client_in_r, client_in_w) = os.pipe()
117 (client_out_r, client_out_w) = os.pipe()
119 client_pid = os.fork()
121 if not client_pid:
122 # We're in the client child
123 os.close(0)
124 os.close(1)
126 os.dup2(client_out_r, 0)
127 os.close(client_out_r)
128 os.close(client_out_w)
130 os.dup2(client_in_w, 1)
131 os.close(client_in_r)
132 os.close(client_in_w)
134 client_args = []
135 client_args.append("--helper-protocol=%s" % opts.client_helper)
136 client_args.append("--username=%s" % opts.client_username)
137 client_args.append("--password=%s" % opts.client_password)
138 client_args.append("--domain=%s" % opts.client_domain)
139 client_args.append("--configfile=%s" % opts.config_file)
141 os.execv(ntlm_auth_path, client_args)
143 client_in = client_in_r
144 os.close(client_in_w)
146 client_out = client_out_w
147 os.close(client_out_r)
149 (server_in_r, server_in_w) = os.pipe()
150 (server_out_r, server_out_w) = os.pipe()
152 server_pid = os.fork()
154 if not server_pid:
155 # We're in the server child
156 os.close(0)
157 os.close(1)
159 os.dup2(server_out_r, 0)
160 os.close(server_out_r)
161 os.close(server_out_w)
163 os.dup2(server_in_w, 1)
164 os.close(server_in_r)
165 os.close(server_in_w)
167 server_args = []
168 server_args.append("--helper-protocol=%s" % opts.server_helper)
169 if not opts.server_use_winbindd:
170 server_args.append("--username=%s" % opts.server_username)
171 server_args.append("--password=%s" % opts.server_password)
172 server_args.append("--domain=%s" % opts.server_domain)
174 server_args.append("--configfile=%s" % opts.config_file)
176 os.execv(ntlm_auth_path, server_args)
178 server_in = server_in_r
179 os.close(server_in_w)
181 server_out = server_out_w
182 os.close(server_out_r)
184 # We're in the parent
185 writeLine(client_out, "YR")
186 buf = readLine(client_in)
188 if buf.count("YR ", 0, 3) != 1:
189 sys.exit(1)
191 writeLine(server_out, buf)
192 buf = readLine(server_in)
194 if buf.count("TT ", 0, 3) != 1:
195 sys.exit(2)
197 writeLine(client_out, buf)
198 buf = readLine(client_in)
200 if buf.count("AF ", 0, 3) != 1:
201 sys.exit(3)
203 # Client sends 'AF <base64 blob>' but server expects 'KK <abse64 blob>'
204 buf = buf.replace("AF", "KK", 1)
206 writeLine(server_out, buf)
207 buf = readLine(server_in)
209 if buf.count("AF ", 0, 3) != 1:
210 sys.exit(4)
212 if opts.client_helper == "ntlmssp-client-1":
213 writeLine(client_out, "GK")
214 buf = readLine(client_in)
216 if buf.count("GK ", 0, 3) != 1:
217 sys.exit(4)
219 writeLine(client_out, "GF")
220 buf = readLine(client_in)
222 if buf.count("GF ", 0, 3) != 1:
223 sys.exit(4)
225 if opts.server_helper == "squid-2.5-ntlmssp":
226 writeLine(server_out, "GK")
227 buf = readLine(server_in)
229 if buf.count("GK ", 0, 3) != 1:
230 sys.exit(4)
232 writeLine(server_out, "GF")
233 buf = readLine(server_in)
235 if buf.count("GF ", 0, 3) != 1:
236 sys.exit(4)
238 os.close(server_in)
239 os.close(server_out)
240 os.close(client_in)
241 os.close(client_out)
242 os.waitpid(server_pid, 0)
243 os.waitpid(client_pid, 0)
244 sys.exit(0)
246 if __name__ == "__main__":
247 main()