* small formatting fixes
[Samba.git] / source / libsmb / cliconnect.c
blob93cf3d95db71e11b3f1078c2e4514fdfa0bcd3a5
1 /*
2 Unix SMB/CIFS implementation.
3 client connect/disconnect routines
4 Copyright (C) Andrew Tridgell 1994-1998
5 Copyright (C) Andrew Barteltt 2001-2002
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 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #define NO_SYSLOG
24 #include "includes.h"
27 static const struct {
28 int prot;
29 const char *name;
30 } prots[] = {
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,"Samba"},
38 {PROTOCOL_NT1,"NT LANMAN 1.0"},
39 {PROTOCOL_NT1,"NT LM 0.12"},
40 {-1,NULL}
43 /****************************************************************************
44 Do an old lanman2 style session setup.
45 ****************************************************************************/
47 static BOOL cli_session_setup_lanman2(struct cli_state *cli, char *user,
48 char *pass, int passlen, const char *workgroup)
50 fstring pword;
51 char *p;
53 if (passlen > sizeof(pword)-1) {
54 return False;
57 /* if in share level security then don't send a password now */
58 if (!(cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL)) {
59 passlen = 0;
62 if (passlen > 0 && (cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) && passlen != 24) {
63 /* Encrypted mode needed, and non encrypted password supplied. */
64 passlen = 24;
65 SMBencrypt(pass,cli->secblob.data,(uchar *)pword);
66 } else if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) && passlen == 24) {
67 /* Encrypted mode needed, and encrypted password supplied. */
68 memcpy(pword, pass, passlen);
69 } else if (passlen > 0) {
70 /* Plaintext mode needed, assume plaintext supplied. */
71 passlen = clistr_push(cli, pword, pass, -1, STR_TERMINATE);
74 /* send a session setup command */
75 memset(cli->outbuf,'\0',smb_size);
76 set_message(cli->outbuf,10, 0, True);
77 SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
78 cli_setup_packet(cli);
80 SCVAL(cli->outbuf,smb_vwv0,0xFF);
81 SSVAL(cli->outbuf,smb_vwv2,cli->max_xmit);
82 SSVAL(cli->outbuf,smb_vwv3,2);
83 SSVAL(cli->outbuf,smb_vwv4,1);
84 SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
85 SSVAL(cli->outbuf,smb_vwv7,passlen);
87 p = smb_buf(cli->outbuf);
88 memcpy(p,pword,passlen);
89 p += passlen;
90 p += clistr_push(cli, p, user, -1, STR_TERMINATE|STR_UPPER);
91 p += clistr_push(cli, p, workgroup, -1, STR_TERMINATE|STR_UPPER);
92 p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
93 p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
94 cli_setup_bcc(cli, p);
96 cli_send_smb(cli);
97 if (!cli_receive_smb(cli))
98 return False;
100 show_msg(cli->inbuf);
102 if (cli_is_error(cli)) {
103 return False;
106 /* use the returned vuid from now on */
107 cli->vuid = SVAL(cli->inbuf,smb_uid);
108 fstrcpy(cli->user_name, user);
110 return True;
113 /****************************************************************************
114 Work out suitable capabilities to offer the server.
115 ****************************************************************************/
117 static uint32 cli_session_setup_capabilities(struct cli_state *cli)
119 uint32 capabilities = CAP_NT_SMBS;
121 if (!cli->force_dos_errors) {
122 capabilities |= CAP_STATUS32;
125 if (cli->use_level_II_oplocks) {
126 capabilities |= CAP_LEVEL_II_OPLOCKS;
129 if (cli->capabilities & CAP_UNICODE) {
130 capabilities |= CAP_UNICODE;
133 return capabilities;
136 /****************************************************************************
137 Do a NT1 guest session setup.
138 ****************************************************************************/
140 static BOOL cli_session_setup_guest(struct cli_state *cli)
142 char *p;
143 uint32 capabilities = cli_session_setup_capabilities(cli);
145 set_message(cli->outbuf,13,0,True);
146 SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
147 cli_setup_packet(cli);
149 SCVAL(cli->outbuf,smb_vwv0,0xFF);
150 SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
151 SSVAL(cli->outbuf,smb_vwv3,2);
152 SSVAL(cli->outbuf,smb_vwv4,cli->pid);
153 SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
154 SSVAL(cli->outbuf,smb_vwv7,0);
155 SSVAL(cli->outbuf,smb_vwv8,0);
156 SIVAL(cli->outbuf,smb_vwv11,capabilities);
157 p = smb_buf(cli->outbuf);
158 p += clistr_push(cli, p, "", -1, STR_TERMINATE); /* username */
159 p += clistr_push(cli, p, "", -1, STR_TERMINATE); /* workgroup */
160 p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
161 p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
162 cli_setup_bcc(cli, p);
164 cli_send_smb(cli);
165 if (!cli_receive_smb(cli))
166 return False;
168 show_msg(cli->inbuf);
170 if (cli_is_error(cli)) {
171 return False;
174 cli->vuid = SVAL(cli->inbuf,smb_uid);
176 p = smb_buf(cli->inbuf);
177 p += clistr_pull(cli, cli->server_os, p, sizeof(fstring), -1, STR_TERMINATE);
178 p += clistr_pull(cli, cli->server_type, p, sizeof(fstring), -1, STR_TERMINATE);
179 p += clistr_pull(cli, cli->server_domain, p, sizeof(fstring), -1, STR_TERMINATE);
181 fstrcpy(cli->user_name, "");
183 return True;
186 /****************************************************************************
187 Do a NT1 plaintext session setup.
188 ****************************************************************************/
190 static BOOL cli_session_setup_plaintext(struct cli_state *cli, char *user,
191 char *pass, char *workgroup)
193 uint32 capabilities = cli_session_setup_capabilities(cli);
194 fstring pword;
195 int passlen;
196 char *p;
198 passlen = clistr_push(cli, pword, pass, sizeof(pword), STR_TERMINATE|STR_ASCII);
200 set_message(cli->outbuf,13,0,True);
201 SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
202 cli_setup_packet(cli);
204 SCVAL(cli->outbuf,smb_vwv0,0xFF);
205 SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
206 SSVAL(cli->outbuf,smb_vwv3,2);
207 SSVAL(cli->outbuf,smb_vwv4,cli->pid);
208 SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
209 SSVAL(cli->outbuf,smb_vwv8,0);
210 SIVAL(cli->outbuf,smb_vwv11,capabilities);
211 p = smb_buf(cli->outbuf);
212 p += clistr_push(cli, p, pword, -1, STR_TERMINATE); /* password */
213 SSVAL(cli->outbuf,smb_vwv7,PTR_DIFF(p, smb_buf(cli->outbuf)));
214 p += clistr_push(cli, p, user, -1, STR_TERMINATE); /* username */
215 p += clistr_push(cli, p, workgroup, -1, STR_TERMINATE); /* workgroup */
216 p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
217 p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
218 cli_setup_bcc(cli, p);
220 cli_send_smb(cli);
221 if (!cli_receive_smb(cli))
222 return False;
224 show_msg(cli->inbuf);
226 if (cli_is_error(cli)) {
227 return False;
230 cli->vuid = SVAL(cli->inbuf,smb_uid);
231 p = smb_buf(cli->inbuf);
232 p += clistr_pull(cli, cli->server_os, p, sizeof(fstring), -1, STR_TERMINATE);
233 p += clistr_pull(cli, cli->server_type, p, sizeof(fstring), -1, STR_TERMINATE);
234 p += clistr_pull(cli, cli->server_domain, p, sizeof(fstring), -1, STR_TERMINATE);
235 fstrcpy(cli->user_name, user);
237 return True;
242 do a NT1 NTLM/LM encrypted session setup
243 @param cli client state to create do session setup on
244 @param user username
245 @param pass *either* cleartext password (passlen !=24) or LM response.
246 @param ntpass NT response, implies ntpasslen >=24, implies pass is not clear
247 @param workgroup The user's domain.
250 static BOOL cli_session_setup_nt1(struct cli_state *cli, char *user,
251 char *pass, int passlen,
252 char *ntpass, int ntpasslen,
253 char *workgroup)
255 uint32 capabilities = cli_session_setup_capabilities(cli);
256 uchar pword[24];
257 uchar ntpword[24];
258 char *p;
259 BOOL tried_signing = False;
261 if (passlen > sizeof(pword) || ntpasslen > sizeof(ntpword)) {
262 return False;
265 if (passlen != 24) {
266 /* non encrypted password supplied. Ignore ntpass. */
267 passlen = 24;
268 ntpasslen = 24;
269 SMBencrypt(pass,cli->secblob.data,pword);
270 SMBNTencrypt(pass,cli->secblob.data,ntpword);
271 if (!cli->sign_info.use_smb_signing && cli->sign_info.negotiated_smb_signing) {
272 cli_calculate_mac_key(cli, pass, ntpword);
273 tried_signing = True;
275 } else {
276 /* pre-encrypted password supplied. Only used for security=server, can't do
277 signing becouse we don't have oringial key */
278 memcpy(pword, pass, 24);
279 if (ntpasslen == 24) {
280 memcpy(ntpword, ntpass, 24);
281 } else {
282 ZERO_STRUCT(ntpword);
286 /* send a session setup command */
287 memset(cli->outbuf,'\0',smb_size);
289 set_message(cli->outbuf,13,0,True);
290 SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
291 cli_setup_packet(cli);
293 SCVAL(cli->outbuf,smb_vwv0,0xFF);
294 SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
295 SSVAL(cli->outbuf,smb_vwv3,2);
296 SSVAL(cli->outbuf,smb_vwv4,cli->pid);
297 SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
298 SSVAL(cli->outbuf,smb_vwv7,passlen);
299 SSVAL(cli->outbuf,smb_vwv8,ntpasslen);
300 SIVAL(cli->outbuf,smb_vwv11,capabilities);
301 p = smb_buf(cli->outbuf);
302 memcpy(p,pword,passlen); p += passlen;
303 memcpy(p,ntpword,ntpasslen); p += ntpasslen;
304 p += clistr_push(cli, p, user, -1, STR_TERMINATE|STR_UPPER);
305 p += clistr_push(cli, p, workgroup, -1, STR_TERMINATE|STR_UPPER);
306 p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
307 p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
308 cli_setup_bcc(cli, p);
310 cli_send_smb(cli);
311 if (!cli_receive_smb(cli)) {
312 if (tried_signing) {
313 /* We only use it if we have a successful non-guest connect */
314 cli->sign_info.use_smb_signing = False;
316 return False;
319 show_msg(cli->inbuf);
321 if (tried_signing && (cli_is_error(cli) || SVAL(cli->inbuf,smb_vwv2) /* guest */)) {
322 /* We only use it if we have a successful non-guest connect */
323 cli->sign_info.use_smb_signing = False;
326 if (cli_is_error(cli)) {
327 return False;
330 /* use the returned vuid from now on */
331 cli->vuid = SVAL(cli->inbuf,smb_uid);
333 p = smb_buf(cli->inbuf);
334 p += clistr_pull(cli, cli->server_os, p, sizeof(fstring), -1, STR_TERMINATE);
335 p += clistr_pull(cli, cli->server_type, p, sizeof(fstring), -1, STR_TERMINATE);
336 p += clistr_pull(cli, cli->server_domain, p, sizeof(fstring), -1, STR_TERMINATE);
338 fstrcpy(cli->user_name, user);
340 return True;
343 /****************************************************************************
344 Send a extended security session setup blob, returning a reply blob.
345 ****************************************************************************/
347 static DATA_BLOB cli_session_setup_blob(struct cli_state *cli, DATA_BLOB blob)
349 uint32 capabilities = cli_session_setup_capabilities(cli);
350 char *p;
351 DATA_BLOB blob2;
352 uint32 len;
354 blob2 = data_blob(NULL, 0);
356 capabilities |= CAP_EXTENDED_SECURITY;
358 /* send a session setup command */
359 memset(cli->outbuf,'\0',smb_size);
361 set_message(cli->outbuf,12,0,True);
362 SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
363 cli_setup_packet(cli);
365 SCVAL(cli->outbuf,smb_vwv0,0xFF);
366 SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
367 SSVAL(cli->outbuf,smb_vwv3,2);
368 SSVAL(cli->outbuf,smb_vwv4,1);
369 SIVAL(cli->outbuf,smb_vwv5,0);
370 SSVAL(cli->outbuf,smb_vwv7,blob.length);
371 SIVAL(cli->outbuf,smb_vwv10,capabilities);
372 p = smb_buf(cli->outbuf);
373 memcpy(p, blob.data, blob.length);
374 p += blob.length;
375 p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
376 p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
377 cli_setup_bcc(cli, p);
379 cli_send_smb(cli);
380 if (!cli_receive_smb(cli))
381 return blob2;
383 show_msg(cli->inbuf);
385 if (cli_is_error(cli) && !NT_STATUS_EQUAL(cli_nt_error(cli),
386 NT_STATUS_MORE_PROCESSING_REQUIRED)) {
387 return blob2;
390 /* use the returned vuid from now on */
391 cli->vuid = SVAL(cli->inbuf,smb_uid);
393 p = smb_buf(cli->inbuf);
395 blob2 = data_blob(p, SVAL(cli->inbuf, smb_vwv3));
397 p += blob2.length;
398 p += clistr_pull(cli, cli->server_os, p, sizeof(fstring), -1, STR_TERMINATE);
400 /* w2k with kerberos doesn't properly null terminate this field */
401 len = smb_buflen(cli->inbuf) - PTR_DIFF(p, smb_buf(cli->inbuf));
402 p += clistr_pull(cli, cli->server_type, p, sizeof(fstring), len, 0);
404 return blob2;
408 #ifdef HAVE_KRB5
409 /****************************************************************************
410 Do a spnego/kerberos encrypted session setup.
411 ****************************************************************************/
413 static BOOL cli_session_setup_kerberos(struct cli_state *cli, char *principal, char *workgroup)
415 DATA_BLOB blob2, negTokenTarg;
417 DEBUG(2,("Doing kerberos session setup\n"));
419 /* generate the encapsulated kerberos5 ticket */
420 negTokenTarg = spnego_gen_negTokenTarg(cli, principal);
422 if (!negTokenTarg.data) return False;
424 #if 0
425 file_save("negTokenTarg.dat", negTokenTarg.data, negTokenTarg.length);
426 #endif
428 blob2 = cli_session_setup_blob(cli, negTokenTarg);
430 /* we don't need this blob for kerberos */
431 data_blob_free(&blob2);
433 data_blob_free(&negTokenTarg);
435 return !cli_is_error(cli);
437 #endif
439 /****************************************************************************
440 Do a spnego/NTLMSSP encrypted session setup.
441 ****************************************************************************/
443 static BOOL cli_session_setup_ntlmssp(struct cli_state *cli, char *user,
444 char *pass, char *workgroup)
446 const char *mechs[] = {OID_NTLMSSP, NULL};
447 DATA_BLOB msg1;
448 DATA_BLOB blob, chal1, chal2, auth;
449 uint8 challenge[8];
450 uint8 nthash[24], lmhash[24], sess_key[16];
451 uint32 neg_flags;
453 neg_flags = NTLMSSP_NEGOTIATE_UNICODE |
454 NTLMSSP_NEGOTIATE_LM_KEY |
455 NTLMSSP_NEGOTIATE_NTLM;
457 memset(sess_key, 0, 16);
459 /* generate the ntlmssp negotiate packet */
460 msrpc_gen(&blob, "CddB",
461 "NTLMSSP",
462 NTLMSSP_NEGOTIATE,
463 neg_flags,
464 sess_key, 16);
466 /* and wrap it in a SPNEGO wrapper */
467 msg1 = gen_negTokenTarg(mechs, blob);
468 data_blob_free(&blob);
470 /* now send that blob on its way */
471 blob = cli_session_setup_blob(cli, msg1);
473 data_blob_free(&msg1);
475 if (!NT_STATUS_EQUAL(cli_nt_error(cli), NT_STATUS_MORE_PROCESSING_REQUIRED)) {
476 return False;
479 #if 0
480 file_save("chal.dat", blob.data, blob.length);
481 #endif
483 /* the server gives us back two challenges */
484 if (!spnego_parse_challenge(blob, &chal1, &chal2)) {
485 DEBUG(3,("Failed to parse challenges\n"));
486 return False;
489 data_blob_free(&blob);
491 /* encrypt the password with the challenge */
492 memcpy(challenge, chal1.data + 24, 8);
493 SMBencrypt(pass, challenge,lmhash);
494 SMBNTencrypt(pass, challenge,nthash);
496 #if 0
497 file_save("nthash.dat", nthash, 24);
498 file_save("lmhash.dat", lmhash, 24);
499 file_save("chal1.dat", chal1.data, chal1.length);
500 #endif
502 data_blob_free(&chal1);
503 data_blob_free(&chal2);
505 /* this generates the actual auth packet */
506 msrpc_gen(&blob, "CdBBUUUBd",
507 "NTLMSSP",
508 NTLMSSP_AUTH,
509 lmhash, 24,
510 nthash, 24,
511 workgroup,
512 user,
513 cli->calling.name,
514 sess_key, 16,
515 neg_flags);
517 /* wrap it in SPNEGO */
518 auth = spnego_gen_auth(blob);
520 data_blob_free(&blob);
522 /* now send the auth packet and we should be done */
523 blob = cli_session_setup_blob(cli, auth);
525 data_blob_free(&auth);
526 data_blob_free(&blob);
528 return !cli_is_error(cli);
531 /****************************************************************************
532 Do a spnego encrypted session setup.
533 ****************************************************************************/
535 static BOOL cli_session_setup_spnego(struct cli_state *cli, char *user,
536 char *pass, char *workgroup)
538 char *principal;
539 char *OIDs[ASN1_MAX_OIDS];
540 uint8 guid[16];
541 int i;
542 BOOL got_kerberos_mechanism = False;
544 /* spnego security cannot use SMB signing (for now). */
545 cli->sign_info.use_smb_signing = False;
547 DEBUG(2,("Doing spnego session setup (blob length=%d)\n", cli->secblob.length));
549 /* the server might not even do spnego */
550 if (cli->secblob.length == 16) {
551 DEBUG(3,("server didn't supply a full spnego negprot\n"));
552 goto ntlmssp;
555 #if 0
556 file_save("negprot.dat", cli->secblob.data, cli->secblob.length);
557 #endif
559 /* the server sent us the first part of the SPNEGO exchange in the negprot
560 reply */
561 if (!spnego_parse_negTokenInit(cli->secblob, guid, OIDs, &principal)) {
562 return False;
565 /* make sure the server understands kerberos */
566 for (i=0;OIDs[i];i++) {
567 DEBUG(3,("got OID=%s\n", OIDs[i]));
568 if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 ||
569 strcmp(OIDs[i], OID_KERBEROS5) == 0) {
570 got_kerberos_mechanism = True;
572 free(OIDs[i]);
574 DEBUG(3,("got principal=%s\n", principal));
576 fstrcpy(cli->user_name, user);
578 #ifdef HAVE_KRB5
579 if (got_kerberos_mechanism && cli->use_kerberos) {
580 return cli_session_setup_kerberos(cli, principal, workgroup);
582 #endif
584 free(principal);
586 ntlmssp:
588 return cli_session_setup_ntlmssp(cli, user, pass, workgroup);
591 /****************************************************************************
592 Send a session setup. The username and workgroup is in UNIX character
593 format and must be converted to DOS codepage format before sending. If the
594 password is in plaintext, the same should be done.
595 ****************************************************************************/
597 BOOL cli_session_setup(struct cli_state *cli,
598 char *user,
599 char *pass, int passlen,
600 char *ntpass, int ntpasslen,
601 char *workgroup)
603 char *p;
604 fstring user2;
606 /* allow for workgroups as part of the username */
607 fstrcpy(user2, user);
608 if ((p=strchr_m(user2,'\\')) || (p=strchr_m(user2,'/')) ||
609 (p=strchr_m(user2,*lp_winbind_separator()))) {
610 *p = 0;
611 user = p+1;
612 workgroup = user2;
615 if (cli->protocol < PROTOCOL_LANMAN1)
616 return True;
618 /* now work out what sort of session setup we are going to
619 do. I have split this into separate functions to make the
620 flow a bit easier to understand (tridge) */
622 /* if its an older server then we have to use the older request format */
623 if (cli->protocol < PROTOCOL_NT1) {
624 return cli_session_setup_lanman2(cli, user, pass, passlen, workgroup);
627 /* if no user is supplied then we have to do an anonymous connection.
628 passwords are ignored */
629 if (!user || !*user) {
630 return cli_session_setup_guest(cli);
633 /* if the server is share level then send a plaintext null
634 password at this point. The password is sent in the tree
635 connect */
636 if ((cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL) == 0) {
637 return cli_session_setup_plaintext(cli, user, "", workgroup);
640 /* if the server doesn't support encryption then we have to use
641 plaintext. The second password is ignored */
642 if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) == 0) {
643 return cli_session_setup_plaintext(cli, user, pass, workgroup);
646 /* if the server supports extended security then use SPNEGO */
647 if (cli->capabilities & CAP_EXTENDED_SECURITY) {
648 return cli_session_setup_spnego(cli, user, pass, workgroup);
651 /* otherwise do a NT1 style session setup */
652 return cli_session_setup_nt1(cli, user,
653 pass, passlen, ntpass, ntpasslen,
654 workgroup);
657 /****************************************************************************
658 Send a uloggoff.
659 *****************************************************************************/
661 BOOL cli_ulogoff(struct cli_state *cli)
663 memset(cli->outbuf,'\0',smb_size);
664 set_message(cli->outbuf,2,0,True);
665 SCVAL(cli->outbuf,smb_com,SMBulogoffX);
666 cli_setup_packet(cli);
667 SSVAL(cli->outbuf,smb_vwv0,0xFF);
668 SSVAL(cli->outbuf,smb_vwv2,0); /* no additional info */
670 cli_send_smb(cli);
671 if (!cli_receive_smb(cli))
672 return False;
674 return !cli_is_error(cli);
677 /****************************************************************************
678 Send a tconX.
679 ****************************************************************************/
681 BOOL cli_send_tconX(struct cli_state *cli,
682 const char *share, const char *dev, const char *pass, int passlen)
684 fstring fullshare, pword;
685 char *p;
686 memset(cli->outbuf,'\0',smb_size);
687 memset(cli->inbuf,'\0',smb_size);
689 fstrcpy(cli->share, share);
691 /* in user level security don't send a password now */
692 if (cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL) {
693 passlen = 1;
694 pass = "";
697 if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) && *pass && passlen != 24) {
699 * Non-encrypted passwords - convert to DOS codepage before encryption.
701 passlen = 24;
702 SMBencrypt(pass,cli->secblob.data,(uchar *)pword);
703 } else {
704 if((cli->sec_mode & (NEGOTIATE_SECURITY_USER_LEVEL|NEGOTIATE_SECURITY_CHALLENGE_RESPONSE)) == 0) {
706 * Non-encrypted passwords - convert to DOS codepage before using.
708 passlen = clistr_push(cli, pword, pass, -1, STR_TERMINATE);
709 } else {
710 memcpy(pword, pass, passlen);
714 if (cli->port == 445) {
715 slprintf(fullshare, sizeof(fullshare)-1,
716 "%s", share);
717 } else {
718 slprintf(fullshare, sizeof(fullshare)-1,
719 "\\\\%s\\%s", cli->desthost, share);
722 set_message(cli->outbuf,4, 0, True);
723 SCVAL(cli->outbuf,smb_com,SMBtconX);
724 cli_setup_packet(cli);
726 SSVAL(cli->outbuf,smb_vwv0,0xFF);
727 SSVAL(cli->outbuf,smb_vwv3,passlen);
729 p = smb_buf(cli->outbuf);
730 memcpy(p,pword,passlen);
731 p += passlen;
732 p += clistr_push(cli, p, fullshare, -1, STR_TERMINATE |STR_UPPER);
733 fstrcpy(p, dev); p += strlen(dev)+1;
735 cli_setup_bcc(cli, p);
737 cli_send_smb(cli);
738 if (!cli_receive_smb(cli))
739 return False;
741 if (cli_is_error(cli)) {
742 return False;
745 clistr_pull(cli, cli->dev, smb_buf(cli->inbuf), sizeof(fstring), -1, STR_TERMINATE|STR_ASCII);
747 if (strcasecmp(share,"IPC$")==0) {
748 fstrcpy(cli->dev, "IPC");
751 if (cli->protocol >= PROTOCOL_NT1 &&
752 smb_buflen(cli->inbuf) == 3) {
753 /* almost certainly win95 - enable bug fixes */
754 cli->win95 = True;
757 cli->cnum = SVAL(cli->inbuf,smb_tid);
758 return True;
761 /****************************************************************************
762 Send a tree disconnect.
763 ****************************************************************************/
765 BOOL cli_tdis(struct cli_state *cli)
767 memset(cli->outbuf,'\0',smb_size);
768 set_message(cli->outbuf,0,0,True);
769 SCVAL(cli->outbuf,smb_com,SMBtdis);
770 SSVAL(cli->outbuf,smb_tid,cli->cnum);
771 cli_setup_packet(cli);
773 cli_send_smb(cli);
774 if (!cli_receive_smb(cli))
775 return False;
777 return !cli_is_error(cli);
780 /****************************************************************************
781 Send a negprot command.
782 ****************************************************************************/
784 void cli_negprot_send(struct cli_state *cli)
786 char *p;
787 int numprots;
789 if (cli->protocol < PROTOCOL_NT1) {
790 cli->use_spnego = False;
793 memset(cli->outbuf,'\0',smb_size);
795 /* setup the protocol strings */
796 set_message(cli->outbuf,0,0,True);
798 p = smb_buf(cli->outbuf);
799 for (numprots=0;
800 prots[numprots].name && prots[numprots].prot<=cli->protocol;
801 numprots++) {
802 *p++ = 2;
803 p += clistr_push(cli, p, prots[numprots].name, -1, STR_TERMINATE);
806 SCVAL(cli->outbuf,smb_com,SMBnegprot);
807 cli_setup_bcc(cli, p);
808 cli_setup_packet(cli);
810 SCVAL(smb_buf(cli->outbuf),0,2);
812 cli_send_smb(cli);
815 /****************************************************************************
816 Send a negprot command.
817 ****************************************************************************/
819 BOOL cli_negprot(struct cli_state *cli)
821 char *p;
822 int numprots;
823 int plength;
825 if (cli->sign_info.use_smb_signing) {
826 DEBUG(0, ("Cannot send negprot again, particularly after setting up SMB Signing\n"));
827 return False;
830 if (cli->protocol < PROTOCOL_NT1) {
831 cli->use_spnego = False;
834 memset(cli->outbuf,'\0',smb_size);
836 /* setup the protocol strings */
837 for (plength=0,numprots=0;
838 prots[numprots].name && prots[numprots].prot<=cli->protocol;
839 numprots++)
840 plength += strlen(prots[numprots].name)+2;
842 set_message(cli->outbuf,0,plength,True);
844 p = smb_buf(cli->outbuf);
845 for (numprots=0;
846 prots[numprots].name && prots[numprots].prot<=cli->protocol;
847 numprots++) {
848 *p++ = 2;
849 p += clistr_push(cli, p, prots[numprots].name, -1, STR_TERMINATE);
852 SCVAL(cli->outbuf,smb_com,SMBnegprot);
853 cli_setup_packet(cli);
855 SCVAL(smb_buf(cli->outbuf),0,2);
857 cli_send_smb(cli);
858 if (!cli_receive_smb(cli))
859 return False;
861 show_msg(cli->inbuf);
863 if (cli_is_error(cli) ||
864 ((int)SVAL(cli->inbuf,smb_vwv0) >= numprots)) {
865 return(False);
868 cli->protocol = prots[SVAL(cli->inbuf,smb_vwv0)].prot;
870 if (cli->protocol >= PROTOCOL_NT1) {
871 /* NT protocol */
872 cli->sec_mode = CVAL(cli->inbuf,smb_vwv1);
873 cli->max_mux = SVAL(cli->inbuf, smb_vwv1+1);
874 cli->max_xmit = IVAL(cli->inbuf,smb_vwv3+1);
875 cli->sesskey = IVAL(cli->inbuf,smb_vwv7+1);
876 cli->serverzone = SVALS(cli->inbuf,smb_vwv15+1);
877 cli->serverzone *= 60;
878 /* this time arrives in real GMT */
879 cli->servertime = interpret_long_date(cli->inbuf+smb_vwv11+1);
880 cli->secblob = data_blob(smb_buf(cli->inbuf),smb_buflen(cli->inbuf));
881 cli->capabilities = IVAL(cli->inbuf,smb_vwv9+1);
882 if (cli->capabilities & CAP_RAW_MODE) {
883 cli->readbraw_supported = True;
884 cli->writebraw_supported = True;
886 /* work out if they sent us a workgroup */
887 if (!(cli->capabilities & CAP_EXTENDED_SECURITY) &&
888 smb_buflen(cli->inbuf) > 8) {
889 clistr_pull(cli, cli->server_domain,
890 smb_buf(cli->inbuf)+8, sizeof(cli->server_domain),
891 smb_buflen(cli->inbuf)-8, STR_UNICODE|STR_NOALIGN);
894 /* A way to attempt to force SMB signing */
895 if (getenv("CLI_FORCE_SMB_SIGNING"))
896 cli->sign_info.negotiated_smb_signing = True;
898 if (cli->sign_info.negotiated_smb_signing && !(cli->sec_mode & NEGOTIATE_SECURITY_SIGNATURES_ENABLED))
899 cli->sign_info.negotiated_smb_signing = False;
901 } else if (cli->protocol >= PROTOCOL_LANMAN1) {
902 cli->use_spnego = False;
903 cli->sec_mode = SVAL(cli->inbuf,smb_vwv1);
904 cli->max_xmit = SVAL(cli->inbuf,smb_vwv2);
905 cli->sesskey = IVAL(cli->inbuf,smb_vwv6);
906 cli->serverzone = SVALS(cli->inbuf,smb_vwv10);
907 cli->serverzone *= 60;
908 /* this time is converted to GMT by make_unix_date */
909 cli->servertime = make_unix_date(cli->inbuf+smb_vwv8);
910 cli->readbraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x1) != 0);
911 cli->writebraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x2) != 0);
912 cli->secblob = data_blob(smb_buf(cli->inbuf),smb_buflen(cli->inbuf));
913 } else {
914 /* the old core protocol */
915 cli->use_spnego = False;
916 cli->sec_mode = 0;
917 cli->serverzone = TimeDiff(time(NULL));
920 cli->max_xmit = MIN(cli->max_xmit, CLI_BUFFER_SIZE);
922 /* a way to force ascii SMB */
923 if (getenv("CLI_FORCE_ASCII")) {
924 cli->capabilities &= ~CAP_UNICODE;
927 return True;
930 /****************************************************************************
931 Send a session request. See rfc1002.txt 4.3 and 4.3.2.
932 ****************************************************************************/
934 BOOL cli_session_request(struct cli_state *cli,
935 struct nmb_name *calling, struct nmb_name *called)
937 char *p;
938 int len = 4;
939 extern pstring user_socket_options;
941 /* 445 doesn't have session request */
942 if (cli->port == 445) return True;
944 if (cli->sign_info.use_smb_signing) {
945 DEBUG(0, ("Cannot send session resquest again, particularly after setting up SMB Signing\n"));
946 return False;
949 /* send a session request (RFC 1002) */
950 memcpy(&(cli->calling), calling, sizeof(*calling));
951 memcpy(&(cli->called ), called , sizeof(*called ));
953 /* put in the destination name */
954 p = cli->outbuf+len;
955 name_mangle(cli->called .name, p, cli->called .name_type);
956 len += name_len(p);
958 /* and my name */
959 p = cli->outbuf+len;
960 name_mangle(cli->calling.name, p, cli->calling.name_type);
961 len += name_len(p);
963 /* setup the packet length
964 * Remove four bytes from the length count, since the length
965 * field in the NBT Session Service header counts the number
966 * of bytes which follow. The cli_send_smb() function knows
967 * about this and accounts for those four bytes.
968 * CRH.
970 len -= 4;
971 _smb_setlen(cli->outbuf,len);
972 SCVAL(cli->outbuf,0,0x81);
974 cli_send_smb(cli);
975 DEBUG(5,("Sent session request\n"));
977 if (!cli_receive_smb(cli))
978 return False;
980 if (CVAL(cli->inbuf,0) == 0x84) {
981 /* C. Hoch 9/14/95 Start */
982 /* For information, here is the response structure.
983 * We do the byte-twiddling to for portability.
984 struct RetargetResponse{
985 unsigned char type;
986 unsigned char flags;
987 int16 length;
988 int32 ip_addr;
989 int16 port;
992 int port = (CVAL(cli->inbuf,8)<<8)+CVAL(cli->inbuf,9);
993 /* SESSION RETARGET */
994 putip((char *)&cli->dest_ip,cli->inbuf+4);
996 cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip, port, LONG_CONNECT_TIMEOUT);
997 if (cli->fd == -1)
998 return False;
1000 DEBUG(3,("Retargeted\n"));
1002 set_socket_options(cli->fd,user_socket_options);
1004 /* Try again */
1006 static int depth;
1007 BOOL ret;
1008 if (depth > 4) {
1009 DEBUG(0,("Retarget recursion - failing\n"));
1010 return False;
1012 depth++;
1013 ret = cli_session_request(cli, calling, called);
1014 depth--;
1015 return ret;
1017 } /* C. Hoch 9/14/95 End */
1019 if (CVAL(cli->inbuf,0) != 0x82) {
1020 /* This is the wrong place to put the error... JRA. */
1021 cli->rap_error = CVAL(cli->inbuf,4);
1022 return False;
1024 return(True);
1027 /****************************************************************************
1028 Open the client sockets.
1029 ****************************************************************************/
1031 BOOL cli_connect(struct cli_state *cli, const char *host, struct in_addr *ip)
1033 extern pstring user_socket_options;
1034 int name_type = 0x20;
1035 char *p;
1037 /* reasonable default hostname */
1038 if (!host) host = "*SMBSERVER";
1040 fstrcpy(cli->desthost, host);
1042 /* allow hostnames of the form NAME#xx and do a netbios lookup */
1043 if ((p = strchr(cli->desthost, '#'))) {
1044 name_type = strtol(p+1, NULL, 16);
1045 *p = 0;
1048 if (!ip || is_zero_ip(*ip)) {
1049 if (!resolve_name(cli->desthost, &cli->dest_ip, name_type)) {
1050 return False;
1052 if (ip) *ip = cli->dest_ip;
1053 } else {
1054 cli->dest_ip = *ip;
1057 if (getenv("LIBSMB_PROG")) {
1058 cli->fd = sock_exec(getenv("LIBSMB_PROG"));
1059 } else {
1060 /* try 445 first, then 139 */
1061 int port = cli->port?cli->port:445;
1062 cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip,
1063 port, cli->timeout);
1064 if (cli->fd == -1 && cli->port == 0) {
1065 port = 139;
1066 cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip,
1067 port, cli->timeout);
1069 if (cli->fd != -1) cli->port = port;
1071 if (cli->fd == -1) {
1072 DEBUG(1,("Error connecting to %s (%s)\n",
1073 ip?inet_ntoa(*ip):host,strerror(errno)));
1074 return False;
1077 set_socket_options(cli->fd,user_socket_options);
1079 return True;
1082 /****************************************************************************
1083 Initialise client credentials for authenticated pipe access.
1084 ****************************************************************************/
1086 static void init_creds(struct ntuser_creds *creds, char* username,
1087 char* domain, char* password)
1089 ZERO_STRUCTP(creds);
1091 pwd_set_cleartext(&creds->pwd, password);
1093 fstrcpy(creds->user_name, username);
1094 fstrcpy(creds->domain, domain);
1096 if (!*username) {
1097 creds->pwd.null_pwd = True;
1102 establishes a connection right up to doing tconX, password specified.
1103 @param output_cli A fully initialised cli structure, non-null only on success
1104 @param dest_host The netbios name of the remote host
1105 @param dest_ip (optional) The the destination IP, NULL for name based lookup
1106 @param port (optional) The destination port (0 for default)
1107 @param service (optional) The share to make the connection to. Should be 'unqualified' in any way.
1108 @param service_type The 'type' of serivice.
1109 @param user Username, unix string
1110 @param domain User's domain
1111 @param password User's password, unencrypted unix string.
1114 NTSTATUS cli_full_connection(struct cli_state **output_cli,
1115 const char *my_name,
1116 const char *dest_host,
1117 struct in_addr *dest_ip, int port,
1118 char *service, char *service_type,
1119 char *user, char *domain,
1120 char *password, int flags)
1122 struct ntuser_creds creds;
1123 NTSTATUS nt_status;
1124 struct nmb_name calling;
1125 struct nmb_name called;
1126 struct cli_state *cli;
1127 struct in_addr ip;
1128 extern pstring global_myname;
1130 if (!my_name)
1131 my_name = global_myname;
1133 if (!(cli = cli_initialise(NULL)))
1134 return NT_STATUS_NO_MEMORY;
1136 make_nmb_name(&calling, my_name, 0x0);
1137 make_nmb_name(&called , dest_host, 0x20);
1139 if (cli_set_port(cli, port) != port) {
1140 cli_shutdown(cli);
1141 return NT_STATUS_UNSUCCESSFUL;
1144 if (dest_ip) {
1145 ip = *dest_ip;
1146 } else {
1147 ZERO_STRUCT(ip);
1150 again:
1152 DEBUG(3,("Connecting to host=%s share=%s\n", dest_host, service));
1154 if (!cli_connect(cli, dest_host, &ip)) {
1155 DEBUG(1,("cli_full_connection: failed to connect to %s (%s)\n",
1156 nmb_namestr(&called), inet_ntoa(ip)));
1157 cli_shutdown(cli);
1158 return NT_STATUS_UNSUCCESSFUL;
1161 if (!cli_session_request(cli, &calling, &called)) {
1162 char *p;
1163 DEBUG(1,("session request to %s failed (%s)\n",
1164 called.name, cli_errstr(cli)));
1165 cli_shutdown(cli);
1166 if ((p=strchr(called.name, '.'))) {
1167 *p = 0;
1168 goto again;
1170 if (strcmp(called.name, "*SMBSERVER")) {
1171 make_nmb_name(&called , "*SMBSERVER", 0x20);
1172 goto again;
1174 return NT_STATUS_UNSUCCESSFUL;
1177 if (flags & CLI_FULL_CONNECTION_DONT_SPNEGO) {
1178 cli->use_spnego = False;
1179 } else if (flags & CLI_FULL_CONNECTION_USE_KERBEROS) {
1180 cli->use_kerberos = True;
1183 if (!cli_negprot(cli)) {
1184 DEBUG(1,("failed negprot\n"));
1185 nt_status = NT_STATUS_UNSUCCESSFUL;
1186 cli_shutdown(cli);
1187 return nt_status;
1190 if (!cli_session_setup(cli, user, password, strlen(password)+1,
1191 password, strlen(password)+1,
1192 domain)) {
1193 if ((flags & CLI_FULL_CONNECTION_ANNONYMOUS_FALLBACK)
1194 && cli_session_setup(cli, "", "", 0, "", 0, domain)) {
1195 } else {
1196 nt_status = cli_nt_error(cli);
1197 DEBUG(1,("failed session setup with %s\n", nt_errstr(nt_status)));
1198 cli_shutdown(cli);
1199 if (NT_STATUS_IS_OK(nt_status))
1200 nt_status = NT_STATUS_UNSUCCESSFUL;
1201 return nt_status;
1205 if (service) {
1206 if (!cli_send_tconX(cli, service, service_type,
1207 (char*)password, strlen(password)+1)) {
1208 DEBUG(1,("failed tcon_X with %s\n", nt_errstr(nt_status)));
1209 nt_status = cli_nt_error(cli);
1210 cli_shutdown(cli);
1211 if (NT_STATUS_IS_OK(nt_status)) {
1212 nt_status = NT_STATUS_UNSUCCESSFUL;
1214 return nt_status;
1218 init_creds(&creds, user, domain, password);
1219 cli_init_creds(cli, &creds);
1221 *output_cli = cli;
1222 return NT_STATUS_OK;
1225 /****************************************************************************
1226 Attempt a NetBIOS session request, falling back to *SMBSERVER if needed.
1227 ****************************************************************************/
1229 BOOL attempt_netbios_session_request(struct cli_state *cli, char *srchost, char *desthost,
1230 struct in_addr *pdest_ip)
1232 struct nmb_name calling, called;
1234 make_nmb_name(&calling, srchost, 0x0);
1237 * If the called name is an IP address
1238 * then use *SMBSERVER immediately.
1241 if(is_ipaddress(desthost))
1242 make_nmb_name(&called, "*SMBSERVER", 0x20);
1243 else
1244 make_nmb_name(&called, desthost, 0x20);
1246 if (!cli_session_request(cli, &calling, &called)) {
1247 struct nmb_name smbservername;
1249 make_nmb_name(&smbservername , "*SMBSERVER", 0x20);
1252 * If the name wasn't *SMBSERVER then
1253 * try with *SMBSERVER if the first name fails.
1256 if (nmb_name_equal(&called, &smbservername)) {
1259 * The name used was *SMBSERVER, don't bother with another name.
1262 DEBUG(0,("attempt_netbios_session_request: %s rejected the session for name *SMBSERVER \
1263 with error %s.\n", desthost, cli_errstr(cli) ));
1264 cli_shutdown(cli);
1265 return False;
1268 cli_shutdown(cli);
1270 if (!cli_initialise(cli) ||
1271 !cli_connect(cli, desthost, pdest_ip) ||
1272 !cli_session_request(cli, &calling, &smbservername)) {
1273 DEBUG(0,("attempt_netbios_session_request: %s rejected the session for \
1274 name *SMBSERVER with error %s\n", desthost, cli_errstr(cli) ));
1275 cli_shutdown(cli);
1276 return False;
1280 return True;