2 Unix SMB/Netbios implementation.
4 SMB client generic functions
5 Copyright (C) Andrew Tridgell 1994-1997
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.
30 extern int DEBUGLEVEL
;
32 /****************************************************************************
33 setup basics in a outgoing packet
34 ****************************************************************************/
35 static void cli_setup_packet(struct cli_state
*cli
)
37 SSVAL(cli
->outbuf
,smb_pid
,cli
->pid
);
38 SSVAL(cli
->outbuf
,smb_uid
,cli
->uid
);
39 SSVAL(cli
->outbuf
,smb_mid
,cli
->mid
);
40 if (cli
->protocol
> PROTOCOL_CORE
) {
41 SCVAL(cli
->outbuf
,smb_flg
,0x8);
42 SSVAL(cli
->outbuf
,smb_flg2
,0x1);
47 /****************************************************************************
48 send a SMB trans or trans2 request
49 ****************************************************************************/
50 static BOOL
cli_send_trans(struct cli_state
*cli
,
51 int trans
, char *name
, int fid
, int flags
,
52 char *data
,char *param
,uint16
*setup
, int ldata
,int lparam
,
53 int lsetup
,int mdata
,int mparam
,int msetup
)
56 int this_ldata
,this_lparam
;
57 int tot_data
=0,tot_param
=0;
58 char *outdata
,*outparam
;
61 this_lparam
= MIN(lparam
,cli
->max_xmit
- (500+lsetup
*2)); /* hack */
62 this_ldata
= MIN(ldata
,cli
->max_xmit
- (500+lsetup
*2+this_lparam
));
64 bzero(cli
->outbuf
,smb_size
);
65 set_message(cli
->outbuf
,14+lsetup
,0,True
);
66 CVAL(cli
->outbuf
,smb_com
) = trans
;
67 SSVAL(cli
->outbuf
,smb_tid
, cli
->cnum
);
68 cli_setup_packet(cli
);
70 outparam
= smb_buf(cli
->outbuf
)+(trans
==SMBtrans
? strlen(name
)+1 : 3);
71 outdata
= outparam
+this_lparam
;
74 SSVAL(cli
->outbuf
,smb_tpscnt
,lparam
); /* tpscnt */
75 SSVAL(cli
->outbuf
,smb_tdscnt
,ldata
); /* tdscnt */
76 SSVAL(cli
->outbuf
,smb_mprcnt
,mparam
); /* mprcnt */
77 SSVAL(cli
->outbuf
,smb_mdrcnt
,mdata
); /* mdrcnt */
78 SCVAL(cli
->outbuf
,smb_msrcnt
,msetup
); /* msrcnt */
79 SSVAL(cli
->outbuf
,smb_flags
,flags
); /* flags */
80 SIVAL(cli
->outbuf
,smb_timeout
,0); /* timeout */
81 SSVAL(cli
->outbuf
,smb_pscnt
,this_lparam
); /* pscnt */
82 SSVAL(cli
->outbuf
,smb_psoff
,smb_offset(outparam
,cli
->outbuf
)); /* psoff */
83 SSVAL(cli
->outbuf
,smb_dscnt
,this_ldata
); /* dscnt */
84 SSVAL(cli
->outbuf
,smb_dsoff
,smb_offset(outdata
,cli
->outbuf
)); /* dsoff */
85 SCVAL(cli
->outbuf
,smb_suwcnt
,lsetup
); /* suwcnt */
86 for (i
=0;i
<lsetup
;i
++) /* setup[] */
87 SSVAL(cli
->outbuf
,smb_setup
+i
*2,setup
[i
]);
88 p
= smb_buf(cli
->outbuf
);
89 if (trans
==SMBtrans
) {
90 strcpy(p
,name
); /* name[] */
92 *p
++ = 0; /* put in a null smb_name */
93 *p
++ = 'D'; *p
++ = ' '; /* observed in OS/2 */
95 if (this_lparam
) /* param[] */
96 memcpy(outparam
,param
,this_lparam
);
97 if (this_ldata
) /* data[] */
98 memcpy(outdata
,data
,this_ldata
);
99 set_message(cli
->outbuf
,14+lsetup
, /* wcnt, bcc */
100 PTR_DIFF(outdata
+this_ldata
,smb_buf(cli
->outbuf
)),False
);
102 show_msg(cli
->outbuf
);
103 send_smb(cli
->fd
,cli
->outbuf
);
105 if (this_ldata
< ldata
|| this_lparam
< lparam
) {
106 /* receive interim response */
107 if (!receive_smb(cli
->fd
,cli
->inbuf
,cli
->timeout
) ||
108 CVAL(cli
->inbuf
,smb_rcls
) != 0) {
112 tot_data
= this_ldata
;
113 tot_param
= this_lparam
;
115 while (tot_data
< ldata
|| tot_param
< lparam
) {
116 this_lparam
= MIN(lparam
-tot_param
,cli
->max_xmit
- 500); /* hack */
117 this_ldata
= MIN(ldata
-tot_data
,cli
->max_xmit
- (500+this_lparam
));
119 set_message(cli
->outbuf
,trans
==SMBtrans
?8:9,0,True
);
120 CVAL(cli
->outbuf
,smb_com
) = trans
==SMBtrans
? SMBtranss
: SMBtranss2
;
122 outparam
= smb_buf(cli
->outbuf
);
123 outdata
= outparam
+this_lparam
;
125 /* secondary request */
126 SSVAL(cli
->outbuf
,smb_tpscnt
,lparam
); /* tpscnt */
127 SSVAL(cli
->outbuf
,smb_tdscnt
,ldata
); /* tdscnt */
128 SSVAL(cli
->outbuf
,smb_spscnt
,this_lparam
); /* pscnt */
129 SSVAL(cli
->outbuf
,smb_spsoff
,smb_offset(outparam
,cli
->outbuf
)); /* psoff */
130 SSVAL(cli
->outbuf
,smb_spsdisp
,tot_param
); /* psdisp */
131 SSVAL(cli
->outbuf
,smb_sdscnt
,this_ldata
); /* dscnt */
132 SSVAL(cli
->outbuf
,smb_sdsoff
,smb_offset(outdata
,cli
->outbuf
)); /* dsoff */
133 SSVAL(cli
->outbuf
,smb_sdsdisp
,tot_data
); /* dsdisp */
134 if (trans
==SMBtrans2
)
135 SSVALS(cli
->outbuf
,smb_sfid
,fid
); /* fid */
136 if (this_lparam
) /* param[] */
137 memcpy(outparam
,param
,this_lparam
);
138 if (this_ldata
) /* data[] */
139 memcpy(outdata
,data
,this_ldata
);
140 set_message(cli
->outbuf
,trans
==SMBtrans
?8:9, /* wcnt, bcc */
141 PTR_DIFF(outdata
+this_ldata
,smb_buf(cli
->outbuf
)),False
);
143 show_msg(cli
->outbuf
);
144 send_smb(cli
->fd
,cli
->outbuf
);
146 tot_data
+= this_ldata
;
147 tot_param
+= this_lparam
;
155 /****************************************************************************
156 receive a SMB trans or trans2 response allocating the necessary memory
157 ****************************************************************************/
158 static BOOL
cli_receive_trans(struct cli_state
*cli
,
159 int trans
,int *data_len
,
160 int *param_len
, char **data
,char **param
)
164 int this_data
,this_param
;
166 *data_len
= *param_len
= 0;
168 if (!receive_smb(cli
->fd
,cli
->inbuf
,cli
->timeout
))
171 show_msg(cli
->inbuf
);
174 if (CVAL(cli
->inbuf
,smb_com
) != trans
) {
175 DEBUG(0,("Expected %s response, got command 0x%02x\n",
176 trans
==SMBtrans
?"SMBtrans":"SMBtrans2",
177 CVAL(cli
->inbuf
,smb_com
)));
180 if (CVAL(cli
->inbuf
,smb_rcls
) != 0)
183 /* parse out the lengths */
184 total_data
= SVAL(cli
->inbuf
,smb_tdrcnt
);
185 total_param
= SVAL(cli
->inbuf
,smb_tprcnt
);
188 *data
= Realloc(*data
,total_data
);
189 *param
= Realloc(*param
,total_param
);
192 this_data
= SVAL(cli
->inbuf
,smb_drcnt
);
193 this_param
= SVAL(cli
->inbuf
,smb_prcnt
);
195 if (this_data
+ *data_len
> total_data
||
196 this_param
+ *param_len
> total_param
) {
197 DEBUG(1,("Data overflow in cli_receive_trans\n"));
202 memcpy(*data
+ SVAL(cli
->inbuf
,smb_drdisp
),
203 smb_base(cli
->inbuf
) + SVAL(cli
->inbuf
,smb_droff
),
206 memcpy(*param
+ SVAL(cli
->inbuf
,smb_prdisp
),
207 smb_base(cli
->inbuf
) + SVAL(cli
->inbuf
,smb_proff
),
209 *data_len
+= this_data
;
210 *param_len
+= this_param
;
212 /* parse out the total lengths again - they can shrink! */
213 total_data
= SVAL(cli
->inbuf
,smb_tdrcnt
);
214 total_param
= SVAL(cli
->inbuf
,smb_tprcnt
);
216 if (total_data
<= *data_len
&& total_param
<= *param_len
)
219 if (!receive_smb(cli
->fd
,cli
->inbuf
,cli
->timeout
))
222 show_msg(cli
->inbuf
);
225 if (CVAL(cli
->inbuf
,smb_com
) != trans
) {
226 DEBUG(0,("Expected %s response, got command 0x%02x\n",
227 trans
==SMBtrans
?"SMBtrans":"SMBtrans2",
228 CVAL(cli
->inbuf
,smb_com
)));
231 if (CVAL(cli
->inbuf
,smb_rcls
) != 0)
239 /****************************************************************************
241 ****************************************************************************/
242 static BOOL
cli_api(struct cli_state
*cli
,
243 int prcnt
,int drcnt
,int mprcnt
,int mdrcnt
,int *rprcnt
,
244 int *rdrcnt
, char *param
,char *data
,
245 char **rparam
, char **rdata
)
247 cli_send_trans(cli
,SMBtrans
,PIPE_LANMAN
,0,0,
252 return (cli_receive_trans(cli
,SMBtrans
,
258 /****************************************************************************
259 perform a NetWkstaUserLogon
260 ****************************************************************************/
261 BOOL
cli_NetWkstaUserLogon(struct cli_state
*cli
,char *user
, char *workstation
)
269 memset(param
, 0, sizeof(param
));
271 /* send a SMBtrans command with api NetWkstaUserLogon */
273 SSVAL(p
,0,132); /* api number */
275 strcpy(p
,"OOWb54WrLh");
276 p
= skip_string(p
,1);
277 strcpy(p
,"WB21BWDWWDDDDDDDzzzD");
278 p
= skip_string(p
,1);
283 p
+= 21; p
++; p
+= 15; p
++;
284 strcpy(p
, workstation
);
287 SSVAL(p
, 0, BUFFER_SIZE
);
289 SSVAL(p
, 0, BUFFER_SIZE
);
294 if (cli_api(cli
, PTR_DIFF(p
,param
),0,
299 cli
->error
= SVAL(rparam
,0);
302 if (cli
->error
== 0) {
303 DEBUG(4,("NetWkstaUserLogon success\n"));
304 cli
->privilages
= SVAL(p
, 24);
305 fstrcpy(cli
->eff_name
,p
+2);
307 DEBUG(1,("NetwkstaUserLogon gave error %d\n", cli
->error
));
311 if (rparam
) free(rparam
);
312 if (rdata
) free(rdata
);
313 return cli
->error
== 0;
317 /****************************************************************************
318 call a NetServerEnum for the specified workgroup and servertype mask.
319 This function then calls the specified callback function for each name returned.
321 The callback function takes 3 arguments: the machine name, the server type and
323 ****************************************************************************/
324 BOOL
cli_NetServerEnum(struct cli_state
*cli
, char *workgroup
, uint32 stype
,
325 void (*fn
)(char *, uint32
, char *))
335 /* send a SMBtrans command with api NetServerEnum */
337 SSVAL(p
,0,0x68); /* api number */
340 p
= skip_string(p
,1);
344 p
= skip_string(p
,1);
346 SSVAL(p
,2,BUFFER_SIZE
);
351 pstrcpy(p
, workgroup
);
352 p
= skip_string(p
,1);
355 PTR_DIFF(p
,param
), /* param count */
358 BUFFER_SIZE
, /* mdrcount */
362 int res
= SVAL(rparam
,0);
363 int converter
=SVAL(rparam
,2);
367 count
=SVAL(rparam
,4);
370 for (i
= 0;i
< count
;i
++, p
+= 26) {
372 int comment_offset
= (IVAL(p
,22) & 0xFFFF)-converter
;
373 char *cmnt
= comment_offset
?(rdata
+comment_offset
):"";
374 if (comment_offset
< 0 || comment_offset
> rdrcnt
) continue;
376 stype
= IVAL(p
,18) & ~SV_TYPE_LOCAL_LIST_ONLY
;
378 fn(sname
, stype
, cmnt
);
383 if (rparam
) free(rparam
);
384 if (rdata
) free(rdata
);
398 {PROTOCOL_CORE
,"PC NETWORK PROGRAM 1.0"},
399 {PROTOCOL_COREPLUS
,"MICROSOFT NETWORKS 1.03"},
400 {PROTOCOL_LANMAN1
,"MICROSOFT NETWORKS 3.0"},
401 {PROTOCOL_LANMAN1
,"LANMAN1.0"},
402 {PROTOCOL_LANMAN2
,"LM1.2X002"},
403 {PROTOCOL_LANMAN2
,"Samba"},
404 {PROTOCOL_NT1
,"NT LM 0.12"},
405 {PROTOCOL_NT1
,"NT LANMAN 1.0"},
410 /****************************************************************************
412 ****************************************************************************/
413 BOOL
cli_session_setup(struct cli_state
*cli
,
415 char *pass
, int passlen
,
416 char *ntpass
, int ntpasslen
,
422 if (cli
->protocol
< PROTOCOL_LANMAN1
)
425 if (passlen
> sizeof(pword
)-1) {
429 if ((cli
->sec_mode
& 2) && *pass
&& passlen
!= 24) {
431 SMBencrypt((uchar
*)pass
,(uchar
*)cli
->cryptkey
,(uchar
*)pword
);
433 memcpy(pword
, pass
, passlen
);
436 /* if in share level security then don't send a password now */
437 if (!(cli
->sec_mode
& 1)) {fstrcpy(pword
, "");passlen
=1;}
439 /* send a session setup command */
440 bzero(cli
->outbuf
,smb_size
);
442 if (cli
->protocol
< PROTOCOL_NT1
) {
443 set_message(cli
->outbuf
,10,1 + strlen(user
) + passlen
,True
);
444 CVAL(cli
->outbuf
,smb_com
) = SMBsesssetupX
;
445 cli_setup_packet(cli
);
447 CVAL(cli
->outbuf
,smb_vwv0
) = 0xFF;
448 SSVAL(cli
->outbuf
,smb_vwv2
,cli
->max_xmit
);
449 SSVAL(cli
->outbuf
,smb_vwv3
,2);
450 SSVAL(cli
->outbuf
,smb_vwv4
,1);
451 SIVAL(cli
->outbuf
,smb_vwv5
,cli
->sesskey
);
452 SSVAL(cli
->outbuf
,smb_vwv7
,passlen
);
453 p
= smb_buf(cli
->outbuf
);
454 memcpy(p
,pword
,passlen
);
459 set_message(cli
->outbuf
,13,0,True
);
460 CVAL(cli
->outbuf
,smb_com
) = SMBsesssetupX
;
461 cli_setup_packet(cli
);
463 CVAL(cli
->outbuf
,smb_vwv0
) = 0xFF;
464 SSVAL(cli
->outbuf
,smb_vwv2
,BUFFER_SIZE
);
465 SSVAL(cli
->outbuf
,smb_vwv3
,2);
466 SSVAL(cli
->outbuf
,smb_vwv4
,cli
->pid
);
467 SIVAL(cli
->outbuf
,smb_vwv5
,cli
->sesskey
);
468 SSVAL(cli
->outbuf
,smb_vwv7
,passlen
);
469 SSVAL(cli
->outbuf
,smb_vwv8
,ntpasslen
);
470 p
= smb_buf(cli
->outbuf
);
471 memcpy(p
,pword
,passlen
);
472 p
+= SVAL(cli
->outbuf
,smb_vwv7
);
473 memcpy(p
,ntpass
,ntpasslen
);
474 p
+= SVAL(cli
->outbuf
,smb_vwv8
);
477 p
= skip_string(p
,1);
480 p
= skip_string(p
,1);
481 strcpy(p
,"Unix");p
= skip_string(p
,1);
482 strcpy(p
,"Samba");p
= skip_string(p
,1);
483 set_message(cli
->outbuf
,13,PTR_DIFF(p
,smb_buf(cli
->outbuf
)),False
);
486 send_smb(cli
->fd
,cli
->outbuf
);
487 if (!receive_smb(cli
->fd
,cli
->inbuf
,cli
->timeout
))
490 show_msg(cli
->inbuf
);
492 if (CVAL(cli
->inbuf
,smb_rcls
) != 0) {
496 /* use the returned uid from now on */
497 cli
->uid
= SVAL(cli
->inbuf
,smb_uid
);
503 /****************************************************************************
505 ****************************************************************************/
506 BOOL
cli_send_tconX(struct cli_state
*cli
,
507 char *share
, char *dev
, char *pass
, int passlen
)
509 fstring fullshare
, pword
;
511 bzero(cli
->outbuf
,smb_size
);
512 bzero(cli
->inbuf
,smb_size
);
514 if (cli
->sec_mode
& 1) {
519 if ((cli
->sec_mode
& 2) && *pass
&& passlen
!= 24) {
521 SMBencrypt((uchar
*)pass
,(uchar
*)cli
->cryptkey
,(uchar
*)pword
);
523 memcpy(pword
, pass
, passlen
);
526 sprintf(fullshare
, "\\\\%s\\%s", cli
->desthost
, share
);
528 set_message(cli
->outbuf
,4,
529 2 + strlen(fullshare
) + passlen
+ strlen(dev
),True
);
530 CVAL(cli
->outbuf
,smb_com
) = SMBtconX
;
531 cli_setup_packet(cli
);
533 SSVAL(cli
->outbuf
,smb_vwv0
,0xFF);
534 SSVAL(cli
->outbuf
,smb_vwv3
,passlen
);
536 p
= smb_buf(cli
->outbuf
);
537 memcpy(p
,pword
,passlen
);
540 p
= skip_string(p
,1);
543 SCVAL(cli
->inbuf
,smb_rcls
, 1);
545 send_smb(cli
->fd
,cli
->outbuf
);
546 if (!receive_smb(cli
->fd
,cli
->inbuf
,cli
->timeout
))
549 if (CVAL(cli
->inbuf
,smb_rcls
) != 0) {
553 cli
->cnum
= SVAL(cli
->inbuf
,smb_tid
);
558 /****************************************************************************
559 send a tree disconnect
560 ****************************************************************************/
561 BOOL
cli_tdis(struct cli_state
*cli
)
563 bzero(cli
->outbuf
,smb_size
);
564 set_message(cli
->outbuf
,0,0,True
);
565 CVAL(cli
->outbuf
,smb_com
) = SMBtdis
;
566 SSVAL(cli
->outbuf
,smb_tid
,cli
->cnum
);
567 cli_setup_packet(cli
);
569 send_smb(cli
->fd
,cli
->outbuf
);
570 if (!receive_smb(cli
->fd
,cli
->inbuf
,cli
->timeout
))
573 return CVAL(cli
->inbuf
,smb_rcls
) == 0;
576 /****************************************************************************
578 ****************************************************************************/
579 BOOL
cli_unlink(struct cli_state
*cli
, char *fname
)
583 bzero(cli
->outbuf
,smb_size
);
584 bzero(cli
->inbuf
,smb_size
);
586 set_message(cli
->outbuf
,1, 2 + strlen(fname
),True
);
588 CVAL(cli
->outbuf
,smb_com
) = SMBunlink
;
589 SSVAL(cli
->outbuf
,smb_tid
,cli
->cnum
);
590 cli_setup_packet(cli
);
592 SSVAL(cli
->outbuf
,smb_vwv0
,aSYSTEM
| aHIDDEN
);
594 p
= smb_buf(cli
->outbuf
);
597 p
= skip_string(p
,1);
599 send_smb(cli
->fd
,cli
->outbuf
);
600 if (!receive_smb(cli
->fd
,cli
->inbuf
,cli
->timeout
)) {
604 if (CVAL(cli
->inbuf
,smb_rcls
) != 0) {
613 /****************************************************************************
615 ****************************************************************************/
616 int cli_open(struct cli_state
*cli
, char *fname
, int flags
, int share_mode
)
620 unsigned accessmode
=0;
624 if (!(flags
& O_EXCL
)) {
631 accessmode
= (share_mode
<<4);
633 if ((flags
& O_RDWR
) == O_RDWR
) {
635 } else if ((flags
& O_WRONLY
) == O_WRONLY
) {
639 bzero(cli
->outbuf
,smb_size
);
640 bzero(cli
->inbuf
,smb_size
);
642 set_message(cli
->outbuf
,15,1 + strlen(fname
),True
);
644 CVAL(cli
->outbuf
,smb_com
) = SMBopenX
;
645 SSVAL(cli
->outbuf
,smb_tid
,cli
->cnum
);
646 cli_setup_packet(cli
);
648 SSVAL(cli
->outbuf
,smb_vwv0
,0xFF);
649 SSVAL(cli
->outbuf
,smb_vwv2
,0); /* no additional info */
650 SSVAL(cli
->outbuf
,smb_vwv3
,accessmode
);
651 SSVAL(cli
->outbuf
,smb_vwv4
,aSYSTEM
| aHIDDEN
);
652 SSVAL(cli
->outbuf
,smb_vwv5
,0);
653 SSVAL(cli
->outbuf
,smb_vwv8
,openfn
);
655 p
= smb_buf(cli
->outbuf
);
657 p
= skip_string(p
,1);
659 send_smb(cli
->fd
,cli
->outbuf
);
660 if (!receive_smb(cli
->fd
,cli
->inbuf
,cli
->timeout
)) {
664 if (CVAL(cli
->inbuf
,smb_rcls
) != 0) {
668 return SVAL(cli
->inbuf
,smb_vwv2
);
674 /****************************************************************************
676 ****************************************************************************/
677 BOOL
cli_close(struct cli_state
*cli
, int fnum
)
679 bzero(cli
->outbuf
,smb_size
);
680 bzero(cli
->inbuf
,smb_size
);
682 set_message(cli
->outbuf
,3,0,True
);
684 CVAL(cli
->outbuf
,smb_com
) = SMBclose
;
685 SSVAL(cli
->outbuf
,smb_tid
,cli
->cnum
);
686 cli_setup_packet(cli
);
688 SSVAL(cli
->outbuf
,smb_vwv0
,fnum
);
689 SIVALS(cli
->outbuf
,smb_vwv1
,-1);
691 send_smb(cli
->fd
,cli
->outbuf
);
692 if (!receive_smb(cli
->fd
,cli
->inbuf
,cli
->timeout
)) {
696 if (CVAL(cli
->inbuf
,smb_rcls
) != 0) {
704 /****************************************************************************
706 ****************************************************************************/
707 BOOL
cli_lock(struct cli_state
*cli
, int fnum
, uint32 offset
, uint32 len
, int timeout
)
711 bzero(cli
->outbuf
,smb_size
);
712 bzero(cli
->inbuf
,smb_size
);
714 set_message(cli
->outbuf
,8,10,True
);
716 CVAL(cli
->outbuf
,smb_com
) = SMBlockingX
;
717 SSVAL(cli
->outbuf
,smb_tid
,cli
->cnum
);
718 cli_setup_packet(cli
);
720 CVAL(cli
->outbuf
,smb_vwv0
) = 0xFF;
721 SSVAL(cli
->outbuf
,smb_vwv2
,fnum
);
722 CVAL(cli
->outbuf
,smb_vwv3
) = 0;
723 SIVALS(cli
->outbuf
, smb_vwv4
, timeout
);
724 SSVAL(cli
->outbuf
,smb_vwv6
,0);
725 SSVAL(cli
->outbuf
,smb_vwv7
,1);
727 p
= smb_buf(cli
->outbuf
);
728 SSVAL(p
, 0, cli
->pid
);
732 send_smb(cli
->fd
,cli
->outbuf
);
733 if (!receive_smb(cli
->fd
,cli
->inbuf
,cli
->timeout
)) {
737 if (CVAL(cli
->inbuf
,smb_rcls
) != 0) {
744 /****************************************************************************
746 ****************************************************************************/
747 BOOL
cli_unlock(struct cli_state
*cli
, int fnum
, uint32 offset
, uint32 len
, int timeout
)
751 bzero(cli
->outbuf
,smb_size
);
752 bzero(cli
->inbuf
,smb_size
);
754 set_message(cli
->outbuf
,8,10,True
);
756 CVAL(cli
->outbuf
,smb_com
) = SMBlockingX
;
757 SSVAL(cli
->outbuf
,smb_tid
,cli
->cnum
);
758 cli_setup_packet(cli
);
760 CVAL(cli
->outbuf
,smb_vwv0
) = 0xFF;
761 SSVAL(cli
->outbuf
,smb_vwv2
,fnum
);
762 CVAL(cli
->outbuf
,smb_vwv3
) = 0;
763 SIVALS(cli
->outbuf
, smb_vwv4
, timeout
);
764 SSVAL(cli
->outbuf
,smb_vwv6
,1);
765 SSVAL(cli
->outbuf
,smb_vwv7
,0);
767 p
= smb_buf(cli
->outbuf
);
768 SSVAL(p
, 0, cli
->pid
);
772 send_smb(cli
->fd
,cli
->outbuf
);
773 if (!receive_smb(cli
->fd
,cli
->inbuf
,cli
->timeout
)) {
777 if (CVAL(cli
->inbuf
,smb_rcls
) != 0) {
785 /****************************************************************************
787 ****************************************************************************/
788 int cli_read(struct cli_state
*cli
, int fnum
, char *buf
, uint32 offset
, uint16 size
)
792 bzero(cli
->outbuf
,smb_size
);
793 bzero(cli
->inbuf
,smb_size
);
795 set_message(cli
->outbuf
,10,0,True
);
797 CVAL(cli
->outbuf
,smb_com
) = SMBreadX
;
798 SSVAL(cli
->outbuf
,smb_tid
,cli
->cnum
);
799 cli_setup_packet(cli
);
801 CVAL(cli
->outbuf
,smb_vwv0
) = 0xFF;
802 SSVAL(cli
->outbuf
,smb_vwv2
,fnum
);
803 SIVAL(cli
->outbuf
,smb_vwv3
,offset
);
804 SSVAL(cli
->outbuf
,smb_vwv5
,size
);
805 SSVAL(cli
->outbuf
,smb_vwv6
,size
);
807 send_smb(cli
->fd
,cli
->outbuf
);
808 if (!receive_smb(cli
->fd
,cli
->inbuf
,cli
->timeout
)) {
812 if (CVAL(cli
->inbuf
,smb_rcls
) != 0) {
816 size
= SVAL(cli
->inbuf
, smb_vwv5
);
817 p
= smb_base(cli
->inbuf
) + SVAL(cli
->inbuf
,smb_vwv6
);
819 memcpy(buf
, p
, size
);
825 /****************************************************************************
827 ****************************************************************************/
828 int cli_write(struct cli_state
*cli
, int fnum
, char *buf
, uint32 offset
, uint16 size
)
832 bzero(cli
->outbuf
,smb_size
);
833 bzero(cli
->inbuf
,smb_size
);
835 set_message(cli
->outbuf
,12,size
,True
);
837 CVAL(cli
->outbuf
,smb_com
) = SMBwriteX
;
838 SSVAL(cli
->outbuf
,smb_tid
,cli
->cnum
);
839 cli_setup_packet(cli
);
841 CVAL(cli
->outbuf
,smb_vwv0
) = 0xFF;
842 SSVAL(cli
->outbuf
,smb_vwv2
,fnum
);
843 SIVAL(cli
->outbuf
,smb_vwv3
,offset
);
845 SSVAL(cli
->outbuf
,smb_vwv10
,size
);
846 SSVAL(cli
->outbuf
,smb_vwv11
,smb_buf(cli
->outbuf
) - smb_base(cli
->outbuf
));
848 p
= smb_base(cli
->outbuf
) + SVAL(cli
->outbuf
,smb_vwv11
);
849 memcpy(p
, buf
, size
);
851 send_smb(cli
->fd
,cli
->outbuf
);
852 if (!receive_smb(cli
->fd
,cli
->inbuf
,cli
->timeout
)) {
856 if (CVAL(cli
->inbuf
,smb_rcls
) != 0) {
860 return SVAL(cli
->inbuf
, smb_vwv2
);
864 /****************************************************************************
866 ****************************************************************************/
867 BOOL
cli_getatr(struct cli_state
*cli
, char *fname
,
868 int *attr
, uint32
*size
, time_t *t
)
872 bzero(cli
->outbuf
,smb_size
);
873 bzero(cli
->inbuf
,smb_size
);
875 set_message(cli
->outbuf
,0,strlen(fname
)+2,True
);
877 CVAL(cli
->outbuf
,smb_com
) = SMBgetatr
;
878 SSVAL(cli
->outbuf
,smb_tid
,cli
->cnum
);
879 cli_setup_packet(cli
);
881 p
= smb_buf(cli
->outbuf
);
885 send_smb(cli
->fd
,cli
->outbuf
);
886 if (!receive_smb(cli
->fd
,cli
->inbuf
,cli
->timeout
)) {
890 if (CVAL(cli
->inbuf
,smb_rcls
) != 0) {
895 *size
= IVAL(cli
->inbuf
, smb_vwv3
);
899 *t
= make_unix_date3(cli
->inbuf
+smb_vwv1
);
903 *attr
= SVAL(cli
->inbuf
,smb_vwv0
);
911 /****************************************************************************
913 ****************************************************************************/
914 BOOL
cli_setatr(struct cli_state
*cli
, char *fname
, int attr
, time_t t
)
918 bzero(cli
->outbuf
,smb_size
);
919 bzero(cli
->inbuf
,smb_size
);
921 set_message(cli
->outbuf
,8,strlen(fname
)+2,True
);
923 CVAL(cli
->outbuf
,smb_com
) = SMBsetatr
;
924 SSVAL(cli
->outbuf
,smb_tid
,cli
->cnum
);
925 cli_setup_packet(cli
);
927 SSVAL(cli
->outbuf
,smb_vwv0
, attr
);
928 put_dos_date3(cli
->outbuf
,smb_vwv1
, t
);
930 p
= smb_buf(cli
->outbuf
);
934 send_smb(cli
->fd
,cli
->outbuf
);
935 if (!receive_smb(cli
->fd
,cli
->inbuf
,cli
->timeout
)) {
939 if (CVAL(cli
->inbuf
,smb_rcls
) != 0) {
946 /****************************************************************************
947 send a qpathinfo call
948 ****************************************************************************/
949 BOOL
cli_qpathinfo(struct cli_state
*cli
, char *fname
,
950 time_t *c_time
, time_t *a_time
, time_t *m_time
, uint32
*size
)
954 uint16 setup
= TRANSACT2_QPATHINFO
;
956 char *rparam
=NULL
, *rdata
=NULL
;
958 param_len
= strlen(fname
) + 7;
960 memset(param
, 0, param_len
);
961 SSVAL(param
, 0, SMB_INFO_STANDARD
);
962 pstrcpy(¶m
[6], fname
);
964 if (!cli_send_trans(cli
, SMBtrans2
, NULL
, -1, 0,
966 data_len
, param_len
, 1,
967 cli
->max_xmit
, 10, 0)) {
971 if (!cli_receive_trans(cli
, SMBtrans2
, &data_len
, ¶m_len
,
976 if (!rdata
|| data_len
< 22) {
981 *c_time
= make_unix_date2(rdata
+0);
984 *a_time
= make_unix_date2(rdata
+4);
987 *m_time
= make_unix_date2(rdata
+8);
990 *size
= IVAL(rdata
, 12);
993 if (rdata
) free(rdata
);
994 if (rparam
) free(rparam
);
999 /****************************************************************************
1000 send a qfileinfo call
1001 ****************************************************************************/
1002 BOOL
cli_qfileinfo(struct cli_state
*cli
, int fnum
,
1003 time_t *c_time
, time_t *a_time
, time_t *m_time
, uint32
*size
)
1007 uint16 setup
= TRANSACT2_QFILEINFO
;
1009 char *rparam
=NULL
, *rdata
=NULL
;
1013 memset(param
, 0, param_len
);
1014 SSVAL(param
, 0, fnum
);
1015 SSVAL(param
, 2, SMB_INFO_STANDARD
);
1017 if (!cli_send_trans(cli
, SMBtrans2
, NULL
, -1, 0,
1018 NULL
, param
, &setup
,
1019 data_len
, param_len
, 1,
1020 cli
->max_xmit
, 2, 0)) {
1024 if (!cli_receive_trans(cli
, SMBtrans2
, &data_len
, ¶m_len
,
1029 if (!rdata
|| data_len
< 22) {
1034 *c_time
= make_unix_date2(rdata
+0);
1037 *a_time
= make_unix_date2(rdata
+4);
1040 *m_time
= make_unix_date2(rdata
+8);
1043 *size
= IVAL(rdata
, 12);
1046 if (rdata
) free(rdata
);
1047 if (rparam
) free(rparam
);
1052 /****************************************************************************
1053 send a negprot command
1054 ****************************************************************************/
1055 BOOL
cli_negprot(struct cli_state
*cli
)
1061 bzero(cli
->outbuf
,smb_size
);
1063 /* setup the protocol strings */
1064 for (plength
=0,numprots
=0;
1065 prots
[numprots
].name
&& prots
[numprots
].prot
<=cli
->protocol
;
1067 plength
+= strlen(prots
[numprots
].name
)+2;
1069 set_message(cli
->outbuf
,0,plength
,True
);
1071 p
= smb_buf(cli
->outbuf
);
1073 prots
[numprots
].name
&& prots
[numprots
].prot
<=cli
->protocol
;
1076 strcpy(p
,prots
[numprots
].name
);
1080 CVAL(cli
->outbuf
,smb_com
) = SMBnegprot
;
1081 cli_setup_packet(cli
);
1083 CVAL(smb_buf(cli
->outbuf
),0) = 2;
1085 send_smb(cli
->fd
,cli
->outbuf
);
1086 if (!receive_smb(cli
->fd
,cli
->inbuf
,cli
->timeout
))
1089 show_msg(cli
->inbuf
);
1091 if (CVAL(cli
->inbuf
,smb_rcls
) != 0 ||
1092 ((int)SVAL(cli
->inbuf
,smb_vwv0
) >= numprots
)) {
1096 cli
->protocol
= prots
[SVAL(cli
->inbuf
,smb_vwv0
)].prot
;
1099 if (cli
->protocol
>= PROTOCOL_NT1
) {
1101 cli
->sec_mode
= CVAL(cli
->inbuf
,smb_vwv1
);
1102 cli
->max_xmit
= IVAL(cli
->inbuf
,smb_vwv3
+1);
1103 cli
->sesskey
= IVAL(cli
->inbuf
,smb_vwv7
+1);
1104 cli
->serverzone
= SVALS(cli
->inbuf
,smb_vwv15
+1)*60;
1105 /* this time arrives in real GMT */
1106 cli
->servertime
= interpret_long_date(cli
->inbuf
+smb_vwv11
+1);
1107 memcpy(cli
->cryptkey
,smb_buf(cli
->inbuf
),8);
1108 if (IVAL(cli
->inbuf
,smb_vwv9
+1) & 1)
1109 cli
->readbraw_supported
=
1110 cli
->writebraw_supported
= True
;
1111 } else if (cli
->protocol
>= PROTOCOL_LANMAN1
) {
1112 cli
->sec_mode
= SVAL(cli
->inbuf
,smb_vwv1
);
1113 cli
->max_xmit
= SVAL(cli
->inbuf
,smb_vwv2
);
1114 cli
->sesskey
= IVAL(cli
->inbuf
,smb_vwv6
);
1115 cli
->serverzone
= SVALS(cli
->inbuf
,smb_vwv10
)*60;
1116 /* this time is converted to GMT by make_unix_date */
1117 cli
->servertime
= make_unix_date(cli
->inbuf
+smb_vwv8
);
1118 cli
->readbraw_supported
= ((SVAL(cli
->inbuf
,smb_vwv5
) & 0x1) != 0);
1119 cli
->writebraw_supported
= ((SVAL(cli
->inbuf
,smb_vwv5
) & 0x2) != 0);
1120 memcpy(cli
->cryptkey
,smb_buf(cli
->inbuf
),8);
1122 /* the old core protocol */
1124 cli
->serverzone
= TimeDiff(time(NULL
));
1131 /****************************************************************************
1132 send a session request
1133 ****************************************************************************/
1134 BOOL
cli_session_request(struct cli_state
*cli
, char *host
, int name_type
,
1140 /* send a session request (RFC 1002) */
1144 p
= strchr(dest
,'.');
1147 fstrcpy(cli
->desthost
, dest
);
1149 /* put in the destination name */
1150 p
= cli
->outbuf
+len
;
1151 name_mangle(dest
,p
,name_type
);
1155 p
= cli
->outbuf
+len
;
1156 name_mangle(myname
,p
,0);
1159 /* setup the packet length */
1160 _smb_setlen(cli
->outbuf
,len
);
1161 CVAL(cli
->outbuf
,0) = 0x81;
1163 send_smb(cli
->fd
,cli
->outbuf
);
1164 DEBUG(5,("Sent session request\n"));
1166 if (!receive_smb(cli
->fd
,cli
->inbuf
,cli
->timeout
))
1169 if (CVAL(cli
->inbuf
,0) != 0x82) {
1170 cli
->error
= CVAL(cli
->inbuf
,0);
1177 /****************************************************************************
1178 open the client sockets
1179 ****************************************************************************/
1180 BOOL
cli_connect(struct cli_state
*cli
, char *host
, struct in_addr
*ip
)
1182 struct in_addr dest_ip
;
1184 fstrcpy(cli
->desthost
, host
);
1189 if ((hp
= Get_Hostbyname(cli
->desthost
)) == 0) {
1193 putip((char *)&dest_ip
,(char *)hp
->h_addr
);
1199 cli
->fd
= open_socket_out(SOCK_STREAM
, &dest_ip
, 139, cli
->timeout
);
1207 /****************************************************************************
1208 initialise a client structure
1209 ****************************************************************************/
1210 BOOL
cli_initialise(struct cli_state
*cli
)
1212 if (cli
->initialised
) cli_shutdown(cli
);
1214 memset(cli
, 0, sizeof(*cli
));
1217 cli
->pid
= getpid();
1219 cli
->uid
= getuid();
1220 cli
->protocol
= PROTOCOL_NT1
;
1221 cli
->timeout
= 20000;
1222 cli
->bufsize
= 0x10000;
1223 cli
->max_xmit
= cli
->bufsize
- 4;
1224 cli
->outbuf
= (char *)malloc(cli
->bufsize
);
1225 cli
->inbuf
= (char *)malloc(cli
->bufsize
);
1226 if (!cli
->outbuf
|| !cli
->inbuf
) return False
;
1227 cli
->initialised
= 1;
1231 /****************************************************************************
1232 shutdown a client structure
1233 ****************************************************************************/
1234 void cli_shutdown(struct cli_state
*cli
)
1236 if (cli
->outbuf
) free(cli
->outbuf
);
1237 if (cli
->inbuf
) free(cli
->inbuf
);
1238 if (cli
->fd
!= -1) close(cli
->fd
);
1239 memset(cli
, 0, sizeof(*cli
));
1242 /****************************************************************************
1243 return a description of the error
1244 ****************************************************************************/
1245 char *cli_errstr(struct cli_state
*cli
)
1247 return smb_errstr(cli
->inbuf
);
1250 /****************************************************************************
1251 return error codes for the last packet
1252 ****************************************************************************/
1253 void cli_error(struct cli_state
*cli
, int *eclass
, int *num
)
1255 *eclass
= CVAL(cli
->inbuf
,smb_rcls
);
1256 *num
= SVAL(cli
->inbuf
,smb_err
);
1259 /****************************************************************************
1260 set socket options on a open connection
1261 ****************************************************************************/
1262 void cli_sockopt(struct cli_state
*cli
, char *options
)
1264 set_socket_options(cli
->fd
, options
);
1267 /****************************************************************************
1268 set the PID to use for smb messages. Return the old pid.
1269 ****************************************************************************/
1270 int cli_setpid(struct cli_state
*cli
, int pid
)