2 Unix SMB/Netbios implementation.
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.
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"},
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
)
52 if (passlen
> sizeof(pword
)-1) {
56 /* if in share level security then don't send a password now */
57 if (!(cli
->sec_mode
& 1)) {
61 if (passlen
> 0 && (cli
->sec_mode
& 2) && passlen
!= 24) {
62 /* Encrypted mode needed, and non encrypted password supplied. */
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
);
90 p
+= clistr_push(cli
, p
, user
, -1, STR_TERMINATE
);
91 cli_setup_bcc(cli
, p
);
94 if (!cli_receive_smb(cli
))
99 if (cli_is_error(cli
)) {
103 /* use the returned vuid from now on */
104 cli
->vuid
= SVAL(cli
->inbuf
,smb_uid
);
105 fstrcpy(cli
->user_name
, user
);
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
;
133 /****************************************************************************
134 Do a NT1 guest session setup.
135 ****************************************************************************/
137 static BOOL
cli_session_setup_guest(struct cli_state
*cli
)
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
);
162 if (!cli_receive_smb(cli
))
165 show_msg(cli
->inbuf
);
167 if (cli_is_error(cli
)) {
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
, "");
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
);
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
);
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
);
219 if (!cli_receive_smb(cli
))
222 show_msg(cli
->inbuf
);
224 if (cli_is_error(cli
)) {
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
);
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
,
248 uint32 capabilities
= cli_session_setup_capabilities(cli
);
249 fstring pword
, ntpword
;
252 if (passlen
> sizeof(pword
)-1 || ntpasslen
> sizeof(ntpword
)-1) {
257 /* non encrypted password supplied. */
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
);
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
);
294 if (!cli_receive_smb(cli
))
297 show_msg(cli
->inbuf
);
299 if (cli_is_error(cli
)) {
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
);
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
,
324 char *pass
, int passlen
,
325 char *ntpass
, int ntpasslen
,
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())) ) {
339 if (cli
->protocol
< PROTOCOL_LANMAN1
)
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
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
,
376 /****************************************************************************
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 */
390 if (!cli_receive_smb(cli
))
393 return !cli_is_error(cli
);
396 /****************************************************************************
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
;
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) {
416 if ((cli
->sec_mode
& 2) && *pass
&& passlen
!= 24) {
418 * Non-encrypted passwords - convert to DOS codepage before encryption.
421 clistr_push(cli
, dos_pword
, pass
, -1, STR_CONVERT
|STR_TERMINATE
);
422 SMBencrypt((uchar
*)dos_pword
,cli
->cryptkey
,(uchar
*)pword
);
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
);
430 memcpy(pword
, pass
, passlen
);
434 if (cli
->port
== 445) {
435 slprintf(fullshare
, sizeof(fullshare
)-1,
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
);
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
);
458 if (!cli_receive_smb(cli
))
461 if (cli_is_error(cli
)) {
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 */
482 cli
->cnum
= SVAL(cli
->inbuf
,smb_tid
);
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
);
500 if (!cli_receive_smb(cli
))
503 return !cli_is_error(cli
);
507 /****************************************************************************
508 Send a negprot command.
509 ****************************************************************************/
511 void cli_negprot_send(struct cli_state
*cli
)
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
);
523 prots
[numprots
].name
&& prots
[numprots
].prot
<=cli
->protocol
;
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);
539 /****************************************************************************
540 Send a negprot command.
541 ****************************************************************************/
543 BOOL
cli_negprot(struct cli_state
*cli
)
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
;
555 plength
+= strlen(prots
[numprots
].name
)+2;
557 set_message(cli
->outbuf
,0,plength
,True
);
559 p
= smb_buf(cli
->outbuf
);
561 prots
[numprots
].name
&& prots
[numprots
].prot
<=cli
->protocol
;
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);
573 if (!cli_receive_smb(cli
))
576 show_msg(cli
->inbuf
);
578 if (cli_is_error(cli
) ||
579 ((int)SVAL(cli
->inbuf
,smb_vwv0
) >= numprots
)) {
583 cli
->protocol
= prots
[SVAL(cli
->inbuf
,smb_vwv0
)].prot
;
585 if (cli
->protocol
>= PROTOCOL_NT1
) {
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);
619 /* the old core protocol */
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
;
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
)
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 */
655 name_mangle(cli
->called
.name
, p
, cli
->called
.name_type
);
660 name_mangle(cli
->calling
.name
, p
, cli
->calling
.name_type
);
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.
671 _smb_setlen(cli
->outbuf
,len
);
672 SCVAL(cli
->outbuf
,0,0x81);
676 #endif /* WITH_SSL */
679 DEBUG(5,("Sent session request\n"));
681 if (!cli_receive_smb(cli
))
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{
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
);
704 DEBUG(3,("Retargeted\n"));
706 set_socket_options(cli
->fd
,user_socket_options
);
713 DEBUG(0,("Retarget recursion - failing\n"));
717 ret
= cli_session_request(cli
, calling
, called
);
721 } /* C. Hoch 9/14/95 End */
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)
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);
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;
750 /* reasonable default hostname */
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);
762 if (!ip
|| is_zero_ip(*ip
)) {
763 if (!resolve_name(cli
->desthost
, &cli
->dest_ip
, name_type
)) {
772 if (getenv("LIBSMB_PROG")) {
773 cli
->fd
= sock_exec(getenv("LIBSMB_PROG"));
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
,
779 if (cli
->fd
== -1 && cli
->port
== 0) {
781 cli
->fd
= open_socket_out(SOCK_STREAM
, &cli
->dest_ip
,
784 if (cli
->fd
!= -1) cli
->port
= port
;
787 DEBUG(1,("Error connecting to %s (%s)\n",
788 inet_ntoa(*ip
),strerror(errno
)));
792 set_socket_options(cli
->fd
,user_socket_options
);
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
))
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
)));
824 if (!cli_session_request(cli
, calling
, called
)) {
825 DEBUG(1,("failed session request\n"));
831 if (!cli_negprot(cli
)) {
832 DEBUG(1,("failed negprot\n"));
838 if (cli
->pwd
.cleartext
|| cli
->pwd
.null_pwd
) {
842 if (cli
->pwd
.null_pwd
) {
843 /* attempt null session */
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
,
857 DEBUG(1,("failed session setup\n"));
863 if (!cli_send_tconX(cli
, service
, service_type
,
864 (char*)passwd
, strlen(passwd
))) {
865 DEBUG(1,("failed tcon_X\n"));
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
),
885 DEBUG(1,("failed session setup\n"));
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",
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"));
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
)
926 pwd_set_cleartext(&creds
->pwd
, password
);
928 fstrcpy(creds
->user_name
, username
);
929 fstrcpy(creds
->domain
, domain
);
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
;
949 struct nmb_name calling
;
950 struct nmb_name called
;
951 struct cli_state
*cli
;
955 DEBUG(0, ("output_cli is NULL!?!"));
959 make_nmb_name(&calling
, my_name
, 0x0);
960 make_nmb_name(&called
, dest_host
, 0x20);
964 if (!(cli
= cli_initialise(NULL
)))
965 return NT_STATUS_NO_MEMORY
;
967 if (cli_set_port(cli
, port
) != port
) {
969 return NT_STATUS_UNSUCCESSFUL
;
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
)));
980 return NT_STATUS_UNSUCCESSFUL
;
983 if (!cli_session_request(cli
, &calling
, &called
)) {
985 DEBUG(1,("session request to %s failed (%s)\n",
986 called
.name
, cli_errstr(cli
)));
988 if ((p
=strchr(called
.name
, '.')) && !is_ipaddress(called
.name
)) {
992 if (strcmp(called
.name
, "*SMBSERVER")) {
993 make_nmb_name(&called
, "*SMBSERVER", 0x20);
996 return NT_STATUS_UNSUCCESSFUL
;
999 if (!cli_negprot(cli
)) {
1000 DEBUG(1,("failed negprot\n"));
1001 nt_status
= NT_STATUS_UNSUCCESSFUL
;
1006 if (!cli_session_setup(cli
, user
, password
, pass_len
, password
, pass_len
,
1008 DEBUG(1,("failed session setup\n"));
1009 nt_status
= cli_nt_error(cli
);
1011 if (NT_STATUS_IS_OK(nt_status
))
1012 nt_status
= NT_STATUS_UNSUCCESSFUL
;
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
);
1022 if (NT_STATUS_IS_OK(nt_status
))
1023 nt_status
= NT_STATUS_UNSUCCESSFUL
;
1028 init_creds(&creds
, user
, domain
, password
, pass_len
);
1029 cli_init_creds(cli
, &creds
);
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);
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
) ));
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
) ));