Correctly check for errors in strlower_m() returns.
[kai/samba.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         buf = os.read(pipe, 2047)
41         newline = buf.find('\n')
42         if newline == -1:
43                 raise ReadChildError()
44         return buf[:newline]
45
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")
55
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)
63
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")
68
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")
74
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]")
83
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")
88
89
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")
100
101
102         parser.add_option("-s", "--configfile", dest="config_file",\
103                                 help="Path to smb.conf file. [default:/etc/samba/smb.conf")
104
105         (opts, args) = parser.parse_args()
106         if len(args) != 1:
107                 parser.error("Invalid number of arguments.")
108
109         if not os.access(args[0], os.X_OK):
110                 parser.error("%s is not executable." % args[0])
111
112         return (opts, args[0])
113
114
115 def main():
116         """main() -> int
117         Run the test.
118         Returns 0 if test succeeded, <>0 otherwise.
119         """
120         (opts, ntlm_auth_path) = parseCommandLine()
121
122         (client_in_r,  client_in_w)  = os.pipe()
123         (client_out_r, client_out_w) = os.pipe()
124
125         client_pid = os.fork()
126
127         if not client_pid:
128                 # We're in the client child
129                 os.close(0)
130                 os.close(1)
131
132                 os.dup2(client_out_r, 0)
133                 os.close(client_out_r)
134                 os.close(client_out_w)
135
136                 os.dup2(client_in_w, 1)
137                 os.close(client_in_r)
138                 os.close(client_in_w)
139
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)
150
151                 os.execv(ntlm_auth_path, client_args)
152
153         client_in = client_in_r
154         os.close(client_in_w)
155
156         client_out = client_out_w
157         os.close(client_out_r)
158
159         (server_in_r,  server_in_w)  = os.pipe()
160         (server_out_r, server_out_w) = os.pipe()
161
162         server_pid = os.fork()
163
164         if not server_pid:
165                 # We're in the server child
166                 os.close(0)
167                 os.close(1)
168
169                 os.dup2(server_out_r, 0)
170                 os.close(server_out_r)
171                 os.close(server_out_w)
172
173                 os.dup2(server_in_w, 1)
174                 os.close(server_in_r)
175                 os.close(server_in_w)
176
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)
183
184                 server_args.append("--configfile=%s" % opts.config_file)
185
186                 os.execv(ntlm_auth_path, server_args)
187
188         server_in = server_in_r
189         os.close(server_in_w)
190
191         server_out = server_out_w
192         os.close(server_out_r)
193
194         if opts.client_helper == "ntlmssp-client-1" and opts.server_helper == "squid-2.5-ntlmssp":
195
196                 # We're in the parent
197                 writeLine(client_out, "YR")
198                 buf = readLine(client_in)
199                 
200                 if buf.count("YR ", 0, 3) != 1:
201                         sys.exit(1)
202
203                 writeLine(server_out, buf)
204                 buf = readLine(server_in)
205
206                 if buf.count("TT ", 0, 3) != 1:
207                         sys.exit(2)
208
209                 writeLine(client_out, buf)
210                 buf = readLine(client_in)
211
212                 if buf.count("AF ", 0, 3) != 1:
213                         sys.exit(3)
214
215                 # Client sends 'AF <base64 blob>' but server expects 'KK <abse64 blob>'
216                 buf = buf.replace("AF", "KK", 1)
217                 
218                 writeLine(server_out, buf)
219                 buf = readLine(server_in)
220                 
221                 if buf.count("AF ", 0, 3) != 1:
222                         sys.exit(4)
223
224         
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)
229                 
230                 if buf.count("YR ", 0, 3) != 1:
231                         sys.exit(1)
232
233                 writeLine(server_out, buf)
234                 buf = readLine(server_in)
235
236                 if buf.count("TT ", 0, 3) != 1:
237                         sys.exit(2)
238
239                 writeLine(client_out, buf)
240                 buf = readLine(client_in)
241
242                 if buf.count("AF ", 0, 3) != 1:
243                         sys.exit(3)
244
245                 # Client sends 'AF <base64 blob>' but server expects 'KK <abse64 blob>'
246                 buf = buf.replace("AF", "KK", 1)
247                 
248                 writeLine(server_out, buf)
249                 buf = readLine(server_in)
250                 
251                 if buf.count("AF * ", 0, 5) != 1:
252                         sys.exit(4)
253
254
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)
259                 
260                 while True:
261                         if buf.count("AF ", 0, 3) != 1 and buf.count("TT ", 0, 3) != 1:
262                                 sys.exit(1)
263
264                         writeLine(client_out, buf)
265                         buf = readLine(client_in)
266                 
267                         if buf.count("AF", 0, 2) == 1:
268                                 break
269
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)
272
273                         writeLine(server_out, buf)
274                         buf = readLine(server_in)
275
276                         if buf.count("AF * ", 0, 5) == 1:
277                                 break
278
279         else:
280                 sys.exit(5)
281
282         if opts.client_helper == "ntlmssp-client-1":
283                 writeLine(client_out, "GK")
284                 buf = readLine(client_in)
285
286                 if buf.count("GK ", 0, 3) != 1:
287                         sys.exit(4)
288
289                 writeLine(client_out, "GF")
290                 buf = readLine(client_in)
291
292                 if buf.count("GF ", 0, 3) != 1:
293                         sys.exit(4)
294
295         if opts.server_helper == "squid-2.5-ntlmssp":
296                 writeLine(server_out, "GK")
297                 buf = readLine(server_in)
298
299                 if buf.count("GK ", 0, 3) != 1:
300                         sys.exit(4)
301
302                 writeLine(server_out, "GF")
303                 buf = readLine(server_in)
304
305                 if buf.count("GF ", 0, 3) != 1:
306                         sys.exit(4)
307
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)
315
316 if __name__ == "__main__":
317         main()
318
319