few edits
[Samba.git] / source / libsmb / cliconnect.c
blob0da6b03dcd5f9a3676950ef7d76d125f1586a7a0
1 /*
2 Unix SMB/Netbios implementation.
3 Version 3.0
4 client connect/disconnect routines
5 Copyright (C) Andrew Tridgell 1994-1998
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,"Samba"},
37 {PROTOCOL_NT1,"NT LANMAN 1.0"},
38 {PROTOCOL_NT1,"NT LM 0.12"},
39 {-1,NULL}
42 /****************************************************************************
43 Do an old lanman2 style session setup.
44 ****************************************************************************/
46 static BOOL cli_session_setup_lanman2(struct cli_state *cli, char *user,
47 char *pass, int passlen)
49 fstring pword;
50 char *p;
52 if (passlen > sizeof(pword)-1) {
53 return False;
56 /* if in share level security then don't send a password now */
57 if (!(cli->sec_mode & 1)) {
58 passlen = 0;
61 if (passlen > 0 && (cli->sec_mode & 2) && passlen != 24) {
62 /* Encrypted mode needed, and non encrypted password supplied. */
63 passlen = 24;
64 clistr_push(cli, pword, pass, -1, STR_CONVERT|STR_TERMINATE);
65 SMBencrypt((uchar *)pword,cli->cryptkey,(uchar *)pword);
66 } else if ((cli->sec_mode & 2) && 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_CONVERT|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);
91 cli_setup_bcc(cli, p);
93 cli_send_smb(cli);
94 if (!cli_receive_smb(cli))
95 return False;
97 show_msg(cli->inbuf);
99 if (cli_is_error(cli)) {
100 return False;
103 /* use the returned vuid from now on */
104 cli->vuid = SVAL(cli->inbuf,smb_uid);
105 fstrcpy(cli->user_name, user);
107 return True;
110 /****************************************************************************
111 Work out suitable capabilities to offer the server.
112 ****************************************************************************/
114 static uint32 cli_session_setup_capabilities(struct cli_state *cli)
116 uint32 capabilities = CAP_NT_SMBS;
118 if (!cli->force_dos_errors) {
119 capabilities |= CAP_STATUS32;
122 if (cli->use_level_II_oplocks) {
123 capabilities |= CAP_LEVEL_II_OPLOCKS;
126 if (cli->capabilities & CAP_UNICODE) {
127 capabilities |= CAP_UNICODE;
130 return capabilities;
133 /****************************************************************************
134 Do a NT1 guest session setup.
135 ****************************************************************************/
137 static BOOL cli_session_setup_guest(struct cli_state *cli)
139 char *p;
140 uint32 capabilities = cli_session_setup_capabilities(cli);
142 set_message(cli->outbuf,13,0,True);
143 SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
144 cli_setup_packet(cli);
146 SCVAL(cli->outbuf,smb_vwv0,0xFF);
147 SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
148 SSVAL(cli->outbuf,smb_vwv3,2);
149 SSVAL(cli->outbuf,smb_vwv4,cli->pid);
150 SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
151 SSVAL(cli->outbuf,smb_vwv7,0);
152 SSVAL(cli->outbuf,smb_vwv8,0);
153 SIVAL(cli->outbuf,smb_vwv11,capabilities);
154 p = smb_buf(cli->outbuf);
155 p += clistr_push(cli, p, "", -1, STR_TERMINATE|STR_CONVERT); /* username */
156 p += clistr_push(cli, p, "", -1, STR_TERMINATE|STR_CONVERT); /* workgroup */
157 p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE|STR_CONVERT);
158 p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE|STR_CONVERT);
159 cli_setup_bcc(cli, p);
161 cli_send_smb(cli);
162 if (!cli_receive_smb(cli))
163 return False;
165 show_msg(cli->inbuf);
167 if (cli_is_error(cli)) {
168 return False;
171 cli->vuid = SVAL(cli->inbuf,smb_uid);
173 p = smb_buf(cli->inbuf);
174 p += clistr_pull(cli, cli->server_os, p, sizeof(fstring), -1, STR_TERMINATE);
175 p += clistr_pull(cli, cli->server_type, p, sizeof(fstring), -1, STR_TERMINATE);
176 p += clistr_pull(cli, cli->server_domain, p, sizeof(fstring), -1, STR_TERMINATE);
178 fstrcpy(cli->user_name, "");
180 return True;
183 /****************************************************************************
184 Do a NT1 plaintext session setup.
185 ****************************************************************************/
187 static BOOL cli_session_setup_plaintext(struct cli_state *cli, char *user,
188 char *pass, char *workgroup)
190 uint32 capabilities = cli_session_setup_capabilities(cli);
191 fstring pword;
192 int passlen;
193 char *p;
195 passlen = clistr_push(cli, pword, pass, sizeof(pword), STR_TERMINATE|STR_CONVERT);
197 set_message(cli->outbuf,13,0,True);
198 SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
199 cli_setup_packet(cli);
201 SCVAL(cli->outbuf,smb_vwv0,0xFF);
202 SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
203 SSVAL(cli->outbuf,smb_vwv3,2);
204 SSVAL(cli->outbuf,smb_vwv4,cli->pid);
205 SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
206 SSVAL(cli->outbuf,smb_vwv7,passlen);
207 SSVAL(cli->outbuf,smb_vwv8,0);
208 SIVAL(cli->outbuf,smb_vwv11,capabilities);
209 p = smb_buf(cli->outbuf);
210 memcpy(p, pword, passlen);
211 p += passlen;
212 p += clistr_push(cli, p, user, -1, STR_TERMINATE|STR_CONVERT); /* username */
213 p += clistr_push(cli, p, workgroup, -1, STR_TERMINATE|STR_CONVERT); /* workgroup */
214 p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE|STR_CONVERT);
215 p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE|STR_CONVERT);
216 cli_setup_bcc(cli, p);
218 cli_send_smb(cli);
219 if (!cli_receive_smb(cli))
220 return False;
222 show_msg(cli->inbuf);
224 if (cli_is_error(cli)) {
225 return False;
228 cli->vuid = SVAL(cli->inbuf,smb_uid);
229 p = smb_buf(cli->inbuf);
230 p += clistr_pull(cli, cli->server_os, p, sizeof(fstring), -1, STR_TERMINATE);
231 p += clistr_pull(cli, cli->server_type, p, sizeof(fstring), -1, STR_TERMINATE);
232 p += clistr_pull(cli, cli->server_domain, p, sizeof(fstring), -1, STR_TERMINATE);
233 fstrcpy(cli->user_name, user);
235 return True;
239 /****************************************************************************
240 Do a NT1 NTLM/LM encrypted session setup.
241 ****************************************************************************/
243 static BOOL cli_session_setup_nt1(struct cli_state *cli, char *user,
244 char *pass, int passlen,
245 char *ntpass, int ntpasslen,
246 char *workgroup)
248 uint32 capabilities = cli_session_setup_capabilities(cli);
249 fstring pword, ntpword;
250 char *p;
252 if (passlen > sizeof(pword)-1 || ntpasslen > sizeof(ntpword)-1) {
253 return False;
256 if (passlen != 24) {
257 /* non encrypted password supplied. */
258 passlen = 24;
259 ntpasslen = 24;
260 clistr_push(cli, pword, pass, sizeof(pword), STR_TERMINATE|STR_CONVERT);
261 clistr_push(cli, ntpword, ntpass, sizeof(ntpword), STR_TERMINATE|STR_CONVERT);
262 SMBencrypt((uchar *)pword,cli->cryptkey,(uchar *)pword);
263 SMBNTencrypt((uchar *)ntpword,cli->cryptkey,(uchar *)ntpword);
264 } else {
265 memcpy(pword, pass, passlen);
266 memcpy(ntpword, ntpass, ntpasslen);
269 /* send a session setup command */
270 memset(cli->outbuf,'\0',smb_size);
272 set_message(cli->outbuf,13,0,True);
273 SCVAL(cli->outbuf,smb_com,SMBsesssetupX);
274 cli_setup_packet(cli);
276 SCVAL(cli->outbuf,smb_vwv0,0xFF);
277 SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
278 SSVAL(cli->outbuf,smb_vwv3,2);
279 SSVAL(cli->outbuf,smb_vwv4,cli->pid);
280 SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
281 SSVAL(cli->outbuf,smb_vwv7,passlen);
282 SSVAL(cli->outbuf,smb_vwv8,ntpasslen);
283 SIVAL(cli->outbuf,smb_vwv11,capabilities);
284 p = smb_buf(cli->outbuf);
285 memcpy(p,pword,passlen); p += passlen;
286 memcpy(p,ntpword,ntpasslen); p += ntpasslen;
287 p += clistr_push(cli, p, user, -1, STR_TERMINATE|STR_UPPER|STR_CONVERT);
288 p += clistr_push(cli, p, workgroup, -1, STR_TERMINATE|STR_UPPER|STR_CONVERT);
289 p += clistr_push(cli, p, "Unix", -1, STR_TERMINATE|STR_CONVERT);
290 p += clistr_push(cli, p, "Samba", -1, STR_TERMINATE|STR_CONVERT);
291 cli_setup_bcc(cli, p);
293 cli_send_smb(cli);
294 if (!cli_receive_smb(cli))
295 return False;
297 show_msg(cli->inbuf);
299 if (cli_is_error(cli)) {
300 return False;
303 /* use the returned vuid from now on */
304 cli->vuid = SVAL(cli->inbuf,smb_uid);
306 p = smb_buf(cli->inbuf);
307 p += clistr_pull(cli, cli->server_os, p, sizeof(fstring), -1, STR_TERMINATE);
308 p += clistr_pull(cli, cli->server_type, p, sizeof(fstring), -1, STR_TERMINATE);
309 p += clistr_pull(cli, cli->server_domain, p, sizeof(fstring), -1, STR_TERMINATE);
311 fstrcpy(cli->user_name, user);
313 return True;
316 /****************************************************************************
317 Send a session setup. The username and workgroup is in UNIX character
318 format and must be converted to DOS codepage format before sending. If the
319 password is in plaintext, the same should be done.
320 ****************************************************************************/
322 BOOL cli_session_setup(struct cli_state *cli,
323 char *user,
324 char *pass, int passlen,
325 char *ntpass, int ntpasslen,
326 char *workgroup)
328 char *p;
329 fstring user2;
331 /* allow for workgroups as part of the username */
332 fstrcpy(user2, user);
333 if ((p=strchr(user2,'\\')) || (p=strchr(user2,'/')) || (p=strchr(user2,*lp_winbind_separator())) ) {
334 *p = 0;
335 user = p+1;
336 workgroup = user2;
339 if (cli->protocol < PROTOCOL_LANMAN1)
340 return True;
342 /* now work out what sort of session setup we are going to
343 do. I have split this into separate functions to make the
344 flow a bit easier to understand (tridge) */
346 /* if its an older server then we have to use the older request format */
347 if (cli->protocol < PROTOCOL_NT1) {
348 return cli_session_setup_lanman2(cli, user, pass, passlen);
351 /* if no user is supplied then we have to do an anonymous connection.
352 passwords are ignored */
353 if (!user || !*user) {
354 return cli_session_setup_guest(cli);
357 /* if the server is share level then send a plaintext null
358 password at this point. The password is sent in the tree
359 connect */
360 if ((cli->sec_mode & 1) == 0) {
361 return cli_session_setup_plaintext(cli, user, "", workgroup);
364 /* if the server doesn't support encryption then we have to use plaintext. The
365 second password is ignored */
366 if ((cli->sec_mode & 2) == 0) {
367 return cli_session_setup_plaintext(cli, user, pass, workgroup);
370 /* Do a NT1 style session setup */
371 return cli_session_setup_nt1(cli, user,
372 pass, passlen, ntpass, ntpasslen,
373 workgroup);
376 /****************************************************************************
377 Send a uloggoff.
378 *****************************************************************************/
380 BOOL cli_ulogoff(struct cli_state *cli)
382 memset(cli->outbuf,'\0',smb_size);
383 set_message(cli->outbuf,2,0,True);
384 SCVAL(cli->outbuf,smb_com,SMBulogoffX);
385 cli_setup_packet(cli);
386 SSVAL(cli->outbuf,smb_vwv0,0xFF);
387 SSVAL(cli->outbuf,smb_vwv2,0); /* no additional info */
389 cli_send_smb(cli);
390 if (!cli_receive_smb(cli))
391 return False;
393 return !cli_is_error(cli);
396 /****************************************************************************
397 Send a tconX.
398 ****************************************************************************/
400 BOOL cli_send_tconX(struct cli_state *cli,
401 const char *share, const char *dev, const char *pass, int passlen)
403 fstring fullshare, pword, dos_pword;
404 char *p;
405 memset(cli->outbuf,'\0',smb_size);
406 memset(cli->inbuf,'\0',smb_size);
408 fstrcpy(cli->share, share);
410 /* in user level security don't send a password now */
411 if (cli->sec_mode & 1) {
412 passlen = 1;
413 pass = "";
416 if ((cli->sec_mode & 2) && *pass && passlen != 24) {
418 * Non-encrypted passwords - convert to DOS codepage before encryption.
420 passlen = 24;
421 clistr_push(cli, dos_pword, pass, -1, STR_CONVERT|STR_TERMINATE);
422 SMBencrypt((uchar *)dos_pword,cli->cryptkey,(uchar *)pword);
423 } else {
424 if((cli->sec_mode & 3) == 0) {
426 * Non-encrypted passwords - convert to DOS codepage before using.
428 passlen = clistr_push(cli, pword, pass, -1, STR_CONVERT|STR_TERMINATE);
429 } else {
430 memcpy(pword, pass, passlen);
434 if (cli->port == 445) {
435 slprintf(fullshare, sizeof(fullshare)-1,
436 "%s", share);
437 } else {
438 slprintf(fullshare, sizeof(fullshare)-1,
439 "\\\\%s\\%s", cli->desthost, share);
442 set_message(cli->outbuf,4, 0, True);
443 SCVAL(cli->outbuf,smb_com,SMBtconX);
444 cli_setup_packet(cli);
446 SSVAL(cli->outbuf,smb_vwv0,0xFF);
447 SSVAL(cli->outbuf,smb_vwv3,passlen);
449 p = smb_buf(cli->outbuf);
450 memcpy(p,pword,passlen);
451 p += passlen;
452 p += clistr_push(cli, p, fullshare, -1, STR_CONVERT|STR_TERMINATE|STR_UPPER);
453 fstrcpy(p, dev); p += strlen(dev)+1;
455 cli_setup_bcc(cli, p);
457 cli_send_smb(cli);
458 if (!cli_receive_smb(cli))
459 return False;
461 if (cli_is_error(cli)) {
462 return False;
465 fstrcpy(cli->dev, "A:");
467 if (cli->protocol >= PROTOCOL_NT1) {
468 clistr_pull(cli, cli->dev, smb_buf(cli->inbuf), sizeof(fstring), -1, STR_TERMINATE);
471 if (strcasecmp(share,"IPC$")==0) {
472 fstrcpy(cli->dev, "IPC");
475 /* only grab the device if we have a recent protocol level */
476 if (cli->protocol >= PROTOCOL_NT1 &&
477 smb_buflen(cli->inbuf) == 3) {
478 /* almost certainly win95 - enable bug fixes */
479 cli->win95 = True;
482 cli->cnum = SVAL(cli->inbuf,smb_tid);
483 return True;
487 /****************************************************************************
488 Send a tree disconnect.
489 ****************************************************************************/
491 BOOL cli_tdis(struct cli_state *cli)
493 memset(cli->outbuf,'\0',smb_size);
494 set_message(cli->outbuf,0,0,True);
495 SCVAL(cli->outbuf,smb_com,SMBtdis);
496 SSVAL(cli->outbuf,smb_tid,cli->cnum);
497 cli_setup_packet(cli);
499 cli_send_smb(cli);
500 if (!cli_receive_smb(cli))
501 return False;
503 return !cli_is_error(cli);
507 /****************************************************************************
508 Send a negprot command.
509 ****************************************************************************/
511 void cli_negprot_send(struct cli_state *cli)
513 char *p;
514 int numprots;
516 memset(cli->outbuf,'\0',smb_size);
518 /* setup the protocol strings */
519 set_message(cli->outbuf,0,0,True);
521 p = smb_buf(cli->outbuf);
522 for (numprots=0;
523 prots[numprots].name && prots[numprots].prot<=cli->protocol;
524 numprots++) {
525 *p++ = 2;
526 p += clistr_push(cli, p, prots[numprots].name, -1, STR_CONVERT|STR_TERMINATE);
529 SCVAL(cli->outbuf,smb_com,SMBnegprot);
530 cli_setup_bcc(cli, p);
531 cli_setup_packet(cli);
533 SCVAL(smb_buf(cli->outbuf),0,2);
535 cli_send_smb(cli);
539 /****************************************************************************
540 Send a negprot command.
541 ****************************************************************************/
543 BOOL cli_negprot(struct cli_state *cli)
545 char *p;
546 int numprots;
547 int plength;
549 memset(cli->outbuf,'\0',smb_size);
551 /* setup the protocol strings */
552 for (plength=0,numprots=0;
553 prots[numprots].name && prots[numprots].prot<=cli->protocol;
554 numprots++)
555 plength += strlen(prots[numprots].name)+2;
557 set_message(cli->outbuf,0,plength,True);
559 p = smb_buf(cli->outbuf);
560 for (numprots=0;
561 prots[numprots].name && prots[numprots].prot<=cli->protocol;
562 numprots++) {
563 *p++ = 2;
564 p += clistr_push(cli, p, prots[numprots].name, -1, STR_CONVERT|STR_TERMINATE);
567 SCVAL(cli->outbuf,smb_com,SMBnegprot);
568 cli_setup_packet(cli);
570 SCVAL(smb_buf(cli->outbuf),0,2);
572 cli_send_smb(cli);
573 if (!cli_receive_smb(cli))
574 return False;
576 show_msg(cli->inbuf);
578 if (cli_is_error(cli) ||
579 ((int)SVAL(cli->inbuf,smb_vwv0) >= numprots)) {
580 return(False);
583 cli->protocol = prots[SVAL(cli->inbuf,smb_vwv0)].prot;
585 if (cli->protocol >= PROTOCOL_NT1) {
586 /* NT protocol */
587 cli->sec_mode = CVAL(cli->inbuf,smb_vwv1);
588 cli->max_mux = SVAL(cli->inbuf, smb_vwv1+1);
589 cli->max_xmit = IVAL(cli->inbuf,smb_vwv3+1);
590 cli->sesskey = IVAL(cli->inbuf,smb_vwv7+1);
591 cli->serverzone = SVALS(cli->inbuf,smb_vwv15+1);
592 cli->serverzone *= 60;
593 /* this time arrives in real GMT */
594 cli->servertime = interpret_long_date(cli->inbuf+smb_vwv11+1);
595 memcpy(cli->cryptkey,smb_buf(cli->inbuf),8);
596 cli->capabilities = IVAL(cli->inbuf,smb_vwv9+1);
597 if (cli->capabilities & CAP_RAW_MODE) {
598 cli->readbraw_supported = True;
599 cli->writebraw_supported = True;
601 /* work out if they sent us a workgroup */
602 if (smb_buflen(cli->inbuf) > 8) {
603 clistr_pull(cli, cli->server_domain,
604 smb_buf(cli->inbuf)+8, sizeof(cli->server_domain),
605 smb_buflen(cli->inbuf)-8, STR_UNICODE|STR_NOALIGN);
607 } else if (cli->protocol >= PROTOCOL_LANMAN1) {
608 cli->sec_mode = SVAL(cli->inbuf,smb_vwv1);
609 cli->max_xmit = SVAL(cli->inbuf,smb_vwv2);
610 cli->sesskey = IVAL(cli->inbuf,smb_vwv6);
611 cli->serverzone = SVALS(cli->inbuf,smb_vwv10);
612 cli->serverzone *= 60;
613 /* this time is converted to GMT by make_unix_date */
614 cli->servertime = make_unix_date(cli->inbuf+smb_vwv8);
615 cli->readbraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x1) != 0);
616 cli->writebraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x2) != 0);
617 memcpy(cli->cryptkey,smb_buf(cli->inbuf),8);
618 } else {
619 /* the old core protocol */
620 cli->sec_mode = 0;
621 cli->serverzone = TimeDiff(time(NULL));
624 cli->max_xmit = MIN(cli->max_xmit, CLI_BUFFER_SIZE);
626 /* a way to force ascii SMB */
627 if (getenv("CLI_FORCE_ASCII")) {
628 cli->capabilities &= ~CAP_UNICODE;
631 return True;
635 /****************************************************************************
636 Send a session request. see rfc1002.txt 4.3 and 4.3.2.
637 ****************************************************************************/
639 BOOL cli_session_request(struct cli_state *cli,
640 struct nmb_name *calling, struct nmb_name *called)
642 char *p;
643 int len = 4;
644 extern pstring user_socket_options;
646 /* 445 doesn't have session request */
647 if (cli->port == 445) return True;
649 /* send a session request (RFC 1002) */
650 memcpy(&(cli->calling), calling, sizeof(*calling));
651 memcpy(&(cli->called ), called , sizeof(*called ));
653 /* put in the destination name */
654 p = cli->outbuf+len;
655 name_mangle(cli->called .name, p, cli->called .name_type);
656 len += name_len(p);
658 /* and my name */
659 p = cli->outbuf+len;
660 name_mangle(cli->calling.name, p, cli->calling.name_type);
661 len += name_len(p);
663 /* setup the packet length
664 * Remove four bytes from the length count, since the length
665 * field in the NBT Session Service header counts the number
666 * of bytes which follow. The cli_send_smb() function knows
667 * about this and accounts for those four bytes.
668 * CRH.
670 len -= 4;
671 _smb_setlen(cli->outbuf,len);
672 SCVAL(cli->outbuf,0,0x81);
674 #ifdef WITH_SSL
675 retry:
676 #endif /* WITH_SSL */
678 cli_send_smb(cli);
679 DEBUG(5,("Sent session request\n"));
681 if (!cli_receive_smb(cli))
682 return False;
684 if (CVAL(cli->inbuf,0) == 0x84) {
685 /* C. Hoch 9/14/95 Start */
686 /* For information, here is the response structure.
687 * We do the byte-twiddling to for portability.
688 struct RetargetResponse{
689 unsigned char type;
690 unsigned char flags;
691 int16 length;
692 int32 ip_addr;
693 int16 port;
696 int port = (CVAL(cli->inbuf,8)<<8)+CVAL(cli->inbuf,9);
697 /* SESSION RETARGET */
698 putip((char *)&cli->dest_ip,cli->inbuf+4);
700 cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip, port, LONG_CONNECT_TIMEOUT);
701 if (cli->fd == -1)
702 return False;
704 DEBUG(3,("Retargeted\n"));
706 set_socket_options(cli->fd,user_socket_options);
708 /* Try again */
710 static int depth;
711 BOOL ret;
712 if (depth > 4) {
713 DEBUG(0,("Retarget recursion - failing\n"));
714 return False;
716 depth++;
717 ret = cli_session_request(cli, calling, called);
718 depth--;
719 return ret;
721 } /* C. Hoch 9/14/95 End */
723 #ifdef WITH_SSL
724 if (CVAL(cli->inbuf,0) == 0x83 && CVAL(cli->inbuf,4) == 0x8e){ /* use ssl */
725 if (!sslutil_fd_is_ssl(cli->fd)){
726 if (sslutil_connect(cli->fd) == 0)
727 goto retry;
730 #endif /* WITH_SSL */
732 if (CVAL(cli->inbuf,0) != 0x82) {
733 /* This is the wrong place to put the error... JRA. */
734 cli->rap_error = CVAL(cli->inbuf,4);
735 return False;
737 return(True);
740 /****************************************************************************
741 Open the client sockets.
742 ****************************************************************************/
744 BOOL cli_connect(struct cli_state *cli, const char *host, struct in_addr *ip)
746 extern pstring user_socket_options;
747 int name_type = 0x20;
748 char *p;
750 /* reasonable default hostname */
751 if (!host)
752 host = "*SMBSERVER";
754 fstrcpy(cli->desthost, host);
756 /* allow hostnames of the form NAME#xx and do a netbios lookup */
757 if ((p = strchr(cli->desthost, '#'))) {
758 name_type = strtol(p+1, NULL, 16);
759 *p = 0;
762 if (!ip || is_zero_ip(*ip)) {
763 if (!resolve_name(cli->desthost, &cli->dest_ip, name_type)) {
764 return False;
766 if (ip)
767 *ip = cli->dest_ip;
768 } else {
769 cli->dest_ip = *ip;
772 if (getenv("LIBSMB_PROG")) {
773 cli->fd = sock_exec(getenv("LIBSMB_PROG"));
774 } else {
775 /* try 445 first, then 139 */
776 int port = cli->port?cli->port:445;
777 cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip,
778 port, cli->timeout);
779 if (cli->fd == -1 && cli->port == 0) {
780 port = 139;
781 cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip,
782 port, cli->timeout);
784 if (cli->fd != -1) cli->port = port;
786 if (cli->fd == -1) {
787 DEBUG(1,("Error connecting to %s (%s)\n",
788 inet_ntoa(*ip),strerror(errno)));
789 return False;
792 set_socket_options(cli->fd,user_socket_options);
794 return True;
797 /****************************************************************************
798 Establishes a connection right up to doing tconX, reading in a password.
799 ****************************************************************************/
801 BOOL cli_establish_connection(struct cli_state *cli,
802 char *dest_host, struct in_addr *dest_ip,
803 struct nmb_name *calling, struct nmb_name *called,
804 char *service, char *service_type,
805 BOOL do_shutdown, BOOL do_tcon)
807 DEBUG(5,("cli_establish_connection: %s connecting to %s (%s) - %s [%s]\n",
808 nmb_namestr(calling), nmb_namestr(called), inet_ntoa(*dest_ip),
809 cli->user_name, cli->domain));
811 /* establish connection */
813 if ((!cli->initialised))
814 return False;
816 if (cli->fd == -1) {
817 if (!cli_connect(cli, dest_host, dest_ip)) {
818 DEBUG(1,("cli_establish_connection: failed to connect to %s (%s)\n",
819 nmb_namestr(called), inet_ntoa(*dest_ip)));
820 return False;
824 if (!cli_session_request(cli, calling, called)) {
825 DEBUG(1,("failed session request\n"));
826 if (do_shutdown)
827 cli_shutdown(cli);
828 return False;
831 if (!cli_negprot(cli)) {
832 DEBUG(1,("failed negprot\n"));
833 if (do_shutdown)
834 cli_shutdown(cli);
835 return False;
838 if (cli->pwd.cleartext || cli->pwd.null_pwd) {
839 fstring passwd;
840 int pass_len;
842 if (cli->pwd.null_pwd) {
843 /* attempt null session */
844 passwd[0] = 0;
845 pass_len = 1;
846 } else {
847 /* attempt clear-text session */
848 pwd_get_cleartext(&(cli->pwd), passwd);
849 pass_len = strlen(passwd);
852 /* attempt clear-text session */
853 if (!cli_session_setup(cli, cli->user_name,
854 passwd, pass_len,
855 NULL, 0,
856 cli->domain)) {
857 DEBUG(1,("failed session setup\n"));
858 if (do_shutdown)
859 cli_shutdown(cli);
860 return False;
862 if (do_tcon) {
863 if (!cli_send_tconX(cli, service, service_type,
864 (char*)passwd, strlen(passwd))) {
865 DEBUG(1,("failed tcon_X\n"));
866 if (do_shutdown)
867 cli_shutdown(cli);
868 return False;
871 } else {
872 /* attempt encrypted session */
873 unsigned char nt_sess_pwd[24];
874 unsigned char lm_sess_pwd[24];
876 /* creates (storing a copy of) and then obtains a 24 byte password OWF */
877 pwd_make_lm_nt_owf(&cli->pwd, cli->cryptkey);
878 pwd_get_lm_nt_owf(&cli->pwd, lm_sess_pwd, nt_sess_pwd);
880 /* attempt encrypted session */
881 if (!cli_session_setup(cli, cli->user_name,
882 (char*)lm_sess_pwd, sizeof(lm_sess_pwd),
883 (char*)nt_sess_pwd, sizeof(nt_sess_pwd),
884 cli->domain)) {
885 DEBUG(1,("failed session setup\n"));
886 if (do_shutdown)
887 cli_shutdown(cli);
888 return False;
891 DEBUG(1,("session setup ok\n"));
893 if (*cli->server_domain || *cli->server_os || *cli->server_type) {
894 DEBUG(1,("Domain=[%s] OS=[%s] Server=[%s]\n",
895 cli->server_domain,
896 cli->server_os,
897 cli->server_type));
900 if (do_tcon) {
901 if (!cli_send_tconX(cli, service, service_type,
902 (char*)nt_sess_pwd, sizeof(nt_sess_pwd))) {
903 DEBUG(1,("failed tcon_X\n"));
904 if (do_shutdown)
905 cli_shutdown(cli);
906 return False;
911 if (do_shutdown)
912 cli_shutdown(cli);
914 return True;
917 /****************************************************************************
918 Initialise client credentials for authenticated pipe access.
919 ****************************************************************************/
921 static void init_creds(struct ntuser_creds *creds, char* username,
922 char* domain, char* password, int pass_len)
924 ZERO_STRUCTP(creds);
926 pwd_set_cleartext(&creds->pwd, password);
928 fstrcpy(creds->user_name, username);
929 fstrcpy(creds->domain, domain);
931 if (!*username) {
932 creds->pwd.null_pwd = True;
936 /****************************************************************************
937 Establishes a connection right up to doing tconX, password specified.
938 ****************************************************************************/
940 NTSTATUS cli_full_connection(struct cli_state **output_cli,
941 const char *my_name, const char *dest_host,
942 struct in_addr *dest_ip, int port,
943 char *service, char *service_type,
944 char *user, char *domain,
945 char *password, int pass_len)
947 struct ntuser_creds creds;
948 NTSTATUS nt_status;
949 struct nmb_name calling;
950 struct nmb_name called;
951 struct cli_state *cli;
952 struct in_addr ip;
954 if (!output_cli)
955 DEBUG(0, ("output_cli is NULL!?!"));
957 *output_cli = NULL;
959 make_nmb_name(&calling, my_name, 0x0);
960 make_nmb_name(&called , dest_host, 0x20);
962 again:
964 if (!(cli = cli_initialise(NULL)))
965 return NT_STATUS_NO_MEMORY;
967 if (cli_set_port(cli, port) != port) {
968 cli_shutdown(cli);
969 return NT_STATUS_UNSUCCESSFUL;
972 ip = *dest_ip;
974 DEBUG(3,("Connecting to host=%s share=%s\n", dest_host, service));
976 if (!cli_connect(cli, dest_host, &ip)) {
977 DEBUG(1,("cli_establish_connection: failed to connect to %s (%s)\n",
978 nmb_namestr(&called), inet_ntoa(*dest_ip)));
979 cli_shutdown(cli);
980 return NT_STATUS_UNSUCCESSFUL;
983 if (!cli_session_request(cli, &calling, &called)) {
984 char *p;
985 DEBUG(1,("session request to %s failed (%s)\n",
986 called.name, cli_errstr(cli)));
987 cli_shutdown(cli);
988 if ((p=strchr(called.name, '.')) && !is_ipaddress(called.name)) {
989 *p = 0;
990 goto again;
992 if (strcmp(called.name, "*SMBSERVER")) {
993 make_nmb_name(&called , "*SMBSERVER", 0x20);
994 goto again;
996 return NT_STATUS_UNSUCCESSFUL;
999 if (!cli_negprot(cli)) {
1000 DEBUG(1,("failed negprot\n"));
1001 nt_status = NT_STATUS_UNSUCCESSFUL;
1002 cli_shutdown(cli);
1003 return nt_status;
1006 if (!cli_session_setup(cli, user, password, pass_len, password, pass_len,
1007 domain)) {
1008 DEBUG(1,("failed session setup\n"));
1009 nt_status = cli_nt_error(cli);
1010 cli_shutdown(cli);
1011 if (NT_STATUS_IS_OK(nt_status))
1012 nt_status = NT_STATUS_UNSUCCESSFUL;
1013 return nt_status;
1016 if (service) {
1017 if (!cli_send_tconX(cli, service, service_type,
1018 (char*)password, pass_len)) {
1019 DEBUG(1,("failed tcon_X\n"));
1020 nt_status = cli_nt_error(cli);
1021 cli_shutdown(cli);
1022 if (NT_STATUS_IS_OK(nt_status))
1023 nt_status = NT_STATUS_UNSUCCESSFUL;
1024 return nt_status;
1028 init_creds(&creds, user, domain, password, pass_len);
1029 cli_init_creds(cli, &creds);
1031 *output_cli = cli;
1032 return NT_STATUS_OK;
1035 /****************************************************************************
1036 Attempt a NetBIOS session request, falling back to *SMBSERVER if needed.
1037 ****************************************************************************/
1039 BOOL attempt_netbios_session_request(struct cli_state *cli, char *srchost, char *desthost,
1040 struct in_addr *pdest_ip)
1042 struct nmb_name calling, called;
1044 make_nmb_name(&calling, srchost, 0x0);
1047 * If the called name is an IP address
1048 * then use *SMBSERVER immediately.
1051 if(is_ipaddress(desthost))
1052 make_nmb_name(&called, "*SMBSERVER", 0x20);
1053 else
1054 make_nmb_name(&called, desthost, 0x20);
1056 if (!cli_session_request(cli, &calling, &called)) {
1058 struct nmb_name smbservername;
1060 make_nmb_name(&smbservername , "*SMBSERVER", 0x20);
1063 * If the name wasn't *SMBSERVER then
1064 * try with *SMBSERVER if the first name fails.
1067 if (nmb_name_equal(&called, &smbservername)) {
1070 * The name used was *SMBSERVER, don't bother with another name.
1073 DEBUG(0,("attempt_netbios_session_request: %s rejected the session for name *SMBSERVER with error %s.\n",
1074 desthost, cli_errstr(cli) ));
1075 return False;
1079 * We need to close the connection here but can't call cli_shutdown as
1080 * will free an allocated cli struct. cli_close_connection was invented
1081 * for this purpose. JRA. Based on work by "Kim R. Pedersen" <krp@filanet.dk>.
1084 cli_close_connection(cli);
1086 if (!cli_initialise(cli) || !cli_connect(cli, desthost, pdest_ip) ||
1087 !cli_session_request(cli, &calling, &smbservername)) {
1088 DEBUG(0,("attempt_netbios_session_request: %s rejected the session for name *SMBSERVER with error %s\n",
1089 desthost, cli_errstr(cli) ));
1090 return False;
1094 return True;