Ticket 1551: Update GPL version from 2 to 3
[midnight-commander.git] / src / vfs / smbfs / helpers / libsmb / clientgen.c
blobcb57a20aa88737879ad029f0e1b7691a1f5cc372
1 /*
2 Unix SMB/Netbios implementation.
3 Version 1.9.
4 SMB client generic functions
6 Copyright (C) Andrew Tridgell 1994-1998
8 Copyright (C) 2011
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/>.
27 #define NO_SYSLOG
29 #include "includes.h"
30 #include "trans2.h"
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)
41 if (port > 0)
42 cli -> port = port;
44 return cli -> port;
47 /****************************************************************************
48 recv an smb
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)
60 size_t len;
61 size_t nwritten=0;
62 ssize_t ret;
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)) {
71 reestablished = True;
72 nwritten=0;
73 continue;
76 if (ret <= 0) {
77 DEBUG(0,("Error writing %d bytes to client. %d. Exiting\n",
78 (int)len,(int)ret));
79 close_sockets();
80 exit(1);
82 nwritten += ret;
85 return True;
88 /*****************************************************
89 RAP error codes - a small start but will be extended.
90 *******************************************************/
92 struct
94 int err;
95 const char *message;
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."},
106 {0, NULL}
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
119 error.
120 *******************************************************/
122 char *cli_errstr(struct cli_state *cli)
124 static fstring error_message;
125 uint8 errclass;
126 uint32 errnum;
127 uint32 nt_rpc_error;
128 int i;
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);
139 if (errclass != 0)
141 return cli_smb_errstr(cli);
145 * Was it an NT error ?
148 if (nt_rpc_error)
150 const char *nt_msg = get_nt_error_msg(nt_rpc_error);
152 if (nt_msg == NULL)
154 slprintf(error_message, sizeof(fstring) - 1, "NT code %d", nt_rpc_error);
156 else
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);
175 break;
179 return error_message;
182 /****************************************************************************
183 setup basics in a outgoing packet
184 ****************************************************************************/
185 static void cli_setup_packet(struct cli_state *cli)
187 cli->rap_error = 0;
188 cli->nt_error = 0;
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);
198 #if 0
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
202 invalid data.
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 */
208 return "";
209 } else {
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));
215 return "<ERROR>";
216 } else {
217 return &rdata[offset];
221 #endif /* 0 */
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,
227 int fid, int flags,
228 uint16 *setup, int lsetup, int msetup,
229 char *param, int lparam, int mparam,
230 char *data, int ldata, int mdata)
232 int i;
233 int this_ldata,this_lparam;
234 int tot_data=0,tot_param=0;
235 char *outdata,*outparam;
236 char *p;
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[] */
268 } else {
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);
280 cli_send_smb(cli);
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) {
286 return(False);
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);
321 cli_send_smb(cli);
323 tot_data += this_ldata;
324 tot_param += this_lparam;
328 return(True);
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)
339 int total_data=0;
340 int total_param=0;
341 int this_data,this_param;
342 uint8 eclass;
343 uint32 ecode;
345 *data_len = *param_len = 0;
347 if (!cli_receive_smb(cli))
348 return False;
350 show_msg(cli->inbuf);
352 /* sanity check */
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)));
357 return(False);
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))
369 return(False);
372 /* parse out the lengths */
373 total_data = SVAL(cli->inbuf,smb_tdrcnt);
374 total_param = SVAL(cli->inbuf,smb_tprcnt);
376 /* allocate it */
377 *data = Realloc(*data,total_data);
378 *param = Realloc(*param,total_param);
380 while (1) {
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"));
387 return False;
390 if (this_data)
391 memcpy(*data + SVAL(cli->inbuf,smb_drdisp),
392 smb_base(cli->inbuf) + SVAL(cli->inbuf,smb_droff),
393 this_data);
394 if (this_param)
395 memcpy(*param + SVAL(cli->inbuf,smb_prdisp),
396 smb_base(cli->inbuf) + SVAL(cli->inbuf,smb_proff),
397 this_param);
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)
406 break;
408 if (!cli_receive_smb(cli))
409 return False;
411 show_msg(cli->inbuf);
413 /* sanity check */
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)));
418 return(False);
420 if (cli_error(cli, &eclass, &ecode, NULL))
422 if(cli->nt_pipe_fnum == 0 || !(eclass == ERRDOS && ecode == ERRmoredata))
423 return(False);
427 return(True);
430 #if 0
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));
455 #endif /*0 */
457 /****************************************************************************
458 call a remote api
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,
475 rparam, rprcnt,
476 rdata, rdrcnt));
479 #if 0
480 /****************************************************************************
481 perform a NetWkstaUserLogon
482 ****************************************************************************/
483 BOOL cli_NetWkstaUserLogon(struct cli_state *cli,char *user, char *workstation)
485 char *rparam = NULL;
486 char *rdata = NULL;
487 char *p;
488 int rdrcnt,rprcnt;
489 pstring param;
491 memset(param, 0, sizeof(param));
493 /* send a SMBtrans command with api NetWkstaUserLogon */
494 p = param;
495 SSVAL(p,0,132); /* api number */
496 p += 2;
497 pstrcpy(p,"OOWb54WrLh");
498 p = skip_string(p,1);
499 pstrcpy(p,"WB21BWDWWDDDDDDDzzzD");
500 p = skip_string(p,1);
501 SSVAL(p,0,1);
502 p += 2;
503 pstrcpy(p,user);
504 strupper(p);
505 p += 21;
506 p++;
507 p += 15;
508 p++;
509 pstrcpy(p, workstation);
510 strupper(p);
511 p += 16;
512 SSVAL(p, 0, CLI_BUFFER_SIZE);
513 p += 2;
514 SSVAL(p, 0, CLI_BUFFER_SIZE);
515 p += 2;
517 if (cli_api(cli,
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 */
522 )) {
523 cli->rap_error = SVAL(rparam,0);
524 p = rdata;
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);
530 } else {
531 DEBUG(1,("NetwkstaUserLogon gave error %d\n", cli->rap_error));
535 if (rparam)
536 free(rparam);
537 if (rdata)
538 free(rdata);
539 return (cli->rap_error == 0);
541 #endif /*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)
548 char *rparam = NULL;
549 char *rdata = NULL;
550 char *p;
551 int rdrcnt,rprcnt;
552 pstring param;
553 int count = -1;
555 /* now send a SMBtrans command with api RNetShareEnum */
556 p = param;
557 SSVAL(p,0,0); /* api number */
558 p += 2;
559 pstrcpy(p,"WrLeh");
560 p = skip_string(p,1);
561 pstrcpy(p,"B13BWz");
562 p = skip_string(p,1);
563 SSVAL(p,0,1);
565 * Win2k needs a *smaller* buffer than 0xFFFF here -
566 * it returns "out of server memory" with 0xFFFF !!! JRA.
568 SSVAL(p,2,0xFFE0);
569 p += 4;
571 if (cli_api(cli,
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);
579 int i;
581 if (res == 0 || res == ERRmoredata) {
582 count=SVAL(rparam,4);
583 p = rdata;
585 for (i=0;i<count;i++,p+=20) {
586 char *sname = p;
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);
592 } else {
593 DEBUG(4,("NetShareEnum res=%d\n", res));
595 } else {
596 DEBUG(4,("NetShareEnum failed\n"));
599 if (rparam)
600 free(rparam);
601 if (rdata)
602 free(rdata);
604 return count;
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
613 the comment.
614 ****************************************************************************/
615 BOOL cli_NetServerEnum(struct cli_state *cli, char *workgroup, uint32 stype,
616 void (*fn)(const char *, uint32, const char *, void *), void *state)
618 char *rparam = NULL;
619 char *rdata = NULL;
620 int rdrcnt,rprcnt;
621 char *p;
622 pstring param;
623 int uLevel = 1;
624 int count = -1;
626 /* send a SMBtrans command with api NetServerEnum */
627 p = param;
628 SSVAL(p,0,0x68); /* api number */
629 p += 2;
630 pstrcpy(p,"WrLehDz");
631 p = skip_string(p,1);
633 pstrcpy(p,"B16BBDz");
635 p = skip_string(p,1);
636 SSVAL(p,0,uLevel);
637 SSVAL(p,2,CLI_BUFFER_SIZE);
638 p += 4;
639 SIVAL(p,0,stype);
640 p += 4;
642 pstrcpy(p, workgroup);
643 p = skip_string(p,1);
645 if (cli_api(cli,
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 */
650 )) {
651 int res = SVAL(rparam,0);
652 int converter=SVAL(rparam,2);
653 int i;
655 if (res == 0 || res == ERRmoredata) {
656 count=SVAL(rparam,4);
657 p = rdata;
659 for (i = 0;i < count;i++, p += 26) {
660 char *sname = p;
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);
672 if (rparam)
673 free(rparam);
674 if (rdata)
675 free(rdata);
677 return(count > 0);
683 static struct {
684 int prot;
685 const char *name;
687 const prots[] =
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"},
697 {-1,NULL}
701 /****************************************************************************
702 send a session setup
703 ****************************************************************************/
704 BOOL cli_session_setup(struct cli_state *cli,
705 char *user,
706 char *pass, int passlen,
707 char *ntpass, int ntpasslen,
708 char *workgroup)
710 char *p;
711 fstring pword, ntpword;
713 if (cli->protocol < PROTOCOL_LANMAN1)
714 return True;
716 if ((size_t) passlen > sizeof(pword)-1 || (size_t)ntpasslen > sizeof(ntpword)-1) {
717 return False;
720 if (((passlen == 0) || (passlen == 1)) && (pass[0] == '\0')) {
721 /* Null session connect. */
722 pword[0] = '\0';
723 ntpword[0] = '\0';
724 } else {
725 if ((cli->sec_mode & 2) && passlen != 24) {
726 passlen = 24;
727 ntpasslen = 24;
728 SMBencrypt((uchar *)pass,(uchar *)cli->cryptkey,(uchar *)pword);
729 SMBNTencrypt((uchar *)ntpass,(uchar *)cli->cryptkey,(uchar *)ntpword);
730 } else {
731 fstrcpy(pword, pass);
732 fstrcpy(ntpword, "");
733 ntpasslen = 0;
737 /* if in share level security then don't send a password now */
738 if (!(cli->sec_mode & 1)) {
739 fstrcpy(pword, "");
740 passlen=1;
741 fstrcpy(ntpword, "");
742 ntpasslen=1;
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);
762 p += passlen;
763 pstrcpy(p,user);
764 strupper(p);
765 unix_to_dos (p, True);
767 else
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);
786 pstrcpy(p,user);
787 strupper(p);
788 unix_to_dos (p, True);
789 p = skip_string(p,1);
790 pstrcpy(p,workgroup);
791 strupper(p);
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);
798 cli_send_smb(cli);
799 if (!cli_receive_smb(cli))
800 return False;
802 show_msg(cli->inbuf);
804 if (CVAL(cli->inbuf,smb_rcls) != 0) {
805 return False;
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
814 * info.
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);
827 return True;
830 /****************************************************************************
831 Send a uloggoff.
832 *****************************************************************************/
833 #if 0
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 */
843 cli_send_smb(cli);
844 if (!cli_receive_smb(cli))
845 return False;
847 return CVAL(cli->inbuf,smb_rcls) == 0;
849 #endif /*0 */
851 /****************************************************************************
852 send a tconX
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;
858 char *p;
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) {
866 passlen = 1;
867 pass = "";
870 if ((cli->sec_mode & 2) && *pass && passlen != 24) {
871 passlen = 24;
872 SMBencrypt((uchar *)pass,(uchar *)cli->cryptkey,(uchar *)pword);
873 } else {
874 memcpy(pword, pass, passlen);
877 slprintf(fullshare, sizeof(fullshare)-1,
878 "\\\\%s\\%s", cli->desthost, share);
879 unix_to_dos(fullshare, True);
880 strupper(fullshare);
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);
892 p += passlen;
893 fstrcpy(p,fullshare);
894 p = skip_string(p,1);
895 pstrcpy(p,dev);
897 SCVAL(cli->inbuf,smb_rcls, 1);
899 cli_send_smb(cli);
900 if (!cli_receive_smb(cli))
901 return False;
903 if (CVAL(cli->inbuf,smb_rcls) != 0) {
904 return False;
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 */
921 cli->win95 = True;
924 cli->cnum = SVAL(cli->inbuf,smb_tid);
925 return True;
928 #if 0
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);
940 cli_send_smb(cli);
941 if (!cli_receive_smb(cli))
942 return False;
944 return CVAL(cli->inbuf,smb_rcls) == 0;
946 #endif /*0 */
948 /****************************************************************************
949 rename a file
950 ****************************************************************************/
951 BOOL cli_rename(struct cli_state *cli, char *fname_src, char *fname_dst)
953 char *p;
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);
967 *p++ = 4;
968 pstrcpy(p,fname_src);
969 p = skip_string(p,1);
970 *p++ = 4;
971 pstrcpy(p,fname_dst);
973 cli_send_smb(cli);
974 if (!cli_receive_smb(cli)) {
975 return False;
978 if (CVAL(cli->inbuf,smb_rcls) != 0) {
979 return False;
982 return True;
985 /****************************************************************************
986 delete a file
987 ****************************************************************************/
988 BOOL cli_unlink(struct cli_state *cli, char *fname)
990 char *p;
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);
1004 *p++ = 4;
1005 pstrcpy(p,fname);
1007 cli_send_smb(cli);
1008 if (!cli_receive_smb(cli)) {
1009 return False;
1012 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1013 return False;
1016 return True;
1019 /****************************************************************************
1020 create a directory
1021 ****************************************************************************/
1022 BOOL cli_mkdir(struct cli_state *cli, char *dname)
1024 char *p;
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);
1036 *p++ = 4;
1037 pstrcpy(p,dname);
1039 cli_send_smb(cli);
1040 if (!cli_receive_smb(cli)) {
1041 return False;
1044 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1045 return False;
1048 return True;
1051 /****************************************************************************
1052 remove a directory
1053 ****************************************************************************/
1054 BOOL cli_rmdir(struct cli_state *cli, char *dname)
1056 char *p;
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);
1068 *p++ = 4;
1069 pstrcpy(p,dname);
1071 cli_send_smb(cli);
1072 if (!cli_receive_smb(cli)) {
1073 return False;
1076 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1077 return False;
1080 return True;
1083 #if 0
1084 /****************************************************************************
1085 open a file
1086 ****************************************************************************/
1087 int cli_nt_create(struct cli_state *cli, char *fname)
1089 char *p;
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);
1112 pstrcpy(p,fname);
1113 p = skip_string(p,1);
1115 cli_send_smb(cli);
1116 if (!cli_receive_smb(cli)) {
1117 return -1;
1120 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1121 return -1;
1124 return SVAL(cli->inbuf,smb_vwv2 + 1);
1126 #endif /*0 */
1128 /****************************************************************************
1129 open a file
1130 ****************************************************************************/
1131 int cli_open(struct cli_state *cli, char *fname, int flags, int share_mode)
1133 char *p;
1134 unsigned openfn=0;
1135 unsigned accessmode=0;
1137 /* you must open for RW not just write - otherwise getattrE doesn't
1138 work! */
1139 if ((flags & O_ACCMODE) == O_WRONLY && strncmp(cli->dev, "LPT", 3)) {
1140 flags = (flags & ~O_ACCMODE) | O_RDWR;
1143 if (flags & O_CREAT)
1144 openfn |= (1<<4);
1145 if (!(flags & O_EXCL)) {
1146 if (flags & O_TRUNC)
1147 openfn |= (1<<1);
1148 else
1149 openfn |= (1<<0);
1152 accessmode = (share_mode<<4);
1154 if ((flags & O_ACCMODE) == O_RDWR) {
1155 accessmode |= 2;
1156 } else if ((flags & O_ACCMODE) == O_WRONLY) {
1157 accessmode |= 1;
1160 #if defined(O_SYNC)
1161 if ((flags & O_SYNC) == O_SYNC) {
1162 accessmode |= (1<<14);
1164 #endif /* O_SYNC */
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);
1183 pstrcpy(p,fname);
1184 p = skip_string(p,1);
1186 cli_send_smb(cli);
1187 if (!cli_receive_smb(cli)) {
1188 return -1;
1191 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1192 return -1;
1195 return SVAL(cli->inbuf,smb_vwv2);
1201 /****************************************************************************
1202 close a file
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);
1218 cli_send_smb(cli);
1219 if (!cli_receive_smb(cli)) {
1220 return False;
1223 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1224 return False;
1227 return True;
1230 #if 0
1231 /****************************************************************************
1232 lock a file
1233 ****************************************************************************/
1234 BOOL cli_lock(struct cli_state *cli, int fnum, uint32 offset, uint32 len, int timeout)
1236 char *p;
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);
1258 SIVAL(p, 6, len);
1259 cli_send_smb(cli);
1261 cli->timeout = (timeout == -1) ? 0x7FFFFFFF : timeout;
1263 if (!cli_receive_smb(cli)) {
1264 cli->timeout = saved_timeout;
1265 return False;
1268 cli->timeout = saved_timeout;
1270 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1271 return False;
1274 return True;
1277 /****************************************************************************
1278 unlock a file
1279 ****************************************************************************/
1280 BOOL cli_unlock(struct cli_state *cli, int fnum, uint32 offset, uint32 len, int timeout)
1282 char *p;
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);
1303 SIVAL(p, 6, len);
1305 cli_send_smb(cli);
1306 if (!cli_receive_smb(cli)) {
1307 return False;
1310 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1311 return False;
1314 return True;
1316 #endif /*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,
1323 size_t size, int i)
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);
1341 cli_send_smb(cli);
1344 /****************************************************************************
1345 read from a file
1346 ****************************************************************************/
1347 size_t cli_read(struct cli_state *cli, int fnum, char *buf, off_t offset, size_t size)
1349 char *p;
1350 int total = -1;
1351 int issued=0;
1352 int received=0;
1353 int mpx = MAX(cli->max_mux-1, 1);
1354 int block = (cli->max_xmit - (smb_size+32)) & ~1023;
1355 int mid;
1356 int blocks = (size + (block-1)) / block;
1358 if (size == 0) return 0;
1360 while (received < blocks) {
1361 int size2;
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);
1366 issued++;
1369 if (!cli_receive_smb(cli)) {
1370 return total;
1373 received++;
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);
1379 continue;
1382 if (size2 <= 0) {
1383 blocks = MIN(blocks, mid-1);
1384 /* this distinguishes EOF from an error */
1385 total = MAX(total, 0);
1386 continue;
1389 if (size2 > block) {
1390 DEBUG(0,("server returned more than we wanted!\n"));
1391 exit(1);
1393 if (mid >= issued) {
1394 DEBUG(0,("invalid mid from server!\n"));
1395 exit(1);
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);
1406 received++;
1409 return total;
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,
1417 size_t size, int i)
1419 char *p;
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);
1448 cli_send_smb(cli);
1451 /****************************************************************************
1452 write to a file
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)
1462 int bwritten = 0;
1463 int issued = 0;
1464 int received = 0;
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,
1477 write_mode,
1478 buf + bsent,
1479 size1, issued);
1480 issued++;
1483 if (!cli_receive_smb(cli))
1485 return bwritten;
1488 received++;
1490 if (CVAL(cli->inbuf,smb_rcls) != 0)
1492 break;
1495 bwritten += SVAL(cli->inbuf, smb_vwv2);
1498 while (received < issued && cli_receive_smb(cli))
1500 received++;
1503 return bwritten;
1506 #if 0
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)
1513 char *p;
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);
1530 *p++ = 1;
1531 SSVAL(p, 0, size);
1532 memcpy(p+2, buf, size);
1534 cli_send_smb(cli);
1535 if (!cli_receive_smb(cli)) {
1536 return False;
1539 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1540 return -1;
1543 return SVAL(cli->inbuf,smb_vwv0);
1545 #endif /*0 */
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);
1565 cli_send_smb(cli);
1566 if (!cli_receive_smb(cli)) {
1567 return False;
1570 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1571 return False;
1574 if (size) {
1575 *size = IVAL(cli->inbuf, smb_vwv6);
1578 if (attr) {
1579 *attr = SVAL(cli->inbuf,smb_vwv10);
1582 if (c_time) {
1583 *c_time = make_unix_date3(cli->inbuf+smb_vwv0);
1586 if (a_time) {
1587 *a_time = make_unix_date3(cli->inbuf+smb_vwv2);
1590 if (m_time) {
1591 *m_time = make_unix_date3(cli->inbuf+smb_vwv4);
1594 return True;
1598 /****************************************************************************
1599 do a SMBgetatr call
1600 ****************************************************************************/
1601 BOOL cli_getatr(struct cli_state *cli, char *fname,
1602 uint16 *attr, size_t *size, time_t *t)
1604 char *p;
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);
1616 *p = 4;
1617 pstrcpy(p+1, fname);
1619 cli_send_smb(cli);
1620 if (!cli_receive_smb(cli)) {
1621 return False;
1624 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1625 return False;
1628 if (size) {
1629 *size = IVAL(cli->inbuf, smb_vwv3);
1632 if (t) {
1633 *t = make_unix_date3(cli->inbuf+smb_vwv1);
1636 if (attr) {
1637 *attr = SVAL(cli->inbuf,smb_vwv0);
1641 return True;
1645 /****************************************************************************
1646 do a SMBsetatr call
1647 ****************************************************************************/
1648 BOOL cli_setatr(struct cli_state *cli, char *fname, uint16 attr, time_t t)
1650 char *p;
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);
1665 *p = 4;
1666 pstrcpy(p+1, fname);
1667 p = skip_string(p,1);
1668 *p = 4;
1670 cli_send_smb(cli);
1671 if (!cli_receive_smb(cli)) {
1672 return False;
1675 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1676 return False;
1679 return True;
1682 #if 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)
1690 int data_len = 0;
1691 int param_len = 0;
1692 uint16 setup = TRANSACT2_QPATHINFO;
1693 pstring param;
1694 char *rparam=NULL, *rdata=NULL;
1695 int count=8;
1696 BOOL ret;
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(&param[6], fname);
1705 do {
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 */
1712 ) &&
1713 cli_receive_trans(cli, SMBtrans2,
1714 &rparam, &param_len,
1715 &rdata, &data_len));
1716 if (!ret) {
1717 /* we need to work around a Win95 bug - sometimes
1718 it gives ERRSRV/ERRerror temprarily */
1719 uint8 eclass;
1720 uint32 ecode;
1721 cli_error(cli, &eclass, &ecode, NULL);
1722 if (eclass != ERRSRV || ecode != ERRerror) break;
1723 msleep(100);
1725 } while (count-- && ret==False);
1727 if (!ret || !rdata || data_len < 22) {
1728 return False;
1731 if (cli->win95) {
1732 date_fn = make_unix_date;
1733 } else {
1734 date_fn = make_unix_date2;
1737 if (c_time) {
1738 *c_time = date_fn(rdata+0);
1740 if (a_time) {
1741 *a_time = date_fn(rdata+4);
1743 if (m_time) {
1744 *m_time = date_fn(rdata+8);
1746 if (size) {
1747 *size = IVAL(rdata, 12);
1749 if (mode) {
1750 *mode = SVAL(rdata,l1_attrFile);
1753 if (rdata) free(rdata);
1754 if (rparam) free(rparam);
1755 return True;
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,
1764 SMB_INO_T *ino)
1766 int data_len = 0;
1767 int param_len = 0;
1768 uint16 setup = TRANSACT2_QPATHINFO;
1769 pstring param;
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(&param[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 */
1784 )) {
1785 return False;
1788 if (!cli_receive_trans(cli, SMBtrans2,
1789 &rparam, &param_len,
1790 &rdata, &data_len)) {
1791 return False;
1794 if (!rdata || data_len < 22) {
1795 return False;
1798 if (c_time) {
1799 *c_time = interpret_long_date(rdata+0) - cli->serverzone;
1801 if (a_time) {
1802 *a_time = interpret_long_date(rdata+8) - cli->serverzone;
1804 if (m_time) {
1805 *m_time = interpret_long_date(rdata+16) - cli->serverzone;
1807 if (w_time) {
1808 *w_time = interpret_long_date(rdata+24) - cli->serverzone;
1810 if (mode) {
1811 *mode = SVAL(rdata, 32);
1813 if (size) {
1814 *size = IVAL(rdata, 48);
1816 if (ino) {
1817 *ino = IVAL(rdata, 64);
1820 if (rdata) free(rdata);
1821 if (rparam) free(rparam);
1822 return True;
1824 #endif /* 0 */
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)
1834 int data_len = 0;
1835 int param_len = 0;
1836 uint16 setup = TRANSACT2_QFILEINFO;
1837 pstring param;
1838 char *rparam=NULL, *rdata=NULL;
1840 /* if its a win95 server then fail this - win95 totally screws it
1841 up */
1842 if (cli->win95) return False;
1844 param_len = 4;
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 */
1856 )) {
1857 return False;
1860 if (!cli_receive_trans(cli, SMBtrans2,
1861 &rparam, &param_len,
1862 &rdata, &data_len)) {
1863 return False;
1866 if (!rdata || data_len < 68) {
1867 return False;
1870 if (c_time) {
1871 *c_time = interpret_long_date(rdata+0) - cli->serverzone;
1873 if (a_time) {
1874 *a_time = interpret_long_date(rdata+8) - cli->serverzone;
1876 if (m_time) {
1877 *m_time = interpret_long_date(rdata+16) - cli->serverzone;
1879 if (w_time) {
1880 *w_time = interpret_long_date(rdata+24) - cli->serverzone;
1882 if (mode) {
1883 *mode = SVAL(rdata, 32);
1885 if (size) {
1886 *size = IVAL(rdata, 48);
1888 if (ino) {
1889 *ino = IVAL(rdata, 64);
1892 if (rdata) free(rdata);
1893 if (rparam) free(rparam);
1894 return True;
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;
1908 if (finfo)
1909 memcpy(finfo,&def_finfo,sizeof(*finfo));
1911 switch (level)
1913 case 1: /* OS/2 understands this */
1914 if (finfo) {
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 */
1926 if (finfo) {
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 */
1938 case 3:
1939 if (finfo) {
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);
1950 case 4:
1951 if (finfo) {
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 */
1963 if (finfo) {
1964 int ret = SVAL(p,0);
1965 int namelen;
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
1975 be right??
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);
1995 return(ret);
1997 return(SVAL(p,0));
2000 DEBUG(1,("Unknown long filename format %d\n",level));
2001 return(SVAL(p,0));
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;
2014 char *p, *p2;
2015 pstring mask;
2016 file_info finfo;
2017 int i;
2018 char *dirlist = NULL;
2019 int dirlist_len = 0;
2020 int total_received = -1;
2021 BOOL First = True;
2022 int ff_resume_key = 0;
2023 int ff_searchcount=0;
2024 int ff_eos=0;
2025 int ff_lastname=0;
2026 int ff_dir_handle=0;
2027 int loop_count = 0;
2028 char *rparam=NULL, *rdata=NULL;
2029 int param_len, data_len;
2031 uint16 setup;
2032 pstring param;
2034 pstrcpy(mask,Mask);
2036 while (ff_eos == 0) {
2037 loop_count++;
2038 if (loop_count > 200) {
2039 DEBUG(0,("Error: Looping in FIND_NEXT??\n"));
2040 break;
2043 param_len = 12+strlen(mask)+1;
2045 if (First) {
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);
2051 SIVAL(param,8,0);
2052 pstrcpy(param+12,mask);
2053 } else {
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 */
2071 NULL, 0,
2072 cli->max_xmit /* data, length, max */
2073 )) {
2074 break;
2077 if (!cli_receive_trans(cli, SMBtrans2,
2078 &rparam, &param_len,
2079 &rdata, &data_len)) {
2080 /* we need to work around a Win95 bug - sometimes
2081 it gives ERRSRV/ERRerror temprarily */
2082 uint8 eclass;
2083 uint32 ecode;
2084 cli_error(cli, &eclass, &ecode, NULL);
2085 if (eclass != ERRSRV || ecode != ERRerror) break;
2086 msleep(100);
2087 continue;
2090 if (total_received == -1) total_received = 0;
2092 /* parse out some important return info */
2093 p = rparam;
2094 if (First) {
2095 ff_dir_handle = SVAL(p,0);
2096 ff_searchcount = SVAL(p,2);
2097 ff_eos = SVAL(p,4);
2098 ff_lastname = SVAL(p,8);
2099 } else {
2100 ff_searchcount = SVAL(p,0);
2101 ff_eos = SVAL(p,2);
2102 ff_lastname = SVAL(p,6);
2105 if (ff_searchcount == 0)
2106 break;
2108 /* point to the data bytes */
2109 p = rdata;
2111 /* we might need the lastname for continuations */
2112 if (ff_lastname > 0) {
2113 switch(info_level)
2115 case 260:
2116 ff_resume_key =0;
2117 StrnCpy(mask,p+ff_lastname,
2118 data_len-ff_lastname);
2119 break;
2120 case 1:
2121 pstrcpy(mask,p + ff_lastname + 1);
2122 ff_resume_key = 0;
2123 break;
2125 } else {
2126 pstrcpy(mask,"");
2129 /* and add them to the dirlist pool */
2130 dirlist = Realloc(dirlist,dirlist_len + data_len);
2132 if (!dirlist) {
2133 DEBUG(0,("Failed to expand dirlist\n"));
2134 break;
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));
2155 First = False;
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)
2174 char *p;
2175 int numprots;
2176 int plength;
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;
2183 numprots++)
2184 plength += strlen(prots[numprots].name)+2;
2186 set_message(cli->outbuf,0,plength,True);
2188 p = smb_buf(cli->outbuf);
2189 for (numprots=0;
2190 prots[numprots].name && prots[numprots].prot<=cli->protocol;
2191 numprots++) {
2192 *p++ = 2;
2193 pstrcpy(p,prots[numprots].name);
2194 p += strlen(p) + 1;
2197 CVAL(cli->outbuf,smb_com) = SMBnegprot;
2198 cli_setup_packet(cli);
2200 CVAL(smb_buf(cli->outbuf),0) = 2;
2202 cli_send_smb(cli);
2203 if (!cli_receive_smb(cli))
2204 return False;
2206 show_msg(cli->inbuf);
2208 if (CVAL(cli->inbuf,smb_rcls) != 0 ||
2209 ((int)SVAL(cli->inbuf,smb_vwv0) >= numprots)) {
2210 return(False);
2213 cli->protocol = prots[SVAL(cli->inbuf,smb_vwv0)].prot;
2216 if (cli->protocol >= PROTOCOL_NT1) {
2217 /* NT protocol */
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);
2241 } else {
2242 /* the old core protocol */
2243 cli->sec_mode = 0;
2244 cli->serverzone = TimeDiff(time(NULL));
2247 cli->max_xmit = MIN(cli->max_xmit, CLI_BUFFER_SIZE);
2249 return True;
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)
2259 char *p;
2260 int len = 4;
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);
2269 len += name_len(p);
2271 /* and my name */
2272 p = cli->outbuf+len;
2273 name_mangle(cli->calling.name, p, cli->calling.name_type);
2274 len += name_len(p);
2276 /* setup the packet length */
2277 _smb_setlen(cli->outbuf,len);
2278 CVAL(cli->outbuf,0) = 0x81;
2280 #ifdef WITH_SSL
2281 retry:
2282 #endif /* WITH_SSL */
2284 cli_send_smb(cli);
2285 DEBUG(5,("Sent session request\n"));
2287 if (!cli_receive_smb(cli))
2288 return False;
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{
2295 unsigned char type;
2296 unsigned char flags;
2297 int16 length;
2298 int32 ip_addr;
2299 int16 port;
2302 int port = (CVAL(cli->inbuf,8)<<8)+CVAL(cli->inbuf,9);
2303 /* SESSION RETARGET */
2304 putip((char *)&cli->dest_ip,cli->inbuf+4);
2306 close_sockets();
2307 cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip, port, LONG_CONNECT_TIMEOUT);
2308 if (cli->fd == -1)
2309 return False;
2311 DEBUG(3,("Retargeted\n"));
2313 set_socket_options(cli->fd,user_socket_options);
2315 /* Try again */
2316 return cli_session_request(cli, calling, called);
2317 } /* C. Hoch 9/14/95 End */
2319 #ifdef WITH_SSL
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)
2323 goto retry;
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);
2331 return False;
2333 return(True);
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)) {
2348 return False;
2350 if (ip) *ip = cli->dest_ip;
2351 } else {
2352 cli->dest_ip = *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);
2359 if (cli->fd == -1)
2360 return False;
2362 return True;
2366 /****************************************************************************
2367 initialise a client structure
2368 ****************************************************************************/
2369 struct cli_state *cli_initialise(struct cli_state *cli)
2371 if (!cli) {
2372 cli = (struct cli_state *)malloc(sizeof(*cli));
2373 if (!cli)
2374 return NULL;
2375 ZERO_STRUCTP(cli);
2378 if (cli->initialised) {
2379 cli_shutdown(cli);
2382 ZERO_STRUCTP(cli);
2384 cli->port = 0;
2385 cli->fd = -1;
2386 cli->cnum = -1;
2387 cli->pid = (uint16)getpid();
2388 cli->mid = 1;
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)
2398 return False;
2401 cli->initialised = 1;
2403 return cli;
2406 /****************************************************************************
2407 shutdown a client structure
2408 ****************************************************************************/
2409 void cli_shutdown(struct cli_state *cli)
2411 if (cli->outbuf)
2413 free(cli->outbuf);
2415 if (cli->inbuf)
2417 free(cli->inbuf);
2419 #ifdef WITH_SSL
2420 if (cli->fd != -1)
2421 sslutil_disconnect(cli->fd);
2422 #endif /* WITH_SSL */
2423 if (cli->fd != -1)
2424 close(cli->fd);
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
2432 otherwise
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);
2440 char rcls;
2441 int code;
2443 if (eclass) *eclass = 0;
2444 if (num ) *num = 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 */
2468 return EINVAL;
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) {
2479 switch (code) {
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) {
2490 switch (code) {
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 */
2499 return EINVAL;
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;
2516 cli->pid = pid;
2517 return ret;
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;
2527 fstring dest_host;
2528 fstring share;
2529 fstring dev;
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"));
2536 return False;
2539 /* copy the parameters necessary to re-establish the connection */
2541 if (cli->cnum != 0)
2543 fstrcpy(share, cli->share);
2544 fstrcpy(dev , cli->dev);
2545 do_tcon = True;
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));
2557 cli->fd = -1;
2559 if (cli_establish_connection(cli,
2560 dest_host, &cli->dest_ip,
2561 &calling, &called,
2562 share, dev, False, do_tcon)) {
2563 if (cli->fd != oldfd) {
2564 if (dup2(cli->fd, oldfd) == oldfd) {
2565 close(cli->fd);
2568 return True;
2570 return False;
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))
2590 return False;
2593 if (cli->fd == -1)
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)));
2599 return False;
2603 if (!cli_session_request(cli, calling, called))
2605 DEBUG(1,("failed session request\n"));
2606 if (do_shutdown)
2607 cli_shutdown(cli);
2608 return False;
2611 if (!cli_negprot(cli))
2613 DEBUG(1,("failed negprot\n"));
2614 if (do_shutdown)
2615 cli_shutdown(cli);
2616 return False;
2619 if (cli->pwd.cleartext || cli->pwd.null_pwd)
2621 fstring passwd;
2622 int pass_len;
2624 if (cli->pwd.null_pwd)
2626 /* attempt null session */
2627 passwd[0] = 0;
2628 pass_len = 1;
2630 else
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,
2639 passwd, pass_len,
2640 NULL, 0,
2641 cli->domain))
2643 DEBUG(1,("failed session setup\n"));
2644 if (do_shutdown)
2646 cli_shutdown(cli);
2648 return False;
2650 if (do_tcon)
2652 if (!cli_send_tconX(cli, service, service_type,
2653 (char*)passwd, strlen(passwd)))
2655 DEBUG(1,("failed tcon_X\n"));
2656 if (do_shutdown)
2658 cli_shutdown(cli);
2660 return False;
2664 else
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),
2678 cli->domain))
2680 DEBUG(1,("failed session setup\n"));
2681 if (do_shutdown)
2682 cli_shutdown(cli);
2683 return False;
2686 if (do_tcon)
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"));
2692 if (do_shutdown)
2693 cli_shutdown(cli);
2694 return False;
2699 if (do_shutdown)
2700 cli_shutdown(cli);
2702 return True;
2706 /****************************************************************************
2707 check for existance of a dir
2708 ****************************************************************************/
2709 BOOL cli_chkpath(struct cli_state *cli, char *path)
2711 pstring path2;
2712 char *p;
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);
2724 *p++ = 4;
2725 safe_strcpy(p,path2,strlen(path2));
2727 cli_send_smb(cli);
2728 if (!cli_receive_smb(cli)) {
2729 return False;
2732 if (cli_error(cli, NULL, NULL, NULL)) return False;
2734 return True;
2737 #if 0
2738 /****************************************************************************
2739 start a message sequence
2740 ****************************************************************************/
2741 BOOL cli_message_start(struct cli_state *cli, char *host, char *username,
2742 int *grp)
2744 char *p;
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);
2754 *p++ = 4;
2755 pstrcpy(p,username);
2756 p = skip_string(p,1);
2757 *p++ = 4;
2758 pstrcpy(p,host);
2759 p = skip_string(p,1);
2761 set_message(cli->outbuf,0,PTR_DIFF(p,smb_buf(cli->outbuf)),False);
2763 cli_send_smb(cli);
2765 if (!cli_receive_smb(cli)) {
2766 return False;
2769 if (cli_error(cli, NULL, NULL, NULL)) return False;
2771 *grp = SVAL(cli->inbuf,smb_vwv0);
2773 return True;
2777 /****************************************************************************
2778 send a message
2779 ****************************************************************************/
2780 BOOL cli_message_text(struct cli_state *cli, char *msg, int len, int grp)
2782 char *p;
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);
2793 *p = 1;
2794 SSVAL(p,1,len);
2795 memcpy(p+3,msg,len);
2796 cli_send_smb(cli);
2798 if (!cli_receive_smb(cli)) {
2799 return False;
2802 if (cli_error(cli, NULL, NULL, NULL)) return False;
2804 return True;
2807 /****************************************************************************
2808 end a message
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);
2821 cli_send_smb(cli);
2823 if (!cli_receive_smb(cli)) {
2824 return False;
2827 if (cli_error(cli, NULL, NULL, NULL)) return False;
2829 return True;
2831 #endif /*0 */
2833 #if 0 /* May be useful one day */
2834 /****************************************************************************
2835 query disk space
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);
2845 cli_send_smb(cli);
2846 if (!cli_receive_smb(cli)) {
2847 return False;
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);
2854 return True;
2856 #endif /* 0 */