s3: Convert cli_sesssetup_ntlmssp to the async API
[ira/wip.git] / source3 / libsmb / cliconnect.c
1 /* 
2    Unix SMB/CIFS implementation.
3    client connect/disconnect routines
4    Copyright (C) Andrew Tridgell 1994-1998
5    Copyright (C) Andrew Bartlett 2001-2003
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
21 #include "includes.h"
22 #include "../libcli/auth/libcli_auth.h"
23 #include "../libcli/auth/spnego.h"
24 #include "smb_krb5.h"
25 #include "ntlmssp.h"
26
27 static const struct {
28         int prot;
29         const char name[24];
30 } prots[10] = {
31         {PROTOCOL_CORE,         "PC NETWORK PROGRAM 1.0"},
32         {PROTOCOL_COREPLUS,     "MICROSOFT NETWORKS 1.03"},
33         {PROTOCOL_LANMAN1,      "MICROSOFT NETWORKS 3.0"},
34         {PROTOCOL_LANMAN1,      "LANMAN1.0"},
35         {PROTOCOL_LANMAN2,      "LM1.2X002"},
36         {PROTOCOL_LANMAN2,      "DOS LANMAN2.1"},
37         {PROTOCOL_LANMAN2,      "LANMAN2.1"},
38         {PROTOCOL_LANMAN2,      "Samba"},
39         {PROTOCOL_NT1,          "NT LANMAN 1.0"},
40         {PROTOCOL_NT1,          "NT LM 0.12"},
41 };
42
43 #define STAR_SMBSERVER "*SMBSERVER"
44
45 /**
46  * Set the user session key for a connection
47  * @param cli The cli structure to add it too
48  * @param session_key The session key used.  (A copy of this is taken for the cli struct)
49  *
50  */
51
52 static void cli_set_session_key (struct cli_state *cli, const DATA_BLOB session_key) 
53 {
54         cli->user_session_key = data_blob(session_key.data, session_key.length);
55 }
56
57 /****************************************************************************
58  Do an old lanman2 style session setup.
59 ****************************************************************************/
60
61 static NTSTATUS cli_session_setup_lanman2(struct cli_state *cli,
62                                           const char *user, 
63                                           const char *pass, size_t passlen,
64                                           const char *workgroup)
65 {
66         DATA_BLOB session_key = data_blob_null;
67         DATA_BLOB lm_response = data_blob_null;
68         NTSTATUS status;
69         fstring pword;
70         char *p;
71
72         if (passlen > sizeof(pword)-1) {
73                 return NT_STATUS_INVALID_PARAMETER;
74         }
75
76         /* LANMAN servers predate NT status codes and Unicode and ignore those 
77            smb flags so we must disable the corresponding default capabilities  
78            that would otherwise cause the Unicode and NT Status flags to be
79            set (and even returned by the server) */
80
81         cli->capabilities &= ~(CAP_UNICODE | CAP_STATUS32);
82
83         /* if in share level security then don't send a password now */
84         if (!(cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL))
85                 passlen = 0;
86
87         if (passlen > 0 && (cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) && passlen != 24) {
88                 /* Encrypted mode needed, and non encrypted password supplied. */
89                 lm_response = data_blob(NULL, 24);
90                 if (!SMBencrypt(pass, cli->secblob.data,(uchar *)lm_response.data)) {
91                         DEBUG(1, ("Password is > 14 chars in length, and is therefore incompatible with Lanman authentication\n"));
92                         return NT_STATUS_ACCESS_DENIED;
93                 }
94         } else if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) && passlen == 24) {
95                 /* Encrypted mode needed, and encrypted password supplied. */
96                 lm_response = data_blob(pass, passlen);
97         } else if (passlen > 0) {
98                 /* Plaintext mode needed, assume plaintext supplied. */
99                 passlen = clistr_push(cli, pword, pass, sizeof(pword), STR_TERMINATE);
100                 lm_response = data_blob(pass, passlen);
101         }
102
103         /* send a session setup command */
104         memset(cli->outbuf,'\0',smb_size);
105         cli_set_message(cli->outbuf,10, 0, True);
106         SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
107         cli_setup_packet(cli);
108         
109         SCVAL(cli->outbuf,smb_vwv0,0xFF);
110         SSVAL(cli->outbuf,smb_vwv2,cli->max_xmit);
111         SSVAL(cli->outbuf,smb_vwv3,2);
112         SSVAL(cli->outbuf,smb_vwv4,1);
113         SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
114         SSVAL(cli->outbuf,smb_vwv7,lm_response.length);
115
116         p = smb_buf(cli->outbuf);
117         memcpy(p,lm_response.data,lm_response.length);
118         p += lm_response.length;
119         p += clistr_push(cli, p, user, -1, STR_TERMINATE|STR_UPPER);
120         p += clistr_push(cli, p, workgroup, -1, STR_TERMINATE|STR_UPPER);
121         p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
122         p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
123         cli_setup_bcc(cli, p);
124
125         if (!cli_send_smb(cli) || !cli_receive_smb(cli)) {
126                 return cli_nt_error(cli);
127         }
128
129         show_msg(cli->inbuf);
130
131         if (cli_is_error(cli)) {
132                 return cli_nt_error(cli);
133         }
134         
135         /* use the returned vuid from now on */
136         cli->vuid = SVAL(cli->inbuf,smb_uid);   
137         status = cli_set_username(cli, user);
138         if (!NT_STATUS_IS_OK(status)) {
139                 return status;
140         }
141
142         if (session_key.data) {
143                 /* Have plaintext orginal */
144                 cli_set_session_key(cli, session_key);
145         }
146
147         return NT_STATUS_OK;
148 }
149
150 /****************************************************************************
151  Work out suitable capabilities to offer the server.
152 ****************************************************************************/
153
154 static uint32 cli_session_setup_capabilities(struct cli_state *cli)
155 {
156         uint32 capabilities = CAP_NT_SMBS;
157
158         if (!cli->force_dos_errors)
159                 capabilities |= CAP_STATUS32;
160
161         if (cli->use_level_II_oplocks)
162                 capabilities |= CAP_LEVEL_II_OPLOCKS;
163
164         capabilities |= (cli->capabilities & (CAP_UNICODE|CAP_LARGE_FILES|CAP_LARGE_READX|CAP_LARGE_WRITEX|CAP_DFS));
165         return capabilities;
166 }
167
168 /****************************************************************************
169  Do a NT1 guest session setup.
170 ****************************************************************************/
171
172 struct cli_session_setup_guest_state {
173         struct cli_state *cli;
174         uint16_t vwv[16];
175         struct iovec bytes;
176 };
177
178 static void cli_session_setup_guest_done(struct tevent_req *subreq);
179
180 struct tevent_req *cli_session_setup_guest_create(TALLOC_CTX *mem_ctx,
181                                                   struct event_context *ev,
182                                                   struct cli_state *cli,
183                                                   struct tevent_req **psmbreq)
184 {
185         struct tevent_req *req, *subreq;
186         struct cli_session_setup_guest_state *state;
187         uint16_t *vwv;
188         uint8_t *bytes;
189
190         req = tevent_req_create(mem_ctx, &state,
191                                 struct cli_session_setup_guest_state);
192         if (req == NULL) {
193                 return NULL;
194         }
195         state->cli = cli;
196         vwv = state->vwv;
197
198         SCVAL(vwv+0, 0, 0xFF);
199         SCVAL(vwv+0, 1, 0);
200         SSVAL(vwv+1, 0, 0);
201         SSVAL(vwv+2, 0, CLI_BUFFER_SIZE);
202         SSVAL(vwv+3, 0, 2);
203         SSVAL(vwv+4, 0, cli->pid);
204         SIVAL(vwv+5, 0, cli->sesskey);
205         SSVAL(vwv+7, 0, 0);
206         SSVAL(vwv+8, 0, 0);
207         SSVAL(vwv+9, 0, 0);
208         SSVAL(vwv+10, 0, 0);
209         SIVAL(vwv+11, 0, cli_session_setup_capabilities(cli));
210
211         bytes = talloc_array(state, uint8_t, 0);
212
213         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), "",  1, /* username */
214                                    NULL);
215         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), "", 1, /* workgroup */
216                                    NULL);
217         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), "Unix", 5, NULL);
218         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), "Samba", 6, NULL);
219
220         if (bytes == NULL) {
221                 TALLOC_FREE(req);
222                 return NULL;
223         }
224
225         state->bytes.iov_base = (void *)bytes;
226         state->bytes.iov_len = talloc_get_size(bytes);
227
228         subreq = cli_smb_req_create(state, ev, cli, SMBsesssetupX, 0, 13, vwv,
229                                     1, &state->bytes);
230         if (subreq == NULL) {
231                 TALLOC_FREE(req);
232                 return NULL;
233         }
234         tevent_req_set_callback(subreq, cli_session_setup_guest_done, req);
235         *psmbreq = subreq;
236         return req;
237 }
238
239 struct tevent_req *cli_session_setup_guest_send(TALLOC_CTX *mem_ctx,
240                                                 struct event_context *ev,
241                                                 struct cli_state *cli)
242 {
243         struct tevent_req *req, *subreq;
244         NTSTATUS status;
245
246         req = cli_session_setup_guest_create(mem_ctx, ev, cli, &subreq);
247         if (req == NULL) {
248                 return NULL;
249         }
250
251         status = cli_smb_req_send(subreq);
252         if (NT_STATUS_IS_OK(status)) {
253                 tevent_req_nterror(req, status);
254                 return tevent_req_post(req, ev);
255         }
256         return req;
257 }
258
259 static void cli_session_setup_guest_done(struct tevent_req *subreq)
260 {
261         struct tevent_req *req = tevent_req_callback_data(
262                 subreq, struct tevent_req);
263         struct cli_session_setup_guest_state *state = tevent_req_data(
264                 req, struct cli_session_setup_guest_state);
265         struct cli_state *cli = state->cli;
266         uint32_t num_bytes;
267         char *inbuf;
268         uint8_t *bytes;
269         uint8_t *p;
270         NTSTATUS status;
271
272         status = cli_smb_recv(subreq, 0, NULL, NULL, &num_bytes, &bytes);
273         if (!NT_STATUS_IS_OK(status)) {
274                 TALLOC_FREE(subreq);
275                 tevent_req_nterror(req, status);
276                 return;
277         }
278
279         inbuf = (char *)cli_smb_inbuf(subreq);
280         p = bytes;
281
282         cli->vuid = SVAL(inbuf, smb_uid);
283
284         p += clistr_pull(inbuf, cli->server_os, (char *)p, sizeof(fstring),
285                          bytes+num_bytes-p, STR_TERMINATE);
286         p += clistr_pull(inbuf, cli->server_type, (char *)p, sizeof(fstring),
287                          bytes+num_bytes-p, STR_TERMINATE);
288         p += clistr_pull(inbuf, cli->server_domain, (char *)p, sizeof(fstring),
289                          bytes+num_bytes-p, STR_TERMINATE);
290
291         if (strstr(cli->server_type, "Samba")) {
292                 cli->is_samba = True;
293         }
294
295         TALLOC_FREE(subreq);
296
297         status = cli_set_username(cli, "");
298         if (!NT_STATUS_IS_OK(status)) {
299                 tevent_req_nterror(req, status);
300                 return;
301         }
302         tevent_req_done(req);
303 }
304
305 NTSTATUS cli_session_setup_guest_recv(struct tevent_req *req)
306 {
307         return tevent_req_simple_recv_ntstatus(req);
308 }
309
310 static NTSTATUS cli_session_setup_guest(struct cli_state *cli)
311 {
312         TALLOC_CTX *frame = talloc_stackframe();
313         struct event_context *ev;
314         struct tevent_req *req;
315         NTSTATUS status = NT_STATUS_OK;
316
317         if (cli_has_async_calls(cli)) {
318                 /*
319                  * Can't use sync call while an async call is in flight
320                  */
321                 status = NT_STATUS_INVALID_PARAMETER;
322                 goto fail;
323         }
324
325         ev = event_context_init(frame);
326         if (ev == NULL) {
327                 status = NT_STATUS_NO_MEMORY;
328                 goto fail;
329         }
330
331         req = cli_session_setup_guest_send(frame, ev, cli);
332         if (req == NULL) {
333                 status = NT_STATUS_NO_MEMORY;
334                 goto fail;
335         }
336
337         if (!tevent_req_poll(req, ev)) {
338                 status = map_nt_error_from_unix(errno);
339                 goto fail;
340         }
341
342         status = cli_session_setup_guest_recv(req);
343  fail:
344         TALLOC_FREE(frame);
345         if (!NT_STATUS_IS_OK(status)) {
346                 cli_set_error(cli, status);
347         }
348         return status;
349 }
350
351 /****************************************************************************
352  Do a NT1 plaintext session setup.
353 ****************************************************************************/
354
355 static NTSTATUS cli_session_setup_plaintext(struct cli_state *cli,
356                                             const char *user, const char *pass,
357                                             const char *workgroup)
358 {
359         uint32 capabilities = cli_session_setup_capabilities(cli);
360         char *p;
361         NTSTATUS status;
362         fstring lanman;
363         
364         fstr_sprintf( lanman, "Samba %s", samba_version_string());
365
366         memset(cli->outbuf, '\0', smb_size);
367         cli_set_message(cli->outbuf,13,0,True);
368         SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
369         cli_setup_packet(cli);
370                         
371         SCVAL(cli->outbuf,smb_vwv0,0xFF);
372         SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
373         SSVAL(cli->outbuf,smb_vwv3,2);
374         SSVAL(cli->outbuf,smb_vwv4,cli->pid);
375         SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
376         SSVAL(cli->outbuf,smb_vwv8,0);
377         SIVAL(cli->outbuf,smb_vwv11,capabilities); 
378         p = smb_buf(cli->outbuf);
379         
380         /* check wether to send the ASCII or UNICODE version of the password */
381         
382         if ( (capabilities & CAP_UNICODE) == 0 ) {
383                 p += clistr_push(cli, p, pass, -1, STR_TERMINATE); /* password */
384                 SSVAL(cli->outbuf,smb_vwv7,PTR_DIFF(p, smb_buf(cli->outbuf)));
385         }
386         else {
387                 /* For ucs2 passwords clistr_push calls ucs2_align, which causes
388                  * the space taken by the unicode password to be one byte too
389                  * long (as we're on an odd byte boundary here). Reduce the
390                  * count by 1 to cope with this. Fixes smbclient against NetApp
391                  * servers which can't cope. Fix from
392                  * bryan.kolodziej@allenlund.com in bug #3840.
393                  */
394                 p += clistr_push(cli, p, pass, -1, STR_UNICODE|STR_TERMINATE); /* unicode password */
395                 SSVAL(cli->outbuf,smb_vwv8,PTR_DIFF(p, smb_buf(cli->outbuf))-1);        
396         }
397         
398         p += clistr_push(cli, p, user, -1, STR_TERMINATE); /* username */
399         p += clistr_push(cli, p, workgroup, -1, STR_TERMINATE); /* workgroup */
400         p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
401         p += clistr_push(cli, p, lanman, -1, STR_TERMINATE);
402         cli_setup_bcc(cli, p);
403
404         if (!cli_send_smb(cli) || !cli_receive_smb(cli)) {
405                 return cli_nt_error(cli);
406         }
407         
408         show_msg(cli->inbuf);
409         
410         if (cli_is_error(cli)) {
411                 return cli_nt_error(cli);
412         }
413
414         cli->vuid = SVAL(cli->inbuf,smb_uid);
415         p = smb_buf(cli->inbuf);
416         p += clistr_pull(cli->inbuf, cli->server_os, p, sizeof(fstring),
417                          -1, STR_TERMINATE);
418         p += clistr_pull(cli->inbuf, cli->server_type, p, sizeof(fstring),
419                          -1, STR_TERMINATE);
420         p += clistr_pull(cli->inbuf, cli->server_domain, p, sizeof(fstring),
421                          -1, STR_TERMINATE);
422         status = cli_set_username(cli, user);
423         if (!NT_STATUS_IS_OK(status)) {
424                 return status;
425         }
426         if (strstr(cli->server_type, "Samba")) {
427                 cli->is_samba = True;
428         }
429
430         return NT_STATUS_OK;
431 }
432
433 /****************************************************************************
434    do a NT1 NTLM/LM encrypted session setup - for when extended security
435    is not negotiated.
436    @param cli client state to create do session setup on
437    @param user username
438    @param pass *either* cleartext password (passlen !=24) or LM response.
439    @param ntpass NT response, implies ntpasslen >=24, implies pass is not clear
440    @param workgroup The user's domain.
441 ****************************************************************************/
442
443 static NTSTATUS cli_session_setup_nt1(struct cli_state *cli, const char *user, 
444                                       const char *pass, size_t passlen,
445                                       const char *ntpass, size_t ntpasslen,
446                                       const char *workgroup)
447 {
448         uint32 capabilities = cli_session_setup_capabilities(cli);
449         DATA_BLOB lm_response = data_blob_null;
450         DATA_BLOB nt_response = data_blob_null;
451         DATA_BLOB session_key = data_blob_null;
452         NTSTATUS result;
453         char *p;
454         bool ok;
455
456         if (passlen == 0) {
457                 /* do nothing - guest login */
458         } else if (passlen != 24) {
459                 if (lp_client_ntlmv2_auth()) {
460                         DATA_BLOB server_chal;
461                         DATA_BLOB names_blob;
462                         server_chal = data_blob(cli->secblob.data, MIN(cli->secblob.length, 8)); 
463
464                         /* note that the 'workgroup' here is a best guess - we don't know
465                            the server's domain at this point.  The 'server name' is also
466                            dodgy... 
467                         */
468                         names_blob = NTLMv2_generate_names_blob(NULL, cli->called.name, workgroup);
469
470                         if (!SMBNTLMv2encrypt(NULL, user, workgroup, pass, &server_chal, 
471                                               &names_blob,
472                                               &lm_response, &nt_response, NULL, &session_key)) {
473                                 data_blob_free(&names_blob);
474                                 data_blob_free(&server_chal);
475                                 return NT_STATUS_ACCESS_DENIED;
476                         }
477                         data_blob_free(&names_blob);
478                         data_blob_free(&server_chal);
479
480                 } else {
481                         uchar nt_hash[16];
482                         E_md4hash(pass, nt_hash);
483
484 #ifdef LANMAN_ONLY
485                         nt_response = data_blob_null;
486 #else
487                         nt_response = data_blob(NULL, 24);
488                         SMBNTencrypt(pass,cli->secblob.data,nt_response.data);
489 #endif
490                         /* non encrypted password supplied. Ignore ntpass. */
491                         if (lp_client_lanman_auth()) {
492                                 lm_response = data_blob(NULL, 24);
493                                 if (!SMBencrypt(pass,cli->secblob.data, lm_response.data)) {
494                                         /* Oops, the LM response is invalid, just put 
495                                            the NT response there instead */
496                                         data_blob_free(&lm_response);
497                                         lm_response = data_blob(nt_response.data, nt_response.length);
498                                 }
499                         } else {
500                                 /* LM disabled, place NT# in LM field instead */
501                                 lm_response = data_blob(nt_response.data, nt_response.length);
502                         }
503
504                         session_key = data_blob(NULL, 16);
505 #ifdef LANMAN_ONLY
506                         E_deshash(pass, session_key.data);
507                         memset(&session_key.data[8], '\0', 8);
508 #else
509                         SMBsesskeygen_ntv1(nt_hash, session_key.data);
510 #endif
511                 }
512                 cli_temp_set_signing(cli);
513         } else {
514                 /* pre-encrypted password supplied.  Only used for 
515                    security=server, can't do
516                    signing because we don't have original key */
517
518                 lm_response = data_blob(pass, passlen);
519                 nt_response = data_blob(ntpass, ntpasslen);
520         }
521
522         /* send a session setup command */
523         memset(cli->outbuf,'\0',smb_size);
524
525         cli_set_message(cli->outbuf,13,0,True);
526         SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
527         cli_setup_packet(cli);
528                         
529         SCVAL(cli->outbuf,smb_vwv0,0xFF);
530         SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
531         SSVAL(cli->outbuf,smb_vwv3,2);
532         SSVAL(cli->outbuf,smb_vwv4,cli->pid);
533         SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
534         SSVAL(cli->outbuf,smb_vwv7,lm_response.length);
535         SSVAL(cli->outbuf,smb_vwv8,nt_response.length);
536         SIVAL(cli->outbuf,smb_vwv11,capabilities); 
537         p = smb_buf(cli->outbuf);
538         if (lm_response.length) {
539                 memcpy(p,lm_response.data, lm_response.length); p += lm_response.length;
540         }
541         if (nt_response.length) {
542                 memcpy(p,nt_response.data, nt_response.length); p += nt_response.length;
543         }
544         p += clistr_push(cli, p, user, -1, STR_TERMINATE);
545
546         /* Upper case here might help some NTLMv2 implementations */
547         p += clistr_push(cli, p, workgroup, -1, STR_TERMINATE|STR_UPPER);
548         p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
549         p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
550         cli_setup_bcc(cli, p);
551
552         if (!cli_send_smb(cli) || !cli_receive_smb(cli)) {
553                 result = cli_nt_error(cli);
554                 goto end;
555         }
556
557         /* show_msg(cli->inbuf); */
558
559         if (cli_is_error(cli)) {
560                 result = cli_nt_error(cli);
561                 goto end;
562         }
563
564 #ifdef LANMAN_ONLY
565         ok = cli_simple_set_signing(cli, session_key, lm_response);
566 #else
567         ok = cli_simple_set_signing(cli, session_key, nt_response);
568 #endif
569         if (ok) {
570                 if (!cli_check_sign_mac(cli, cli->inbuf, 1)) {
571                         result = NT_STATUS_ACCESS_DENIED;
572                         goto end;
573                 }
574         }
575
576         /* use the returned vuid from now on */
577         cli->vuid = SVAL(cli->inbuf,smb_uid);
578         
579         p = smb_buf(cli->inbuf);
580         p += clistr_pull(cli->inbuf, cli->server_os, p, sizeof(fstring),
581                          -1, STR_TERMINATE);
582         p += clistr_pull(cli->inbuf, cli->server_type, p, sizeof(fstring),
583                          -1, STR_TERMINATE);
584         p += clistr_pull(cli->inbuf, cli->server_domain, p, sizeof(fstring),
585                          -1, STR_TERMINATE);
586
587         if (strstr(cli->server_type, "Samba")) {
588                 cli->is_samba = True;
589         }
590
591         result = cli_set_username(cli, user);
592         if (!NT_STATUS_IS_OK(result)) {
593                 goto end;
594         }
595
596         if (session_key.data) {
597                 /* Have plaintext orginal */
598                 cli_set_session_key(cli, session_key);
599         }
600
601         result = NT_STATUS_OK;
602 end:    
603         data_blob_free(&lm_response);
604         data_blob_free(&nt_response);
605         data_blob_free(&session_key);
606         return result;
607 }
608
609 /****************************************************************************
610  Send a extended security session setup blob
611 ****************************************************************************/
612
613 static bool cli_session_setup_blob_send(struct cli_state *cli, DATA_BLOB blob)
614 {
615         uint32 capabilities = cli_session_setup_capabilities(cli);
616         char *p;
617
618         capabilities |= CAP_EXTENDED_SECURITY;
619
620         /* send a session setup command */
621         memset(cli->outbuf,'\0',smb_size);
622
623         cli_set_message(cli->outbuf,12,0,True);
624         SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
625
626         cli_setup_packet(cli);
627
628         SCVAL(cli->outbuf,smb_vwv0,0xFF);
629         SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
630         SSVAL(cli->outbuf,smb_vwv3,2);
631         SSVAL(cli->outbuf,smb_vwv4,1);
632         SIVAL(cli->outbuf,smb_vwv5,0);
633         SSVAL(cli->outbuf,smb_vwv7,blob.length);
634         SIVAL(cli->outbuf,smb_vwv10,capabilities); 
635         p = smb_buf(cli->outbuf);
636         memcpy(p, blob.data, blob.length);
637         p += blob.length;
638         p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
639         p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
640         cli_setup_bcc(cli, p);
641         return cli_send_smb(cli);
642 }
643
644 /****************************************************************************
645  Send a extended security session setup blob, returning a reply blob.
646 ****************************************************************************/
647
648 static DATA_BLOB cli_session_setup_blob_receive(struct cli_state *cli)
649 {
650         DATA_BLOB blob2 = data_blob_null;
651         char *p;
652         size_t len;
653
654         if (!cli_receive_smb(cli))
655                 return blob2;
656
657         show_msg(cli->inbuf);
658
659         if (cli_is_error(cli) && !NT_STATUS_EQUAL(cli_nt_error(cli),
660                                                   NT_STATUS_MORE_PROCESSING_REQUIRED)) {
661                 return blob2;
662         }
663
664         /* use the returned vuid from now on */
665         cli->vuid = SVAL(cli->inbuf,smb_uid);
666
667         p = smb_buf(cli->inbuf);
668
669         blob2 = data_blob(p, SVAL(cli->inbuf, smb_vwv3));
670
671         p += blob2.length;
672         p += clistr_pull(cli->inbuf, cli->server_os, p, sizeof(fstring),
673                          -1, STR_TERMINATE);
674
675         /* w2k with kerberos doesn't properly null terminate this field */
676         len = smb_bufrem(cli->inbuf, p);
677         if (p + len < cli->inbuf + cli->bufsize+SAFETY_MARGIN - 2) {
678                 char *end_of_buf = p + len;
679
680                 SSVAL(p, len, 0);
681                 /* Now it's null terminated. */
682                 p += clistr_pull(cli->inbuf, cli->server_type, p, sizeof(fstring),
683                         -1, STR_TERMINATE);
684                 /*
685                  * See if there's another string. If so it's the
686                  * server domain (part of the 'standard' Samba
687                  * server signature).
688                  */
689                 if (p < end_of_buf) {
690                         p += clistr_pull(cli->inbuf, cli->server_domain, p, sizeof(fstring),
691                                 -1, STR_TERMINATE);
692                 }
693         } else {
694                 /*
695                  * No room to null terminate so we can't see if there
696                  * is another string (server_domain) afterwards.
697                  */
698                 p += clistr_pull(cli->inbuf, cli->server_type, p, sizeof(fstring),
699                                  len, 0);
700         }
701         return blob2;
702 }
703
704 /* The following is calculated from :
705  * (smb_size-4) = 35
706  * (smb_wcnt * 2) = 24 (smb_wcnt == 12 in cli_session_setup_blob_send() )
707  * (strlen("Unix") + 1 + strlen("Samba") + 1) * 2 = 22 (unicode strings at
708  * end of packet.
709  */
710
711 #define BASE_SESSSETUP_BLOB_PACKET_SIZE (35 + 24 + 22)
712
713 struct cli_sesssetup_blob_state {
714         struct tevent_context *ev;
715         struct cli_state *cli;
716         DATA_BLOB blob;
717         uint16_t max_blob_size;
718         uint16_t vwv[12];
719         uint8_t *buf;
720
721         NTSTATUS status;
722         char *inbuf;
723         DATA_BLOB ret_blob;
724 };
725
726 static bool cli_sesssetup_blob_next(struct cli_sesssetup_blob_state *state,
727                                     struct tevent_req **psubreq);
728 static void cli_sesssetup_blob_done(struct tevent_req *subreq);
729
730 static struct tevent_req *cli_sesssetup_blob_send(TALLOC_CTX *mem_ctx,
731                                                   struct tevent_context *ev,
732                                                   struct cli_state *cli,
733                                                   DATA_BLOB blob)
734 {
735         struct tevent_req *req, *subreq;
736         struct cli_sesssetup_blob_state *state;
737
738         req = tevent_req_create(mem_ctx, &state,
739                                 struct cli_sesssetup_blob_state);
740         if (req == NULL) {
741                 return NULL;
742         }
743         state->ev = ev;
744         state->blob = blob;
745         state->cli = cli;
746
747         if (cli->max_xmit < BASE_SESSSETUP_BLOB_PACKET_SIZE + 1) {
748                 DEBUG(1, ("cli_session_setup_blob: cli->max_xmit too small "
749                           "(was %u, need minimum %u)\n",
750                           (unsigned int)cli->max_xmit,
751                           BASE_SESSSETUP_BLOB_PACKET_SIZE));
752                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
753                 return tevent_req_post(req, ev);
754         }
755         state->max_blob_size =
756                 MIN(cli->max_xmit - BASE_SESSSETUP_BLOB_PACKET_SIZE, 0xFFFF);
757
758         if (!cli_sesssetup_blob_next(state, &subreq)) {
759                 tevent_req_nomem(NULL, req);
760                 return tevent_req_post(req, ev);
761         }
762         tevent_req_set_callback(subreq, cli_sesssetup_blob_done, req);
763         return req;
764 }
765
766 static bool cli_sesssetup_blob_next(struct cli_sesssetup_blob_state *state,
767                                     struct tevent_req **psubreq)
768 {
769         struct tevent_req *subreq;
770         uint16_t thistime;
771
772         SCVAL(state->vwv+0, 0, 0xFF);
773         SCVAL(state->vwv+0, 1, 0);
774         SSVAL(state->vwv+1, 0, 0);
775         SSVAL(state->vwv+2, 0, CLI_BUFFER_SIZE);
776         SSVAL(state->vwv+3, 0, 2);
777         SSVAL(state->vwv+4, 0, 1);
778         SIVAL(state->vwv+5, 0, 0);
779
780         thistime = MIN(state->blob.length, state->max_blob_size);
781         SSVAL(state->vwv+7, 0, thistime);
782
783         SSVAL(state->vwv+8, 0, 0);
784         SSVAL(state->vwv+9, 0, 0);
785         SIVAL(state->vwv+10, 0,
786               cli_session_setup_capabilities(state->cli)
787               | CAP_EXTENDED_SECURITY);
788
789         state->buf = (uint8_t *)talloc_memdup(state, state->blob.data,
790                                               thistime);
791         if (state->buf == NULL) {
792                 return false;
793         }
794         state->blob.data += thistime;
795         state->blob.length -= thistime;
796
797         state->buf = smb_bytes_push_str(state->buf, cli_ucs2(state->cli),
798                                         "Unix", 5, NULL);
799         state->buf = smb_bytes_push_str(state->buf, cli_ucs2(state->cli),
800                                         "Samba", 6, NULL);
801         if (state->buf == NULL) {
802                 return false;
803         }
804         subreq = cli_smb_send(state, state->ev, state->cli, SMBsesssetupX, 0,
805                               12, state->vwv,
806                               talloc_get_size(state->buf), state->buf);
807         if (subreq == NULL) {
808                 return false;
809         }
810         *psubreq = subreq;
811         return true;
812 }
813
814 static void cli_sesssetup_blob_done(struct tevent_req *subreq)
815 {
816         struct tevent_req *req = tevent_req_callback_data(
817                 subreq, struct tevent_req);
818         struct cli_sesssetup_blob_state *state = tevent_req_data(
819                 req, struct cli_sesssetup_blob_state);
820         struct cli_state *cli = state->cli;
821         uint8_t wct;
822         uint16_t *vwv;
823         uint32_t num_bytes;
824         uint8_t *bytes;
825         NTSTATUS status;
826         uint8_t *p;
827         uint16_t blob_length;
828
829         status = cli_smb_recv(subreq, 1, &wct, &vwv, &num_bytes, &bytes);
830         if (!NT_STATUS_IS_OK(status)
831             && !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
832                 TALLOC_FREE(subreq);
833                 tevent_req_nterror(req, status);
834                 return;
835         }
836
837         state->status = status;
838         TALLOC_FREE(state->buf);
839
840         state->inbuf = (char *)cli_smb_inbuf(subreq);
841         cli->vuid = SVAL(state->inbuf, smb_uid);
842
843         blob_length = SVAL(vwv+3, 0);
844         if (blob_length > num_bytes) {
845                 TALLOC_FREE(subreq);
846                 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
847                 return;
848         }
849         state->ret_blob = data_blob_const(bytes, blob_length);
850
851         p = bytes + blob_length;
852
853         p += clistr_pull(state->inbuf, cli->server_os,
854                          (char *)p, sizeof(fstring),
855                          bytes+num_bytes-p, STR_TERMINATE);
856         p += clistr_pull(state->inbuf, cli->server_type,
857                          (char *)p, sizeof(fstring),
858                          bytes+num_bytes-p, STR_TERMINATE);
859         p += clistr_pull(state->inbuf, cli->server_domain,
860                          (char *)p, sizeof(fstring),
861                          bytes+num_bytes-p, STR_TERMINATE);
862
863         if (strstr(cli->server_type, "Samba")) {
864                 cli->is_samba = True;
865         }
866
867         if (state->blob.length != 0) {
868                 TALLOC_FREE(subreq);
869                 /*
870                  * More to send
871                  */
872                 if (!cli_sesssetup_blob_next(state, &subreq)) {
873                         tevent_req_nomem(NULL, req);
874                         return;
875                 }
876                 tevent_req_set_callback(subreq, cli_sesssetup_blob_done, req);
877                 return;
878         }
879         tevent_req_done(req);
880 }
881
882 static NTSTATUS cli_sesssetup_blob_recv(struct tevent_req *req,
883                                         TALLOC_CTX *mem_ctx,
884                                         DATA_BLOB *pblob,
885                                         char **pinbuf)
886 {
887         struct cli_sesssetup_blob_state *state = tevent_req_data(
888                 req, struct cli_sesssetup_blob_state);
889         NTSTATUS status;
890         char *inbuf;
891
892         if (tevent_req_is_nterror(req, &status)) {
893                 state->cli->vuid = 0;
894                 return status;
895         }
896
897         inbuf = talloc_move(mem_ctx, &state->inbuf);
898         if (pblob != NULL) {
899                 *pblob = state->ret_blob;
900         }
901         if (pinbuf != NULL) {
902                 *pinbuf = inbuf;
903         }
904         /* could be NT_STATUS_MORE_PROCESSING_REQUIRED */
905         return state->status;
906 }
907
908 #ifdef HAVE_KRB5
909
910 /****************************************************************************
911  Use in-memory credentials cache
912 ****************************************************************************/
913
914 static void use_in_memory_ccache(void) {
915         setenv(KRB5_ENV_CCNAME, "MEMORY:cliconnect", 1);
916 }
917
918 /****************************************************************************
919  Do a spnego/kerberos encrypted session setup.
920 ****************************************************************************/
921
922 struct cli_session_setup_kerberos_state {
923         struct cli_state *cli;
924         DATA_BLOB negTokenTarg;
925         DATA_BLOB session_key_krb5;
926         ADS_STATUS ads_status;
927 };
928
929 static void cli_session_setup_kerberos_done(struct tevent_req *subreq);
930
931 static struct tevent_req *cli_session_setup_kerberos_send(
932         TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct cli_state *cli,
933         const char *principal, const char *workgroup)
934 {
935         struct tevent_req *req, *subreq;
936         struct cli_session_setup_kerberos_state *state;
937         int rc;
938
939         DEBUG(2,("Doing kerberos session setup\n"));
940
941         req = tevent_req_create(mem_ctx, &state,
942                                 struct cli_session_setup_kerberos_state);
943         if (req == NULL) {
944                 return NULL;
945         }
946         state->cli = cli;
947         state->ads_status = ADS_SUCCESS;
948
949         cli_temp_set_signing(cli);
950
951         /*
952          * Ok, this is cheated: spnego_gen_negTokenTarg can block if
953          * we have to acquire a ticket. To be fixed later :-)
954          */
955         rc = spnego_gen_negTokenTarg(principal, 0, &state->negTokenTarg,
956                                      &state->session_key_krb5, 0, NULL);
957         if (rc) {
958                 DEBUG(1, ("cli_session_setup_kerberos: "
959                           "spnego_gen_negTokenTarg failed: %s\n",
960                           error_message(rc)));
961                 state->ads_status = ADS_ERROR_KRB5(rc);
962                 tevent_req_nterror(req, NT_STATUS_UNSUCCESSFUL);
963                 return tevent_req_post(req, ev);
964         }
965
966 #if 0
967         file_save("negTokenTarg.dat", state->negTokenTarg.data,
968                   state->negTokenTarg.length);
969 #endif
970
971         subreq = cli_sesssetup_blob_send(state, ev, cli, state->negTokenTarg);
972         if (tevent_req_nomem(subreq, req)) {
973                 return tevent_req_post(req, ev);
974         }
975         tevent_req_set_callback(subreq, cli_session_setup_kerberos_done, req);
976         return req;
977 }
978
979 static void cli_session_setup_kerberos_done(struct tevent_req *subreq)
980 {
981         struct tevent_req *req = tevent_req_callback_data(
982                 subreq, struct tevent_req);
983         struct cli_session_setup_kerberos_state *state = tevent_req_data(
984                 req, struct cli_session_setup_kerberos_state);
985         char *inbuf = NULL;
986         NTSTATUS status;
987
988         status = cli_sesssetup_blob_recv(subreq, talloc_tos(), NULL, &inbuf);
989         if (!NT_STATUS_IS_OK(status)) {
990                 TALLOC_FREE(subreq);
991                 tevent_req_nterror(req, status);
992                 return;
993         }
994
995         cli_set_session_key(state->cli, state->session_key_krb5);
996
997         if (cli_simple_set_signing(state->cli, state->session_key_krb5,
998                                    data_blob_null)
999             && !cli_check_sign_mac(state->cli, inbuf, 1)) {
1000                 TALLOC_FREE(subreq);
1001                 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
1002                 return;
1003         }
1004         TALLOC_FREE(subreq);
1005         tevent_req_done(req);
1006 }
1007
1008 static ADS_STATUS cli_session_setup_kerberos_recv(struct tevent_req *req)
1009 {
1010         struct cli_session_setup_kerberos_state *state = tevent_req_data(
1011                 req, struct cli_session_setup_kerberos_state);
1012         NTSTATUS status;
1013
1014         if (tevent_req_is_nterror(req, &status)) {
1015                 return ADS_ERROR_NT(status);
1016         }
1017         return state->ads_status;
1018 }
1019
1020 static ADS_STATUS cli_session_setup_kerberos(struct cli_state *cli,
1021                                              const char *principal,
1022                                              const char *workgroup)
1023 {
1024         struct tevent_context *ev;
1025         struct tevent_req *req;
1026         ADS_STATUS status = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
1027
1028         if (cli_has_async_calls(cli)) {
1029                 return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
1030         }
1031         ev = tevent_context_init(talloc_tos());
1032         if (ev == NULL) {
1033                 goto fail;
1034         }
1035         req = cli_session_setup_kerberos_send(ev, ev, cli, principal,
1036                                               workgroup);
1037         if (req == NULL) {
1038                 goto fail;
1039         }
1040         if (!tevent_req_poll(req, ev)) {
1041                 status = ADS_ERROR_SYSTEM(errno);
1042                 goto fail;
1043         }
1044         status = cli_session_setup_kerberos_recv(req);
1045 fail:
1046         TALLOC_FREE(ev);
1047         return status;
1048 }
1049 #endif  /* HAVE_KRB5 */
1050
1051 /****************************************************************************
1052  Do a spnego/NTLMSSP encrypted session setup.
1053 ****************************************************************************/
1054
1055 struct cli_session_setup_ntlmssp_state {
1056         struct tevent_context *ev;
1057         struct cli_state *cli;
1058         struct ntlmssp_state *ntlmssp_state;
1059         int turn;
1060         DATA_BLOB blob_out;
1061 };
1062
1063 static int cli_session_setup_ntlmssp_state_destructor(
1064         struct cli_session_setup_ntlmssp_state *state)
1065 {
1066         if (state->ntlmssp_state != NULL) {
1067                 ntlmssp_end(&state->ntlmssp_state);
1068         }
1069         return 0;
1070 }
1071
1072 static void cli_session_setup_ntlmssp_done(struct tevent_req *req);
1073
1074 static struct tevent_req *cli_session_setup_ntlmssp_send(
1075         TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct cli_state *cli,
1076         const char *user, const char *pass, const char *domain)
1077 {
1078         struct tevent_req *req, *subreq;
1079         struct cli_session_setup_ntlmssp_state *state;
1080         NTSTATUS status;
1081         DATA_BLOB blob_out;
1082
1083         req = tevent_req_create(mem_ctx, &state,
1084                                 struct cli_session_setup_ntlmssp_state);
1085         if (req == NULL) {
1086                 return NULL;
1087         }
1088         state->ev = ev;
1089         state->cli = cli;
1090         state->turn = 1;
1091
1092         state->ntlmssp_state = NULL;
1093         talloc_set_destructor(
1094                 state, cli_session_setup_ntlmssp_state_destructor);
1095
1096         cli_temp_set_signing(cli);
1097
1098         status = ntlmssp_client_start(&state->ntlmssp_state);
1099         if (!NT_STATUS_IS_OK(status)) {
1100                 goto fail;
1101         }
1102         ntlmssp_want_feature(state->ntlmssp_state,
1103                              NTLMSSP_FEATURE_SESSION_KEY);
1104         status = ntlmssp_set_username(state->ntlmssp_state, user);
1105         if (!NT_STATUS_IS_OK(status)) {
1106                 goto fail;
1107         }
1108         status = ntlmssp_set_domain(state->ntlmssp_state, domain);
1109         if (!NT_STATUS_IS_OK(status)) {
1110                 goto fail;
1111         }
1112         status = ntlmssp_set_password(state->ntlmssp_state, pass);
1113         if (!NT_STATUS_IS_OK(status)) {
1114                 goto fail;
1115         }
1116         status = ntlmssp_update(state->ntlmssp_state, data_blob_null,
1117                                 &blob_out);
1118         if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1119                 goto fail;
1120         }
1121
1122         state->blob_out = gen_negTokenInit(OID_NTLMSSP, blob_out);
1123         data_blob_free(&blob_out);
1124
1125         subreq = cli_sesssetup_blob_send(state, ev, cli, state->blob_out);
1126         if (tevent_req_nomem(subreq, req)) {
1127                 return tevent_req_post(req, ev);
1128         }
1129         tevent_req_set_callback(subreq, cli_session_setup_ntlmssp_done, req);
1130         return req;
1131 fail:
1132         tevent_req_nterror(req, status);
1133         return tevent_req_post(req, ev);
1134 }
1135
1136 static void cli_session_setup_ntlmssp_done(struct tevent_req *subreq)
1137 {
1138         struct tevent_req *req = tevent_req_callback_data(
1139                 subreq, struct tevent_req);
1140         struct cli_session_setup_ntlmssp_state *state = tevent_req_data(
1141                 req, struct cli_session_setup_ntlmssp_state);
1142         DATA_BLOB blob_in, msg_in, blob_out;
1143         char *inbuf = NULL;
1144         bool parse_ret;
1145         NTSTATUS status;
1146
1147         status = cli_sesssetup_blob_recv(subreq, talloc_tos(), &blob_in,
1148                                          &inbuf);
1149         TALLOC_FREE(subreq);
1150         data_blob_free(&state->blob_out);
1151
1152         if (NT_STATUS_IS_OK(status)) {
1153                 if (state->cli->server_domain[0] == '\0') {
1154                         fstrcpy(state->cli->server_domain,
1155                                 state->ntlmssp_state->server_domain);
1156                 }
1157                 cli_set_session_key(
1158                         state->cli, state->ntlmssp_state->session_key);
1159
1160                 if (cli_simple_set_signing(
1161                             state->cli, state->ntlmssp_state->session_key,
1162                             data_blob_null)
1163                     && !cli_check_sign_mac(state->cli, inbuf, 1)) {
1164                         TALLOC_FREE(subreq);
1165                         tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
1166                         return;
1167                 }
1168                 TALLOC_FREE(subreq);
1169                 ntlmssp_end(&state->ntlmssp_state);
1170                 tevent_req_done(req);
1171                 return;
1172         }
1173         if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1174                 tevent_req_nterror(req, status);
1175                 return;
1176         }
1177
1178         if (blob_in.length == 0) {
1179                 tevent_req_nterror(req, NT_STATUS_UNSUCCESSFUL);
1180                 return;
1181         }
1182
1183         if ((state->turn == 1)
1184             && NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1185                 DATA_BLOB tmp_blob = data_blob_null;
1186                 /* the server might give us back two challenges */
1187                 parse_ret = spnego_parse_challenge(blob_in, &msg_in,
1188                                                    &tmp_blob);
1189                 data_blob_free(&tmp_blob);
1190         } else {
1191                 parse_ret = spnego_parse_auth_response(blob_in, status,
1192                                                        OID_NTLMSSP, &msg_in);
1193         }
1194         state->turn += 1;
1195
1196         if (!parse_ret) {
1197                 DEBUG(3,("Failed to parse auth response\n"));
1198                 if (NT_STATUS_IS_OK(status)
1199                     || NT_STATUS_EQUAL(status,
1200                                        NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1201                         tevent_req_nterror(
1202                                 req, NT_STATUS_INVALID_NETWORK_RESPONSE);
1203                         return;
1204                 }
1205         }
1206
1207         status = ntlmssp_update(state->ntlmssp_state, msg_in, &blob_out);
1208
1209         if (!NT_STATUS_IS_OK(status)
1210             && !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1211                 TALLOC_FREE(subreq);
1212                 ntlmssp_end(&state->ntlmssp_state);
1213                 tevent_req_nterror(req, status);
1214                 return;
1215         }
1216
1217         state->blob_out = spnego_gen_auth(blob_out);
1218         TALLOC_FREE(subreq);
1219         if (tevent_req_nomem(state->blob_out.data, req)) {
1220                 return;
1221         }
1222
1223         subreq = cli_sesssetup_blob_send(state, state->ev, state->cli,
1224                                          state->blob_out);
1225         if (tevent_req_nomem(subreq, req)) {
1226                 return;
1227         }
1228         tevent_req_set_callback(subreq, cli_session_setup_ntlmssp_done, req);
1229 }
1230
1231 static NTSTATUS cli_session_setup_ntlmssp_recv(struct tevent_req *req)
1232 {
1233         struct cli_session_setup_ntlmssp_state *state = tevent_req_data(
1234                 req, struct cli_session_setup_ntlmssp_state);
1235         NTSTATUS status;
1236
1237         if (tevent_req_is_nterror(req, &status)) {
1238                 state->cli->vuid = 0;
1239                 return status;
1240         }
1241         return NT_STATUS_OK;
1242 }
1243
1244 static NTSTATUS cli_session_setup_ntlmssp(struct cli_state *cli,
1245                                           const char *user,
1246                                           const char *pass,
1247                                           const char *domain)
1248 {
1249         struct tevent_context *ev;
1250         struct tevent_req *req;
1251         NTSTATUS status = NT_STATUS_NO_MEMORY;
1252
1253         if (cli_has_async_calls(cli)) {
1254                 return NT_STATUS_INVALID_PARAMETER;
1255         }
1256         ev = tevent_context_init(talloc_tos());
1257         if (ev == NULL) {
1258                 goto fail;
1259         }
1260         req = cli_session_setup_ntlmssp_send(ev, ev, cli, user, pass, domain);
1261         if (req == NULL) {
1262                 goto fail;
1263         }
1264         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
1265                 goto fail;
1266         }
1267         status = cli_session_setup_ntlmssp_recv(req);
1268 fail:
1269         TALLOC_FREE(ev);
1270         if (!NT_STATUS_IS_OK(status)) {
1271                 cli_set_error(cli, status);
1272         }
1273         return status;
1274 }
1275
1276 /****************************************************************************
1277  Do a spnego encrypted session setup.
1278
1279  user_domain: The shortname of the domain the user/machine is a member of.
1280  dest_realm: The realm we're connecting to, if NULL we use our default realm.
1281 ****************************************************************************/
1282
1283 ADS_STATUS cli_session_setup_spnego(struct cli_state *cli, const char *user, 
1284                               const char *pass, const char *user_domain,
1285                               const char * dest_realm)
1286 {
1287         char *principal = NULL;
1288         char *OIDs[ASN1_MAX_OIDS];
1289         int i;
1290         DATA_BLOB blob;
1291         const char *p = NULL;
1292         char *account = NULL;
1293         NTSTATUS status;
1294
1295         DEBUG(3,("Doing spnego session setup (blob length=%lu)\n", (unsigned long)cli->secblob.length));
1296
1297         /* the server might not even do spnego */
1298         if (cli->secblob.length <= 16) {
1299                 DEBUG(3,("server didn't supply a full spnego negprot\n"));
1300                 goto ntlmssp;
1301         }
1302
1303 #if 0
1304         file_save("negprot.dat", cli->secblob.data, cli->secblob.length);
1305 #endif
1306
1307         /* there is 16 bytes of GUID before the real spnego packet starts */
1308         blob = data_blob(cli->secblob.data+16, cli->secblob.length-16);
1309
1310         /* The server sent us the first part of the SPNEGO exchange in the
1311          * negprot reply. It is WRONG to depend on the principal sent in the
1312          * negprot reply, but right now we do it. If we don't receive one,
1313          * we try to best guess, then fall back to NTLM.  */
1314         if (!spnego_parse_negTokenInit(blob, OIDs, &principal)) {
1315                 data_blob_free(&blob);
1316                 return ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
1317         }
1318         data_blob_free(&blob);
1319
1320         /* make sure the server understands kerberos */
1321         for (i=0;OIDs[i];i++) {
1322                 if (i == 0)
1323                         DEBUG(3,("got OID=%s\n", OIDs[i]));
1324                 else
1325                         DEBUGADD(3,("got OID=%s\n", OIDs[i]));
1326                 if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 ||
1327                     strcmp(OIDs[i], OID_KERBEROS5) == 0) {
1328                         cli->got_kerberos_mechanism = True;
1329                 }
1330                 talloc_free(OIDs[i]);
1331         }
1332
1333         DEBUG(3,("got principal=%s\n", principal ? principal : "<null>"));
1334
1335         status = cli_set_username(cli, user);
1336         if (!NT_STATUS_IS_OK(status)) {
1337                 return ADS_ERROR_NT(status);
1338         }
1339
1340 #ifdef HAVE_KRB5
1341         /* If password is set we reauthenticate to kerberos server
1342          * and do not store results */
1343
1344         if (cli->got_kerberos_mechanism && cli->use_kerberos) {
1345                 ADS_STATUS rc;
1346
1347                 if (pass && *pass) {
1348                         int ret;
1349
1350                         use_in_memory_ccache();
1351                         ret = kerberos_kinit_password(user, pass, 0 /* no time correction for now */, NULL);
1352
1353                         if (ret){
1354                                 TALLOC_FREE(principal);
1355                                 DEBUG(0, ("Kinit failed: %s\n", error_message(ret)));
1356                                 if (cli->fallback_after_kerberos)
1357                                         goto ntlmssp;
1358                                 return ADS_ERROR_KRB5(ret);
1359                         }
1360                 }
1361
1362                 /* If we get a bad principal, try to guess it if
1363                    we have a valid host NetBIOS name.
1364                  */
1365                 if (strequal(principal, ADS_IGNORE_PRINCIPAL)) {
1366                         TALLOC_FREE(principal);
1367                 }
1368
1369                 if (principal == NULL &&
1370                         !is_ipaddress(cli->desthost) &&
1371                         !strequal(STAR_SMBSERVER,
1372                                 cli->desthost)) {
1373                         char *realm = NULL;
1374                         char *machine = NULL;
1375                         char *host = NULL;
1376                         DEBUG(3,("cli_session_setup_spnego: got a "
1377                                 "bad server principal, trying to guess ...\n"));
1378
1379                         host = strchr_m(cli->desthost, '.');
1380                         if (host) {
1381                                 machine = SMB_STRNDUP(cli->desthost,
1382                                         host - cli->desthost);
1383                         } else {
1384                                 machine = SMB_STRDUP(cli->desthost);
1385                         }
1386                         if (machine == NULL) {
1387                                 return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
1388                         }
1389
1390                         if (dest_realm) {
1391                                 realm = SMB_STRDUP(dest_realm);
1392                                 strupper_m(realm);
1393                         } else {
1394                                 realm = kerberos_get_default_realm_from_ccache();
1395                         }
1396                         if (realm && *realm) {
1397                                 principal = talloc_asprintf(NULL, "%s$@%s",
1398                                                         machine, realm);
1399                                 if (!principal) {
1400                                         SAFE_FREE(machine);
1401                                         SAFE_FREE(realm);
1402                                         return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
1403                                 }
1404                                 DEBUG(3,("cli_session_setup_spnego: guessed "
1405                                         "server principal=%s\n",
1406                                         principal ? principal : "<null>"));
1407                         }
1408                         SAFE_FREE(machine);
1409                         SAFE_FREE(realm);
1410                 }
1411
1412                 if (principal) {
1413                         rc = cli_session_setup_kerberos(cli, principal,
1414                                 dest_realm);
1415                         if (ADS_ERR_OK(rc) || !cli->fallback_after_kerberos) {
1416                                 TALLOC_FREE(principal);
1417                                 return rc;
1418                         }
1419                 }
1420         }
1421 #endif
1422
1423         TALLOC_FREE(principal);
1424
1425 ntlmssp:
1426
1427         account = talloc_strdup(talloc_tos(), user);
1428         if (!account) {
1429                 return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
1430         }
1431
1432         /* when falling back to ntlmssp while authenticating with a machine
1433          * account strip off the realm - gd */
1434
1435         if ((p = strchr_m(user, '@')) != NULL) {
1436                 account[PTR_DIFF(p,user)] = '\0';
1437         }
1438
1439         return ADS_ERROR_NT(cli_session_setup_ntlmssp(cli, account, pass, user_domain));
1440 }
1441
1442 /****************************************************************************
1443  Send a session setup. The username and workgroup is in UNIX character
1444  format and must be converted to DOS codepage format before sending. If the
1445  password is in plaintext, the same should be done.
1446 ****************************************************************************/
1447
1448 NTSTATUS cli_session_setup(struct cli_state *cli,
1449                            const char *user,
1450                            const char *pass, int passlen,
1451                            const char *ntpass, int ntpasslen,
1452                            const char *workgroup)
1453 {
1454         char *p;
1455         fstring user2;
1456
1457         if (user) {
1458                 fstrcpy(user2, user);
1459         } else {
1460                 user2[0] ='\0';
1461         }
1462
1463         if (!workgroup) {
1464                 workgroup = "";
1465         }
1466
1467         /* allow for workgroups as part of the username */
1468         if ((p=strchr_m(user2,'\\')) || (p=strchr_m(user2,'/')) ||
1469             (p=strchr_m(user2,*lp_winbind_separator()))) {
1470                 *p = 0;
1471                 user = p+1;
1472                 workgroup = user2;
1473         }
1474
1475         if (cli->protocol < PROTOCOL_LANMAN1) {
1476                 return NT_STATUS_OK;
1477         }
1478
1479         /* now work out what sort of session setup we are going to
1480            do. I have split this into separate functions to make the
1481            flow a bit easier to understand (tridge) */
1482
1483         /* if its an older server then we have to use the older request format */
1484
1485         if (cli->protocol < PROTOCOL_NT1) {
1486                 if (!lp_client_lanman_auth() && passlen != 24 && (*pass)) {
1487                         DEBUG(1, ("Server requested LM password but 'client lanman auth'"
1488                                   " is disabled\n"));
1489                         return NT_STATUS_ACCESS_DENIED;
1490                 }
1491
1492                 if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) == 0 &&
1493                     !lp_client_plaintext_auth() && (*pass)) {
1494                         DEBUG(1, ("Server requested plaintext password but "
1495                                   "'client plaintext auth' is disabled\n"));
1496                         return NT_STATUS_ACCESS_DENIED;
1497                 }
1498
1499                 return cli_session_setup_lanman2(cli, user, pass, passlen,
1500                                                  workgroup);
1501         }
1502
1503         /* if no user is supplied then we have to do an anonymous connection.
1504            passwords are ignored */
1505
1506         if (!user || !*user)
1507                 return cli_session_setup_guest(cli);
1508
1509         /* if the server is share level then send a plaintext null
1510            password at this point. The password is sent in the tree
1511            connect */
1512
1513         if ((cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL) == 0) 
1514                 return cli_session_setup_plaintext(cli, user, "", workgroup);
1515
1516         /* if the server doesn't support encryption then we have to use 
1517            plaintext. The second password is ignored */
1518
1519         if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) == 0) {
1520                 if (!lp_client_plaintext_auth() && (*pass)) {
1521                         DEBUG(1, ("Server requested plaintext password but "
1522                                   "'client plaintext auth' is disabled\n"));
1523                         return NT_STATUS_ACCESS_DENIED;
1524                 }
1525                 return cli_session_setup_plaintext(cli, user, pass, workgroup);
1526         }
1527
1528         /* if the server supports extended security then use SPNEGO */
1529
1530         if (cli->capabilities & CAP_EXTENDED_SECURITY) {
1531                 ADS_STATUS status = cli_session_setup_spnego(cli, user, pass,
1532                                                              workgroup, NULL);
1533                 if (!ADS_ERR_OK(status)) {
1534                         DEBUG(3, ("SPNEGO login failed: %s\n", ads_errstr(status)));
1535                         return ads_ntstatus(status);
1536                 }
1537         } else {
1538                 NTSTATUS status;
1539
1540                 /* otherwise do a NT1 style session setup */
1541                 status = cli_session_setup_nt1(cli, user, pass, passlen,
1542                                                ntpass, ntpasslen, workgroup);
1543                 if (!NT_STATUS_IS_OK(status)) {
1544                         DEBUG(3,("cli_session_setup: NT1 session setup "
1545                                  "failed: %s\n", nt_errstr(status)));
1546                         return status;
1547                 }
1548         }
1549
1550         if (strstr(cli->server_type, "Samba")) {
1551                 cli->is_samba = True;
1552         }
1553
1554         return NT_STATUS_OK;
1555 }
1556
1557 /****************************************************************************
1558  Send a uloggoff.
1559 *****************************************************************************/
1560
1561 bool cli_ulogoff(struct cli_state *cli)
1562 {
1563         memset(cli->outbuf,'\0',smb_size);
1564         cli_set_message(cli->outbuf,2,0,True);
1565         SCVAL(cli->outbuf,smb_com,SMBulogoffX);
1566         cli_setup_packet(cli);
1567         SSVAL(cli->outbuf,smb_vwv0,0xFF);
1568         SSVAL(cli->outbuf,smb_vwv2,0);  /* no additional info */
1569
1570         cli_send_smb(cli);
1571         if (!cli_receive_smb(cli))
1572                 return False;
1573
1574         if (cli_is_error(cli)) {
1575                 return False;
1576         }
1577
1578         cli->vuid = -1;
1579         return True;
1580 }
1581
1582 /****************************************************************************
1583  Send a tconX.
1584 ****************************************************************************/
1585
1586 struct cli_tcon_andx_state {
1587         struct cli_state *cli;
1588         uint16_t vwv[4];
1589         struct iovec bytes;
1590 };
1591
1592 static void cli_tcon_andx_done(struct tevent_req *subreq);
1593
1594 struct tevent_req *cli_tcon_andx_create(TALLOC_CTX *mem_ctx,
1595                                         struct event_context *ev,
1596                                         struct cli_state *cli,
1597                                         const char *share, const char *dev,
1598                                         const char *pass, int passlen,
1599                                         struct tevent_req **psmbreq)
1600 {
1601         struct tevent_req *req, *subreq;
1602         struct cli_tcon_andx_state *state;
1603         fstring pword;
1604         uint16_t *vwv;
1605         char *tmp = NULL;
1606         uint8_t *bytes;
1607
1608         req = tevent_req_create(mem_ctx, &state, struct cli_tcon_andx_state);
1609         if (req == NULL) {
1610                 return NULL;
1611         }
1612         state->cli = cli;
1613         vwv = state->vwv;
1614
1615         fstrcpy(cli->share, share);
1616
1617         /* in user level security don't send a password now */
1618         if (cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL) {
1619                 passlen = 1;
1620                 pass = "";
1621         } else if (pass == NULL) {
1622                 DEBUG(1, ("Server not using user level security and no "
1623                           "password supplied.\n"));
1624                 goto access_denied;
1625         }
1626
1627         if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) &&
1628             *pass && passlen != 24) {
1629                 if (!lp_client_lanman_auth()) {
1630                         DEBUG(1, ("Server requested LANMAN password "
1631                                   "(share-level security) but "
1632                                   "'client lanman auth' is disabled\n"));
1633                         goto access_denied;
1634                 }
1635
1636                 /*
1637                  * Non-encrypted passwords - convert to DOS codepage before
1638                  * encryption.
1639                  */
1640                 passlen = 24;
1641                 SMBencrypt(pass, cli->secblob.data, (uchar *)pword);
1642         } else {
1643                 if((cli->sec_mode & (NEGOTIATE_SECURITY_USER_LEVEL
1644                                      |NEGOTIATE_SECURITY_CHALLENGE_RESPONSE))
1645                    == 0) {
1646                         if (!lp_client_plaintext_auth() && (*pass)) {
1647                                 DEBUG(1, ("Server requested plaintext "
1648                                           "password but 'client plaintext "
1649                                           "auth' is disabled\n"));
1650                                 goto access_denied;
1651                         }
1652
1653                         /*
1654                          * Non-encrypted passwords - convert to DOS codepage
1655                          * before using.
1656                          */
1657                         passlen = clistr_push(cli, pword, pass, sizeof(pword),
1658                                               STR_TERMINATE);
1659                         if (passlen == -1) {
1660                                 DEBUG(1, ("clistr_push(pword) failed\n"));
1661                                 goto access_denied;
1662                         }
1663                 } else {
1664                         if (passlen) {
1665                                 memcpy(pword, pass, passlen);
1666                         }
1667                 }
1668         }
1669
1670         SCVAL(vwv+0, 0, 0xFF);
1671         SCVAL(vwv+0, 1, 0);
1672         SSVAL(vwv+1, 0, 0);
1673         SSVAL(vwv+2, 0, TCONX_FLAG_EXTENDED_RESPONSE);
1674         SSVAL(vwv+3, 0, passlen);
1675
1676         if (passlen) {
1677                 bytes = (uint8_t *)talloc_memdup(state, pword, passlen);
1678         } else {
1679                 bytes = talloc_array(state, uint8_t, 0);
1680         }
1681
1682         /*
1683          * Add the sharename
1684          */
1685         tmp = talloc_asprintf_strupper_m(talloc_tos(), "\\\\%s\\%s",
1686                                          cli->desthost, share);
1687         if (tmp == NULL) {
1688                 TALLOC_FREE(req);
1689                 return NULL;
1690         }
1691         bytes = smb_bytes_push_str(bytes, cli_ucs2(cli), tmp, strlen(tmp)+1,
1692                                    NULL);
1693         TALLOC_FREE(tmp);
1694
1695         /*
1696          * Add the devicetype
1697          */
1698         tmp = talloc_strdup_upper(talloc_tos(), dev);
1699         if (tmp == NULL) {
1700                 TALLOC_FREE(req);
1701                 return NULL;
1702         }
1703         bytes = smb_bytes_push_str(bytes, false, tmp, strlen(tmp)+1, NULL);
1704         TALLOC_FREE(tmp);
1705
1706         if (bytes == NULL) {
1707                 TALLOC_FREE(req);
1708                 return NULL;
1709         }
1710
1711         state->bytes.iov_base = (void *)bytes;
1712         state->bytes.iov_len = talloc_get_size(bytes);
1713
1714         subreq = cli_smb_req_create(state, ev, cli, SMBtconX, 0, 4, vwv,
1715                                     1, &state->bytes);
1716         if (subreq == NULL) {
1717                 TALLOC_FREE(req);
1718                 return NULL;
1719         }
1720         tevent_req_set_callback(subreq, cli_tcon_andx_done, req);
1721         *psmbreq = subreq;
1722         return req;
1723
1724  access_denied:
1725         tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
1726         return tevent_req_post(req, ev);
1727 }
1728
1729 struct tevent_req *cli_tcon_andx_send(TALLOC_CTX *mem_ctx,
1730                                       struct event_context *ev,
1731                                       struct cli_state *cli,
1732                                       const char *share, const char *dev,
1733                                       const char *pass, int passlen)
1734 {
1735         struct tevent_req *req, *subreq;
1736         NTSTATUS status;
1737
1738         req = cli_tcon_andx_create(mem_ctx, ev, cli, share, dev, pass, passlen,
1739                                    &subreq);
1740         if (req == NULL) {
1741                 return NULL;
1742         }
1743         status = cli_smb_req_send(subreq);
1744         if (!NT_STATUS_IS_OK(status)) {
1745                 tevent_req_nterror(req, status);
1746                 return tevent_req_post(req, ev);
1747         }
1748         return req;
1749 }
1750
1751 static void cli_tcon_andx_done(struct tevent_req *subreq)
1752 {
1753         struct tevent_req *req = tevent_req_callback_data(
1754                 subreq, struct tevent_req);
1755         struct cli_tcon_andx_state *state = tevent_req_data(
1756                 req, struct cli_tcon_andx_state);
1757         struct cli_state *cli = state->cli;
1758         char *inbuf = (char *)cli_smb_inbuf(subreq);
1759         uint8_t wct;
1760         uint16_t *vwv;
1761         uint32_t num_bytes;
1762         uint8_t *bytes;
1763         NTSTATUS status;
1764
1765         status = cli_smb_recv(subreq, 0, &wct, &vwv, &num_bytes, &bytes);
1766         if (!NT_STATUS_IS_OK(status)) {
1767                 TALLOC_FREE(subreq);
1768                 tevent_req_nterror(req, status);
1769                 return;
1770         }
1771
1772         clistr_pull(inbuf, cli->dev, bytes, sizeof(fstring), num_bytes,
1773                     STR_TERMINATE|STR_ASCII);
1774
1775         if ((cli->protocol >= PROTOCOL_NT1) && (num_bytes == 3)) {
1776                 /* almost certainly win95 - enable bug fixes */
1777                 cli->win95 = True;
1778         }
1779
1780         /*
1781          * Make sure that we have the optional support 16-bit field. WCT > 2.
1782          * Avoids issues when connecting to Win9x boxes sharing files
1783          */
1784
1785         cli->dfsroot = false;
1786
1787         if ((wct > 2) && (cli->protocol >= PROTOCOL_LANMAN2)) {
1788                 cli->dfsroot = ((SVAL(vwv+2, 0) & SMB_SHARE_IN_DFS) != 0);
1789         }
1790
1791         cli->cnum = SVAL(inbuf,smb_tid);
1792         tevent_req_done(req);
1793 }
1794
1795 NTSTATUS cli_tcon_andx_recv(struct tevent_req *req)
1796 {
1797         return tevent_req_simple_recv_ntstatus(req);
1798 }
1799
1800 NTSTATUS cli_tcon_andx(struct cli_state *cli, const char *share,
1801                        const char *dev, const char *pass, int passlen)
1802 {
1803         TALLOC_CTX *frame = talloc_stackframe();
1804         struct event_context *ev;
1805         struct tevent_req *req;
1806         NTSTATUS status = NT_STATUS_OK;
1807
1808         if (cli_has_async_calls(cli)) {
1809                 /*
1810                  * Can't use sync call while an async call is in flight
1811                  */
1812                 status = NT_STATUS_INVALID_PARAMETER;
1813                 goto fail;
1814         }
1815
1816         ev = event_context_init(frame);
1817         if (ev == NULL) {
1818                 status = NT_STATUS_NO_MEMORY;
1819                 goto fail;
1820         }
1821
1822         req = cli_tcon_andx_send(frame, ev, cli, share, dev, pass, passlen);
1823         if (req == NULL) {
1824                 status = NT_STATUS_NO_MEMORY;
1825                 goto fail;
1826         }
1827
1828         if (!tevent_req_poll(req, ev)) {
1829                 status = map_nt_error_from_unix(errno);
1830                 goto fail;
1831         }
1832
1833         status = cli_tcon_andx_recv(req);
1834  fail:
1835         TALLOC_FREE(frame);
1836         if (!NT_STATUS_IS_OK(status)) {
1837                 cli_set_error(cli, status);
1838         }
1839         return status;
1840 }
1841
1842 /****************************************************************************
1843  Send a tree disconnect.
1844 ****************************************************************************/
1845
1846 bool cli_tdis(struct cli_state *cli)
1847 {
1848         memset(cli->outbuf,'\0',smb_size);
1849         cli_set_message(cli->outbuf,0,0,True);
1850         SCVAL(cli->outbuf,smb_com,SMBtdis);
1851         SSVAL(cli->outbuf,smb_tid,cli->cnum);
1852         cli_setup_packet(cli);
1853
1854         cli_send_smb(cli);
1855         if (!cli_receive_smb(cli))
1856                 return False;
1857
1858         if (cli_is_error(cli)) {
1859                 return False;
1860         }
1861
1862         cli->cnum = -1;
1863         return True;
1864 }
1865
1866 /****************************************************************************
1867  Send a negprot command.
1868 ****************************************************************************/
1869
1870 void cli_negprot_sendsync(struct cli_state *cli)
1871 {
1872         char *p;
1873         int numprots;
1874
1875         if (cli->protocol < PROTOCOL_NT1)
1876                 cli->use_spnego = False;
1877
1878         memset(cli->outbuf,'\0',smb_size);
1879
1880         /* setup the protocol strings */
1881         cli_set_message(cli->outbuf,0,0,True);
1882
1883         p = smb_buf(cli->outbuf);
1884         for (numprots=0; numprots < ARRAY_SIZE(prots); numprots++) {
1885                 if (prots[numprots].prot > cli->protocol) {
1886                         break;
1887                 }
1888                 *p++ = 2;
1889                 p += clistr_push(cli, p, prots[numprots].name, -1, STR_TERMINATE);
1890         }
1891
1892         SCVAL(cli->outbuf,smb_com,SMBnegprot);
1893         cli_setup_bcc(cli, p);
1894         cli_setup_packet(cli);
1895
1896         SCVAL(smb_buf(cli->outbuf),0,2);
1897
1898         cli_send_smb(cli);
1899 }
1900
1901 /****************************************************************************
1902  Send a negprot command.
1903 ****************************************************************************/
1904
1905 struct cli_negprot_state {
1906         struct cli_state *cli;
1907 };
1908
1909 static void cli_negprot_done(struct tevent_req *subreq);
1910
1911 struct tevent_req *cli_negprot_send(TALLOC_CTX *mem_ctx,
1912                                     struct event_context *ev,
1913                                     struct cli_state *cli)
1914 {
1915         struct tevent_req *req, *subreq;
1916         struct cli_negprot_state *state;
1917         uint8_t *bytes = NULL;
1918         int numprots;
1919         uint16_t cnum;
1920
1921         req = tevent_req_create(mem_ctx, &state, struct cli_negprot_state);
1922         if (req == NULL) {
1923                 return NULL;
1924         }
1925         state->cli = cli;
1926
1927         if (cli->protocol < PROTOCOL_NT1)
1928                 cli->use_spnego = False;
1929
1930         /* setup the protocol strings */
1931         for (numprots=0; numprots < ARRAY_SIZE(prots); numprots++) {
1932                 uint8_t c = 2;
1933                 if (prots[numprots].prot > cli->protocol) {
1934                         break;
1935                 }
1936                 bytes = (uint8_t *)talloc_append_blob(
1937                         state, bytes, data_blob_const(&c, sizeof(c)));
1938                 if (tevent_req_nomem(bytes, req)) {
1939                         return tevent_req_post(req, ev);
1940                 }
1941                 bytes = smb_bytes_push_str(bytes, false,
1942                                            prots[numprots].name,
1943                                            strlen(prots[numprots].name)+1,
1944                                            NULL);
1945                 if (tevent_req_nomem(bytes, req)) {
1946                         return tevent_req_post(req, ev);
1947                 }
1948         }
1949
1950         cnum = cli->cnum;
1951
1952         cli->cnum = 0;
1953         subreq = cli_smb_send(state, ev, cli, SMBnegprot, 0, 0, NULL,
1954                               talloc_get_size(bytes), bytes);
1955         cli->cnum = cnum;
1956
1957         if (tevent_req_nomem(subreq, req)) {
1958                 return tevent_req_post(req, ev);
1959         }
1960         tevent_req_set_callback(subreq, cli_negprot_done, req);
1961         return req;
1962 }
1963
1964 static void cli_negprot_done(struct tevent_req *subreq)
1965 {
1966         struct tevent_req *req = tevent_req_callback_data(
1967                 subreq, struct tevent_req);
1968         struct cli_negprot_state *state = tevent_req_data(
1969                 req, struct cli_negprot_state);
1970         struct cli_state *cli = state->cli;
1971         uint8_t wct;
1972         uint16_t *vwv;
1973         uint32_t num_bytes;
1974         uint8_t *bytes;
1975         NTSTATUS status;
1976         uint16_t protnum;
1977
1978         status = cli_smb_recv(subreq, 1, &wct, &vwv, &num_bytes, &bytes);
1979         if (!NT_STATUS_IS_OK(status)) {
1980                 TALLOC_FREE(subreq);
1981                 tevent_req_nterror(req, status);
1982                 return;
1983         }
1984
1985         protnum = SVAL(vwv, 0);
1986
1987         if ((protnum >= ARRAY_SIZE(prots))
1988             || (prots[protnum].prot > cli->protocol)) {
1989                 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
1990                 return;
1991         }
1992
1993         cli->protocol = prots[protnum].prot;
1994
1995         if ((cli->protocol < PROTOCOL_NT1) &&
1996             client_is_signing_mandatory(cli)) {
1997                 DEBUG(0,("cli_negprot: SMB signing is mandatory and the selected protocol level doesn't support it.\n"));
1998                 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
1999                 return;
2000         }
2001
2002         if (cli->protocol >= PROTOCOL_NT1) {    
2003                 struct timespec ts;
2004                 bool negotiated_smb_signing = false;
2005
2006                 /* NT protocol */
2007                 cli->sec_mode = CVAL(vwv + 1, 0);
2008                 cli->max_mux = SVAL(vwv + 1, 1);
2009                 cli->max_xmit = IVAL(vwv + 3, 1);
2010                 cli->sesskey = IVAL(vwv + 7, 1);
2011                 cli->serverzone = SVALS(vwv + 15, 1);
2012                 cli->serverzone *= 60;
2013                 /* this time arrives in real GMT */
2014                 ts = interpret_long_date(((char *)(vwv+11))+1);
2015                 cli->servertime = ts.tv_sec;
2016                 cli->secblob = data_blob(bytes, num_bytes);
2017                 cli->capabilities = IVAL(vwv + 9, 1);
2018                 if (cli->capabilities & CAP_RAW_MODE) {
2019                         cli->readbraw_supported = True;
2020                         cli->writebraw_supported = True;      
2021                 }
2022                 /* work out if they sent us a workgroup */
2023                 if (!(cli->capabilities & CAP_EXTENDED_SECURITY) &&
2024                     smb_buflen(cli->inbuf) > 8) {
2025                         clistr_pull(cli->inbuf, cli->server_domain,
2026                                     bytes+8, sizeof(cli->server_domain),
2027                                     num_bytes-8,
2028                                     STR_UNICODE|STR_NOALIGN);
2029                 }
2030
2031                 /*
2032                  * As signing is slow we only turn it on if either the client or
2033                  * the server require it. JRA.
2034                  */
2035
2036                 if (cli->sec_mode & NEGOTIATE_SECURITY_SIGNATURES_REQUIRED) {
2037                         /* Fail if server says signing is mandatory and we don't want to support it. */
2038                         if (!client_is_signing_allowed(cli)) {
2039                                 DEBUG(0,("cli_negprot: SMB signing is mandatory and we have disabled it.\n"));
2040                                 tevent_req_nterror(req,
2041                                                    NT_STATUS_ACCESS_DENIED);
2042                                 return;
2043                         }
2044                         negotiated_smb_signing = true;
2045                 } else if (client_is_signing_mandatory(cli) && client_is_signing_allowed(cli)) {
2046                         /* Fail if client says signing is mandatory and the server doesn't support it. */
2047                         if (!(cli->sec_mode & NEGOTIATE_SECURITY_SIGNATURES_ENABLED)) {
2048                                 DEBUG(1,("cli_negprot: SMB signing is mandatory and the server doesn't support it.\n"));
2049                                 tevent_req_nterror(req,
2050                                                    NT_STATUS_ACCESS_DENIED);
2051                                 return;
2052                         }
2053                         negotiated_smb_signing = true;
2054                 } else if (cli->sec_mode & NEGOTIATE_SECURITY_SIGNATURES_ENABLED) {
2055                         negotiated_smb_signing = true;
2056                 }
2057
2058                 if (negotiated_smb_signing) {
2059                         cli_set_signing_negotiated(cli);
2060                 }
2061
2062                 if (cli->capabilities & (CAP_LARGE_READX|CAP_LARGE_WRITEX)) {
2063                         SAFE_FREE(cli->outbuf);
2064                         SAFE_FREE(cli->inbuf);
2065                         cli->outbuf = (char *)SMB_MALLOC(CLI_SAMBA_MAX_LARGE_READX_SIZE+LARGE_WRITEX_HDR_SIZE+SAFETY_MARGIN);
2066                         cli->inbuf = (char *)SMB_MALLOC(CLI_SAMBA_MAX_LARGE_READX_SIZE+LARGE_WRITEX_HDR_SIZE+SAFETY_MARGIN);
2067                         cli->bufsize = CLI_SAMBA_MAX_LARGE_READX_SIZE + LARGE_WRITEX_HDR_SIZE;
2068                 }
2069
2070         } else if (cli->protocol >= PROTOCOL_LANMAN1) {
2071                 cli->use_spnego = False;
2072                 cli->sec_mode = SVAL(vwv + 1, 0);
2073                 cli->max_xmit = SVAL(vwv + 2, 0);
2074                 cli->max_mux = SVAL(vwv + 3, 0);
2075                 cli->sesskey = IVAL(vwv + 6, 0);
2076                 cli->serverzone = SVALS(vwv + 10, 0);
2077                 cli->serverzone *= 60;
2078                 /* this time is converted to GMT by make_unix_date */
2079                 cli->servertime = cli_make_unix_date(
2080                         cli, (char *)(vwv + 8));
2081                 cli->readbraw_supported = ((SVAL(vwv + 5, 0) & 0x1) != 0);
2082                 cli->writebraw_supported = ((SVAL(vwv + 5, 0) & 0x2) != 0);
2083                 cli->secblob = data_blob(bytes, num_bytes);
2084         } else {
2085                 /* the old core protocol */
2086                 cli->use_spnego = False;
2087                 cli->sec_mode = 0;
2088                 cli->serverzone = get_time_zone(time(NULL));
2089         }
2090
2091         cli->max_xmit = MIN(cli->max_xmit, CLI_BUFFER_SIZE);
2092
2093         /* a way to force ascii SMB */
2094         if (getenv("CLI_FORCE_ASCII"))
2095                 cli->capabilities &= ~CAP_UNICODE;
2096
2097         tevent_req_done(req);
2098 }
2099
2100 NTSTATUS cli_negprot_recv(struct tevent_req *req)
2101 {
2102         return tevent_req_simple_recv_ntstatus(req);
2103 }
2104
2105 NTSTATUS cli_negprot(struct cli_state *cli)
2106 {
2107         TALLOC_CTX *frame = talloc_stackframe();
2108         struct event_context *ev;
2109         struct tevent_req *req;
2110         NTSTATUS status = NT_STATUS_OK;
2111
2112         if (cli_has_async_calls(cli)) {
2113                 /*
2114                  * Can't use sync call while an async call is in flight
2115                  */
2116                 status = NT_STATUS_INVALID_PARAMETER;
2117                 goto fail;
2118         }
2119
2120         ev = event_context_init(frame);
2121         if (ev == NULL) {
2122                 status = NT_STATUS_NO_MEMORY;
2123                 goto fail;
2124         }
2125
2126         req = cli_negprot_send(frame, ev, cli);
2127         if (req == NULL) {
2128                 status = NT_STATUS_NO_MEMORY;
2129                 goto fail;
2130         }
2131
2132         if (!tevent_req_poll(req, ev)) {
2133                 status = map_nt_error_from_unix(errno);
2134                 goto fail;
2135         }
2136
2137         status = cli_negprot_recv(req);
2138  fail:
2139         TALLOC_FREE(frame);
2140         if (!NT_STATUS_IS_OK(status)) {
2141                 cli_set_error(cli, status);
2142         }
2143         return status;
2144 }
2145
2146 /****************************************************************************
2147  Send a session request. See rfc1002.txt 4.3 and 4.3.2.
2148 ****************************************************************************/
2149
2150 bool cli_session_request(struct cli_state *cli,
2151                          struct nmb_name *calling, struct nmb_name *called)
2152 {
2153         char *p;
2154         int len = 4;
2155         char *tmp;
2156
2157         /* 445 doesn't have session request */
2158         if (cli->port == 445)
2159                 return True;
2160
2161         memcpy(&(cli->calling), calling, sizeof(*calling));
2162         memcpy(&(cli->called ), called , sizeof(*called ));
2163
2164         /* put in the destination name */
2165
2166         tmp = name_mangle(talloc_tos(), cli->called.name,
2167                           cli->called.name_type);
2168         if (tmp == NULL) {
2169                 return false;
2170         }
2171
2172         p = cli->outbuf+len;
2173         memcpy(p, tmp, name_len(tmp));
2174         len += name_len(tmp);
2175         TALLOC_FREE(tmp);
2176
2177         /* and my name */
2178
2179         tmp = name_mangle(talloc_tos(), cli->calling.name,
2180                           cli->calling.name_type);
2181         if (tmp == NULL) {
2182                 return false;
2183         }
2184
2185         p = cli->outbuf+len;
2186         memcpy(p, tmp, name_len(tmp));
2187         len += name_len(tmp);
2188         TALLOC_FREE(tmp);
2189
2190         /* send a session request (RFC 1002) */
2191         /* setup the packet length
2192          * Remove four bytes from the length count, since the length
2193          * field in the NBT Session Service header counts the number
2194          * of bytes which follow.  The cli_send_smb() function knows
2195          * about this and accounts for those four bytes.
2196          * CRH.
2197          */
2198         len -= 4;
2199         _smb_setlen(cli->outbuf,len);
2200         SCVAL(cli->outbuf,0,0x81);
2201
2202         cli_send_smb(cli);
2203         DEBUG(5,("Sent session request\n"));
2204
2205         if (!cli_receive_smb(cli))
2206                 return False;
2207
2208         if (CVAL(cli->inbuf,0) == 0x84) {
2209                 /* C. Hoch  9/14/95 Start */
2210                 /* For information, here is the response structure.
2211                  * We do the byte-twiddling to for portability.
2212                 struct RetargetResponse{
2213                 unsigned char type;
2214                 unsigned char flags;
2215                 int16 length;
2216                 int32 ip_addr;
2217                 int16 port;
2218                 };
2219                 */
2220                 uint16_t port = (CVAL(cli->inbuf,8)<<8)+CVAL(cli->inbuf,9);
2221                 struct in_addr dest_ip;
2222                 NTSTATUS status;
2223
2224                 /* SESSION RETARGET */
2225                 putip((char *)&dest_ip,cli->inbuf+4);
2226                 in_addr_to_sockaddr_storage(&cli->dest_ss, dest_ip);
2227
2228                 status = open_socket_out(&cli->dest_ss, port,
2229                                          LONG_CONNECT_TIMEOUT, &cli->fd);
2230                 if (!NT_STATUS_IS_OK(status)) {
2231                         return False;
2232                 }
2233
2234                 DEBUG(3,("Retargeted\n"));
2235
2236                 set_socket_options(cli->fd, lp_socket_options());
2237
2238                 /* Try again */
2239                 {
2240                         static int depth;
2241                         bool ret;
2242                         if (depth > 4) {
2243                                 DEBUG(0,("Retarget recursion - failing\n"));
2244                                 return False;
2245                         }
2246                         depth++;
2247                         ret = cli_session_request(cli, calling, called);
2248                         depth--;
2249                         return ret;
2250                 }
2251         } /* C. Hoch 9/14/95 End */
2252
2253         if (CVAL(cli->inbuf,0) != 0x82) {
2254                 /* This is the wrong place to put the error... JRA. */
2255                 cli->rap_error = CVAL(cli->inbuf,4);
2256                 return False;
2257         }
2258         return(True);
2259 }
2260
2261 struct fd_struct {
2262         int fd;
2263 };
2264
2265 static void smb_sock_connected(struct tevent_req *req)
2266 {
2267         struct fd_struct *pfd = tevent_req_callback_data(
2268                 req, struct fd_struct);
2269         int fd;
2270         NTSTATUS status;
2271
2272         status = open_socket_out_defer_recv(req, &fd);
2273         if (NT_STATUS_IS_OK(status)) {
2274                 pfd->fd = fd;
2275         }
2276 }
2277
2278 static NTSTATUS open_smb_socket(const struct sockaddr_storage *pss,
2279                                 uint16_t *port, int timeout, int *pfd)
2280 {
2281         struct event_context *ev;
2282         struct tevent_req *r139, *r445;
2283         struct fd_struct *fd139, *fd445;
2284         NTSTATUS status = NT_STATUS_NO_MEMORY;
2285
2286         if (*port != 0) {
2287                 return open_socket_out(pss, *port, timeout, pfd);
2288         }
2289
2290         ev = event_context_init(talloc_tos());
2291         if (ev == NULL) {
2292                 return NT_STATUS_NO_MEMORY;
2293         }
2294
2295         fd139 = talloc(ev, struct fd_struct);
2296         if (fd139 == NULL) {
2297                 goto done;
2298         }
2299         fd139->fd = -1;
2300
2301         fd445 = talloc(ev, struct fd_struct);
2302         if (fd445 == NULL) {
2303                 goto done;
2304         }
2305         fd445->fd = -1;
2306
2307         r445 = open_socket_out_defer_send(ev, ev, timeval_set(0, 0),
2308                                           pss, 445, timeout);
2309         r139 = open_socket_out_defer_send(ev, ev, timeval_set(0, 3000),
2310                                           pss, 139, timeout);
2311         if ((r445 == NULL) || (r139 == NULL)) {
2312                 goto done;
2313         }
2314         tevent_req_set_callback(r445, smb_sock_connected, fd445);
2315         tevent_req_set_callback(r139, smb_sock_connected, fd139);
2316
2317         while ((fd445->fd == -1) && (fd139->fd == -1)
2318                && (tevent_req_is_in_progress(r139)
2319                    || tevent_req_is_in_progress(r445))) {
2320                 event_loop_once(ev);
2321         }
2322
2323         if ((fd139->fd != -1) && (fd445->fd != -1)) {
2324                 close(fd139->fd);
2325                 fd139->fd = -1;
2326         }
2327
2328         if (fd445->fd != -1) {
2329                 *port = 445;
2330                 *pfd = fd445->fd;
2331                 status = NT_STATUS_OK;
2332                 goto done;
2333         }
2334         if (fd139->fd != -1) {
2335                 *port = 139;
2336                 *pfd = fd139->fd;
2337                 status = NT_STATUS_OK;
2338                 goto done;
2339         }
2340
2341         status = open_socket_out_defer_recv(r445, &fd445->fd);
2342  done:
2343         TALLOC_FREE(ev);
2344         return status;
2345 }
2346
2347 /****************************************************************************
2348  Open the client sockets.
2349 ****************************************************************************/
2350
2351 NTSTATUS cli_connect(struct cli_state *cli,
2352                 const char *host,
2353                 struct sockaddr_storage *dest_ss)
2354
2355 {
2356         int name_type = 0x20;
2357         TALLOC_CTX *frame = talloc_stackframe();
2358         unsigned int num_addrs = 0;
2359         unsigned int i = 0;
2360         struct sockaddr_storage *ss_arr = NULL;
2361         char *p = NULL;
2362
2363         /* reasonable default hostname */
2364         if (!host) {
2365                 host = STAR_SMBSERVER;
2366         }
2367
2368         fstrcpy(cli->desthost, host);
2369
2370         /* allow hostnames of the form NAME#xx and do a netbios lookup */
2371         if ((p = strchr(cli->desthost, '#'))) {
2372                 name_type = strtol(p+1, NULL, 16);
2373                 *p = 0;
2374         }
2375
2376         if (!dest_ss || is_zero_addr((struct sockaddr *)dest_ss)) {
2377                 NTSTATUS status =resolve_name_list(frame,
2378                                         cli->desthost,
2379                                         name_type,
2380                                         &ss_arr,
2381                                         &num_addrs);
2382                 if (!NT_STATUS_IS_OK(status)) {
2383                         TALLOC_FREE(frame);
2384                         return NT_STATUS_BAD_NETWORK_NAME;
2385                 }
2386         } else {
2387                 num_addrs = 1;
2388                 ss_arr = TALLOC_P(frame, struct sockaddr_storage);
2389                 if (!ss_arr) {
2390                         TALLOC_FREE(frame);
2391                         return NT_STATUS_NO_MEMORY;
2392                 }
2393                 *ss_arr = *dest_ss;
2394         }
2395
2396         for (i = 0; i < num_addrs; i++) {
2397                 cli->dest_ss = ss_arr[i];
2398                 if (getenv("LIBSMB_PROG")) {
2399                         cli->fd = sock_exec(getenv("LIBSMB_PROG"));
2400                 } else {
2401                         uint16_t port = cli->port;
2402                         NTSTATUS status;
2403                         status = open_smb_socket(&cli->dest_ss, &port,
2404                                                  cli->timeout, &cli->fd);
2405                         if (NT_STATUS_IS_OK(status)) {
2406                                 cli->port = port;
2407                         }
2408                 }
2409                 if (cli->fd == -1) {
2410                         char addr[INET6_ADDRSTRLEN];
2411                         print_sockaddr(addr, sizeof(addr), &ss_arr[i]);
2412                         DEBUG(2,("Error connecting to %s (%s)\n",
2413                                  dest_ss?addr:host,strerror(errno)));
2414                 } else {
2415                         /* Exit from loop on first connection. */
2416                         break;
2417                 }
2418         }
2419
2420         if (cli->fd == -1) {
2421                 TALLOC_FREE(frame);
2422                 return map_nt_error_from_unix(errno);
2423         }
2424
2425         if (dest_ss) {
2426                 *dest_ss = cli->dest_ss;
2427         }
2428
2429         set_socket_options(cli->fd, lp_socket_options());
2430
2431         TALLOC_FREE(frame);
2432         return NT_STATUS_OK;
2433 }
2434
2435 /**
2436    establishes a connection to after the negprot. 
2437    @param output_cli A fully initialised cli structure, non-null only on success
2438    @param dest_host The netbios name of the remote host
2439    @param dest_ss (optional) The the destination IP, NULL for name based lookup
2440    @param port (optional) The destination port (0 for default)
2441    @param retry bool. Did this connection fail with a retryable error ?
2442
2443 */
2444 NTSTATUS cli_start_connection(struct cli_state **output_cli, 
2445                               const char *my_name, 
2446                               const char *dest_host, 
2447                               struct sockaddr_storage *dest_ss, int port,
2448                               int signing_state, int flags,
2449                               bool *retry) 
2450 {
2451         NTSTATUS nt_status;
2452         struct nmb_name calling;
2453         struct nmb_name called;
2454         struct cli_state *cli;
2455         struct sockaddr_storage ss;
2456
2457         if (retry)
2458                 *retry = False;
2459
2460         if (!my_name) 
2461                 my_name = global_myname();
2462
2463         if (!(cli = cli_initialise_ex(signing_state))) {
2464                 return NT_STATUS_NO_MEMORY;
2465         }
2466
2467         make_nmb_name(&calling, my_name, 0x0);
2468         make_nmb_name(&called , dest_host, 0x20);
2469
2470         cli_set_port(cli, port);
2471         cli_set_timeout(cli, 10000); /* 10 seconds. */
2472
2473         if (dest_ss) {
2474                 ss = *dest_ss;
2475         } else {
2476                 zero_sockaddr(&ss);
2477         }
2478
2479 again:
2480
2481         DEBUG(3,("Connecting to host=%s\n", dest_host));
2482
2483         nt_status = cli_connect(cli, dest_host, &ss);
2484         if (!NT_STATUS_IS_OK(nt_status)) {
2485                 char addr[INET6_ADDRSTRLEN];
2486                 print_sockaddr(addr, sizeof(addr), &ss);
2487                 DEBUG(1,("cli_start_connection: failed to connect to %s (%s). Error %s\n",
2488                          nmb_namestr(&called), addr, nt_errstr(nt_status) ));
2489                 cli_shutdown(cli);
2490                 return nt_status;
2491         }
2492
2493         if (retry)
2494                 *retry = True;
2495
2496         if (!cli_session_request(cli, &calling, &called)) {
2497                 char *p;
2498                 DEBUG(1,("session request to %s failed (%s)\n",
2499                          called.name, cli_errstr(cli)));
2500                 if ((p=strchr(called.name, '.')) && !is_ipaddress(called.name)) {
2501                         *p = 0;
2502                         goto again;
2503                 }
2504                 if (strcmp(called.name, STAR_SMBSERVER)) {
2505                         make_nmb_name(&called , STAR_SMBSERVER, 0x20);
2506                         goto again;
2507                 }
2508                 return NT_STATUS_BAD_NETWORK_NAME;
2509         }
2510
2511         if (flags & CLI_FULL_CONNECTION_DONT_SPNEGO)
2512                 cli->use_spnego = False;
2513         else if (flags & CLI_FULL_CONNECTION_USE_KERBEROS)
2514                 cli->use_kerberos = True;
2515
2516         if ((flags & CLI_FULL_CONNECTION_FALLBACK_AFTER_KERBEROS) &&
2517              cli->use_kerberos) {
2518                 cli->fallback_after_kerberos = true;
2519         }
2520
2521         nt_status = cli_negprot(cli);
2522         if (!NT_STATUS_IS_OK(nt_status)) {
2523                 DEBUG(1, ("failed negprot: %s\n", nt_errstr(nt_status)));
2524                 cli_shutdown(cli);
2525                 return nt_status;
2526         }
2527
2528         *output_cli = cli;
2529         return NT_STATUS_OK;
2530 }
2531
2532
2533 /**
2534    establishes a connection right up to doing tconX, password specified.
2535    @param output_cli A fully initialised cli structure, non-null only on success
2536    @param dest_host The netbios name of the remote host
2537    @param dest_ip (optional) The the destination IP, NULL for name based lookup
2538    @param port (optional) The destination port (0 for default)
2539    @param service (optional) The share to make the connection to.  Should be 'unqualified' in any way.
2540    @param service_type The 'type' of serivice. 
2541    @param user Username, unix string
2542    @param domain User's domain
2543    @param password User's password, unencrypted unix string.
2544    @param retry bool. Did this connection fail with a retryable error ?
2545 */
2546
2547 NTSTATUS cli_full_connection(struct cli_state **output_cli, 
2548                              const char *my_name, 
2549                              const char *dest_host, 
2550                              struct sockaddr_storage *dest_ss, int port,
2551                              const char *service, const char *service_type,
2552                              const char *user, const char *domain, 
2553                              const char *password, int flags,
2554                              int signing_state,
2555                              bool *retry) 
2556 {
2557         NTSTATUS nt_status;
2558         struct cli_state *cli = NULL;
2559         int pw_len = password ? strlen(password)+1 : 0;
2560
2561         *output_cli = NULL;
2562
2563         if (password == NULL) {
2564                 password = "";
2565         }
2566
2567         nt_status = cli_start_connection(&cli, my_name, dest_host,
2568                                          dest_ss, port, signing_state,
2569                                          flags, retry);
2570
2571         if (!NT_STATUS_IS_OK(nt_status)) {
2572                 return nt_status;
2573         }
2574
2575         cli->use_oplocks = ((flags & CLI_FULL_CONNECTION_OPLOCKS) != 0);
2576         cli->use_level_II_oplocks =
2577                 ((flags & CLI_FULL_CONNECTION_LEVEL_II_OPLOCKS) != 0);
2578
2579         nt_status = cli_session_setup(cli, user, password, pw_len, password,
2580                                       pw_len, domain);
2581         if (!NT_STATUS_IS_OK(nt_status)) {
2582
2583                 if (!(flags & CLI_FULL_CONNECTION_ANONYMOUS_FALLBACK)) {
2584                         DEBUG(1,("failed session setup with %s\n",
2585                                  nt_errstr(nt_status)));
2586                         cli_shutdown(cli);
2587                         return nt_status;
2588                 }
2589
2590                 nt_status = cli_session_setup(cli, "", "", 0, "", 0, domain);
2591                 if (!NT_STATUS_IS_OK(nt_status)) {
2592                         DEBUG(1,("anonymous failed session setup with %s\n",
2593                                  nt_errstr(nt_status)));
2594                         cli_shutdown(cli);
2595                         return nt_status;
2596                 }
2597         }
2598
2599         if (service) {
2600                 nt_status = cli_tcon_andx(cli, service, service_type, password,
2601                                           pw_len);
2602                 if (!NT_STATUS_IS_OK(nt_status)) {
2603                         DEBUG(1,("failed tcon_X with %s\n", nt_errstr(nt_status)));
2604                         cli_shutdown(cli);
2605                         if (NT_STATUS_IS_OK(nt_status)) {
2606                                 nt_status = NT_STATUS_UNSUCCESSFUL;
2607                         }
2608                         return nt_status;
2609                 }
2610         }
2611
2612         nt_status = cli_init_creds(cli, user, domain, password);
2613         if (!NT_STATUS_IS_OK(nt_status)) {
2614                 cli_shutdown(cli);
2615                 return nt_status;
2616         }
2617
2618         *output_cli = cli;
2619         return NT_STATUS_OK;
2620 }
2621
2622 /****************************************************************************
2623  Attempt a NetBIOS session request, falling back to *SMBSERVER if needed.
2624 ****************************************************************************/
2625
2626 bool attempt_netbios_session_request(struct cli_state **ppcli, const char *srchost, const char *desthost,
2627                                      struct sockaddr_storage *pdest_ss)
2628 {
2629         struct nmb_name calling, called;
2630
2631         make_nmb_name(&calling, srchost, 0x0);
2632
2633         /*
2634          * If the called name is an IP address
2635          * then use *SMBSERVER immediately.
2636          */
2637
2638         if(is_ipaddress(desthost)) {
2639                 make_nmb_name(&called, STAR_SMBSERVER, 0x20);
2640         } else {
2641                 make_nmb_name(&called, desthost, 0x20);
2642         }
2643
2644         if (!cli_session_request(*ppcli, &calling, &called)) {
2645                 NTSTATUS status;
2646                 struct nmb_name smbservername;
2647
2648                 make_nmb_name(&smbservername, STAR_SMBSERVER, 0x20);
2649
2650                 /*
2651                  * If the name wasn't *SMBSERVER then
2652                  * try with *SMBSERVER if the first name fails.
2653                  */
2654
2655                 if (nmb_name_equal(&called, &smbservername)) {
2656
2657                         /*
2658                          * The name used was *SMBSERVER, don't bother with another name.
2659                          */
2660
2661                         DEBUG(0,("attempt_netbios_session_request: %s rejected the session for name *SMBSERVER \
2662 with error %s.\n", desthost, cli_errstr(*ppcli) ));
2663                         return False;
2664                 }
2665
2666                 /* Try again... */
2667                 cli_shutdown(*ppcli);
2668
2669                 *ppcli = cli_initialise();
2670                 if (!*ppcli) {
2671                         /* Out of memory... */
2672                         return False;
2673                 }
2674
2675                 status = cli_connect(*ppcli, desthost, pdest_ss);
2676                 if (!NT_STATUS_IS_OK(status) ||
2677                                 !cli_session_request(*ppcli, &calling, &smbservername)) {
2678                         DEBUG(0,("attempt_netbios_session_request: %s rejected the session for \
2679 name *SMBSERVER with error %s\n", desthost, cli_errstr(*ppcli) ));
2680                         return False;
2681                 }
2682         }
2683
2684         return True;
2685 }
2686
2687 /****************************************************************************
2688  Send an old style tcon.
2689 ****************************************************************************/
2690 NTSTATUS cli_raw_tcon(struct cli_state *cli, 
2691                       const char *service, const char *pass, const char *dev,
2692                       uint16 *max_xmit, uint16 *tid)
2693 {
2694         char *p;
2695
2696         if (!lp_client_plaintext_auth() && (*pass)) {
2697                 DEBUG(1, ("Server requested plaintext password but 'client "
2698                           "plaintext auth' is disabled\n"));
2699                 return NT_STATUS_ACCESS_DENIED;
2700         }
2701
2702         memset(cli->outbuf,'\0',smb_size);
2703         memset(cli->inbuf,'\0',smb_size);
2704
2705         cli_set_message(cli->outbuf, 0, 0, True);
2706         SCVAL(cli->outbuf,smb_com,SMBtcon);
2707         cli_setup_packet(cli);
2708
2709         p = smb_buf(cli->outbuf);
2710         *p++ = 4; p += clistr_push(cli, p, service, -1, STR_TERMINATE | STR_NOALIGN);
2711         *p++ = 4; p += clistr_push(cli, p, pass, -1, STR_TERMINATE | STR_NOALIGN);
2712         *p++ = 4; p += clistr_push(cli, p, dev, -1, STR_TERMINATE | STR_NOALIGN);
2713
2714         cli_setup_bcc(cli, p);
2715
2716         cli_send_smb(cli);
2717         if (!cli_receive_smb(cli)) {
2718                 return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
2719         }
2720
2721         if (cli_is_error(cli)) {
2722                 return cli_nt_error(cli);
2723         }
2724
2725         *max_xmit = SVAL(cli->inbuf, smb_vwv0);
2726         *tid = SVAL(cli->inbuf, smb_vwv1);
2727
2728         return NT_STATUS_OK;
2729 }
2730
2731 /* Return a cli_state pointing at the IPC$ share for the given server */
2732
2733 struct cli_state *get_ipc_connect(char *server,
2734                                 struct sockaddr_storage *server_ss,
2735                                 const struct user_auth_info *user_info)
2736 {
2737         struct cli_state *cli;
2738         NTSTATUS nt_status;
2739         uint32_t flags = CLI_FULL_CONNECTION_ANONYMOUS_FALLBACK;
2740
2741         if (user_info->use_kerberos) {
2742                 flags |= CLI_FULL_CONNECTION_USE_KERBEROS;
2743         }
2744
2745         nt_status = cli_full_connection(&cli, NULL, server, server_ss, 0, "IPC$", "IPC", 
2746                                         user_info->username ? user_info->username : "",
2747                                         lp_workgroup(),
2748                                         user_info->password ? user_info->password : "",
2749                                         flags,
2750                                         Undefined, NULL);
2751
2752         if (NT_STATUS_IS_OK(nt_status)) {
2753                 return cli;
2754         } else if (is_ipaddress(server)) {
2755             /* windows 9* needs a correct NMB name for connections */
2756             fstring remote_name;
2757
2758             if (name_status_find("*", 0, 0, server_ss, remote_name)) {
2759                 cli = get_ipc_connect(remote_name, server_ss, user_info);
2760                 if (cli)
2761                     return cli;
2762             }
2763         }
2764         return NULL;
2765 }
2766
2767 /*
2768  * Given the IP address of a master browser on the network, return its
2769  * workgroup and connect to it.
2770  *
2771  * This function is provided to allow additional processing beyond what
2772  * get_ipc_connect_master_ip_bcast() does, e.g. to retrieve the list of master
2773  * browsers and obtain each master browsers' list of domains (in case the
2774  * first master browser is recently on the network and has not yet
2775  * synchronized with other master browsers and therefore does not yet have the
2776  * entire network browse list)
2777  */
2778
2779 struct cli_state *get_ipc_connect_master_ip(TALLOC_CTX *ctx,
2780                                 struct ip_service *mb_ip,
2781                                 const struct user_auth_info *user_info,
2782                                 char **pp_workgroup_out)
2783 {
2784         char addr[INET6_ADDRSTRLEN];
2785         fstring name;
2786         struct cli_state *cli;
2787         struct sockaddr_storage server_ss;
2788
2789         *pp_workgroup_out = NULL;
2790
2791         print_sockaddr(addr, sizeof(addr), &mb_ip->ss);
2792         DEBUG(99, ("Looking up name of master browser %s\n",
2793                    addr));
2794
2795         /*
2796          * Do a name status query to find out the name of the master browser.
2797          * We use <01><02>__MSBROWSE__<02>#01 if *#00 fails because a domain
2798          * master browser will not respond to a wildcard query (or, at least,
2799          * an NT4 server acting as the domain master browser will not).
2800          *
2801          * We might be able to use ONLY the query on MSBROWSE, but that's not
2802          * yet been tested with all Windows versions, so until it is, leave
2803          * the original wildcard query as the first choice and fall back to
2804          * MSBROWSE if the wildcard query fails.
2805          */
2806         if (!name_status_find("*", 0, 0x1d, &mb_ip->ss, name) &&
2807             !name_status_find(MSBROWSE, 1, 0x1d, &mb_ip->ss, name)) {
2808
2809                 DEBUG(99, ("Could not retrieve name status for %s\n",
2810                            addr));
2811                 return NULL;
2812         }
2813
2814         if (!find_master_ip(name, &server_ss)) {
2815                 DEBUG(99, ("Could not find master ip for %s\n", name));
2816                 return NULL;
2817         }
2818
2819         *pp_workgroup_out = talloc_strdup(ctx, name);
2820
2821         DEBUG(4, ("found master browser %s, %s\n", name, addr));
2822
2823         print_sockaddr(addr, sizeof(addr), &server_ss);
2824         cli = get_ipc_connect(addr, &server_ss, user_info);
2825
2826         return cli;
2827 }
2828
2829 /*
2830  * Return the IP address and workgroup of a master browser on the network, and
2831  * connect to it.
2832  */
2833
2834 struct cli_state *get_ipc_connect_master_ip_bcast(TALLOC_CTX *ctx,
2835                                         const struct user_auth_info *user_info,
2836                                         char **pp_workgroup_out)
2837 {
2838         struct ip_service *ip_list;
2839         struct cli_state *cli;
2840         int i, count;
2841
2842         *pp_workgroup_out = NULL;
2843
2844         DEBUG(99, ("Do broadcast lookup for workgroups on local network\n"));
2845
2846         /* Go looking for workgroups by broadcasting on the local network */
2847
2848         if (!NT_STATUS_IS_OK(name_resolve_bcast(MSBROWSE, 1, &ip_list,
2849                                                 &count))) {
2850                 DEBUG(99, ("No master browsers responded\n"));
2851                 return False;
2852         }
2853
2854         for (i = 0; i < count; i++) {
2855                 char addr[INET6_ADDRSTRLEN];
2856                 print_sockaddr(addr, sizeof(addr), &ip_list[i].ss);
2857                 DEBUG(99, ("Found master browser %s\n", addr));
2858
2859                 cli = get_ipc_connect_master_ip(ctx, &ip_list[i],
2860                                 user_info, pp_workgroup_out);
2861                 if (cli)
2862                         return(cli);
2863         }
2864
2865         return NULL;
2866 }