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