* fix to display correct form information in REG_BINARY information
[Samba.git] / source / libsmb / cliconnect.c
blobd304da7f51868311c2fb37e9f80c63d93b42be93
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_vwv7,passlen);
210 SSVAL(cli->outbuf,smb_vwv8,0);
211 SIVAL(cli->outbuf,smb_vwv11,capabilities);
212 p = smb_buf(cli->outbuf);
213 memcpy(p, pword, passlen);
214 p += passlen;
215 p += clistr_push(cli, p, user, -1, STR_TERMINATE); /* username */
216 p += clistr_push(cli, p, workgroup, -1, STR_TERMINATE); /* workgroup */
217 p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
218 p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
219 cli_setup_bcc(cli, p);
221 cli_send_smb(cli);
222 if (!cli_receive_smb(cli))
223 return False;
225 show_msg(cli->inbuf);
227 if (cli_is_error(cli)) {
228 return False;
231 cli->vuid = SVAL(cli->inbuf,smb_uid);
232 p = smb_buf(cli->inbuf);
233 p += clistr_pull(cli, cli->server_os, p, sizeof(fstring), -1, STR_TERMINATE);
234 p += clistr_pull(cli, cli->server_type, p, sizeof(fstring), -1, STR_TERMINATE);
235 p += clistr_pull(cli, cli->server_domain, p, sizeof(fstring), -1, STR_TERMINATE);
236 fstrcpy(cli->user_name, user);
238 return True;
243 do a NT1 NTLM/LM encrypted session setup
244 @param cli client state to create do session setup on
245 @param user username
246 @param pass *either* cleartext password (passlen !=24) or LM response.
247 @param ntpass NT response, implies ntpasslen >=24, implies pass is not clear
248 @param workgroup The user's domain.
251 static BOOL cli_session_setup_nt1(struct cli_state *cli, char *user,
252 char *pass, int passlen,
253 char *ntpass, int ntpasslen,
254 char *workgroup)
256 uint32 capabilities = cli_session_setup_capabilities(cli);
257 uchar pword[24];
258 uchar ntpword[24];
259 char *p;
260 BOOL tried_signing = False;
262 if (passlen > sizeof(pword) || ntpasslen > sizeof(ntpword)) {
263 return False;
266 if (passlen != 24) {
267 /* non encrypted password supplied. Ignore ntpass. */
268 passlen = 24;
269 ntpasslen = 24;
270 SMBencrypt(pass,cli->secblob.data,pword);
271 SMBNTencrypt(pass,cli->secblob.data,ntpword);
272 if (!cli->sign_info.use_smb_signing && cli->sign_info.negotiated_smb_signing) {
273 cli_calculate_mac_key(cli, pass, ntpword);
274 tried_signing = True;
276 } else {
277 /* pre-encrypted password supplied. Only used for security=server, can't do
278 signing becouse we don't have oringial key */
279 memcpy(pword, pass, 24);
280 if (ntpasslen == 24) {
281 memcpy(ntpword, ntpass, 24);
282 } else {
283 ZERO_STRUCT(ntpword);
287 /* send a session setup command */
288 memset(cli->outbuf,'\0',smb_size);
290 set_message(cli->outbuf,13,0,True);
291 SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
292 cli_setup_packet(cli);
294 SCVAL(cli->outbuf,smb_vwv0,0xFF);
295 SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
296 SSVAL(cli->outbuf,smb_vwv3,2);
297 SSVAL(cli->outbuf,smb_vwv4,cli->pid);
298 SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
299 SSVAL(cli->outbuf,smb_vwv7,passlen);
300 SSVAL(cli->outbuf,smb_vwv8,ntpasslen);
301 SIVAL(cli->outbuf,smb_vwv11,capabilities);
302 p = smb_buf(cli->outbuf);
303 memcpy(p,pword,passlen); p += passlen;
304 memcpy(p,ntpword,ntpasslen); p += ntpasslen;
305 p += clistr_push(cli, p, user, -1, STR_TERMINATE|STR_UPPER);
306 p += clistr_push(cli, p, workgroup, -1, STR_TERMINATE|STR_UPPER);
307 p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
308 p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
309 cli_setup_bcc(cli, p);
311 cli_send_smb(cli);
312 if (!cli_receive_smb(cli)) {
313 if (tried_signing) {
314 /* We only use it if we have a successful non-guest connect */
315 cli->sign_info.use_smb_signing = False;
317 return False;
320 show_msg(cli->inbuf);
322 if (tried_signing && (cli_is_error(cli) || SVAL(cli->inbuf,smb_vwv2) /* guest */)) {
323 /* We only use it if we have a successful non-guest connect */
324 cli->sign_info.use_smb_signing = False;
327 if (cli_is_error(cli)) {
328 return False;
331 /* use the returned vuid from now on */
332 cli->vuid = SVAL(cli->inbuf,smb_uid);
334 p = smb_buf(cli->inbuf);
335 p += clistr_pull(cli, cli->server_os, p, sizeof(fstring), -1, STR_TERMINATE);
336 p += clistr_pull(cli, cli->server_type, p, sizeof(fstring), -1, STR_TERMINATE);
337 p += clistr_pull(cli, cli->server_domain, p, sizeof(fstring), -1, STR_TERMINATE);
339 fstrcpy(cli->user_name, user);
341 return True;
344 /****************************************************************************
345 Send a extended security session setup blob, returning a reply blob.
346 ****************************************************************************/
348 static DATA_BLOB cli_session_setup_blob(struct cli_state *cli, DATA_BLOB blob)
350 uint32 capabilities = cli_session_setup_capabilities(cli);
351 char *p;
352 DATA_BLOB blob2;
353 uint32 len;
355 blob2 = data_blob(NULL, 0);
357 capabilities |= CAP_EXTENDED_SECURITY;
359 /* send a session setup command */
360 memset(cli->outbuf,'\0',smb_size);
362 set_message(cli->outbuf,12,0,True);
363 SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
364 cli_setup_packet(cli);
366 SCVAL(cli->outbuf,smb_vwv0,0xFF);
367 SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
368 SSVAL(cli->outbuf,smb_vwv3,2);
369 SSVAL(cli->outbuf,smb_vwv4,1);
370 SIVAL(cli->outbuf,smb_vwv5,0);
371 SSVAL(cli->outbuf,smb_vwv7,blob.length);
372 SIVAL(cli->outbuf,smb_vwv10,capabilities);
373 p = smb_buf(cli->outbuf);
374 memcpy(p, blob.data, blob.length);
375 p += blob.length;
376 p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE);
377 p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE);
378 cli_setup_bcc(cli, p);
380 cli_send_smb(cli);
381 if (!cli_receive_smb(cli))
382 return blob2;
384 show_msg(cli->inbuf);
386 if (cli_is_error(cli) && !NT_STATUS_EQUAL(cli_nt_error(cli),
387 NT_STATUS_MORE_PROCESSING_REQUIRED)) {
388 return blob2;
391 /* use the returned vuid from now on */
392 cli->vuid = SVAL(cli->inbuf,smb_uid);
394 p = smb_buf(cli->inbuf);
396 blob2 = data_blob(p, SVAL(cli->inbuf, smb_vwv3));
398 p += blob2.length;
399 p += clistr_pull(cli, cli->server_os, p, sizeof(fstring), -1, STR_TERMINATE);
401 /* w2k with kerberos doesn't properly null terminate this field */
402 len = smb_buflen(cli->inbuf) - PTR_DIFF(p, smb_buf(cli->inbuf));
403 p += clistr_pull(cli, cli->server_type, p, sizeof(fstring), len, 0);
405 return blob2;
409 #ifdef HAVE_KRB5
410 /****************************************************************************
411 Do a spnego/kerberos encrypted session setup.
412 ****************************************************************************/
414 static BOOL cli_session_setup_kerberos(struct cli_state *cli, char *principal, char *workgroup)
416 DATA_BLOB blob2, negTokenTarg;
418 DEBUG(2,("Doing kerberos session setup\n"));
420 /* generate the encapsulated kerberos5 ticket */
421 negTokenTarg = spnego_gen_negTokenTarg(cli, principal);
423 if (!negTokenTarg.data) return False;
425 #if 0
426 file_save("negTokenTarg.dat", negTokenTarg.data, negTokenTarg.length);
427 #endif
429 blob2 = cli_session_setup_blob(cli, negTokenTarg);
431 /* we don't need this blob for kerberos */
432 data_blob_free(&blob2);
434 data_blob_free(&negTokenTarg);
436 return !cli_is_error(cli);
438 #endif
440 /****************************************************************************
441 Do a spnego/NTLMSSP encrypted session setup.
442 ****************************************************************************/
444 static BOOL cli_session_setup_ntlmssp(struct cli_state *cli, char *user,
445 char *pass, char *workgroup)
447 const char *mechs[] = {OID_NTLMSSP, NULL};
448 DATA_BLOB msg1;
449 DATA_BLOB blob, chal1, chal2, auth;
450 uint8 challenge[8];
451 uint8 nthash[24], lmhash[24], sess_key[16];
452 uint32 neg_flags;
454 neg_flags = NTLMSSP_NEGOTIATE_UNICODE |
455 NTLMSSP_NEGOTIATE_LM_KEY |
456 NTLMSSP_NEGOTIATE_NTLM;
458 memset(sess_key, 0, 16);
460 /* generate the ntlmssp negotiate packet */
461 msrpc_gen(&blob, "CddB",
462 "NTLMSSP",
463 NTLMSSP_NEGOTIATE,
464 neg_flags,
465 sess_key, 16);
467 /* and wrap it in a SPNEGO wrapper */
468 msg1 = gen_negTokenTarg(mechs, blob);
469 data_blob_free(&blob);
471 /* now send that blob on its way */
472 blob = cli_session_setup_blob(cli, msg1);
474 data_blob_free(&msg1);
476 if (!NT_STATUS_EQUAL(cli_nt_error(cli), NT_STATUS_MORE_PROCESSING_REQUIRED)) {
477 return False;
480 #if 0
481 file_save("chal.dat", blob.data, blob.length);
482 #endif
484 /* the server gives us back two challenges */
485 if (!spnego_parse_challenge(blob, &chal1, &chal2)) {
486 DEBUG(3,("Failed to parse challenges\n"));
487 return False;
490 data_blob_free(&blob);
492 /* encrypt the password with the challenge */
493 memcpy(challenge, chal1.data + 24, 8);
494 SMBencrypt(pass, challenge,lmhash);
495 SMBNTencrypt(pass, challenge,nthash);
497 #if 0
498 file_save("nthash.dat", nthash, 24);
499 file_save("lmhash.dat", lmhash, 24);
500 file_save("chal1.dat", chal1.data, chal1.length);
501 #endif
503 data_blob_free(&chal1);
504 data_blob_free(&chal2);
506 /* this generates the actual auth packet */
507 msrpc_gen(&blob, "CdBBUUUBd",
508 "NTLMSSP",
509 NTLMSSP_AUTH,
510 lmhash, 24,
511 nthash, 24,
512 workgroup,
513 user,
514 cli->calling.name,
515 sess_key, 16,
516 neg_flags);
518 /* wrap it in SPNEGO */
519 auth = spnego_gen_auth(blob);
521 data_blob_free(&blob);
523 /* now send the auth packet and we should be done */
524 blob = cli_session_setup_blob(cli, auth);
526 data_blob_free(&auth);
527 data_blob_free(&blob);
529 return !cli_is_error(cli);
532 /****************************************************************************
533 Do a spnego encrypted session setup.
534 ****************************************************************************/
536 static BOOL cli_session_setup_spnego(struct cli_state *cli, char *user,
537 char *pass, char *workgroup)
539 char *principal;
540 char *OIDs[ASN1_MAX_OIDS];
541 uint8 guid[16];
542 int i;
543 BOOL got_kerberos_mechanism = False;
545 /* spnego security cannot use SMB signing (for now). */
546 cli->sign_info.use_smb_signing = False;
548 DEBUG(2,("Doing spnego session setup (blob length=%d)\n", cli->secblob.length));
550 /* the server might not even do spnego */
551 if (cli->secblob.length == 16) {
552 DEBUG(3,("server didn't supply a full spnego negprot\n"));
553 goto ntlmssp;
556 #if 0
557 file_save("negprot.dat", cli->secblob.data, cli->secblob.length);
558 #endif
560 /* the server sent us the first part of the SPNEGO exchange in the negprot
561 reply */
562 if (!spnego_parse_negTokenInit(cli->secblob, guid, OIDs, &principal)) {
563 return False;
566 /* make sure the server understands kerberos */
567 for (i=0;OIDs[i];i++) {
568 DEBUG(3,("got OID=%s\n", OIDs[i]));
569 if (strcmp(OIDs[i], OID_KERBEROS5_OLD) == 0 ||
570 strcmp(OIDs[i], OID_KERBEROS5) == 0) {
571 got_kerberos_mechanism = True;
573 free(OIDs[i]);
575 DEBUG(3,("got principal=%s\n", principal));
577 fstrcpy(cli->user_name, user);
579 #ifdef HAVE_KRB5
580 if (got_kerberos_mechanism && cli->use_kerberos) {
581 return cli_session_setup_kerberos(cli, principal, workgroup);
583 #endif
585 free(principal);
587 ntlmssp:
589 return cli_session_setup_ntlmssp(cli, user, pass, workgroup);
592 /****************************************************************************
593 Send a session setup. The username and workgroup is in UNIX character
594 format and must be converted to DOS codepage format before sending. If the
595 password is in plaintext, the same should be done.
596 ****************************************************************************/
598 BOOL cli_session_setup(struct cli_state *cli,
599 char *user,
600 char *pass, int passlen,
601 char *ntpass, int ntpasslen,
602 char *workgroup)
604 char *p;
605 fstring user2;
607 /* allow for workgroups as part of the username */
608 fstrcpy(user2, user);
609 if ((p=strchr_m(user2,'\\')) || (p=strchr_m(user2,'/')) ||
610 (p=strchr_m(user2,*lp_winbind_separator()))) {
611 *p = 0;
612 user = p+1;
613 workgroup = user2;
616 if (cli->protocol < PROTOCOL_LANMAN1)
617 return True;
619 /* now work out what sort of session setup we are going to
620 do. I have split this into separate functions to make the
621 flow a bit easier to understand (tridge) */
623 /* if its an older server then we have to use the older request format */
624 if (cli->protocol < PROTOCOL_NT1) {
625 return cli_session_setup_lanman2(cli, user, pass, passlen, workgroup);
628 /* if no user is supplied then we have to do an anonymous connection.
629 passwords are ignored */
630 if (!user || !*user) {
631 return cli_session_setup_guest(cli);
634 /* if the server is share level then send a plaintext null
635 password at this point. The password is sent in the tree
636 connect */
637 if ((cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL) == 0) {
638 return cli_session_setup_plaintext(cli, user, "", workgroup);
641 /* if the server doesn't support encryption then we have to use
642 plaintext. The second password is ignored */
643 if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) == 0) {
644 return cli_session_setup_plaintext(cli, user, pass, workgroup);
647 /* if the server supports extended security then use SPNEGO */
648 if (cli->capabilities & CAP_EXTENDED_SECURITY) {
649 return cli_session_setup_spnego(cli, user, pass, workgroup);
652 /* otherwise do a NT1 style session setup */
653 return cli_session_setup_nt1(cli, user,
654 pass, passlen, ntpass, ntpasslen,
655 workgroup);
658 /****************************************************************************
659 Send a uloggoff.
660 *****************************************************************************/
662 BOOL cli_ulogoff(struct cli_state *cli)
664 memset(cli->outbuf,'\0',smb_size);
665 set_message(cli->outbuf,2,0,True);
666 SCVAL(cli->outbuf,smb_com,SMBulogoffX);
667 cli_setup_packet(cli);
668 SSVAL(cli->outbuf,smb_vwv0,0xFF);
669 SSVAL(cli->outbuf,smb_vwv2,0); /* no additional info */
671 cli_send_smb(cli);
672 if (!cli_receive_smb(cli))
673 return False;
675 return !cli_is_error(cli);
678 /****************************************************************************
679 Send a tconX.
680 ****************************************************************************/
682 BOOL cli_send_tconX(struct cli_state *cli,
683 const char *share, const char *dev, const char *pass, int passlen)
685 fstring fullshare, pword;
686 char *p;
687 memset(cli->outbuf,'\0',smb_size);
688 memset(cli->inbuf,'\0',smb_size);
690 fstrcpy(cli->share, share);
692 /* in user level security don't send a password now */
693 if (cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL) {
694 passlen = 1;
695 pass = "";
698 if ((cli->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) && *pass && passlen != 24) {
700 * Non-encrypted passwords - convert to DOS codepage before encryption.
702 passlen = 24;
703 SMBencrypt(pass,cli->secblob.data,(uchar *)pword);
704 } else {
705 if((cli->sec_mode & (NEGOTIATE_SECURITY_USER_LEVEL|NEGOTIATE_SECURITY_CHALLENGE_RESPONSE)) == 0) {
707 * Non-encrypted passwords - convert to DOS codepage before using.
709 passlen = clistr_push(cli, pword, pass, -1, STR_TERMINATE);
710 } else {
711 memcpy(pword, pass, passlen);
715 if (cli->port == 445) {
716 slprintf(fullshare, sizeof(fullshare)-1,
717 "%s", share);
718 } else {
719 slprintf(fullshare, sizeof(fullshare)-1,
720 "\\\\%s\\%s", cli->desthost, share);
723 set_message(cli->outbuf,4, 0, True);
724 SCVAL(cli->outbuf,smb_com,SMBtconX);
725 cli_setup_packet(cli);
727 SSVAL(cli->outbuf,smb_vwv0,0xFF);
728 SSVAL(cli->outbuf,smb_vwv3,passlen);
730 p = smb_buf(cli->outbuf);
731 memcpy(p,pword,passlen);
732 p += passlen;
733 p += clistr_push(cli, p, fullshare, -1, STR_TERMINATE |STR_UPPER);
734 fstrcpy(p, dev); p += strlen(dev)+1;
736 cli_setup_bcc(cli, p);
738 cli_send_smb(cli);
739 if (!cli_receive_smb(cli))
740 return False;
742 if (cli_is_error(cli)) {
743 return False;
746 clistr_pull(cli, cli->dev, smb_buf(cli->inbuf), sizeof(fstring), -1, STR_TERMINATE|STR_ASCII);
748 if (strcasecmp(share,"IPC$")==0) {
749 fstrcpy(cli->dev, "IPC");
752 if (cli->protocol >= PROTOCOL_NT1 &&
753 smb_buflen(cli->inbuf) == 3) {
754 /* almost certainly win95 - enable bug fixes */
755 cli->win95 = True;
758 cli->cnum = SVAL(cli->inbuf,smb_tid);
759 return True;
762 /****************************************************************************
763 Send a tree disconnect.
764 ****************************************************************************/
766 BOOL cli_tdis(struct cli_state *cli)
768 memset(cli->outbuf,'\0',smb_size);
769 set_message(cli->outbuf,0,0,True);
770 SCVAL(cli->outbuf,smb_com,SMBtdis);
771 SSVAL(cli->outbuf,smb_tid,cli->cnum);
772 cli_setup_packet(cli);
774 cli_send_smb(cli);
775 if (!cli_receive_smb(cli))
776 return False;
778 return !cli_is_error(cli);
781 /****************************************************************************
782 Send a negprot command.
783 ****************************************************************************/
785 void cli_negprot_send(struct cli_state *cli)
787 char *p;
788 int numprots;
790 if (cli->protocol < PROTOCOL_NT1) {
791 cli->use_spnego = False;
794 memset(cli->outbuf,'\0',smb_size);
796 /* setup the protocol strings */
797 set_message(cli->outbuf,0,0,True);
799 p = smb_buf(cli->outbuf);
800 for (numprots=0;
801 prots[numprots].name && prots[numprots].prot<=cli->protocol;
802 numprots++) {
803 *p++ = 2;
804 p += clistr_push(cli, p, prots[numprots].name, -1, STR_TERMINATE);
807 SCVAL(cli->outbuf,smb_com,SMBnegprot);
808 cli_setup_bcc(cli, p);
809 cli_setup_packet(cli);
811 SCVAL(smb_buf(cli->outbuf),0,2);
813 cli_send_smb(cli);
816 /****************************************************************************
817 Send a negprot command.
818 ****************************************************************************/
820 BOOL cli_negprot(struct cli_state *cli)
822 char *p;
823 int numprots;
824 int plength;
826 if (cli->sign_info.use_smb_signing) {
827 DEBUG(0, ("Cannot send negprot again, particularly after setting up SMB Signing\n"));
828 return False;
831 if (cli->protocol < PROTOCOL_NT1) {
832 cli->use_spnego = False;
835 memset(cli->outbuf,'\0',smb_size);
837 /* setup the protocol strings */
838 for (plength=0,numprots=0;
839 prots[numprots].name && prots[numprots].prot<=cli->protocol;
840 numprots++)
841 plength += strlen(prots[numprots].name)+2;
843 set_message(cli->outbuf,0,plength,True);
845 p = smb_buf(cli->outbuf);
846 for (numprots=0;
847 prots[numprots].name && prots[numprots].prot<=cli->protocol;
848 numprots++) {
849 *p++ = 2;
850 p += clistr_push(cli, p, prots[numprots].name, -1, STR_TERMINATE);
853 SCVAL(cli->outbuf,smb_com,SMBnegprot);
854 cli_setup_packet(cli);
856 SCVAL(smb_buf(cli->outbuf),0,2);
858 cli_send_smb(cli);
859 if (!cli_receive_smb(cli))
860 return False;
862 show_msg(cli->inbuf);
864 if (cli_is_error(cli) ||
865 ((int)SVAL(cli->inbuf,smb_vwv0) >= numprots)) {
866 return(False);
869 cli->protocol = prots[SVAL(cli->inbuf,smb_vwv0)].prot;
871 if (cli->protocol >= PROTOCOL_NT1) {
872 /* NT protocol */
873 cli->sec_mode = CVAL(cli->inbuf,smb_vwv1);
874 cli->max_mux = SVAL(cli->inbuf, smb_vwv1+1);
875 cli->max_xmit = IVAL(cli->inbuf,smb_vwv3+1);
876 cli->sesskey = IVAL(cli->inbuf,smb_vwv7+1);
877 cli->serverzone = SVALS(cli->inbuf,smb_vwv15+1);
878 cli->serverzone *= 60;
879 /* this time arrives in real GMT */
880 cli->servertime = interpret_long_date(cli->inbuf+smb_vwv11+1);
881 cli->secblob = data_blob(smb_buf(cli->inbuf),smb_buflen(cli->inbuf));
882 cli->capabilities = IVAL(cli->inbuf,smb_vwv9+1);
883 if (cli->capabilities & CAP_RAW_MODE) {
884 cli->readbraw_supported = True;
885 cli->writebraw_supported = True;
887 /* work out if they sent us a workgroup */
888 if (!(cli->capabilities & CAP_EXTENDED_SECURITY) &&
889 smb_buflen(cli->inbuf) > 8) {
890 clistr_pull(cli, cli->server_domain,
891 smb_buf(cli->inbuf)+8, sizeof(cli->server_domain),
892 smb_buflen(cli->inbuf)-8, STR_UNICODE|STR_NOALIGN);
895 /* A way to attempt to force SMB signing */
896 if (getenv("CLI_FORCE_SMB_SIGNING"))
897 cli->sign_info.negotiated_smb_signing = True;
899 if (cli->sign_info.negotiated_smb_signing && !(cli->sec_mode & NEGOTIATE_SECURITY_SIGNATURES_ENABLED))
900 cli->sign_info.negotiated_smb_signing = False;
902 } else if (cli->protocol >= PROTOCOL_LANMAN1) {
903 cli->use_spnego = False;
904 cli->sec_mode = SVAL(cli->inbuf,smb_vwv1);
905 cli->max_xmit = SVAL(cli->inbuf,smb_vwv2);
906 cli->sesskey = IVAL(cli->inbuf,smb_vwv6);
907 cli->serverzone = SVALS(cli->inbuf,smb_vwv10);
908 cli->serverzone *= 60;
909 /* this time is converted to GMT by make_unix_date */
910 cli->servertime = make_unix_date(cli->inbuf+smb_vwv8);
911 cli->readbraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x1) != 0);
912 cli->writebraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x2) != 0);
913 cli->secblob = data_blob(smb_buf(cli->inbuf),smb_buflen(cli->inbuf));
914 } else {
915 /* the old core protocol */
916 cli->use_spnego = False;
917 cli->sec_mode = 0;
918 cli->serverzone = TimeDiff(time(NULL));
921 cli->max_xmit = MIN(cli->max_xmit, CLI_BUFFER_SIZE);
923 /* a way to force ascii SMB */
924 if (getenv("CLI_FORCE_ASCII")) {
925 cli->capabilities &= ~CAP_UNICODE;
928 return True;
931 /****************************************************************************
932 Send a session request. See rfc1002.txt 4.3 and 4.3.2.
933 ****************************************************************************/
935 BOOL cli_session_request(struct cli_state *cli,
936 struct nmb_name *calling, struct nmb_name *called)
938 char *p;
939 int len = 4;
940 extern pstring user_socket_options;
942 /* 445 doesn't have session request */
943 if (cli->port == 445) return True;
945 if (cli->sign_info.use_smb_signing) {
946 DEBUG(0, ("Cannot send session resquest again, particularly after setting up SMB Signing\n"));
947 return False;
950 /* send a session request (RFC 1002) */
951 memcpy(&(cli->calling), calling, sizeof(*calling));
952 memcpy(&(cli->called ), called , sizeof(*called ));
954 /* put in the destination name */
955 p = cli->outbuf+len;
956 name_mangle(cli->called .name, p, cli->called .name_type);
957 len += name_len(p);
959 /* and my name */
960 p = cli->outbuf+len;
961 name_mangle(cli->calling.name, p, cli->calling.name_type);
962 len += name_len(p);
964 /* setup the packet length
965 * Remove four bytes from the length count, since the length
966 * field in the NBT Session Service header counts the number
967 * of bytes which follow. The cli_send_smb() function knows
968 * about this and accounts for those four bytes.
969 * CRH.
971 len -= 4;
972 _smb_setlen(cli->outbuf,len);
973 SCVAL(cli->outbuf,0,0x81);
975 cli_send_smb(cli);
976 DEBUG(5,("Sent session request\n"));
978 if (!cli_receive_smb(cli))
979 return False;
981 if (CVAL(cli->inbuf,0) == 0x84) {
982 /* C. Hoch 9/14/95 Start */
983 /* For information, here is the response structure.
984 * We do the byte-twiddling to for portability.
985 struct RetargetResponse{
986 unsigned char type;
987 unsigned char flags;
988 int16 length;
989 int32 ip_addr;
990 int16 port;
993 int port = (CVAL(cli->inbuf,8)<<8)+CVAL(cli->inbuf,9);
994 /* SESSION RETARGET */
995 putip((char *)&cli->dest_ip,cli->inbuf+4);
997 cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip, port, LONG_CONNECT_TIMEOUT);
998 if (cli->fd == -1)
999 return False;
1001 DEBUG(3,("Retargeted\n"));
1003 set_socket_options(cli->fd,user_socket_options);
1005 /* Try again */
1007 static int depth;
1008 BOOL ret;
1009 if (depth > 4) {
1010 DEBUG(0,("Retarget recursion - failing\n"));
1011 return False;
1013 depth++;
1014 ret = cli_session_request(cli, calling, called);
1015 depth--;
1016 return ret;
1018 } /* C. Hoch 9/14/95 End */
1020 if (CVAL(cli->inbuf,0) != 0x82) {
1021 /* This is the wrong place to put the error... JRA. */
1022 cli->rap_error = CVAL(cli->inbuf,4);
1023 return False;
1025 return(True);
1028 /****************************************************************************
1029 Open the client sockets.
1030 ****************************************************************************/
1032 BOOL cli_connect(struct cli_state *cli, const char *host, struct in_addr *ip)
1034 extern pstring user_socket_options;
1035 int name_type = 0x20;
1036 char *p;
1038 /* reasonable default hostname */
1039 if (!host) host = "*SMBSERVER";
1041 fstrcpy(cli->desthost, host);
1043 /* allow hostnames of the form NAME#xx and do a netbios lookup */
1044 if ((p = strchr(cli->desthost, '#'))) {
1045 name_type = strtol(p+1, NULL, 16);
1046 *p = 0;
1049 if (!ip || is_zero_ip(*ip)) {
1050 if (!resolve_name(cli->desthost, &cli->dest_ip, name_type)) {
1051 return False;
1053 if (ip) *ip = cli->dest_ip;
1054 } else {
1055 cli->dest_ip = *ip;
1058 if (getenv("LIBSMB_PROG")) {
1059 cli->fd = sock_exec(getenv("LIBSMB_PROG"));
1060 } else {
1061 /* try 445 first, then 139 */
1062 int port = cli->port?cli->port:445;
1063 cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip,
1064 port, cli->timeout);
1065 if (cli->fd == -1 && cli->port == 0) {
1066 port = 139;
1067 cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip,
1068 port, cli->timeout);
1070 if (cli->fd != -1) cli->port = port;
1072 if (cli->fd == -1) {
1073 DEBUG(1,("Error connecting to %s (%s)\n",
1074 ip?inet_ntoa(*ip):host,strerror(errno)));
1075 return False;
1078 set_socket_options(cli->fd,user_socket_options);
1080 return True;
1083 /****************************************************************************
1084 Initialise client credentials for authenticated pipe access.
1085 ****************************************************************************/
1087 static void init_creds(struct ntuser_creds *creds, char* username,
1088 char* domain, char* password)
1090 ZERO_STRUCTP(creds);
1092 pwd_set_cleartext(&creds->pwd, password);
1094 fstrcpy(creds->user_name, username);
1095 fstrcpy(creds->domain, domain);
1097 if (!*username) {
1098 creds->pwd.null_pwd = True;
1103 establishes a connection right up to doing tconX, password specified.
1104 @param output_cli A fully initialised cli structure, non-null only on success
1105 @param dest_host The netbios name of the remote host
1106 @param dest_ip (optional) The the destination IP, NULL for name based lookup
1107 @param port (optional) The destination port (0 for default)
1108 @param service (optional) The share to make the connection to. Should be 'unqualified' in any way.
1109 @param service_type The 'type' of serivice.
1110 @param user Username, unix string
1111 @param domain User's domain
1112 @param password User's password, unencrypted unix string.
1115 NTSTATUS cli_full_connection(struct cli_state **output_cli,
1116 const char *my_name,
1117 const char *dest_host,
1118 struct in_addr *dest_ip, int port,
1119 char *service, char *service_type,
1120 char *user, char *domain,
1121 char *password, int flags)
1123 struct ntuser_creds creds;
1124 NTSTATUS nt_status;
1125 struct nmb_name calling;
1126 struct nmb_name called;
1127 struct cli_state *cli;
1128 struct in_addr ip;
1129 extern pstring global_myname;
1131 if (!my_name)
1132 my_name = global_myname;
1134 if (!(cli = cli_initialise(NULL)))
1135 return NT_STATUS_NO_MEMORY;
1137 make_nmb_name(&calling, my_name, 0x0);
1138 make_nmb_name(&called , dest_host, 0x20);
1140 if (cli_set_port(cli, port) != port) {
1141 cli_shutdown(cli);
1142 return NT_STATUS_UNSUCCESSFUL;
1145 if (dest_ip) {
1146 ip = *dest_ip;
1147 } else {
1148 ZERO_STRUCT(ip);
1151 again:
1153 DEBUG(3,("Connecting to host=%s share=%s\n", dest_host, service));
1155 if (!cli_connect(cli, dest_host, &ip)) {
1156 DEBUG(1,("cli_full_connection: failed to connect to %s (%s)\n",
1157 nmb_namestr(&called), inet_ntoa(ip)));
1158 cli_shutdown(cli);
1159 return NT_STATUS_UNSUCCESSFUL;
1162 if (!cli_session_request(cli, &calling, &called)) {
1163 char *p;
1164 DEBUG(1,("session request to %s failed (%s)\n",
1165 called.name, cli_errstr(cli)));
1166 cli_shutdown(cli);
1167 if ((p=strchr(called.name, '.'))) {
1168 *p = 0;
1169 goto again;
1171 if (strcmp(called.name, "*SMBSERVER")) {
1172 make_nmb_name(&called , "*SMBSERVER", 0x20);
1173 goto again;
1175 return NT_STATUS_UNSUCCESSFUL;
1178 if (flags & CLI_FULL_CONNECTION_DONT_SPNEGO) {
1179 cli->use_spnego = False;
1180 } else if (flags & CLI_FULL_CONNECTION_USE_KERBEROS) {
1181 cli->use_kerberos = True;
1184 if (!cli_negprot(cli)) {
1185 DEBUG(1,("failed negprot\n"));
1186 nt_status = NT_STATUS_UNSUCCESSFUL;
1187 cli_shutdown(cli);
1188 return nt_status;
1191 if (!cli_session_setup(cli, user, password, strlen(password)+1,
1192 password, strlen(password)+1,
1193 domain)) {
1194 if (!(flags & CLI_FULL_CONNECTION_ANNONYMOUS_FALLBACK)
1195 || cli_session_setup(cli, "", "", 0,
1196 "", 0, domain)) {
1197 } else {
1198 nt_status = cli_nt_error(cli);
1199 DEBUG(1,("failed session setup with %s\n", nt_errstr(nt_status)));
1200 cli_shutdown(cli);
1201 if (NT_STATUS_IS_OK(nt_status))
1202 nt_status = NT_STATUS_UNSUCCESSFUL;
1203 return nt_status;
1207 if (service) {
1208 if (!cli_send_tconX(cli, service, service_type,
1209 (char*)password, strlen(password)+1)) {
1210 DEBUG(1,("failed tcon_X with %s\n", nt_errstr(nt_status)));
1211 nt_status = cli_nt_error(cli);
1212 cli_shutdown(cli);
1213 if (NT_STATUS_IS_OK(nt_status)) {
1214 nt_status = NT_STATUS_UNSUCCESSFUL;
1216 return nt_status;
1220 init_creds(&creds, user, domain, password);
1221 cli_init_creds(cli, &creds);
1223 *output_cli = cli;
1224 return NT_STATUS_OK;
1227 /****************************************************************************
1228 Attempt a NetBIOS session request, falling back to *SMBSERVER if needed.
1229 ****************************************************************************/
1231 BOOL attempt_netbios_session_request(struct cli_state *cli, char *srchost, char *desthost,
1232 struct in_addr *pdest_ip)
1234 struct nmb_name calling, called;
1236 make_nmb_name(&calling, srchost, 0x0);
1239 * If the called name is an IP address
1240 * then use *SMBSERVER immediately.
1243 if(is_ipaddress(desthost))
1244 make_nmb_name(&called, "*SMBSERVER", 0x20);
1245 else
1246 make_nmb_name(&called, desthost, 0x20);
1248 if (!cli_session_request(cli, &calling, &called)) {
1249 struct nmb_name smbservername;
1251 make_nmb_name(&smbservername , "*SMBSERVER", 0x20);
1254 * If the name wasn't *SMBSERVER then
1255 * try with *SMBSERVER if the first name fails.
1258 if (nmb_name_equal(&called, &smbservername)) {
1261 * The name used was *SMBSERVER, don't bother with another name.
1264 DEBUG(0,("attempt_netbios_session_request: %s rejected the session for name *SMBSERVER \
1265 with error %s.\n", desthost, cli_errstr(cli) ));
1266 cli_shutdown(cli);
1267 return False;
1270 cli_shutdown(cli);
1272 if (!cli_initialise(cli) ||
1273 !cli_connect(cli, desthost, pdest_ip) ||
1274 !cli_session_request(cli, &calling, &smbservername)) {
1275 DEBUG(0,("attempt_netbios_session_request: %s rejected the session for \
1276 name *SMBSERVER with error %s\n", desthost, cli_errstr(cli) ));
1277 cli_shutdown(cli);
1278 return False;
1282 return True;