2 Unix SMB/Netbios implementation.
4 SMB client generic functions
6 Copyright (C) Andrew Tridgell 1994-1998
9 The Free Software Foundation, Inc.
11 This file is part of the Midnight Commander.
13 The Midnight Commander is free software: you can redistribute it
14 and/or modify it under the terms of the GNU General Public License as
15 published by the Free Software Foundation, either version 3 of the License,
16 or (at your option) any later version.
18 The Midnight Commander is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
23 You should have received a copy of the GNU General Public License
24 along with this program. If not, see <http://www.gnu.org/licenses/>.
33 extern int DEBUGLEVEL
;
34 extern pstring user_socket_options
;
37 * Change the port number used to call on
39 int cli_set_port(struct cli_state
*cli
, int port
)
47 /****************************************************************************
49 ****************************************************************************/
50 static BOOL
cli_receive_smb(struct cli_state
*cli
)
52 return client_receive_smb(cli
->fd
,cli
->inbuf
,cli
->timeout
);
55 /****************************************************************************
56 send an smb to a fd and re-establish if necessary
57 ****************************************************************************/
58 static BOOL
cli_send_smb(struct cli_state
*cli
)
63 BOOL reestablished
=False
;
65 len
= smb_len(cli
->outbuf
) + 4;
67 while (nwritten
< len
) {
68 ret
= write_socket(cli
->fd
,cli
->outbuf
+nwritten
,len
- nwritten
);
69 if (ret
<= 0 && errno
== EPIPE
&& !reestablished
) {
70 if (cli_reestablish_connection(cli
)) {
77 DEBUG(0,("Error writing %d bytes to client. %d. Exiting\n",
88 /*****************************************************
89 RAP error codes - a small start but will be extended.
90 *******************************************************/
96 } const rap_errmap
[] =
98 {5, "User has insufficient privilege" },
99 {86, "The specified password is invalid" },
100 {2226, "Operation only permitted on a Primary Domain Controller" },
101 {2242, "The password of this user has expired." },
102 {2243, "The password of this user cannot change." },
103 {2244, "This password cannot be used now (password history conflict)." },
104 {2245, "The password is shorter than required." },
105 {2246, "The password of this user is too recent to change."},
109 /****************************************************************************
110 return a description of an SMB error
111 ****************************************************************************/
112 static char *cli_smb_errstr(struct cli_state
*cli
)
114 return smb_errstr(cli
->inbuf
);
117 /******************************************************
118 Return an error message - either an SMB error or a RAP
120 *******************************************************/
122 char *cli_errstr(struct cli_state
*cli
)
124 static fstring error_message
;
131 * Errors are of three kinds - smb errors,
132 * dealt with by cli_smb_errstr, NT errors,
133 * whose code is in cli.nt_error, and rap
134 * errors, whose error code is in cli.rap_error.
137 cli_error(cli
, &errclass
, &errnum
, &nt_rpc_error
);
141 return cli_smb_errstr(cli
);
145 * Was it an NT error ?
150 const char *nt_msg
= get_nt_error_msg(nt_rpc_error
);
154 slprintf(error_message
, sizeof(fstring
) - 1, "NT code %d", nt_rpc_error
);
158 fstrcpy(error_message
, nt_msg
);
161 return error_message
;
165 * Must have been a rap error.
168 slprintf(error_message
, sizeof(error_message
) - 1, "code %d", cli
->rap_error
);
170 for (i
= 0; rap_errmap
[i
].message
!= NULL
; i
++)
172 if (rap_errmap
[i
].err
== cli
->rap_error
)
174 fstrcpy( error_message
, rap_errmap
[i
].message
);
179 return error_message
;
182 /****************************************************************************
183 setup basics in a outgoing packet
184 ****************************************************************************/
185 static void cli_setup_packet(struct cli_state
*cli
)
189 SSVAL(cli
->outbuf
,smb_pid
,cli
->pid
);
190 SSVAL(cli
->outbuf
,smb_uid
,cli
->vuid
);
191 SSVAL(cli
->outbuf
,smb_mid
,cli
->mid
);
192 if (cli
->protocol
> PROTOCOL_CORE
) {
193 SCVAL(cli
->outbuf
,smb_flg
,0x8);
194 SSVAL(cli
->outbuf
,smb_flg2
,0x1);
199 /*****************************************************************************
200 Convert a character pointer in a cli_call_api() response to a form we can use.
201 This function contains code to prevent core dumps if the server returns
203 *****************************************************************************/
204 static char *fix_char_ptr(unsigned int datap
, unsigned int converter
,
205 char *rdata
, int rdrcnt
)
207 if (datap
== 0) { /* turn NULL pointers into zero length strings */
210 unsigned int offset
= datap
- converter
;
212 if (offset
>= rdrcnt
) {
213 DEBUG(1,("bad char ptr: datap=%u, converter=%u rdrcnt=%d>",
214 datap
, converter
, rdrcnt
));
217 return &rdata
[offset
];
222 /****************************************************************************
223 send a SMB trans or trans2 request
224 ****************************************************************************/
225 static BOOL
cli_send_trans(struct cli_state
*cli
, int trans
,
226 const char *name
, int pipe_name_len
,
228 uint16
*setup
, int lsetup
, int msetup
,
229 char *param
, int lparam
, int mparam
,
230 char *data
, int ldata
, int mdata
)
233 int this_ldata
,this_lparam
;
234 int tot_data
=0,tot_param
=0;
235 char *outdata
,*outparam
;
238 this_lparam
= MIN(lparam
,cli
->max_xmit
- (500+lsetup
*2)); /* hack */
239 this_ldata
= MIN(ldata
,cli
->max_xmit
- (500+lsetup
*2+this_lparam
));
241 memset(cli
->outbuf
,'\0',smb_size
);
242 set_message(cli
->outbuf
,14+lsetup
,0,True
);
243 CVAL(cli
->outbuf
,smb_com
) = trans
;
244 SSVAL(cli
->outbuf
,smb_tid
, cli
->cnum
);
245 cli_setup_packet(cli
);
247 outparam
= smb_buf(cli
->outbuf
)+(trans
==SMBtrans
? pipe_name_len
+1 : 3);
248 outdata
= outparam
+this_lparam
;
250 /* primary request */
251 SSVAL(cli
->outbuf
,smb_tpscnt
,lparam
); /* tpscnt */
252 SSVAL(cli
->outbuf
,smb_tdscnt
,ldata
); /* tdscnt */
253 SSVAL(cli
->outbuf
,smb_mprcnt
,mparam
); /* mprcnt */
254 SSVAL(cli
->outbuf
,smb_mdrcnt
,mdata
); /* mdrcnt */
255 SCVAL(cli
->outbuf
,smb_msrcnt
,msetup
); /* msrcnt */
256 SSVAL(cli
->outbuf
,smb_flags
,flags
); /* flags */
257 SIVAL(cli
->outbuf
,smb_timeout
,0); /* timeout */
258 SSVAL(cli
->outbuf
,smb_pscnt
,this_lparam
); /* pscnt */
259 SSVAL(cli
->outbuf
,smb_psoff
,smb_offset(outparam
,cli
->outbuf
)); /* psoff */
260 SSVAL(cli
->outbuf
,smb_dscnt
,this_ldata
); /* dscnt */
261 SSVAL(cli
->outbuf
,smb_dsoff
,smb_offset(outdata
,cli
->outbuf
)); /* dsoff */
262 SCVAL(cli
->outbuf
,smb_suwcnt
,lsetup
); /* suwcnt */
263 for (i
=0;i
<lsetup
;i
++) /* setup[] */
264 SSVAL(cli
->outbuf
,smb_setup
+i
*2,setup
[i
]);
265 p
= smb_buf(cli
->outbuf
);
266 if (trans
==SMBtrans
) {
267 memcpy(p
,name
, pipe_name_len
+ 1); /* name[] */
269 *p
++ = 0; /* put in a null smb_name */
270 *p
++ = 'D'; *p
++ = ' '; /* observed in OS/2 */
272 if (this_lparam
) /* param[] */
273 memcpy(outparam
,param
,this_lparam
);
274 if (this_ldata
) /* data[] */
275 memcpy(outdata
,data
,this_ldata
);
276 set_message(cli
->outbuf
,14+lsetup
, /* wcnt, bcc */
277 PTR_DIFF(outdata
+this_ldata
,smb_buf(cli
->outbuf
)),False
);
279 show_msg(cli
->outbuf
);
282 if (this_ldata
< ldata
|| this_lparam
< lparam
) {
283 /* receive interim response */
284 if (!cli_receive_smb(cli
) ||
285 CVAL(cli
->inbuf
,smb_rcls
) != 0) {
289 tot_data
= this_ldata
;
290 tot_param
= this_lparam
;
292 while (tot_data
< ldata
|| tot_param
< lparam
) {
293 this_lparam
= MIN(lparam
-tot_param
,cli
->max_xmit
- 500); /* hack */
294 this_ldata
= MIN(ldata
-tot_data
,cli
->max_xmit
- (500+this_lparam
));
296 set_message(cli
->outbuf
,trans
==SMBtrans
?8:9,0,True
);
297 CVAL(cli
->outbuf
,smb_com
) = trans
==SMBtrans
? SMBtranss
: SMBtranss2
;
299 outparam
= smb_buf(cli
->outbuf
);
300 outdata
= outparam
+this_lparam
;
302 /* secondary request */
303 SSVAL(cli
->outbuf
,smb_tpscnt
,lparam
); /* tpscnt */
304 SSVAL(cli
->outbuf
,smb_tdscnt
,ldata
); /* tdscnt */
305 SSVAL(cli
->outbuf
,smb_spscnt
,this_lparam
); /* pscnt */
306 SSVAL(cli
->outbuf
,smb_spsoff
,smb_offset(outparam
,cli
->outbuf
)); /* psoff */
307 SSVAL(cli
->outbuf
,smb_spsdisp
,tot_param
); /* psdisp */
308 SSVAL(cli
->outbuf
,smb_sdscnt
,this_ldata
); /* dscnt */
309 SSVAL(cli
->outbuf
,smb_sdsoff
,smb_offset(outdata
,cli
->outbuf
)); /* dsoff */
310 SSVAL(cli
->outbuf
,smb_sdsdisp
,tot_data
); /* dsdisp */
311 if (trans
==SMBtrans2
)
312 SSVALS(cli
->outbuf
,smb_sfid
,fid
); /* fid */
313 if (this_lparam
) /* param[] */
314 memcpy(outparam
,param
,this_lparam
);
315 if (this_ldata
) /* data[] */
316 memcpy(outdata
,data
,this_ldata
);
317 set_message(cli
->outbuf
,trans
==SMBtrans
?8:9, /* wcnt, bcc */
318 PTR_DIFF(outdata
+this_ldata
,smb_buf(cli
->outbuf
)),False
);
320 show_msg(cli
->outbuf
);
323 tot_data
+= this_ldata
;
324 tot_param
+= this_lparam
;
332 /****************************************************************************
333 receive a SMB trans or trans2 response allocating the necessary memory
334 ****************************************************************************/
335 static BOOL
cli_receive_trans(struct cli_state
*cli
,int trans
,
336 char **param
, int *param_len
,
337 char **data
, int *data_len
)
341 int this_data
,this_param
;
345 *data_len
= *param_len
= 0;
347 if (!cli_receive_smb(cli
))
350 show_msg(cli
->inbuf
);
353 if (CVAL(cli
->inbuf
,smb_com
) != trans
) {
354 DEBUG(0,("Expected %s response, got command 0x%02x\n",
355 trans
==SMBtrans
?"SMBtrans":"SMBtrans2",
356 CVAL(cli
->inbuf
,smb_com
)));
361 * An NT RPC pipe call can return ERRDOS, ERRmoredata
362 * to a trans call. This is not an error and should not
363 * be treated as such.
366 if (cli_error(cli
, &eclass
, &ecode
, NULL
))
368 if(cli
->nt_pipe_fnum
== 0 || !(eclass
== ERRDOS
&& ecode
== ERRmoredata
))
372 /* parse out the lengths */
373 total_data
= SVAL(cli
->inbuf
,smb_tdrcnt
);
374 total_param
= SVAL(cli
->inbuf
,smb_tprcnt
);
377 *data
= Realloc(*data
,total_data
);
378 *param
= Realloc(*param
,total_param
);
381 this_data
= SVAL(cli
->inbuf
,smb_drcnt
);
382 this_param
= SVAL(cli
->inbuf
,smb_prcnt
);
384 if (this_data
+ *data_len
> total_data
||
385 this_param
+ *param_len
> total_param
) {
386 DEBUG(1,("Data overflow in cli_receive_trans\n"));
391 memcpy(*data
+ SVAL(cli
->inbuf
,smb_drdisp
),
392 smb_base(cli
->inbuf
) + SVAL(cli
->inbuf
,smb_droff
),
395 memcpy(*param
+ SVAL(cli
->inbuf
,smb_prdisp
),
396 smb_base(cli
->inbuf
) + SVAL(cli
->inbuf
,smb_proff
),
398 *data_len
+= this_data
;
399 *param_len
+= this_param
;
401 /* parse out the total lengths again - they can shrink! */
402 total_data
= SVAL(cli
->inbuf
,smb_tdrcnt
);
403 total_param
= SVAL(cli
->inbuf
,smb_tprcnt
);
405 if (total_data
<= *data_len
&& total_param
<= *param_len
)
408 if (!cli_receive_smb(cli
))
411 show_msg(cli
->inbuf
);
414 if (CVAL(cli
->inbuf
,smb_com
) != trans
) {
415 DEBUG(0,("Expected %s response, got command 0x%02x\n",
416 trans
==SMBtrans
?"SMBtrans":"SMBtrans2",
417 CVAL(cli
->inbuf
,smb_com
)));
420 if (cli_error(cli
, &eclass
, &ecode
, NULL
))
422 if(cli
->nt_pipe_fnum
== 0 || !(eclass
== ERRDOS
&& ecode
== ERRmoredata
))
431 /****************************************************************************
432 Call a remote api on an arbitrary pipe. takes param, data and setup buffers.
433 ****************************************************************************/
434 BOOL
cli_api_pipe(struct cli_state
*cli
, char *pipe_name
, int pipe_name_len
,
435 uint16
*setup
, uint32 setup_count
, uint32 max_setup_count
,
436 char *params
, uint32 param_count
, uint32 max_param_count
,
437 char *data
, uint32 data_count
, uint32 max_data_count
,
438 char **rparam
, uint32
*rparam_count
,
439 char **rdata
, uint32
*rdata_count
)
441 if (pipe_name_len
== 0)
442 pipe_name_len
= strlen(pipe_name
);
444 cli_send_trans(cli
, SMBtrans
,
445 pipe_name
, pipe_name_len
,
446 0,0, /* fid, flags */
447 setup
, setup_count
, max_setup_count
,
448 params
, param_count
, max_param_count
,
449 data
, data_count
, max_data_count
);
451 return (cli_receive_trans(cli
, SMBtrans
,
452 rparam
, (int *)rparam_count
,
453 rdata
, (int *)rdata_count
));
457 /****************************************************************************
459 ****************************************************************************/
460 BOOL
cli_api(struct cli_state
*cli
,
461 char *param
, int prcnt
, int mprcnt
,
462 char *data
, int drcnt
, int mdrcnt
,
463 char **rparam
, int *rprcnt
,
464 char **rdata
, int *rdrcnt
)
466 cli_send_trans(cli
,SMBtrans
,
467 PIPE_LANMAN
,strlen(PIPE_LANMAN
), /* Name, length */
468 0,0, /* fid, flags */
469 NULL
,0,0, /* Setup, length, max */
470 param
, prcnt
, mprcnt
, /* Params, length, max */
471 data
, drcnt
, mdrcnt
/* Data, length, max */
474 return (cli_receive_trans(cli
,SMBtrans
,
480 /****************************************************************************
481 perform a NetWkstaUserLogon
482 ****************************************************************************/
483 BOOL
cli_NetWkstaUserLogon(struct cli_state
*cli
,char *user
, char *workstation
)
491 memset(param
, 0, sizeof(param
));
493 /* send a SMBtrans command with api NetWkstaUserLogon */
495 SSVAL(p
,0,132); /* api number */
497 pstrcpy(p
,"OOWb54WrLh");
498 p
= skip_string(p
,1);
499 pstrcpy(p
,"WB21BWDWWDDDDDDDzzzD");
500 p
= skip_string(p
,1);
509 pstrcpy(p
, workstation
);
512 SSVAL(p
, 0, CLI_BUFFER_SIZE
);
514 SSVAL(p
, 0, CLI_BUFFER_SIZE
);
518 param
, PTR_DIFF(p
,param
),1024, /* param, length, max */
519 NULL
, 0, CLI_BUFFER_SIZE
, /* data, length, max */
520 &rparam
, &rprcnt
, /* return params, return size */
521 &rdata
, &rdrcnt
/* return data, return size */
523 cli
->rap_error
= SVAL(rparam
,0);
526 if (cli
->rap_error
== 0) {
527 DEBUG(4,("NetWkstaUserLogon success\n"));
528 cli
->privileges
= SVAL(p
, 24);
529 fstrcpy(cli
->eff_name
,p
+2);
531 DEBUG(1,("NetwkstaUserLogon gave error %d\n", cli
->rap_error
));
539 return (cli
->rap_error
== 0);
543 /****************************************************************************
544 call a NetShareEnum - try and browse available connections on a host
545 ****************************************************************************/
546 int cli_RNetShareEnum(struct cli_state
*cli
, void (*fn
)(const char *, uint32
, const char *, void *), void * state
)
555 /* now send a SMBtrans command with api RNetShareEnum */
557 SSVAL(p
,0,0); /* api number */
560 p
= skip_string(p
,1);
562 p
= skip_string(p
,1);
565 * Win2k needs a *smaller* buffer than 0xFFFF here -
566 * it returns "out of server memory" with 0xFFFF !!! JRA.
572 param
, PTR_DIFF(p
,param
), 1024, /* Param, length, maxlen */
573 NULL
, 0, 0xFFE0, /* data, length, maxlen - Win2k needs a small buffer here too ! */
574 &rparam
, &rprcnt
, /* return params, length */
575 &rdata
, &rdrcnt
)) /* return data, length */
577 int res
= SVAL(rparam
,0);
578 int converter
=SVAL(rparam
,2);
581 if (res
== 0 || res
== ERRmoredata
) {
582 count
=SVAL(rparam
,4);
585 for (i
=0;i
<count
;i
++,p
+=20) {
587 int type
= SVAL(p
,14);
588 int comment_offset
= IVAL(p
,16) & 0xFFFF;
589 const char *cmnt
= comment_offset
?(rdata
+comment_offset
-converter
):"";
590 fn(sname
, type
, cmnt
, state
);
593 DEBUG(4,("NetShareEnum res=%d\n", res
));
596 DEBUG(4,("NetShareEnum failed\n"));
608 /****************************************************************************
609 call a NetServerEnum for the specified workgroup and servertype mask.
610 This function then calls the specified callback function for each name returned.
612 The callback function takes 3 arguments: the machine name, the server type and
614 ****************************************************************************/
615 BOOL
cli_NetServerEnum(struct cli_state
*cli
, char *workgroup
, uint32 stype
,
616 void (*fn
)(const char *, uint32
, const char *, void *), void *state
)
626 /* send a SMBtrans command with api NetServerEnum */
628 SSVAL(p
,0,0x68); /* api number */
630 pstrcpy(p
,"WrLehDz");
631 p
= skip_string(p
,1);
633 pstrcpy(p
,"B16BBDz");
635 p
= skip_string(p
,1);
637 SSVAL(p
,2,CLI_BUFFER_SIZE
);
642 pstrcpy(p
, workgroup
);
643 p
= skip_string(p
,1);
646 param
, PTR_DIFF(p
,param
), 8, /* params, length, max */
647 NULL
, 0, CLI_BUFFER_SIZE
, /* data, length, max */
648 &rparam
, &rprcnt
, /* return params, return size */
649 &rdata
, &rdrcnt
/* return data, return size */
651 int res
= SVAL(rparam
,0);
652 int converter
=SVAL(rparam
,2);
655 if (res
== 0 || res
== ERRmoredata
) {
656 count
=SVAL(rparam
,4);
659 for (i
= 0;i
< count
;i
++, p
+= 26) {
661 int comment_offset
= (IVAL(p
,22) & 0xFFFF)-converter
;
662 const char *cmnt
= comment_offset
?(rdata
+comment_offset
):"";
663 if (comment_offset
< 0 || comment_offset
> rdrcnt
) continue;
665 stype
= IVAL(p
,18) & ~SV_TYPE_LOCAL_LIST_ONLY
;
667 fn(sname
, stype
, cmnt
, state
);
689 {PROTOCOL_CORE
,"PC NETWORK PROGRAM 1.0"},
690 {PROTOCOL_COREPLUS
,"MICROSOFT NETWORKS 1.03"},
691 {PROTOCOL_LANMAN1
,"MICROSOFT NETWORKS 3.0"},
692 {PROTOCOL_LANMAN1
,"LANMAN1.0"},
693 {PROTOCOL_LANMAN2
,"LM1.2X002"},
694 {PROTOCOL_LANMAN2
,"Samba"},
695 {PROTOCOL_NT1
,"NT LANMAN 1.0"},
696 {PROTOCOL_NT1
,"NT LM 0.12"},
701 /****************************************************************************
703 ****************************************************************************/
704 BOOL
cli_session_setup(struct cli_state
*cli
,
706 char *pass
, int passlen
,
707 char *ntpass
, int ntpasslen
,
711 fstring pword
, ntpword
;
713 if (cli
->protocol
< PROTOCOL_LANMAN1
)
716 if ((size_t) passlen
> sizeof(pword
)-1 || (size_t)ntpasslen
> sizeof(ntpword
)-1) {
720 if (((passlen
== 0) || (passlen
== 1)) && (pass
[0] == '\0')) {
721 /* Null session connect. */
725 if ((cli
->sec_mode
& 2) && passlen
!= 24) {
728 SMBencrypt((uchar
*)pass
,(uchar
*)cli
->cryptkey
,(uchar
*)pword
);
729 SMBNTencrypt((uchar
*)ntpass
,(uchar
*)cli
->cryptkey
,(uchar
*)ntpword
);
731 fstrcpy(pword
, pass
);
732 fstrcpy(ntpword
, "");
737 /* if in share level security then don't send a password now */
738 if (!(cli
->sec_mode
& 1)) {
741 fstrcpy(ntpword
, "");
745 /* send a session setup command */
746 memset(cli
->outbuf
,'\0',smb_size
);
748 if (cli
->protocol
< PROTOCOL_NT1
)
750 set_message(cli
->outbuf
,10,1 + strlen(user
) + passlen
,True
);
751 CVAL(cli
->outbuf
,smb_com
) = SMBsesssetupX
;
752 cli_setup_packet(cli
);
754 CVAL(cli
->outbuf
,smb_vwv0
) = 0xFF;
755 SSVAL(cli
->outbuf
,smb_vwv2
,cli
->max_xmit
);
756 SSVAL(cli
->outbuf
,smb_vwv3
,2);
757 SSVAL(cli
->outbuf
,smb_vwv4
,1);
758 SIVAL(cli
->outbuf
,smb_vwv5
,cli
->sesskey
);
759 SSVAL(cli
->outbuf
,smb_vwv7
,passlen
);
760 p
= smb_buf(cli
->outbuf
);
761 memcpy(p
,pword
,passlen
);
765 unix_to_dos (p
, True
);
769 set_message(cli
->outbuf
,13,0,True
);
770 CVAL(cli
->outbuf
,smb_com
) = SMBsesssetupX
;
771 cli_setup_packet(cli
);
773 CVAL(cli
->outbuf
,smb_vwv0
) = 0xFF;
774 SSVAL(cli
->outbuf
,smb_vwv2
,CLI_BUFFER_SIZE
);
775 SSVAL(cli
->outbuf
,smb_vwv3
,2);
776 SSVAL(cli
->outbuf
,smb_vwv4
,cli
->pid
);
777 SIVAL(cli
->outbuf
,smb_vwv5
,cli
->sesskey
);
778 SSVAL(cli
->outbuf
,smb_vwv7
,passlen
);
779 SSVAL(cli
->outbuf
,smb_vwv8
,ntpasslen
);
780 SSVAL(cli
->outbuf
,smb_vwv11
,0);
781 p
= smb_buf(cli
->outbuf
);
782 memcpy(p
,pword
,passlen
);
783 p
+= SVAL(cli
->outbuf
,smb_vwv7
);
784 memcpy(p
,ntpword
,ntpasslen
);
785 p
+= SVAL(cli
->outbuf
,smb_vwv8
);
788 unix_to_dos (p
, True
);
789 p
= skip_string(p
,1);
790 pstrcpy(p
,workgroup
);
792 p
= skip_string(p
,1);
793 pstrcpy(p
,"Unix");p
= skip_string(p
,1);
794 pstrcpy(p
,"Samba");p
= skip_string(p
,1);
795 set_message(cli
->outbuf
,13,PTR_DIFF(p
,smb_buf(cli
->outbuf
)),False
);
799 if (!cli_receive_smb(cli
))
802 show_msg(cli
->inbuf
);
804 if (CVAL(cli
->inbuf
,smb_rcls
) != 0) {
808 /* use the returned vuid from now on */
809 cli
->vuid
= SVAL(cli
->inbuf
,smb_uid
);
811 if (cli
->protocol
>= PROTOCOL_NT1
) {
813 * Save off some of the connected server
816 char *server_domain
,*server_os
,*server_type
;
817 server_os
= smb_buf(cli
->inbuf
);
818 server_type
= skip_string(server_os
,1);
819 server_domain
= skip_string(server_type
,1);
820 fstrcpy(cli
->server_os
, server_os
);
821 fstrcpy(cli
->server_type
, server_type
);
822 fstrcpy(cli
->server_domain
, server_domain
);
825 fstrcpy(cli
->user_name
, user
);
830 /****************************************************************************
832 *****************************************************************************/
834 BOOL
cli_ulogoff(struct cli_state
*cli
)
836 memset(cli
->outbuf
,'\0',smb_size
);
837 set_message(cli
->outbuf
,2,0,True
);
838 CVAL(cli
->outbuf
,smb_com
) = SMBulogoffX
;
839 cli_setup_packet(cli
);
840 SSVAL(cli
->outbuf
,smb_vwv0
,0xFF);
841 SSVAL(cli
->outbuf
,smb_vwv2
,0); /* no additional info */
844 if (!cli_receive_smb(cli
))
847 return CVAL(cli
->inbuf
,smb_rcls
) == 0;
851 /****************************************************************************
853 ****************************************************************************/
854 BOOL
cli_send_tconX(struct cli_state
*cli
,
855 const char *share
, const char *dev
, const char *pass
, int passlen
)
857 fstring fullshare
, pword
;
859 memset(cli
->outbuf
,'\0',smb_size
);
860 memset(cli
->inbuf
,'\0',smb_size
);
862 fstrcpy(cli
->share
, share
);
864 /* in user level security don't send a password now */
865 if (cli
->sec_mode
& 1) {
870 if ((cli
->sec_mode
& 2) && *pass
&& passlen
!= 24) {
872 SMBencrypt((uchar
*)pass
,(uchar
*)cli
->cryptkey
,(uchar
*)pword
);
874 memcpy(pword
, pass
, passlen
);
877 slprintf(fullshare
, sizeof(fullshare
)-1,
878 "\\\\%s\\%s", cli
->desthost
, share
);
879 unix_to_dos(fullshare
, True
);
882 set_message(cli
->outbuf
,4,
883 2 + strlen(fullshare
) + passlen
+ strlen(dev
),True
);
884 CVAL(cli
->outbuf
,smb_com
) = SMBtconX
;
885 cli_setup_packet(cli
);
887 SSVAL(cli
->outbuf
,smb_vwv0
,0xFF);
888 SSVAL(cli
->outbuf
,smb_vwv3
,passlen
);
890 p
= smb_buf(cli
->outbuf
);
891 memcpy(p
,pword
,passlen
);
893 fstrcpy(p
,fullshare
);
894 p
= skip_string(p
,1);
897 SCVAL(cli
->inbuf
,smb_rcls
, 1);
900 if (!cli_receive_smb(cli
))
903 if (CVAL(cli
->inbuf
,smb_rcls
) != 0) {
907 fstrcpy(cli
->dev
, "A:");
909 if (cli
->protocol
>= PROTOCOL_NT1
) {
910 fstrcpy(cli
->dev
, smb_buf(cli
->inbuf
));
913 if (strcasecmp(share
,"IPC$")==0) {
914 fstrcpy(cli
->dev
, "IPC");
917 /* only grab the device if we have a recent protocol level */
918 if (cli
->protocol
>= PROTOCOL_NT1
&&
919 smb_buflen(cli
->inbuf
) == 3) {
920 /* almost certainly win95 - enable bug fixes */
924 cli
->cnum
= SVAL(cli
->inbuf
,smb_tid
);
929 /****************************************************************************
930 send a tree disconnect
931 ****************************************************************************/
932 BOOL
cli_tdis(struct cli_state
*cli
)
934 memset(cli
->outbuf
,'\0',smb_size
);
935 set_message(cli
->outbuf
,0,0,True
);
936 CVAL(cli
->outbuf
,smb_com
) = SMBtdis
;
937 SSVAL(cli
->outbuf
,smb_tid
,cli
->cnum
);
938 cli_setup_packet(cli
);
941 if (!cli_receive_smb(cli
))
944 return CVAL(cli
->inbuf
,smb_rcls
) == 0;
948 /****************************************************************************
950 ****************************************************************************/
951 BOOL
cli_rename(struct cli_state
*cli
, char *fname_src
, char *fname_dst
)
955 memset(cli
->outbuf
,'\0',smb_size
);
956 memset(cli
->inbuf
,'\0',smb_size
);
958 set_message(cli
->outbuf
,1, 4 + strlen(fname_src
) + strlen(fname_dst
), True
);
960 CVAL(cli
->outbuf
,smb_com
) = SMBmv
;
961 SSVAL(cli
->outbuf
,smb_tid
,cli
->cnum
);
962 cli_setup_packet(cli
);
964 SSVAL(cli
->outbuf
,smb_vwv0
,aSYSTEM
| aHIDDEN
);
966 p
= smb_buf(cli
->outbuf
);
968 pstrcpy(p
,fname_src
);
969 p
= skip_string(p
,1);
971 pstrcpy(p
,fname_dst
);
974 if (!cli_receive_smb(cli
)) {
978 if (CVAL(cli
->inbuf
,smb_rcls
) != 0) {
985 /****************************************************************************
987 ****************************************************************************/
988 BOOL
cli_unlink(struct cli_state
*cli
, char *fname
)
992 memset(cli
->outbuf
,'\0',smb_size
);
993 memset(cli
->inbuf
,'\0',smb_size
);
995 set_message(cli
->outbuf
,1, 2 + strlen(fname
),True
);
997 CVAL(cli
->outbuf
,smb_com
) = SMBunlink
;
998 SSVAL(cli
->outbuf
,smb_tid
,cli
->cnum
);
999 cli_setup_packet(cli
);
1001 SSVAL(cli
->outbuf
,smb_vwv0
,aSYSTEM
| aHIDDEN
);
1003 p
= smb_buf(cli
->outbuf
);
1008 if (!cli_receive_smb(cli
)) {
1012 if (CVAL(cli
->inbuf
,smb_rcls
) != 0) {
1019 /****************************************************************************
1021 ****************************************************************************/
1022 BOOL
cli_mkdir(struct cli_state
*cli
, char *dname
)
1026 memset(cli
->outbuf
,'\0',smb_size
);
1027 memset(cli
->inbuf
,'\0',smb_size
);
1029 set_message(cli
->outbuf
,0, 2 + strlen(dname
),True
);
1031 CVAL(cli
->outbuf
,smb_com
) = SMBmkdir
;
1032 SSVAL(cli
->outbuf
,smb_tid
,cli
->cnum
);
1033 cli_setup_packet(cli
);
1035 p
= smb_buf(cli
->outbuf
);
1040 if (!cli_receive_smb(cli
)) {
1044 if (CVAL(cli
->inbuf
,smb_rcls
) != 0) {
1051 /****************************************************************************
1053 ****************************************************************************/
1054 BOOL
cli_rmdir(struct cli_state
*cli
, char *dname
)
1058 memset(cli
->outbuf
,'\0',smb_size
);
1059 memset(cli
->inbuf
,'\0',smb_size
);
1061 set_message(cli
->outbuf
,0, 2 + strlen(dname
),True
);
1063 CVAL(cli
->outbuf
,smb_com
) = SMBrmdir
;
1064 SSVAL(cli
->outbuf
,smb_tid
,cli
->cnum
);
1065 cli_setup_packet(cli
);
1067 p
= smb_buf(cli
->outbuf
);
1072 if (!cli_receive_smb(cli
)) {
1076 if (CVAL(cli
->inbuf
,smb_rcls
) != 0) {
1084 /****************************************************************************
1086 ****************************************************************************/
1087 int cli_nt_create(struct cli_state
*cli
, char *fname
)
1091 memset(cli
->outbuf
,'\0',smb_size
);
1092 memset(cli
->inbuf
,'\0',smb_size
);
1094 set_message(cli
->outbuf
,24,1 + strlen(fname
),True
);
1096 CVAL(cli
->outbuf
,smb_com
) = SMBntcreateX
;
1097 SSVAL(cli
->outbuf
,smb_tid
,cli
->cnum
);
1098 cli_setup_packet(cli
);
1100 SSVAL(cli
->outbuf
,smb_vwv0
,0xFF);
1101 SIVAL(cli
->outbuf
,smb_ntcreate_Flags
, 0x06);
1102 SIVAL(cli
->outbuf
,smb_ntcreate_RootDirectoryFid
, 0x0);
1103 SIVAL(cli
->outbuf
,smb_ntcreate_DesiredAccess
, 0x2019f);
1104 SIVAL(cli
->outbuf
,smb_ntcreate_FileAttributes
, 0x0);
1105 SIVAL(cli
->outbuf
,smb_ntcreate_ShareAccess
, 0x03);
1106 SIVAL(cli
->outbuf
,smb_ntcreate_CreateDisposition
, 0x01);
1107 SIVAL(cli
->outbuf
,smb_ntcreate_CreateOptions
, 0x0);
1108 SIVAL(cli
->outbuf
,smb_ntcreate_ImpersonationLevel
, 0x02);
1109 SSVAL(cli
->outbuf
,smb_ntcreate_NameLength
, strlen(fname
));
1111 p
= smb_buf(cli
->outbuf
);
1113 p
= skip_string(p
,1);
1116 if (!cli_receive_smb(cli
)) {
1120 if (CVAL(cli
->inbuf
,smb_rcls
) != 0) {
1124 return SVAL(cli
->inbuf
,smb_vwv2
+ 1);
1128 /****************************************************************************
1130 ****************************************************************************/
1131 int cli_open(struct cli_state
*cli
, char *fname
, int flags
, int share_mode
)
1135 unsigned accessmode
=0;
1137 /* you must open for RW not just write - otherwise getattrE doesn't
1139 if ((flags
& O_ACCMODE
) == O_WRONLY
&& strncmp(cli
->dev
, "LPT", 3)) {
1140 flags
= (flags
& ~O_ACCMODE
) | O_RDWR
;
1143 if (flags
& O_CREAT
)
1145 if (!(flags
& O_EXCL
)) {
1146 if (flags
& O_TRUNC
)
1152 accessmode
= (share_mode
<<4);
1154 if ((flags
& O_ACCMODE
) == O_RDWR
) {
1156 } else if ((flags
& O_ACCMODE
) == O_WRONLY
) {
1161 if ((flags
& O_SYNC
) == O_SYNC
) {
1162 accessmode
|= (1<<14);
1166 memset(cli
->outbuf
,'\0',smb_size
);
1167 memset(cli
->inbuf
,'\0',smb_size
);
1169 set_message(cli
->outbuf
,15,1 + strlen(fname
),True
);
1171 CVAL(cli
->outbuf
,smb_com
) = SMBopenX
;
1172 SSVAL(cli
->outbuf
,smb_tid
,cli
->cnum
);
1173 cli_setup_packet(cli
);
1175 SSVAL(cli
->outbuf
,smb_vwv0
,0xFF);
1176 SSVAL(cli
->outbuf
,smb_vwv2
,0); /* no additional info */
1177 SSVAL(cli
->outbuf
,smb_vwv3
,accessmode
);
1178 SSVAL(cli
->outbuf
,smb_vwv4
,aSYSTEM
| aHIDDEN
);
1179 SSVAL(cli
->outbuf
,smb_vwv5
,0);
1180 SSVAL(cli
->outbuf
,smb_vwv8
,openfn
);
1182 p
= smb_buf(cli
->outbuf
);
1184 p
= skip_string(p
,1);
1187 if (!cli_receive_smb(cli
)) {
1191 if (CVAL(cli
->inbuf
,smb_rcls
) != 0) {
1195 return SVAL(cli
->inbuf
,smb_vwv2
);
1201 /****************************************************************************
1203 ****************************************************************************/
1204 BOOL
cli_close(struct cli_state
*cli
, int fnum
)
1206 memset(cli
->outbuf
,'\0',smb_size
);
1207 memset(cli
->inbuf
,'\0',smb_size
);
1209 set_message(cli
->outbuf
,3,0,True
);
1211 CVAL(cli
->outbuf
,smb_com
) = SMBclose
;
1212 SSVAL(cli
->outbuf
,smb_tid
,cli
->cnum
);
1213 cli_setup_packet(cli
);
1215 SSVAL(cli
->outbuf
,smb_vwv0
,fnum
);
1216 SIVALS(cli
->outbuf
,smb_vwv1
,-1);
1219 if (!cli_receive_smb(cli
)) {
1223 if (CVAL(cli
->inbuf
,smb_rcls
) != 0) {
1231 /****************************************************************************
1233 ****************************************************************************/
1234 BOOL
cli_lock(struct cli_state
*cli
, int fnum
, uint32 offset
, uint32 len
, int timeout
)
1237 int saved_timeout
= cli
->timeout
;
1239 memset(cli
->outbuf
,'\0',smb_size
);
1240 memset(cli
->inbuf
,'\0', smb_size
);
1242 set_message(cli
->outbuf
,8,10,True
);
1244 CVAL(cli
->outbuf
,smb_com
) = SMBlockingX
;
1245 SSVAL(cli
->outbuf
,smb_tid
,cli
->cnum
);
1246 cli_setup_packet(cli
);
1248 CVAL(cli
->outbuf
,smb_vwv0
) = 0xFF;
1249 SSVAL(cli
->outbuf
,smb_vwv2
,fnum
);
1250 CVAL(cli
->outbuf
,smb_vwv3
) = 0;
1251 SIVALS(cli
->outbuf
, smb_vwv4
, timeout
);
1252 SSVAL(cli
->outbuf
,smb_vwv6
,0);
1253 SSVAL(cli
->outbuf
,smb_vwv7
,1);
1255 p
= smb_buf(cli
->outbuf
);
1256 SSVAL(p
, 0, cli
->pid
);
1257 SIVAL(p
, 2, offset
);
1261 cli
->timeout
= (timeout
== -1) ? 0x7FFFFFFF : timeout
;
1263 if (!cli_receive_smb(cli
)) {
1264 cli
->timeout
= saved_timeout
;
1268 cli
->timeout
= saved_timeout
;
1270 if (CVAL(cli
->inbuf
,smb_rcls
) != 0) {
1277 /****************************************************************************
1279 ****************************************************************************/
1280 BOOL
cli_unlock(struct cli_state
*cli
, int fnum
, uint32 offset
, uint32 len
, int timeout
)
1284 memset(cli
->outbuf
,'\0',smb_size
);
1285 memset(cli
->inbuf
,'\0',smb_size
);
1287 set_message(cli
->outbuf
,8,10,True
);
1289 CVAL(cli
->outbuf
,smb_com
) = SMBlockingX
;
1290 SSVAL(cli
->outbuf
,smb_tid
,cli
->cnum
);
1291 cli_setup_packet(cli
);
1293 CVAL(cli
->outbuf
,smb_vwv0
) = 0xFF;
1294 SSVAL(cli
->outbuf
,smb_vwv2
,fnum
);
1295 CVAL(cli
->outbuf
,smb_vwv3
) = 0;
1296 SIVALS(cli
->outbuf
, smb_vwv4
, timeout
);
1297 SSVAL(cli
->outbuf
,smb_vwv6
,1);
1298 SSVAL(cli
->outbuf
,smb_vwv7
,0);
1300 p
= smb_buf(cli
->outbuf
);
1301 SSVAL(p
, 0, cli
->pid
);
1302 SIVAL(p
, 2, offset
);
1306 if (!cli_receive_smb(cli
)) {
1310 if (CVAL(cli
->inbuf
,smb_rcls
) != 0) {
1319 /****************************************************************************
1320 issue a single SMBread and don't wait for a reply
1321 ****************************************************************************/
1322 static void cli_issue_read(struct cli_state
*cli
, int fnum
, off_t offset
,
1325 memset(cli
->outbuf
,'\0',smb_size
);
1326 memset(cli
->inbuf
,'\0',smb_size
);
1328 set_message(cli
->outbuf
,10,0,True
);
1330 CVAL(cli
->outbuf
,smb_com
) = SMBreadX
;
1331 SSVAL(cli
->outbuf
,smb_tid
,cli
->cnum
);
1332 cli_setup_packet(cli
);
1334 CVAL(cli
->outbuf
,smb_vwv0
) = 0xFF;
1335 SSVAL(cli
->outbuf
,smb_vwv2
,fnum
);
1336 SIVAL(cli
->outbuf
,smb_vwv3
,offset
);
1337 SSVAL(cli
->outbuf
,smb_vwv5
,size
);
1338 SSVAL(cli
->outbuf
,smb_vwv6
,size
);
1339 SSVAL(cli
->outbuf
,smb_mid
,cli
->mid
+ i
);
1344 /****************************************************************************
1346 ****************************************************************************/
1347 size_t cli_read(struct cli_state
*cli
, int fnum
, char *buf
, off_t offset
, size_t size
)
1353 int mpx
= MAX(cli
->max_mux
-1, 1);
1354 int block
= (cli
->max_xmit
- (smb_size
+32)) & ~1023;
1356 int blocks
= (size
+ (block
-1)) / block
;
1358 if (size
== 0) return 0;
1360 while (received
< blocks
) {
1363 while (issued
- received
< mpx
&& issued
< blocks
) {
1364 int size1
= MIN(block
, (int) size
-issued
*block
);
1365 cli_issue_read(cli
, fnum
, offset
+issued
*block
, size1
, issued
);
1369 if (!cli_receive_smb(cli
)) {
1374 mid
= SVAL(cli
->inbuf
, smb_mid
) - cli
->mid
;
1375 size2
= SVAL(cli
->inbuf
, smb_vwv5
);
1377 if (CVAL(cli
->inbuf
,smb_rcls
) != 0) {
1378 blocks
= MIN(blocks
, mid
-1);
1383 blocks
= MIN(blocks
, mid
-1);
1384 /* this distinguishes EOF from an error */
1385 total
= MAX(total
, 0);
1389 if (size2
> block
) {
1390 DEBUG(0,("server returned more than we wanted!\n"));
1393 if (mid
>= issued
) {
1394 DEBUG(0,("invalid mid from server!\n"));
1397 p
= smb_base(cli
->inbuf
) + SVAL(cli
->inbuf
,smb_vwv6
);
1399 memcpy(buf
+mid
*block
, p
, size2
);
1401 total
= MAX(total
, mid
*block
+ size2
);
1404 while (received
< issued
) {
1405 cli_receive_smb(cli
);
1413 /****************************************************************************
1414 issue a single SMBwrite and don't wait for a reply
1415 ****************************************************************************/
1416 static void cli_issue_write(struct cli_state
*cli
, int fnum
, off_t offset
, uint16 mode
, const char *buf
,
1421 memset(cli
->outbuf
,'\0',smb_size
);
1422 memset(cli
->inbuf
,'\0',smb_size
);
1424 set_message(cli
->outbuf
,12,size
,True
);
1426 CVAL(cli
->outbuf
,smb_com
) = SMBwriteX
;
1427 SSVAL(cli
->outbuf
,smb_tid
,cli
->cnum
);
1428 cli_setup_packet(cli
);
1430 CVAL(cli
->outbuf
,smb_vwv0
) = 0xFF;
1431 SSVAL(cli
->outbuf
,smb_vwv2
,fnum
);
1433 SIVAL(cli
->outbuf
,smb_vwv3
,offset
);
1434 SIVAL(cli
->outbuf
,smb_vwv5
,IS_BITS_SET_ALL(mode
, 0x0008) ? 0xFFFFFFFF : 0);
1435 SSVAL(cli
->outbuf
,smb_vwv7
,mode
);
1437 SSVAL(cli
->outbuf
,smb_vwv8
,IS_BITS_SET_ALL(mode
, 0x0008) ? size
: 0);
1438 SSVAL(cli
->outbuf
,smb_vwv10
,size
);
1439 SSVAL(cli
->outbuf
,smb_vwv11
,
1440 smb_buf(cli
->outbuf
) - smb_base(cli
->outbuf
));
1442 p
= smb_base(cli
->outbuf
) + SVAL(cli
->outbuf
,smb_vwv11
);
1443 memcpy(p
, buf
, size
);
1445 SSVAL(cli
->outbuf
,smb_mid
,cli
->mid
+ i
);
1447 show_msg(cli
->outbuf
);
1451 /****************************************************************************
1453 write_mode: 0x0001 disallow write cacheing
1454 0x0002 return bytes remaining
1455 0x0004 use raw named pipe protocol
1456 0x0008 start of message mode named pipe protocol
1457 ****************************************************************************/
1458 ssize_t
cli_write(struct cli_state
*cli
,
1459 int fnum
, uint16 write_mode
,
1460 const char *buf
, off_t offset
, size_t size
)
1465 int mpx
= MAX(cli
->max_mux
-1, 1);
1466 int block
= (cli
->max_xmit
- (smb_size
+32)) & ~1023;
1467 int blocks
= (size
+ (block
-1)) / block
;
1469 while (received
< blocks
) {
1471 while ((issued
- received
< mpx
) && (issued
< blocks
))
1473 int bsent
= issued
* block
;
1474 int size1
= MIN(block
, (int) size
- bsent
);
1476 cli_issue_write(cli
, fnum
, offset
+ bsent
,
1483 if (!cli_receive_smb(cli
))
1490 if (CVAL(cli
->inbuf
,smb_rcls
) != 0)
1495 bwritten
+= SVAL(cli
->inbuf
, smb_vwv2
);
1498 while (received
< issued
&& cli_receive_smb(cli
))
1507 /****************************************************************************
1508 write to a file using a SMBwrite and not bypassing 0 byte writes
1509 ****************************************************************************/
1510 ssize_t
cli_smbwrite(struct cli_state
*cli
,
1511 int fnum
, const char *buf
, off_t offset
, size_t size
)
1515 memset(cli
->outbuf
,'\0',smb_size
);
1516 memset(cli
->inbuf
,'\0',smb_size
);
1518 set_message(cli
->outbuf
,5, 3 + size
,True
);
1520 CVAL(cli
->outbuf
,smb_com
) = SMBwrite
;
1521 SSVAL(cli
->outbuf
,smb_tid
,cli
->cnum
);
1522 cli_setup_packet(cli
);
1524 SSVAL(cli
->outbuf
,smb_vwv0
,fnum
);
1525 SSVAL(cli
->outbuf
,smb_vwv1
,size
);
1526 SIVAL(cli
->outbuf
,smb_vwv2
,offset
);
1527 SSVAL(cli
->outbuf
,smb_vwv4
,0);
1529 p
= smb_buf(cli
->outbuf
);
1532 memcpy(p
+2, buf
, size
);
1535 if (!cli_receive_smb(cli
)) {
1539 if (CVAL(cli
->inbuf
,smb_rcls
) != 0) {
1543 return SVAL(cli
->inbuf
,smb_vwv0
);
1547 /****************************************************************************
1548 do a SMBgetattrE call
1549 ****************************************************************************/
1550 BOOL
cli_getattrE(struct cli_state
*cli
, int fd
,
1551 uint16
*attr
, size_t *size
,
1552 time_t *c_time
, time_t *a_time
, time_t *m_time
)
1554 memset(cli
->outbuf
,'\0',smb_size
);
1555 memset(cli
->inbuf
,'\0',smb_size
);
1557 set_message(cli
->outbuf
,2,0,True
);
1559 CVAL(cli
->outbuf
,smb_com
) = SMBgetattrE
;
1560 SSVAL(cli
->outbuf
,smb_tid
,cli
->cnum
);
1561 cli_setup_packet(cli
);
1563 SSVAL(cli
->outbuf
,smb_vwv0
,fd
);
1566 if (!cli_receive_smb(cli
)) {
1570 if (CVAL(cli
->inbuf
,smb_rcls
) != 0) {
1575 *size
= IVAL(cli
->inbuf
, smb_vwv6
);
1579 *attr
= SVAL(cli
->inbuf
,smb_vwv10
);
1583 *c_time
= make_unix_date3(cli
->inbuf
+smb_vwv0
);
1587 *a_time
= make_unix_date3(cli
->inbuf
+smb_vwv2
);
1591 *m_time
= make_unix_date3(cli
->inbuf
+smb_vwv4
);
1598 /****************************************************************************
1600 ****************************************************************************/
1601 BOOL
cli_getatr(struct cli_state
*cli
, char *fname
,
1602 uint16
*attr
, size_t *size
, time_t *t
)
1606 memset(cli
->outbuf
,'\0',smb_size
);
1607 memset(cli
->inbuf
,'\0',smb_size
);
1609 set_message(cli
->outbuf
,0,strlen(fname
)+2,True
);
1611 CVAL(cli
->outbuf
,smb_com
) = SMBgetatr
;
1612 SSVAL(cli
->outbuf
,smb_tid
,cli
->cnum
);
1613 cli_setup_packet(cli
);
1615 p
= smb_buf(cli
->outbuf
);
1617 pstrcpy(p
+1, fname
);
1620 if (!cli_receive_smb(cli
)) {
1624 if (CVAL(cli
->inbuf
,smb_rcls
) != 0) {
1629 *size
= IVAL(cli
->inbuf
, smb_vwv3
);
1633 *t
= make_unix_date3(cli
->inbuf
+smb_vwv1
);
1637 *attr
= SVAL(cli
->inbuf
,smb_vwv0
);
1645 /****************************************************************************
1647 ****************************************************************************/
1648 BOOL
cli_setatr(struct cli_state
*cli
, char *fname
, uint16 attr
, time_t t
)
1652 memset(cli
->outbuf
,'\0',smb_size
);
1653 memset(cli
->inbuf
,'\0',smb_size
);
1655 set_message(cli
->outbuf
,8,strlen(fname
)+4,True
);
1657 CVAL(cli
->outbuf
,smb_com
) = SMBsetatr
;
1658 SSVAL(cli
->outbuf
,smb_tid
,cli
->cnum
);
1659 cli_setup_packet(cli
);
1661 SSVAL(cli
->outbuf
,smb_vwv0
, attr
);
1662 put_dos_date3(cli
->outbuf
,smb_vwv1
, t
);
1664 p
= smb_buf(cli
->outbuf
);
1666 pstrcpy(p
+1, fname
);
1667 p
= skip_string(p
,1);
1671 if (!cli_receive_smb(cli
)) {
1675 if (CVAL(cli
->inbuf
,smb_rcls
) != 0) {
1683 /****************************************************************************
1684 send a qpathinfo call
1685 ****************************************************************************/
1686 BOOL
cli_qpathinfo(struct cli_state
*cli
, const char *fname
,
1687 time_t *c_time
, time_t *a_time
, time_t *m_time
,
1688 size_t *size
, uint16
*mode
)
1692 uint16 setup
= TRANSACT2_QPATHINFO
;
1694 char *rparam
=NULL
, *rdata
=NULL
;
1697 time_t (*date_fn
)(void *);
1699 param_len
= strlen(fname
) + 7;
1701 memset(param
, 0, param_len
);
1702 SSVAL(param
, 0, SMB_INFO_STANDARD
);
1703 pstrcpy(¶m
[6], fname
);
1706 ret
= (cli_send_trans(cli
, SMBtrans2
,
1707 NULL
, 0, /* Name, length */
1708 -1, 0, /* fid, flags */
1709 &setup
, 1, 0, /* setup, length, max */
1710 param
, param_len
, 10, /* param, length, max */
1711 NULL
, data_len
, cli
->max_xmit
/* data, length, max */
1713 cli_receive_trans(cli
, SMBtrans2
,
1714 &rparam
, ¶m_len
,
1715 &rdata
, &data_len
));
1717 /* we need to work around a Win95 bug - sometimes
1718 it gives ERRSRV/ERRerror temprarily */
1721 cli_error(cli
, &eclass
, &ecode
, NULL
);
1722 if (eclass
!= ERRSRV
|| ecode
!= ERRerror
) break;
1725 } while (count
-- && ret
==False
);
1727 if (!ret
|| !rdata
|| data_len
< 22) {
1732 date_fn
= make_unix_date
;
1734 date_fn
= make_unix_date2
;
1738 *c_time
= date_fn(rdata
+0);
1741 *a_time
= date_fn(rdata
+4);
1744 *m_time
= date_fn(rdata
+8);
1747 *size
= IVAL(rdata
, 12);
1750 *mode
= SVAL(rdata
,l1_attrFile
);
1753 if (rdata
) free(rdata
);
1754 if (rparam
) free(rparam
);
1758 /****************************************************************************
1759 send a qpathinfo call with the SMB_QUERY_FILE_ALL_INFO info level
1760 ****************************************************************************/
1761 BOOL
cli_qpathinfo2(struct cli_state
*cli
, const char *fname
,
1762 time_t *c_time
, time_t *a_time
, time_t *m_time
,
1763 time_t *w_time
, size_t *size
, uint16
*mode
,
1768 uint16 setup
= TRANSACT2_QPATHINFO
;
1770 char *rparam
=NULL
, *rdata
=NULL
;
1772 param_len
= strlen(fname
) + 7;
1774 memset(param
, 0, param_len
);
1775 SSVAL(param
, 0, SMB_QUERY_FILE_ALL_INFO
);
1776 pstrcpy(¶m
[6], fname
);
1778 if (!cli_send_trans(cli
, SMBtrans2
,
1779 NULL
, 0, /* name, length */
1780 -1, 0, /* fid, flags */
1781 &setup
, 1, 0, /* setup, length, max */
1782 param
, param_len
, 10, /* param, length, max */
1783 NULL
, data_len
, cli
->max_xmit
/* data, length, max */
1788 if (!cli_receive_trans(cli
, SMBtrans2
,
1789 &rparam
, ¶m_len
,
1790 &rdata
, &data_len
)) {
1794 if (!rdata
|| data_len
< 22) {
1799 *c_time
= interpret_long_date(rdata
+0) - cli
->serverzone
;
1802 *a_time
= interpret_long_date(rdata
+8) - cli
->serverzone
;
1805 *m_time
= interpret_long_date(rdata
+16) - cli
->serverzone
;
1808 *w_time
= interpret_long_date(rdata
+24) - cli
->serverzone
;
1811 *mode
= SVAL(rdata
, 32);
1814 *size
= IVAL(rdata
, 48);
1817 *ino
= IVAL(rdata
, 64);
1820 if (rdata
) free(rdata
);
1821 if (rparam
) free(rparam
);
1826 /****************************************************************************
1827 send a qfileinfo call
1828 ****************************************************************************/
1829 BOOL
cli_qfileinfo(struct cli_state
*cli
, int fnum
,
1830 uint16
*mode
, size_t *size
,
1831 time_t *c_time
, time_t *a_time
, time_t *m_time
,
1832 time_t *w_time
, SMB_INO_T
*ino
)
1836 uint16 setup
= TRANSACT2_QFILEINFO
;
1838 char *rparam
=NULL
, *rdata
=NULL
;
1840 /* if its a win95 server then fail this - win95 totally screws it
1842 if (cli
->win95
) return False
;
1846 memset(param
, 0, param_len
);
1847 SSVAL(param
, 0, fnum
);
1848 SSVAL(param
, 2, SMB_QUERY_FILE_ALL_INFO
);
1850 if (!cli_send_trans(cli
, SMBtrans2
,
1851 NULL
, 0, /* name, length */
1852 -1, 0, /* fid, flags */
1853 &setup
, 1, 0, /* setup, length, max */
1854 param
, param_len
, 2, /* param, length, max */
1855 NULL
, data_len
, cli
->max_xmit
/* data, length, max */
1860 if (!cli_receive_trans(cli
, SMBtrans2
,
1861 &rparam
, ¶m_len
,
1862 &rdata
, &data_len
)) {
1866 if (!rdata
|| data_len
< 68) {
1871 *c_time
= interpret_long_date(rdata
+0) - cli
->serverzone
;
1874 *a_time
= interpret_long_date(rdata
+8) - cli
->serverzone
;
1877 *m_time
= interpret_long_date(rdata
+16) - cli
->serverzone
;
1880 *w_time
= interpret_long_date(rdata
+24) - cli
->serverzone
;
1883 *mode
= SVAL(rdata
, 32);
1886 *size
= IVAL(rdata
, 48);
1889 *ino
= IVAL(rdata
, 64);
1892 if (rdata
) free(rdata
);
1893 if (rparam
) free(rparam
);
1898 /****************************************************************************
1899 interpret a long filename structure - this is mostly guesses at the moment
1900 The length of the structure is returned
1901 The structure of a long filename depends on the info level. 260 is used
1902 by NT and 2 is used by OS/2
1903 ****************************************************************************/
1904 static int interpret_long_filename(int level
,char *p
,file_info
*finfo
)
1906 extern file_info
const def_finfo
;
1909 memcpy(finfo
,&def_finfo
,sizeof(*finfo
));
1913 case 1: /* OS/2 understands this */
1915 /* these dates are converted to GMT by make_unix_date */
1916 finfo
->ctime
= make_unix_date2(p
+4);
1917 finfo
->atime
= make_unix_date2(p
+8);
1918 finfo
->mtime
= make_unix_date2(p
+12);
1919 finfo
->size
= IVAL(p
,16);
1920 finfo
->mode
= CVAL(p
,24);
1921 pstrcpy(finfo
->name
,p
+27);
1923 return(28 + CVAL(p
,26));
1925 case 2: /* this is what OS/2 uses mostly */
1927 /* these dates are converted to GMT by make_unix_date */
1928 finfo
->ctime
= make_unix_date2(p
+4);
1929 finfo
->atime
= make_unix_date2(p
+8);
1930 finfo
->mtime
= make_unix_date2(p
+12);
1931 finfo
->size
= IVAL(p
,16);
1932 finfo
->mode
= CVAL(p
,24);
1933 pstrcpy(finfo
->name
,p
+31);
1935 return(32 + CVAL(p
,30));
1937 /* levels 3 and 4 are untested */
1940 /* these dates are probably like the other ones */
1941 finfo
->ctime
= make_unix_date2(p
+8);
1942 finfo
->atime
= make_unix_date2(p
+12);
1943 finfo
->mtime
= make_unix_date2(p
+16);
1944 finfo
->size
= IVAL(p
,20);
1945 finfo
->mode
= CVAL(p
,28);
1946 pstrcpy(finfo
->name
,p
+33);
1948 return(SVAL(p
,4)+4);
1952 /* these dates are probably like the other ones */
1953 finfo
->ctime
= make_unix_date2(p
+8);
1954 finfo
->atime
= make_unix_date2(p
+12);
1955 finfo
->mtime
= make_unix_date2(p
+16);
1956 finfo
->size
= IVAL(p
,20);
1957 finfo
->mode
= CVAL(p
,28);
1958 pstrcpy(finfo
->name
,p
+37);
1960 return(SVAL(p
,4)+4);
1962 case 260: /* NT uses this, but also accepts 2 */
1964 int ret
= SVAL(p
,0);
1966 p
+= 4; /* next entry offset */
1967 p
+= 4; /* fileindex */
1969 /* these dates appear to arrive in a
1970 weird way. It seems to be localtime
1971 plus the serverzone given in the
1972 initial connect. This is GMT when
1973 DST is not in effect and one hour
1974 from GMT otherwise. Can this really
1977 I suppose this could be called
1978 kludge-GMT. Is is the GMT you get
1979 by using the current DST setting on
1980 a different localtime. It will be
1981 cheap to calculate, I suppose, as
1982 no DST tables will be needed */
1984 finfo
->ctime
= interpret_long_date(p
); p
+= 8;
1985 finfo
->atime
= interpret_long_date(p
); p
+= 8;
1986 finfo
->mtime
= interpret_long_date(p
); p
+= 8; p
+= 8;
1987 finfo
->size
= IVAL(p
,0); p
+= 8;
1988 p
+= 8; /* alloc size */
1989 finfo
->mode
= CVAL(p
,0); p
+= 4;
1990 namelen
= IVAL(p
,0); p
+= 4;
1991 p
+= 4; /* EA size */
1992 p
+= 2; /* short name len? */
1993 p
+= 24; /* short name? */
1994 StrnCpy(finfo
->name
,p
,namelen
);
2000 DEBUG(1,("Unknown long filename format %d\n",level
));
2005 /****************************************************************************
2006 do a directory listing, calling fn on each file found
2007 ****************************************************************************/
2008 int cli_list(struct cli_state
*cli
,const char *Mask
,uint16 attribute
,
2009 void (*fn
)(file_info
*, const char *, void *), void *state
)
2011 int max_matches
= 512;
2012 /* NT uses 260, OS/2 uses 2. Both accept 1. */
2013 int info_level
= cli
->protocol
<PROTOCOL_NT1
?1:260;
2018 char *dirlist
= NULL
;
2019 int dirlist_len
= 0;
2020 int total_received
= -1;
2022 int ff_resume_key
= 0;
2023 int ff_searchcount
=0;
2026 int ff_dir_handle
=0;
2028 char *rparam
=NULL
, *rdata
=NULL
;
2029 int param_len
, data_len
;
2036 while (ff_eos
== 0) {
2038 if (loop_count
> 200) {
2039 DEBUG(0,("Error: Looping in FIND_NEXT??\n"));
2043 param_len
= 12+strlen(mask
)+1;
2046 setup
= TRANSACT2_FINDFIRST
;
2047 SSVAL(param
,0,attribute
); /* attribute */
2048 SSVAL(param
,2,max_matches
); /* max count */
2049 SSVAL(param
,4,8+4+2); /* resume required + close on end + continue */
2050 SSVAL(param
,6,info_level
);
2052 pstrcpy(param
+12,mask
);
2054 setup
= TRANSACT2_FINDNEXT
;
2055 SSVAL(param
,0,ff_dir_handle
);
2056 SSVAL(param
,2,max_matches
); /* max count */
2057 SSVAL(param
,4,info_level
);
2058 SIVAL(param
,6,ff_resume_key
); /* ff_resume_key */
2059 SSVAL(param
,10,8+4+2); /* resume required + close on end + continue */
2060 pstrcpy(param
+12,mask
);
2062 DEBUG(5,("hand=0x%X resume=%d ff_lastname=%d mask=%s\n",
2063 ff_dir_handle
,ff_resume_key
,ff_lastname
,mask
));
2066 if (!cli_send_trans(cli
, SMBtrans2
,
2067 NULL
, 0, /* Name, length */
2068 -1, 0, /* fid, flags */
2069 &setup
, 1, 0, /* setup, length, max */
2070 param
, param_len
, 10, /* param, length, max */
2072 cli
->max_xmit
/* data, length, max */
2077 if (!cli_receive_trans(cli
, SMBtrans2
,
2078 &rparam
, ¶m_len
,
2079 &rdata
, &data_len
)) {
2080 /* we need to work around a Win95 bug - sometimes
2081 it gives ERRSRV/ERRerror temprarily */
2084 cli_error(cli
, &eclass
, &ecode
, NULL
);
2085 if (eclass
!= ERRSRV
|| ecode
!= ERRerror
) break;
2090 if (total_received
== -1) total_received
= 0;
2092 /* parse out some important return info */
2095 ff_dir_handle
= SVAL(p
,0);
2096 ff_searchcount
= SVAL(p
,2);
2098 ff_lastname
= SVAL(p
,8);
2100 ff_searchcount
= SVAL(p
,0);
2102 ff_lastname
= SVAL(p
,6);
2105 if (ff_searchcount
== 0)
2108 /* point to the data bytes */
2111 /* we might need the lastname for continuations */
2112 if (ff_lastname
> 0) {
2117 StrnCpy(mask
,p
+ff_lastname
,
2118 data_len
-ff_lastname
);
2121 pstrcpy(mask
,p
+ ff_lastname
+ 1);
2129 /* and add them to the dirlist pool */
2130 dirlist
= Realloc(dirlist
,dirlist_len
+ data_len
);
2133 DEBUG(0,("Failed to expand dirlist\n"));
2137 /* put in a length for the last entry, to ensure we can chain entries
2138 into the next packet */
2139 for (p2
=p
,i
=0;i
<(ff_searchcount
-1);i
++)
2140 p2
+= interpret_long_filename(info_level
,p2
,NULL
);
2141 SSVAL(p2
,0,data_len
- PTR_DIFF(p2
,p
));
2143 /* grab the data for later use */
2144 memcpy(dirlist
+dirlist_len
,p
,data_len
);
2145 dirlist_len
+= data_len
;
2147 total_received
+= ff_searchcount
;
2149 if (rdata
) free(rdata
); rdata
= NULL
;
2150 if (rparam
) free(rparam
); rparam
= NULL
;
2152 DEBUG(3,("received %d entries (eos=%d resume=%d)\n",
2153 ff_searchcount
,ff_eos
,ff_resume_key
));
2158 for (p
=dirlist
,i
=0;i
<total_received
;i
++) {
2159 p
+= interpret_long_filename(info_level
,p
,&finfo
);
2160 fn(&finfo
, Mask
, state
);
2163 /* free up the dirlist buffer */
2164 if (dirlist
) free(dirlist
);
2165 return(total_received
);
2169 /****************************************************************************
2170 send a negprot command
2171 ****************************************************************************/
2172 BOOL
cli_negprot(struct cli_state
*cli
)
2178 memset(cli
->outbuf
,'\0',smb_size
);
2180 /* setup the protocol strings */
2181 for (plength
=0,numprots
=0;
2182 prots
[numprots
].name
&& prots
[numprots
].prot
<=cli
->protocol
;
2184 plength
+= strlen(prots
[numprots
].name
)+2;
2186 set_message(cli
->outbuf
,0,plength
,True
);
2188 p
= smb_buf(cli
->outbuf
);
2190 prots
[numprots
].name
&& prots
[numprots
].prot
<=cli
->protocol
;
2193 pstrcpy(p
,prots
[numprots
].name
);
2197 CVAL(cli
->outbuf
,smb_com
) = SMBnegprot
;
2198 cli_setup_packet(cli
);
2200 CVAL(smb_buf(cli
->outbuf
),0) = 2;
2203 if (!cli_receive_smb(cli
))
2206 show_msg(cli
->inbuf
);
2208 if (CVAL(cli
->inbuf
,smb_rcls
) != 0 ||
2209 ((int)SVAL(cli
->inbuf
,smb_vwv0
) >= numprots
)) {
2213 cli
->protocol
= prots
[SVAL(cli
->inbuf
,smb_vwv0
)].prot
;
2216 if (cli
->protocol
>= PROTOCOL_NT1
) {
2218 cli
->sec_mode
= CVAL(cli
->inbuf
,smb_vwv1
);
2219 cli
->max_mux
= SVAL(cli
->inbuf
, smb_vwv1
+1);
2220 cli
->max_xmit
= IVAL(cli
->inbuf
,smb_vwv3
+1);
2221 cli
->sesskey
= IVAL(cli
->inbuf
,smb_vwv7
+1);
2222 cli
->serverzone
= SVALS(cli
->inbuf
,smb_vwv15
+1)*60;
2223 /* this time arrives in real GMT */
2224 cli
->servertime
= interpret_long_date(cli
->inbuf
+smb_vwv11
+1);
2225 memcpy(cli
->cryptkey
,smb_buf(cli
->inbuf
),8);
2226 cli
->capabilities
= IVAL(cli
->inbuf
,smb_vwv9
+1);
2227 if (cli
->capabilities
& 1) {
2228 cli
->readbraw_supported
= True
;
2229 cli
->writebraw_supported
= True
;
2231 } else if (cli
->protocol
>= PROTOCOL_LANMAN1
) {
2232 cli
->sec_mode
= SVAL(cli
->inbuf
,smb_vwv1
);
2233 cli
->max_xmit
= SVAL(cli
->inbuf
,smb_vwv2
);
2234 cli
->sesskey
= IVAL(cli
->inbuf
,smb_vwv6
);
2235 cli
->serverzone
= SVALS(cli
->inbuf
,smb_vwv10
)*60;
2236 /* this time is converted to GMT by make_unix_date */
2237 cli
->servertime
= make_unix_date(cli
->inbuf
+smb_vwv8
);
2238 cli
->readbraw_supported
= ((SVAL(cli
->inbuf
,smb_vwv5
) & 0x1) != 0);
2239 cli
->writebraw_supported
= ((SVAL(cli
->inbuf
,smb_vwv5
) & 0x2) != 0);
2240 memcpy(cli
->cryptkey
,smb_buf(cli
->inbuf
),8);
2242 /* the old core protocol */
2244 cli
->serverzone
= TimeDiff(time(NULL
));
2247 cli
->max_xmit
= MIN(cli
->max_xmit
, CLI_BUFFER_SIZE
);
2253 /****************************************************************************
2254 send a session request. see rfc1002.txt 4.3 and 4.3.2
2255 ****************************************************************************/
2256 BOOL
cli_session_request(struct cli_state
*cli
,
2257 struct nmb_name
*calling
, struct nmb_name
*called
)
2261 /* send a session request (RFC 1002) */
2263 memcpy(&(cli
->calling
), calling
, sizeof(*calling
));
2264 memcpy(&(cli
->called
), called
, sizeof(*called
));
2266 /* put in the destination name */
2267 p
= cli
->outbuf
+len
;
2268 name_mangle(cli
->called
.name
, p
, cli
->called
.name_type
);
2272 p
= cli
->outbuf
+len
;
2273 name_mangle(cli
->calling
.name
, p
, cli
->calling
.name_type
);
2276 /* setup the packet length */
2277 _smb_setlen(cli
->outbuf
,len
);
2278 CVAL(cli
->outbuf
,0) = 0x81;
2282 #endif /* WITH_SSL */
2285 DEBUG(5,("Sent session request\n"));
2287 if (!cli_receive_smb(cli
))
2290 if (CVAL(cli
->inbuf
,0) == 0x84) {
2291 /* C. Hoch 9/14/95 Start */
2292 /* For information, here is the response structure.
2293 * We do the byte-twiddling to for portability.
2294 struct RetargetResponse{
2296 unsigned char flags;
2302 int port
= (CVAL(cli
->inbuf
,8)<<8)+CVAL(cli
->inbuf
,9);
2303 /* SESSION RETARGET */
2304 putip((char *)&cli
->dest_ip
,cli
->inbuf
+4);
2307 cli
->fd
= open_socket_out(SOCK_STREAM
, &cli
->dest_ip
, port
, LONG_CONNECT_TIMEOUT
);
2311 DEBUG(3,("Retargeted\n"));
2313 set_socket_options(cli
->fd
,user_socket_options
);
2316 return cli_session_request(cli
, calling
, called
);
2317 } /* C. Hoch 9/14/95 End */
2320 if (CVAL(cli
->inbuf
,0) == 0x83 && CVAL(cli
->inbuf
,4) == 0x8e){ /* use ssl */
2321 if (!sslutil_fd_is_ssl(cli
->fd
)){
2322 if (sslutil_connect(cli
->fd
) == 0)
2326 #endif /* WITH_SSL */
2328 if (CVAL(cli
->inbuf
,0) != 0x82) {
2329 /* This is the wrong place to put the error... JRA. */
2330 cli
->rap_error
= CVAL(cli
->inbuf
,0);
2337 /****************************************************************************
2338 open the client sockets
2339 ****************************************************************************/
2340 BOOL
cli_connect(struct cli_state
*cli
, const char *host
, struct in_addr
*ip
)
2342 extern struct in_addr ipzero
;
2344 fstrcpy(cli
->desthost
, host
);
2346 if (!ip
|| ip_equal(*ip
, ipzero
)) {
2347 if (!resolve_name( cli
->desthost
, &cli
->dest_ip
, 0x20)) {
2350 if (ip
) *ip
= cli
->dest_ip
;
2355 if (cli
-> port
== 0) cli
-> port
= 139; /* Set to default */
2357 cli
->fd
= open_socket_out(SOCK_STREAM
, &cli
->dest_ip
,
2358 cli
-> port
, cli
->timeout
);
2366 /****************************************************************************
2367 initialise a client structure
2368 ****************************************************************************/
2369 struct cli_state
*cli_initialise(struct cli_state
*cli
)
2372 cli
= (struct cli_state
*)malloc(sizeof(*cli
));
2378 if (cli
->initialised
) {
2387 cli
->pid
= (uint16
)getpid();
2389 cli
->vuid
= UID_FIELD_INVALID
;
2390 cli
->protocol
= PROTOCOL_NT1
;
2391 cli
->timeout
= 20000; /* Timeout is in milliseconds. */
2392 cli
->bufsize
= CLI_BUFFER_SIZE
+4;
2393 cli
->max_xmit
= cli
->bufsize
;
2394 cli
->outbuf
= (char *)malloc(cli
->bufsize
);
2395 cli
->inbuf
= (char *)malloc(cli
->bufsize
);
2396 if (!cli
->outbuf
|| !cli
->inbuf
)
2401 cli
->initialised
= 1;
2406 /****************************************************************************
2407 shutdown a client structure
2408 ****************************************************************************/
2409 void cli_shutdown(struct cli_state
*cli
)
2421 sslutil_disconnect(cli
->fd
);
2422 #endif /* WITH_SSL */
2425 memset(cli
, 0, sizeof(*cli
));
2429 /****************************************************************************
2430 return error codes for the last packet
2431 returns 0 if there was no error and the best approx of a unix errno
2434 for 32 bit "warnings", a return code of 0 is expected.
2436 ****************************************************************************/
2437 int cli_error(struct cli_state
*cli
, uint8
*eclass
, uint32
*num
, uint32
*nt_rpc_error
)
2439 int flgs2
= SVAL(cli
->inbuf
,smb_flg2
);
2443 if (eclass
) *eclass
= 0;
2445 if (nt_rpc_error
) *nt_rpc_error
= cli
->nt_error
;
2447 if (flgs2
& FLAGS2_32_BIT_ERROR_CODES
) {
2448 /* 32 bit error codes detected */
2449 uint32 nt_err
= IVAL(cli
->inbuf
,smb_rcls
);
2450 if (num
) *num
= nt_err
;
2451 DEBUG(10,("cli_error: 32 bit codes: code=%08x\n", nt_err
));
2452 if (!IS_BITS_SET_ALL(nt_err
, 0xc0000000)) return 0;
2454 switch (nt_err
& 0xFFFFFF) {
2455 case NT_STATUS_ACCESS_VIOLATION
: return EACCES
;
2456 case NT_STATUS_NO_SUCH_FILE
: return ENOENT
;
2457 case NT_STATUS_NO_SUCH_DEVICE
: return ENODEV
;
2458 case NT_STATUS_INVALID_HANDLE
: return EBADF
;
2459 case NT_STATUS_NO_MEMORY
: return ENOMEM
;
2460 case NT_STATUS_ACCESS_DENIED
: return EACCES
;
2461 case NT_STATUS_OBJECT_NAME_NOT_FOUND
: return ENOENT
;
2462 case NT_STATUS_SHARING_VIOLATION
: return EBUSY
;
2463 case NT_STATUS_OBJECT_PATH_INVALID
: return ENOTDIR
;
2464 case NT_STATUS_OBJECT_NAME_COLLISION
: return EEXIST
;
2467 /* for all other cases - a default code */
2471 rcls
= CVAL(cli
->inbuf
,smb_rcls
);
2472 code
= SVAL(cli
->inbuf
,smb_err
);
2473 if (rcls
== 0) return 0;
2475 if (eclass
) *eclass
= rcls
;
2476 if (num
) *num
= code
;
2478 if (rcls
== ERRDOS
) {
2480 case ERRbadfile
: return ENOENT
;
2481 case ERRbadpath
: return ENOTDIR
;
2482 case ERRnoaccess
: return EACCES
;
2483 case ERRfilexists
: return EEXIST
;
2484 case ERRrename
: return EEXIST
;
2485 case ERRbadshare
: return EBUSY
;
2486 case ERRlock
: return EBUSY
;
2489 if (rcls
== ERRSRV
) {
2491 case ERRbadpw
: return EPERM
;
2492 case ERRaccess
: return EACCES
;
2493 case ERRnoresource
: return ENOMEM
;
2494 case ERRinvdevice
: return ENODEV
;
2495 case ERRinvnetname
: return ENODEV
;
2498 /* for other cases */
2502 /****************************************************************************
2503 set socket options on a open connection
2504 ****************************************************************************/
2505 void cli_sockopt(struct cli_state
*cli
, char *options
)
2507 set_socket_options(cli
->fd
, options
);
2510 /****************************************************************************
2511 set the PID to use for smb messages. Return the old pid.
2512 ****************************************************************************/
2513 uint16
cli_setpid(struct cli_state
*cli
, uint16 pid
)
2515 uint16 ret
= cli
->pid
;
2520 /****************************************************************************
2521 re-establishes a connection
2522 ****************************************************************************/
2523 BOOL
cli_reestablish_connection(struct cli_state
*cli
)
2525 struct nmb_name calling
;
2526 struct nmb_name called
;
2530 BOOL do_tcon
= False
;
2531 int oldfd
= cli
->fd
;
2533 if (!cli
->initialised
|| cli
->fd
== -1)
2535 DEBUG(3,("cli_reestablish_connection: not connected\n"));
2539 /* copy the parameters necessary to re-establish the connection */
2543 fstrcpy(share
, cli
->share
);
2544 fstrcpy(dev
, cli
->dev
);
2548 memcpy(&called
, &(cli
->called
), sizeof(called
));
2549 memcpy(&calling
, &(cli
->calling
), sizeof(calling
));
2550 fstrcpy(dest_host
, cli
->full_dest_host_name
);
2552 DEBUG(5,("cli_reestablish_connection: %s connecting to %s (ip %s) - %s [%s]\n",
2553 nmb_namestr(&calling
), nmb_namestr(&called
),
2554 inet_ntoa(cli
->dest_ip
),
2555 cli
->user_name
, cli
->domain
));
2559 if (cli_establish_connection(cli
,
2560 dest_host
, &cli
->dest_ip
,
2562 share
, dev
, False
, do_tcon
)) {
2563 if (cli
->fd
!= oldfd
) {
2564 if (dup2(cli
->fd
, oldfd
) == oldfd
) {
2573 /****************************************************************************
2574 establishes a connection right up to doing tconX, reading in a password.
2575 ****************************************************************************/
2576 BOOL
cli_establish_connection(struct cli_state
*cli
,
2577 char *dest_host
, struct in_addr
*dest_ip
,
2578 struct nmb_name
*calling
, struct nmb_name
*called
,
2579 char *service
, char *service_type
,
2580 BOOL do_shutdown
, BOOL do_tcon
)
2582 DEBUG(5,("cli_establish_connection: %s connecting to %s (%s) - %s [%s]\n",
2583 nmb_namestr(calling
), nmb_namestr(called
), inet_ntoa(*dest_ip
),
2584 cli
->user_name
, cli
->domain
));
2586 /* establish connection */
2588 if ((!cli
->initialised
))
2595 if (!cli_connect(cli
, dest_host
, dest_ip
))
2597 DEBUG(1,("cli_establish_connection: failed to connect to %s (%s)\n",
2598 nmb_namestr(calling
), inet_ntoa(*dest_ip
)));
2603 if (!cli_session_request(cli
, calling
, called
))
2605 DEBUG(1,("failed session request\n"));
2611 if (!cli_negprot(cli
))
2613 DEBUG(1,("failed negprot\n"));
2619 if (cli
->pwd
.cleartext
|| cli
->pwd
.null_pwd
)
2624 if (cli
->pwd
.null_pwd
)
2626 /* attempt null session */
2632 /* attempt clear-text session */
2633 pwd_get_cleartext(&(cli
->pwd
), passwd
);
2634 pass_len
= strlen(passwd
);
2637 /* attempt clear-text session */
2638 if (!cli_session_setup(cli
, cli
->user_name
,
2643 DEBUG(1,("failed session setup\n"));
2652 if (!cli_send_tconX(cli
, service
, service_type
,
2653 (char*)passwd
, strlen(passwd
)))
2655 DEBUG(1,("failed tcon_X\n"));
2666 /* attempt encrypted session */
2667 unsigned char nt_sess_pwd
[24];
2668 unsigned char lm_sess_pwd
[24];
2670 /* creates (storing a copy of) and then obtains a 24 byte password OWF */
2671 pwd_make_lm_nt_owf(&(cli
->pwd
), cli
->cryptkey
);
2672 pwd_get_lm_nt_owf(&(cli
->pwd
), lm_sess_pwd
, nt_sess_pwd
);
2674 /* attempt encrypted session */
2675 if (!cli_session_setup(cli
, cli
->user_name
,
2676 (char*)lm_sess_pwd
, sizeof(lm_sess_pwd
),
2677 (char*)nt_sess_pwd
, sizeof(nt_sess_pwd
),
2680 DEBUG(1,("failed session setup\n"));
2688 if (!cli_send_tconX(cli
, service
, service_type
,
2689 (char*)nt_sess_pwd
, sizeof(nt_sess_pwd
)))
2691 DEBUG(1,("failed tcon_X\n"));
2706 /****************************************************************************
2707 check for existance of a dir
2708 ****************************************************************************/
2709 BOOL
cli_chkpath(struct cli_state
*cli
, char *path
)
2714 safe_strcpy(path2
,path
,sizeof(pstring
)-1);
2715 trim_string(path2
,NULL
,"\\");
2716 if (!*path2
) *path2
= '\\';
2718 memset(cli
->outbuf
,'\0',smb_size
);
2719 set_message(cli
->outbuf
,0,4 + strlen(path2
),True
);
2720 SCVAL(cli
->outbuf
,smb_com
,SMBchkpth
);
2721 SSVAL(cli
->outbuf
,smb_tid
,cli
->cnum
);
2722 cli_setup_packet(cli
);
2723 p
= smb_buf(cli
->outbuf
);
2725 safe_strcpy(p
,path2
,strlen(path2
));
2728 if (!cli_receive_smb(cli
)) {
2732 if (cli_error(cli
, NULL
, NULL
, NULL
)) return False
;
2738 /****************************************************************************
2739 start a message sequence
2740 ****************************************************************************/
2741 BOOL
cli_message_start(struct cli_state
*cli
, char *host
, char *username
,
2746 /* send a SMBsendstrt command */
2747 memset(cli
->outbuf
,'\0',smb_size
);
2748 set_message(cli
->outbuf
,0,0,True
);
2749 CVAL(cli
->outbuf
,smb_com
) = SMBsendstrt
;
2750 SSVAL(cli
->outbuf
,smb_tid
,cli
->cnum
);
2751 cli_setup_packet(cli
);
2753 p
= smb_buf(cli
->outbuf
);
2755 pstrcpy(p
,username
);
2756 p
= skip_string(p
,1);
2759 p
= skip_string(p
,1);
2761 set_message(cli
->outbuf
,0,PTR_DIFF(p
,smb_buf(cli
->outbuf
)),False
);
2765 if (!cli_receive_smb(cli
)) {
2769 if (cli_error(cli
, NULL
, NULL
, NULL
)) return False
;
2771 *grp
= SVAL(cli
->inbuf
,smb_vwv0
);
2777 /****************************************************************************
2779 ****************************************************************************/
2780 BOOL
cli_message_text(struct cli_state
*cli
, char *msg
, int len
, int grp
)
2784 memset(cli
->outbuf
,'\0',smb_size
);
2785 set_message(cli
->outbuf
,1,len
+3,True
);
2786 CVAL(cli
->outbuf
,smb_com
) = SMBsendtxt
;
2787 SSVAL(cli
->outbuf
,smb_tid
,cli
->cnum
);
2788 cli_setup_packet(cli
);
2790 SSVAL(cli
->outbuf
,smb_vwv0
,grp
);
2792 p
= smb_buf(cli
->outbuf
);
2795 memcpy(p
+3,msg
,len
);
2798 if (!cli_receive_smb(cli
)) {
2802 if (cli_error(cli
, NULL
, NULL
, NULL
)) return False
;
2807 /****************************************************************************
2809 ****************************************************************************/
2810 BOOL
cli_message_end(struct cli_state
*cli
, int grp
)
2812 memset(cli
->outbuf
,'\0',smb_size
);
2813 set_message(cli
->outbuf
,1,0,True
);
2814 CVAL(cli
->outbuf
,smb_com
) = SMBsendend
;
2815 SSVAL(cli
->outbuf
,smb_tid
,cli
->cnum
);
2817 SSVAL(cli
->outbuf
,smb_vwv0
,grp
);
2819 cli_setup_packet(cli
);
2823 if (!cli_receive_smb(cli
)) {
2827 if (cli_error(cli
, NULL
, NULL
, NULL
)) return False
;
2833 #if 0 /* May be useful one day */
2834 /****************************************************************************
2836 ****************************************************************************/
2837 BOOL
cli_dskattr(struct cli_state
*cli
, int *bsize
, int *total
, int *avail
)
2839 memset(cli
->outbuf
,'\0',smb_size
);
2840 set_message(cli
->outbuf
,0,0,True
);
2841 CVAL(cli
->outbuf
,smb_com
) = SMBdskattr
;
2842 SSVAL(cli
->outbuf
,smb_tid
,cli
->cnum
);
2843 cli_setup_packet(cli
);
2846 if (!cli_receive_smb(cli
)) {
2850 *bsize
= SVAL(cli
->inbuf
,smb_vwv1
)*SVAL(cli
->inbuf
,smb_vwv2
);
2851 *total
= SVAL(cli
->inbuf
,smb_vwv0
);
2852 *avail
= SVAL(cli
->inbuf
,smb_vwv3
);