2 Unix SMB/Netbios implementation.
4 SMB client generic functions
5 Copyright (C) Andrew Tridgell 1994-1998
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28 extern int DEBUGLEVEL;
30 /*****************************************************
31 RAP error codes - a small start but will be extended.
32 *******************************************************/
40 {5, "User has insufficient privilege" },
41 {86, "The specified password is invalid" },
42 {2226, "Operation only permitted on a Primary Domain Controller" },
43 {2242, "The password of this user has expired." },
44 {2243, "The password of this user cannot change." },
45 {2244, "This password cannot be used now (password history conflict)." },
46 {2245, "The password is shorter than required." },
47 {2246, "The password of this user is too recent to change."},
51 /****************************************************************************
52 return a description of an SMB error
53 ****************************************************************************/
54 static char *cli_smb_errstr(struct cli_state *cli)
56 return smb_errstr(cli->inbuf);
59 /******************************************************
60 Return an error message - either an SMB error or a RAP
62 *******************************************************/
64 char *cli_errstr(struct cli_state *cli)
66 static fstring error_message;
72 * Errors are of three kinds - smb errors,
73 * dealt with by cli_smb_errstr, NT errors,
74 * whose code is in cli.nt_error, and rap
75 * errors, whose error code is in cli.rap_error.
78 cli_error(cli, &errclass, &errnum);
82 return cli_smb_errstr(cli);
86 * Was it an NT error ?
91 char *nt_msg = get_nt_error_msg(cli->nt_error);
95 slprintf(error_message, sizeof(fstring) - 1, "NT code %d", cli->nt_error);
99 fstrcpy(error_message, nt_msg);
102 return error_message;
106 * Must have been a rap error.
109 slprintf(error_message, sizeof(error_message) - 1, "code %d", cli->rap_error);
111 for (i = 0; rap_errmap[i].message != NULL; i++)
113 if (rap_errmap[i].err == cli->rap_error)
115 fstrcpy( error_message, rap_errmap[i].message);
120 return error_message;
123 /****************************************************************************
124 setup basics in a outgoing packet
125 ****************************************************************************/
126 static void cli_setup_packet(struct cli_state *cli)
130 SSVAL(cli->outbuf,smb_pid,cli->pid);
131 SSVAL(cli->outbuf,smb_uid,cli->vuid);
132 SSVAL(cli->outbuf,smb_mid,cli->mid);
133 if (cli->protocol > PROTOCOL_CORE) {
134 SCVAL(cli->outbuf,smb_flg,0x8);
135 SSVAL(cli->outbuf,smb_flg2,0x1);
140 /*****************************************************************************
141 Convert a character pointer in a cli_call_api() response to a form we can use.
142 This function contains code to prevent core dumps if the server returns
144 *****************************************************************************/
145 static char *fix_char_ptr(unsigned int datap, unsigned int converter,
146 char *rdata, int rdrcnt)
148 if (datap == 0) { /* turn NULL pointers into zero length strings */
151 unsigned int offset = datap - converter;
153 if (offset >= rdrcnt) {
154 DEBUG(1,("bad char ptr: datap=%u, converter=%u rdrcnt=%d>",
155 datap, converter, rdrcnt));
158 return &rdata[offset];
163 /****************************************************************************
164 send a SMB trans or trans2 request
165 ****************************************************************************/
166 static BOOL cli_send_trans(struct cli_state *cli, int trans,
167 char *name, int pipe_name_len,
169 uint16 *setup, int lsetup, int msetup,
170 char *param, int lparam, int mparam,
171 char *data, int ldata, int mdata)
174 int this_ldata,this_lparam;
175 int tot_data=0,tot_param=0;
176 char *outdata,*outparam;
179 this_lparam = MIN(lparam,cli->max_xmit - (500+lsetup*2)); /* hack */
180 this_ldata = MIN(ldata,cli->max_xmit - (500+lsetup*2+this_lparam));
182 bzero(cli->outbuf,smb_size);
183 set_message(cli->outbuf,14+lsetup,0,True);
184 CVAL(cli->outbuf,smb_com) = trans;
185 SSVAL(cli->outbuf,smb_tid, cli->cnum);
186 cli_setup_packet(cli);
188 outparam = smb_buf(cli->outbuf)+(trans==SMBtrans ? pipe_name_len+1 : 3);
189 outdata = outparam+this_lparam;
191 /* primary request */
192 SSVAL(cli->outbuf,smb_tpscnt,lparam); /* tpscnt */
193 SSVAL(cli->outbuf,smb_tdscnt,ldata); /* tdscnt */
194 SSVAL(cli->outbuf,smb_mprcnt,mparam); /* mprcnt */
195 SSVAL(cli->outbuf,smb_mdrcnt,mdata); /* mdrcnt */
196 SCVAL(cli->outbuf,smb_msrcnt,msetup); /* msrcnt */
197 SSVAL(cli->outbuf,smb_flags,flags); /* flags */
198 SIVAL(cli->outbuf,smb_timeout,0); /* timeout */
199 SSVAL(cli->outbuf,smb_pscnt,this_lparam); /* pscnt */
200 SSVAL(cli->outbuf,smb_psoff,smb_offset(outparam,cli->outbuf)); /* psoff */
201 SSVAL(cli->outbuf,smb_dscnt,this_ldata); /* dscnt */
202 SSVAL(cli->outbuf,smb_dsoff,smb_offset(outdata,cli->outbuf)); /* dsoff */
203 SCVAL(cli->outbuf,smb_suwcnt,lsetup); /* suwcnt */
204 for (i=0;i<lsetup;i++) /* setup[] */
205 SSVAL(cli->outbuf,smb_setup+i*2,setup[i]);
206 p = smb_buf(cli->outbuf);
207 if (trans==SMBtrans) {
208 memcpy(p,name, pipe_name_len + 1); /* name[] */
210 *p++ = 0; /* put in a null smb_name */
211 *p++ = 'D'; *p++ = ' '; /* observed in OS/2 */
213 if (this_lparam) /* param[] */
214 memcpy(outparam,param,this_lparam);
215 if (this_ldata) /* data[] */
216 memcpy(outdata,data,this_ldata);
217 set_message(cli->outbuf,14+lsetup, /* wcnt, bcc */
218 PTR_DIFF(outdata+this_ldata,smb_buf(cli->outbuf)),False);
220 show_msg(cli->outbuf);
221 send_smb(cli->fd,cli->outbuf);
223 if (this_ldata < ldata || this_lparam < lparam) {
224 /* receive interim response */
225 if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout) ||
226 CVAL(cli->inbuf,smb_rcls) != 0) {
230 tot_data = this_ldata;
231 tot_param = this_lparam;
233 while (tot_data < ldata || tot_param < lparam) {
234 this_lparam = MIN(lparam-tot_param,cli->max_xmit - 500); /* hack */
235 this_ldata = MIN(ldata-tot_data,cli->max_xmit - (500+this_lparam));
237 set_message(cli->outbuf,trans==SMBtrans?8:9,0,True);
238 CVAL(cli->outbuf,smb_com) = trans==SMBtrans ? SMBtranss : SMBtranss2;
240 outparam = smb_buf(cli->outbuf);
241 outdata = outparam+this_lparam;
243 /* secondary request */
244 SSVAL(cli->outbuf,smb_tpscnt,lparam); /* tpscnt */
245 SSVAL(cli->outbuf,smb_tdscnt,ldata); /* tdscnt */
246 SSVAL(cli->outbuf,smb_spscnt,this_lparam); /* pscnt */
247 SSVAL(cli->outbuf,smb_spsoff,smb_offset(outparam,cli->outbuf)); /* psoff */
248 SSVAL(cli->outbuf,smb_spsdisp,tot_param); /* psdisp */
249 SSVAL(cli->outbuf,smb_sdscnt,this_ldata); /* dscnt */
250 SSVAL(cli->outbuf,smb_sdsoff,smb_offset(outdata,cli->outbuf)); /* dsoff */
251 SSVAL(cli->outbuf,smb_sdsdisp,tot_data); /* dsdisp */
252 if (trans==SMBtrans2)
253 SSVALS(cli->outbuf,smb_sfid,fid); /* fid */
254 if (this_lparam) /* param[] */
255 memcpy(outparam,param,this_lparam);
256 if (this_ldata) /* data[] */
257 memcpy(outdata,data,this_ldata);
258 set_message(cli->outbuf,trans==SMBtrans?8:9, /* wcnt, bcc */
259 PTR_DIFF(outdata+this_ldata,smb_buf(cli->outbuf)),False);
261 show_msg(cli->outbuf);
262 send_smb(cli->fd,cli->outbuf);
264 tot_data += this_ldata;
265 tot_param += this_lparam;
273 /****************************************************************************
274 receive a SMB trans or trans2 response allocating the necessary memory
275 ****************************************************************************/
276 static BOOL cli_receive_trans(struct cli_state *cli,int trans,
277 char **param, int *param_len,
278 char **data, int *data_len)
282 int this_data,this_param;
284 *data_len = *param_len = 0;
286 if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout))
289 show_msg(cli->inbuf);
292 if (CVAL(cli->inbuf,smb_com) != trans) {
293 DEBUG(0,("Expected %s response, got command 0x%02x\n",
294 trans==SMBtrans?"SMBtrans":"SMBtrans2",
295 CVAL(cli->inbuf,smb_com)));
299 if (cli_error(cli, NULL, NULL))
304 /* parse out the lengths */
305 total_data = SVAL(cli->inbuf,smb_tdrcnt);
306 total_param = SVAL(cli->inbuf,smb_tprcnt);
309 *data = Realloc(*data,total_data);
310 *param = Realloc(*param,total_param);
313 this_data = SVAL(cli->inbuf,smb_drcnt);
314 this_param = SVAL(cli->inbuf,smb_prcnt);
316 if (this_data + *data_len > total_data ||
317 this_param + *param_len > total_param) {
318 DEBUG(1,("Data overflow in cli_receive_trans\n"));
323 memcpy(*data + SVAL(cli->inbuf,smb_drdisp),
324 smb_base(cli->inbuf) + SVAL(cli->inbuf,smb_droff),
327 memcpy(*param + SVAL(cli->inbuf,smb_prdisp),
328 smb_base(cli->inbuf) + SVAL(cli->inbuf,smb_proff),
330 *data_len += this_data;
331 *param_len += this_param;
333 /* parse out the total lengths again - they can shrink! */
334 total_data = SVAL(cli->inbuf,smb_tdrcnt);
335 total_param = SVAL(cli->inbuf,smb_tprcnt);
337 if (total_data <= *data_len && total_param <= *param_len)
340 if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout))
343 show_msg(cli->inbuf);
346 if (CVAL(cli->inbuf,smb_com) != trans) {
347 DEBUG(0,("Expected %s response, got command 0x%02x\n",
348 trans==SMBtrans?"SMBtrans":"SMBtrans2",
349 CVAL(cli->inbuf,smb_com)));
352 if (cli_error(cli, NULL, NULL))
361 /****************************************************************************
362 Call a remote api on an arbitrary pipe. takes param, data and setup buffers.
363 ****************************************************************************/
364 BOOL cli_api_pipe(struct cli_state *cli, char *pipe_name, int pipe_name_len,
365 uint16 *setup, uint32 setup_count, uint32 max_setup_count,
366 char *params, uint32 param_count, uint32 max_param_count,
367 char *data, uint32 data_count, uint32 max_data_count,
368 char **rparam, uint32 *rparam_count,
369 char **rdata, uint32 *rdata_count)
371 if (pipe_name_len == 0)
372 pipe_name_len = strlen(pipe_name);
374 cli_send_trans(cli, SMBtrans,
375 pipe_name, pipe_name_len,
376 0,0, /* fid, flags */
377 setup, setup_count, max_setup_count,
378 params, param_count, max_param_count,
379 data, data_count, max_data_count);
381 return (cli_receive_trans(cli, SMBtrans,
382 rparam, (int *)rparam_count,
383 rdata, (int *)rdata_count));
386 /****************************************************************************
388 ****************************************************************************/
389 BOOL cli_api(struct cli_state *cli,
390 char *param, int prcnt, int mprcnt,
391 char *data, int drcnt, int mdrcnt,
392 char **rparam, int *rprcnt,
393 char **rdata, int *rdrcnt)
395 cli_send_trans(cli,SMBtrans,
396 PIPE_LANMAN,strlen(PIPE_LANMAN), /* Name, length */
397 0,0, /* fid, flags */
398 NULL,0,0, /* Setup, length, max */
399 param, prcnt, mprcnt, /* Params, length, max */
400 data, drcnt, mdrcnt /* Data, length, max */
403 return (cli_receive_trans(cli,SMBtrans,
409 /****************************************************************************
410 perform a NetWkstaUserLogon
411 ****************************************************************************/
412 BOOL cli_NetWkstaUserLogon(struct cli_state *cli,char *user, char *workstation)
420 memset(param, 0, sizeof(param));
422 /* send a SMBtrans command with api NetWkstaUserLogon */
424 SSVAL(p,0,132); /* api number */
426 pstrcpy(p,"OOWb54WrLh");
427 p = skip_string(p,1);
428 pstrcpy(p,"WB21BWDWWDDDDDDDzzzD");
429 p = skip_string(p,1);
438 pstrcpy(p, workstation);
441 SSVAL(p, 0, CLI_BUFFER_SIZE);
443 SSVAL(p, 0, CLI_BUFFER_SIZE);
447 param, PTR_DIFF(p,param),1024, /* param, length, max */
448 NULL, 0, CLI_BUFFER_SIZE, /* data, length, max */
449 &rparam, &rprcnt, /* return params, return size */
450 &rdata, &rdrcnt /* return data, return size */
452 cli->rap_error = SVAL(rparam,0);
455 if (cli->rap_error == 0) {
456 DEBUG(4,("NetWkstaUserLogon success\n"));
457 cli->privilages = SVAL(p, 24);
458 fstrcpy(cli->eff_name,p+2);
460 DEBUG(1,("NetwkstaUserLogon gave error %d\n", cli->rap_error));
468 return (cli->rap_error == 0);
471 /****************************************************************************
472 call a NetShareEnum - try and browse available connections on a host
473 ****************************************************************************/
474 BOOL cli_RNetShareEnum(struct cli_state *cli, void (*fn)(const char *, uint32, const char *))
483 /* now send a SMBtrans command with api RNetShareEnum */
485 SSVAL(p,0,0); /* api number */
488 p = skip_string(p,1);
490 p = skip_string(p,1);
492 SSVAL(p,2,CLI_BUFFER_SIZE);
496 param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */
497 NULL, 0, CLI_BUFFER_SIZE, /* data, length, maxlen */
498 &rparam, &rprcnt, /* return params, length */
499 &rdata, &rdrcnt)) /* return data, length */
501 int res = SVAL(rparam,0);
502 int converter=SVAL(rparam,2);
507 count=SVAL(rparam,4);
510 for (i=0;i<count;i++,p+=20)
513 int type = SVAL(p,14);
514 int comment_offset = IVAL(p,16) & 0xFFFF;
515 char *cmnt = comment_offset?(rdata+comment_offset-converter):"";
516 fn(sname, type, cmnt);
530 /****************************************************************************
531 call a NetServerEnum for the specified workgroup and servertype mask.
532 This function then calls the specified callback function for each name returned.
534 The callback function takes 3 arguments: the machine name, the server type and
536 ****************************************************************************/
537 BOOL cli_NetServerEnum(struct cli_state *cli, char *workgroup, uint32 stype,
538 void (*fn)(const char *, uint32, const char *))
548 /* send a SMBtrans command with api NetServerEnum */
550 SSVAL(p,0,0x68); /* api number */
552 pstrcpy(p,"WrLehDz");
553 p = skip_string(p,1);
555 pstrcpy(p,"B16BBDz");
557 p = skip_string(p,1);
559 SSVAL(p,2,CLI_BUFFER_SIZE);
564 pstrcpy(p, workgroup);
565 p = skip_string(p,1);
568 param, PTR_DIFF(p,param), 8, /* params, length, max */
569 NULL, 0, CLI_BUFFER_SIZE, /* data, length, max */
570 &rparam, &rprcnt, /* return params, return size */
571 &rdata, &rdrcnt /* return data, return size */
573 int res = SVAL(rparam,0);
574 int converter=SVAL(rparam,2);
578 count=SVAL(rparam,4);
581 for (i = 0;i < count;i++, p += 26) {
583 int comment_offset = (IVAL(p,22) & 0xFFFF)-converter;
584 char *cmnt = comment_offset?(rdata+comment_offset):"";
585 if (comment_offset < 0 || comment_offset > rdrcnt) continue;
587 stype = IVAL(p,18) & ~SV_TYPE_LOCAL_LIST_ONLY;
589 fn(sname, stype, cmnt);
611 {PROTOCOL_CORE,"PC NETWORK PROGRAM 1.0"},
612 {PROTOCOL_COREPLUS,"MICROSOFT NETWORKS 1.03"},
613 {PROTOCOL_LANMAN1,"MICROSOFT NETWORKS 3.0"},
614 {PROTOCOL_LANMAN1,"LANMAN1.0"},
615 {PROTOCOL_LANMAN2,"LM1.2X002"},
616 {PROTOCOL_LANMAN2,"Samba"},
617 {PROTOCOL_NT1,"NT LM 0.12"},
618 {PROTOCOL_NT1,"NT LANMAN 1.0"},
623 /****************************************************************************
625 ****************************************************************************/
626 BOOL cli_session_setup(struct cli_state *cli,
628 char *pass, int passlen,
629 char *ntpass, int ntpasslen,
633 fstring pword, ntpword;
635 if (cli->protocol < PROTOCOL_LANMAN1)
638 if (passlen > sizeof(pword)-1 || ntpasslen > sizeof(ntpword)-1) {
642 if (((passlen == 0) || (passlen == 1)) && (pass[0] == '\0')) {
643 /* Null session connect. */
647 if ((cli->sec_mode & 2) && passlen != 24) {
650 SMBencrypt((uchar *)pass,(uchar *)cli->cryptkey,(uchar *)pword);
651 SMBNTencrypt((uchar *)ntpass,(uchar *)cli->cryptkey,(uchar *)ntpword);
653 fstrcpy(pword, pass);
654 fstrcpy(ntpword, "");
659 /* if in share level security then don't send a password now */
660 if (!(cli->sec_mode & 1)) {
663 fstrcpy(ntpword, "");
667 /* send a session setup command */
668 bzero(cli->outbuf,smb_size);
670 if (cli->protocol < PROTOCOL_NT1)
672 set_message(cli->outbuf,10,1 + strlen(user) + passlen,True);
673 CVAL(cli->outbuf,smb_com) = SMBsesssetupX;
674 cli_setup_packet(cli);
676 CVAL(cli->outbuf,smb_vwv0) = 0xFF;
677 SSVAL(cli->outbuf,smb_vwv2,cli->max_xmit);
678 SSVAL(cli->outbuf,smb_vwv3,2);
679 SSVAL(cli->outbuf,smb_vwv4,1);
680 SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
681 SSVAL(cli->outbuf,smb_vwv7,passlen);
682 p = smb_buf(cli->outbuf);
683 memcpy(p,pword,passlen);
690 set_message(cli->outbuf,13,0,True);
691 CVAL(cli->outbuf,smb_com) = SMBsesssetupX;
692 cli_setup_packet(cli);
694 CVAL(cli->outbuf,smb_vwv0) = 0xFF;
695 SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
696 SSVAL(cli->outbuf,smb_vwv3,2);
697 SSVAL(cli->outbuf,smb_vwv4,cli->pid);
698 SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
699 SSVAL(cli->outbuf,smb_vwv7,passlen);
700 SSVAL(cli->outbuf,smb_vwv8,ntpasslen);
701 SSVAL(cli->outbuf,smb_vwv11,CAP_STATUS32);
702 p = smb_buf(cli->outbuf);
703 memcpy(p,pword,passlen);
704 p += SVAL(cli->outbuf,smb_vwv7);
705 memcpy(p,ntpword,ntpasslen);
706 p += SVAL(cli->outbuf,smb_vwv8);
709 p = skip_string(p,1);
710 pstrcpy(p,workgroup);
712 p = skip_string(p,1);
713 pstrcpy(p,"Unix");p = skip_string(p,1);
714 pstrcpy(p,"Samba");p = skip_string(p,1);
715 set_message(cli->outbuf,13,PTR_DIFF(p,smb_buf(cli->outbuf)),False);
718 send_smb(cli->fd,cli->outbuf);
719 if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout))
722 show_msg(cli->inbuf);
724 if (CVAL(cli->inbuf,smb_rcls) != 0) {
728 /* use the returned vuid from now on */
729 cli->vuid = SVAL(cli->inbuf,smb_uid);
734 /****************************************************************************
736 *****************************************************************************/
738 BOOL cli_ulogoff(struct cli_state *cli)
740 bzero(cli->outbuf,smb_size);
741 set_message(cli->outbuf,2,0,True);
742 CVAL(cli->outbuf,smb_com) = SMBulogoffX;
743 cli_setup_packet(cli);
744 SSVAL(cli->outbuf,smb_vwv0,0xFF);
745 SSVAL(cli->outbuf,smb_vwv2,0); /* no additional info */
747 send_smb(cli->fd,cli->outbuf);
748 if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout))
751 return CVAL(cli->inbuf,smb_rcls) == 0;
754 /****************************************************************************
756 ****************************************************************************/
757 BOOL cli_send_tconX(struct cli_state *cli,
758 char *share, char *dev, char *pass, int passlen)
760 fstring fullshare, pword;
762 bzero(cli->outbuf,smb_size);
763 bzero(cli->inbuf,smb_size);
765 fstrcpy(cli->share, share);
767 if (cli->sec_mode & 1) {
772 if ((cli->sec_mode & 2) && *pass && passlen != 24) {
774 SMBencrypt((uchar *)pass,(uchar *)cli->cryptkey,(uchar *)pword);
776 memcpy(pword, pass, passlen);
779 slprintf(fullshare, sizeof(fullshare)-1,
780 "\\\\%s\\%s", cli->desthost, share);
782 set_message(cli->outbuf,4,
783 2 + strlen(fullshare) + passlen + strlen(dev),True);
784 CVAL(cli->outbuf,smb_com) = SMBtconX;
785 cli_setup_packet(cli);
787 SSVAL(cli->outbuf,smb_vwv0,0xFF);
788 SSVAL(cli->outbuf,smb_vwv3,passlen);
790 p = smb_buf(cli->outbuf);
791 memcpy(p,pword,passlen);
793 fstrcpy(p,fullshare);
794 p = skip_string(p,1);
797 SCVAL(cli->inbuf,smb_rcls, 1);
799 send_smb(cli->fd,cli->outbuf);
800 if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout))
803 if (CVAL(cli->inbuf,smb_rcls) != 0) {
807 fstrcpy(cli->dev, smb_buf(cli->inbuf));
809 if (cli->protocol >= PROTOCOL_NT1 &&
810 smb_buflen(cli->inbuf) == 3) {
811 /* almost certainly win95 - enable bug fixes */
815 cli->cnum = SVAL(cli->inbuf,smb_tid);
820 /****************************************************************************
821 send a tree disconnect
822 ****************************************************************************/
823 BOOL cli_tdis(struct cli_state *cli)
825 bzero(cli->outbuf,smb_size);
826 set_message(cli->outbuf,0,0,True);
827 CVAL(cli->outbuf,smb_com) = SMBtdis;
828 SSVAL(cli->outbuf,smb_tid,cli->cnum);
829 cli_setup_packet(cli);
831 send_smb(cli->fd,cli->outbuf);
832 if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout))
835 return CVAL(cli->inbuf,smb_rcls) == 0;
838 /****************************************************************************
840 ****************************************************************************/
841 BOOL cli_rename(struct cli_state *cli, char *fname_src, char *fname_dst)
845 bzero(cli->outbuf,smb_size);
846 bzero(cli->inbuf,smb_size);
848 set_message(cli->outbuf,1, 4 + strlen(fname_src) + strlen(fname_dst), True);
850 CVAL(cli->outbuf,smb_com) = SMBmv;
851 SSVAL(cli->outbuf,smb_tid,cli->cnum);
852 cli_setup_packet(cli);
854 SSVAL(cli->outbuf,smb_vwv0,aSYSTEM | aHIDDEN);
856 p = smb_buf(cli->outbuf);
858 pstrcpy(p,fname_src);
859 p = skip_string(p,1);
861 pstrcpy(p,fname_dst);
863 send_smb(cli->fd,cli->outbuf);
864 if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) {
868 if (CVAL(cli->inbuf,smb_rcls) != 0) {
875 /****************************************************************************
877 ****************************************************************************/
878 BOOL cli_unlink(struct cli_state *cli, char *fname)
882 bzero(cli->outbuf,smb_size);
883 bzero(cli->inbuf,smb_size);
885 set_message(cli->outbuf,1, 2 + strlen(fname),True);
887 CVAL(cli->outbuf,smb_com) = SMBunlink;
888 SSVAL(cli->outbuf,smb_tid,cli->cnum);
889 cli_setup_packet(cli);
891 SSVAL(cli->outbuf,smb_vwv0,aSYSTEM | aHIDDEN);
893 p = smb_buf(cli->outbuf);
897 send_smb(cli->fd,cli->outbuf);
898 if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) {
902 if (CVAL(cli->inbuf,smb_rcls) != 0) {
909 /****************************************************************************
911 ****************************************************************************/
912 BOOL cli_mkdir(struct cli_state *cli, char *dname)
916 bzero(cli->outbuf,smb_size);
917 bzero(cli->inbuf,smb_size);
919 set_message(cli->outbuf,0, 2 + strlen(dname),True);
921 CVAL(cli->outbuf,smb_com) = SMBmkdir;
922 SSVAL(cli->outbuf,smb_tid,cli->cnum);
923 cli_setup_packet(cli);
925 p = smb_buf(cli->outbuf);
929 send_smb(cli->fd,cli->outbuf);
930 if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) {
934 if (CVAL(cli->inbuf,smb_rcls) != 0) {
941 /****************************************************************************
943 ****************************************************************************/
944 BOOL cli_rmdir(struct cli_state *cli, char *dname)
948 bzero(cli->outbuf,smb_size);
949 bzero(cli->inbuf,smb_size);
951 set_message(cli->outbuf,0, 2 + strlen(dname),True);
953 CVAL(cli->outbuf,smb_com) = SMBrmdir;
954 SSVAL(cli->outbuf,smb_tid,cli->cnum);
955 cli_setup_packet(cli);
957 p = smb_buf(cli->outbuf);
961 send_smb(cli->fd,cli->outbuf);
962 if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) {
966 if (CVAL(cli->inbuf,smb_rcls) != 0) {
975 /****************************************************************************
977 ****************************************************************************/
978 int cli_open(struct cli_state *cli, char *fname, int flags, int share_mode)
982 unsigned accessmode=0;
984 /* you must open for RW not just write - otherwise getattrE doesn't
986 if ((flags & O_ACCMODE) == O_WRONLY) {
987 flags = (flags & ~O_ACCMODE) | O_RDWR;
992 if (!(flags & O_EXCL)) {
999 accessmode = (share_mode<<4);
1001 if ((flags & O_ACCMODE) == O_RDWR) {
1003 } else if ((flags & O_ACCMODE) == O_WRONLY) {
1008 if ((flags & O_SYNC) == O_SYNC) {
1009 accessmode |= (1<<14);
1013 bzero(cli->outbuf,smb_size);
1014 bzero(cli->inbuf,smb_size);
1016 set_message(cli->outbuf,15,1 + strlen(fname),True);
1018 CVAL(cli->outbuf,smb_com) = SMBopenX;
1019 SSVAL(cli->outbuf,smb_tid,cli->cnum);
1020 cli_setup_packet(cli);
1022 SSVAL(cli->outbuf,smb_vwv0,0xFF);
1023 SSVAL(cli->outbuf,smb_vwv2,0); /* no additional info */
1024 SSVAL(cli->outbuf,smb_vwv3,accessmode);
1025 SSVAL(cli->outbuf,smb_vwv4,aSYSTEM | aHIDDEN);
1026 SSVAL(cli->outbuf,smb_vwv5,0);
1027 SSVAL(cli->outbuf,smb_vwv8,openfn);
1029 p = smb_buf(cli->outbuf);
1031 p = skip_string(p,1);
1033 send_smb(cli->fd,cli->outbuf);
1034 if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) {
1038 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1042 return SVAL(cli->inbuf,smb_vwv2);
1048 /****************************************************************************
1050 ****************************************************************************/
1051 BOOL cli_close(struct cli_state *cli, int fnum)
1053 bzero(cli->outbuf,smb_size);
1054 bzero(cli->inbuf,smb_size);
1056 set_message(cli->outbuf,3,0,True);
1058 CVAL(cli->outbuf,smb_com) = SMBclose;
1059 SSVAL(cli->outbuf,smb_tid,cli->cnum);
1060 cli_setup_packet(cli);
1062 SSVAL(cli->outbuf,smb_vwv0,fnum);
1063 SIVALS(cli->outbuf,smb_vwv1,-1);
1065 send_smb(cli->fd,cli->outbuf);
1066 if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) {
1070 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1078 /****************************************************************************
1080 ****************************************************************************/
1081 BOOL cli_lock(struct cli_state *cli, int fnum, uint32 offset, uint32 len, int timeout)
1085 bzero(cli->outbuf,smb_size);
1086 bzero(cli->inbuf,smb_size);
1088 set_message(cli->outbuf,8,10,True);
1090 CVAL(cli->outbuf,smb_com) = SMBlockingX;
1091 SSVAL(cli->outbuf,smb_tid,cli->cnum);
1092 cli_setup_packet(cli);
1094 CVAL(cli->outbuf,smb_vwv0) = 0xFF;
1095 SSVAL(cli->outbuf,smb_vwv2,fnum);
1096 CVAL(cli->outbuf,smb_vwv3) = 0;
1097 SIVALS(cli->outbuf, smb_vwv4, timeout);
1098 SSVAL(cli->outbuf,smb_vwv6,0);
1099 SSVAL(cli->outbuf,smb_vwv7,1);
1101 p = smb_buf(cli->outbuf);
1102 SSVAL(p, 0, cli->pid);
1103 SIVAL(p, 2, offset);
1106 send_smb(cli->fd,cli->outbuf);
1107 if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) {
1111 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1118 /****************************************************************************
1120 ****************************************************************************/
1121 BOOL cli_unlock(struct cli_state *cli, int fnum, uint32 offset, uint32 len, int timeout)
1125 bzero(cli->outbuf,smb_size);
1126 bzero(cli->inbuf,smb_size);
1128 set_message(cli->outbuf,8,10,True);
1130 CVAL(cli->outbuf,smb_com) = SMBlockingX;
1131 SSVAL(cli->outbuf,smb_tid,cli->cnum);
1132 cli_setup_packet(cli);
1134 CVAL(cli->outbuf,smb_vwv0) = 0xFF;
1135 SSVAL(cli->outbuf,smb_vwv2,fnum);
1136 CVAL(cli->outbuf,smb_vwv3) = 0;
1137 SIVALS(cli->outbuf, smb_vwv4, timeout);
1138 SSVAL(cli->outbuf,smb_vwv6,1);
1139 SSVAL(cli->outbuf,smb_vwv7,0);
1141 p = smb_buf(cli->outbuf);
1142 SSVAL(p, 0, cli->pid);
1143 SIVAL(p, 2, offset);
1146 send_smb(cli->fd,cli->outbuf);
1147 if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) {
1151 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1160 /****************************************************************************
1161 issue a single SMBread and don't wait for a reply
1162 ****************************************************************************/
1163 static void cli_issue_read(struct cli_state *cli, int fnum, off_t offset,
1166 bzero(cli->outbuf,smb_size);
1167 bzero(cli->inbuf,smb_size);
1169 set_message(cli->outbuf,10,0,True);
1171 CVAL(cli->outbuf,smb_com) = SMBreadX;
1172 SSVAL(cli->outbuf,smb_tid,cli->cnum);
1173 cli_setup_packet(cli);
1175 CVAL(cli->outbuf,smb_vwv0) = 0xFF;
1176 SSVAL(cli->outbuf,smb_vwv2,fnum);
1177 SIVAL(cli->outbuf,smb_vwv3,offset);
1178 SSVAL(cli->outbuf,smb_vwv5,size);
1179 SSVAL(cli->outbuf,smb_vwv6,size);
1180 SSVAL(cli->outbuf,smb_mid,cli->mid + i);
1182 send_smb(cli->fd,cli->outbuf);
1185 /****************************************************************************
1187 ****************************************************************************/
1188 size_t cli_read(struct cli_state *cli, int fnum, char *buf, off_t offset, size_t size)
1194 int mpx = MAX(cli->max_mux-1, 1);
1195 int block = (cli->max_xmit - (smb_size+32)) & ~1023;
1197 int blocks = (size + (block-1)) / block;
1199 while (received < blocks) {
1202 while (issued - received < mpx && issued < blocks) {
1203 int size1 = MIN(block, size-issued*block);
1204 cli_issue_read(cli, fnum, offset+issued*block, size1, issued);
1208 if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) {
1213 mid = SVAL(cli->inbuf, smb_mid) - cli->mid;
1214 size2 = SVAL(cli->inbuf, smb_vwv5);
1216 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1217 blocks = MIN(blocks, mid-1);
1222 blocks = MIN(blocks, mid-1);
1223 /* this distinguishes EOF from an error */
1224 total = MAX(total, 0);
1228 if (size2 > block) {
1229 DEBUG(0,("server returned more than we wanted!\n"));
1232 if (mid >= issued) {
1233 DEBUG(0,("invalid mid from server!\n"));
1236 p = smb_base(cli->inbuf) + SVAL(cli->inbuf,smb_vwv6);
1238 memcpy(buf+mid*block, p, size2);
1240 total = MAX(total, mid*block + size2);
1243 while (received < issued) {
1244 client_receive_smb(cli->fd,cli->inbuf,cli->timeout);
1252 /****************************************************************************
1253 issue a single SMBwrite and don't wait for a reply
1254 ****************************************************************************/
1255 static void cli_issue_write(struct cli_state *cli, int fnum, off_t offset, char *buf,
1260 bzero(cli->outbuf,smb_size);
1261 bzero(cli->inbuf,smb_size);
1263 set_message(cli->outbuf,12,size,True);
1265 CVAL(cli->outbuf,smb_com) = SMBwriteX;
1266 SSVAL(cli->outbuf,smb_tid,cli->cnum);
1267 cli_setup_packet(cli);
1269 CVAL(cli->outbuf,smb_vwv0) = 0xFF;
1270 SSVAL(cli->outbuf,smb_vwv2,fnum);
1271 SIVAL(cli->outbuf,smb_vwv3,offset);
1273 SSVAL(cli->outbuf,smb_vwv10,size);
1274 SSVAL(cli->outbuf,smb_vwv11,
1275 smb_buf(cli->outbuf) - smb_base(cli->outbuf));
1277 p = smb_base(cli->outbuf) + SVAL(cli->outbuf,smb_vwv11);
1278 memcpy(p, buf, size);
1280 SSVAL(cli->outbuf,smb_mid,cli->mid + i);
1282 send_smb(cli->fd,cli->outbuf);
1285 /****************************************************************************
1287 ****************************************************************************/
1288 size_t cli_write(struct cli_state *cli, int fnum, char *buf, off_t offset, size_t size)
1293 int mpx = MAX(cli->max_mux-1, 1);
1294 int block = (cli->max_xmit - (smb_size+32)) & ~1023;
1296 int blocks = (size + (block-1)) / block;
1298 while (received < blocks) {
1301 while (issued - received < mpx && issued < blocks) {
1302 int size1 = MIN(block, size-issued*block);
1303 cli_issue_write(cli, fnum, offset+issued*block, buf + issued*block,
1308 if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) {
1313 mid = SVAL(cli->inbuf, smb_mid) - cli->mid;
1314 size2 = SVAL(cli->inbuf, smb_vwv2);
1316 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1317 blocks = MIN(blocks, mid-1);
1322 blocks = MIN(blocks, mid-1);
1323 /* this distinguishes EOF from an error */
1324 total = MAX(total, 0);
1330 total = MAX(total, mid*block + size2);
1333 while (received < issued) {
1334 client_receive_smb(cli->fd,cli->inbuf,cli->timeout);
1342 /****************************************************************************
1343 do a SMBgetattrE call
1344 ****************************************************************************/
1345 BOOL cli_getattrE(struct cli_state *cli, int fd,
1346 int *attr, uint32 *size,
1347 time_t *c_time, time_t *a_time, time_t *m_time)
1349 bzero(cli->outbuf,smb_size);
1350 bzero(cli->inbuf,smb_size);
1352 set_message(cli->outbuf,2,0,True);
1354 CVAL(cli->outbuf,smb_com) = SMBgetattrE;
1355 SSVAL(cli->outbuf,smb_tid,cli->cnum);
1356 cli_setup_packet(cli);
1358 SSVAL(cli->outbuf,smb_vwv0,fd);
1360 send_smb(cli->fd,cli->outbuf);
1361 if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) {
1365 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1370 *size = IVAL(cli->inbuf, smb_vwv6);
1374 *attr = SVAL(cli->inbuf,smb_vwv10);
1378 *c_time = make_unix_date3(cli->inbuf+smb_vwv0);
1382 *a_time = make_unix_date3(cli->inbuf+smb_vwv2);
1386 *m_time = make_unix_date3(cli->inbuf+smb_vwv4);
1393 /****************************************************************************
1395 ****************************************************************************/
1396 BOOL cli_getatr(struct cli_state *cli, char *fname,
1397 uint32 *attr, size_t *size, time_t *t)
1401 bzero(cli->outbuf,smb_size);
1402 bzero(cli->inbuf,smb_size);
1404 set_message(cli->outbuf,0,strlen(fname)+2,True);
1406 CVAL(cli->outbuf,smb_com) = SMBgetatr;
1407 SSVAL(cli->outbuf,smb_tid,cli->cnum);
1408 cli_setup_packet(cli);
1410 p = smb_buf(cli->outbuf);
1412 pstrcpy(p+1, fname);
1414 send_smb(cli->fd,cli->outbuf);
1415 if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) {
1419 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1424 *size = IVAL(cli->inbuf, smb_vwv3);
1428 *t = make_unix_date3(cli->inbuf+smb_vwv1);
1432 *attr = SVAL(cli->inbuf,smb_vwv0);
1440 /****************************************************************************
1442 ****************************************************************************/
1443 BOOL cli_setatr(struct cli_state *cli, char *fname, int attr, time_t t)
1447 bzero(cli->outbuf,smb_size);
1448 bzero(cli->inbuf,smb_size);
1450 set_message(cli->outbuf,8,strlen(fname)+4,True);
1452 CVAL(cli->outbuf,smb_com) = SMBsetatr;
1453 SSVAL(cli->outbuf,smb_tid,cli->cnum);
1454 cli_setup_packet(cli);
1456 SSVAL(cli->outbuf,smb_vwv0, attr);
1457 put_dos_date3(cli->outbuf,smb_vwv1, t);
1459 p = smb_buf(cli->outbuf);
1461 pstrcpy(p+1, fname);
1462 p = skip_string(p,1);
1465 send_smb(cli->fd,cli->outbuf);
1466 if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) {
1470 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1477 /****************************************************************************
1478 send a qpathinfo call
1479 ****************************************************************************/
1480 BOOL cli_qpathinfo(struct cli_state *cli, const char *fname,
1481 time_t *c_time, time_t *a_time, time_t *m_time,
1482 size_t *size, uint32 *mode)
1486 uint16 setup = TRANSACT2_QPATHINFO;
1488 char *rparam=NULL, *rdata=NULL;
1491 time_t (*date_fn)(void *);
1493 param_len = strlen(fname) + 7;
1495 memset(param, 0, param_len);
1496 SSVAL(param, 0, SMB_INFO_STANDARD);
1497 pstrcpy(¶m[6], fname);
1500 ret = (cli_send_trans(cli, SMBtrans2,
1501 NULL, 0, /* Name, length */
1502 -1, 0, /* fid, flags */
1503 &setup, 1, 0, /* setup, length, max */
1504 param, param_len, 10, /* param, length, max */
1505 NULL, data_len, cli->max_xmit /* data, length, max */
1507 cli_receive_trans(cli, SMBtrans2,
1508 &rparam, ¶m_len,
1509 &rdata, &data_len));
1511 /* we need to work around a Win95 bug - sometimes
1512 it gives ERRSRV/ERRerror temprarily */
1515 cli_error(cli, &eclass, &ecode);
1516 if (eclass != ERRSRV || ecode != ERRerror) break;
1519 } while (count-- && ret==False);
1521 if (!ret || !rdata || data_len < 22) {
1526 date_fn = make_unix_date;
1528 date_fn = make_unix_date2;
1532 *c_time = date_fn(rdata+0);
1535 *a_time = date_fn(rdata+4);
1538 *m_time = date_fn(rdata+8);
1541 *size = IVAL(rdata, 12);
1544 *mode = SVAL(rdata,l1_attrFile);
1547 if (rdata) free(rdata);
1548 if (rparam) free(rparam);
1552 /****************************************************************************
1553 send a qpathinfo call with the SMB_QUERY_FILE_ALL_INFO info level
1554 ****************************************************************************/
1555 BOOL cli_qpathinfo2(struct cli_state *cli, char *fname,
1556 time_t *c_time, time_t *a_time, time_t *m_time,
1557 time_t *w_time, uint32 *size)
1561 uint16 setup = TRANSACT2_QPATHINFO;
1563 char *rparam=NULL, *rdata=NULL;
1565 param_len = strlen(fname) + 7;
1567 memset(param, 0, param_len);
1568 SSVAL(param, 0, SMB_QUERY_FILE_ALL_INFO);
1569 pstrcpy(¶m[6], fname);
1571 if (!cli_send_trans(cli, SMBtrans2,
1572 NULL, 0, /* name, length */
1573 -1, 0, /* fid, flags */
1574 &setup, 1, 0, /* setup, length, max */
1575 param, param_len, 10, /* param, length, max */
1576 NULL, data_len, cli->max_xmit /* data, length, max */
1581 if (!cli_receive_trans(cli, SMBtrans2,
1582 &rparam, ¶m_len,
1583 &rdata, &data_len)) {
1587 if (!rdata || data_len < 22) {
1592 *c_time = interpret_long_date(rdata+0) - cli->serverzone;
1595 *a_time = interpret_long_date(rdata+8) - cli->serverzone;
1598 *m_time = interpret_long_date(rdata+16) - cli->serverzone;
1601 *w_time = interpret_long_date(rdata+24) - cli->serverzone;
1604 *size = IVAL(rdata, 40);
1607 if (rdata) free(rdata);
1608 if (rparam) free(rparam);
1613 /****************************************************************************
1614 send a qfileinfo call
1615 ****************************************************************************/
1616 BOOL cli_qfileinfo(struct cli_state *cli, int fnum,
1617 uint32 *mode, size_t *size,
1618 time_t *c_time, time_t *a_time, time_t *m_time)
1622 uint16 setup = TRANSACT2_QFILEINFO;
1624 char *rparam=NULL, *rdata=NULL;
1628 memset(param, 0, param_len);
1629 SSVAL(param, 0, fnum);
1630 SSVAL(param, 2, SMB_INFO_STANDARD);
1632 if (!cli_send_trans(cli, SMBtrans2,
1633 NULL, 0, /* name, length */
1634 -1, 0, /* fid, flags */
1635 &setup, 1, 0, /* setup, length, max */
1636 param, param_len, 2, /* param, length, max */
1637 NULL, data_len, cli->max_xmit /* data, length, max */
1642 if (!cli_receive_trans(cli, SMBtrans2,
1643 &rparam, ¶m_len,
1644 &rdata, &data_len)) {
1648 if (!rdata || data_len < 22) {
1653 *c_time = make_unix_date2(rdata+0);
1656 *a_time = make_unix_date2(rdata+4);
1659 *m_time = make_unix_date2(rdata+8);
1662 *size = IVAL(rdata, 12);
1665 *mode = SVAL(rdata,l1_attrFile);
1668 if (rdata) free(rdata);
1669 if (rparam) free(rparam);
1674 /****************************************************************************
1675 interpret a long filename structure - this is mostly guesses at the moment
1676 The length of the structure is returned
1677 The structure of a long filename depends on the info level. 260 is used
1678 by NT and 2 is used by OS/2
1679 ****************************************************************************/
1680 static int interpret_long_filename(int level,char *p,file_info *finfo)
1682 extern file_info def_finfo;
1685 memcpy(finfo,&def_finfo,sizeof(*finfo));
1689 case 1: /* OS/2 understands this */
1691 /* these dates are converted to GMT by make_unix_date */
1692 finfo->ctime = make_unix_date2(p+4);
1693 finfo->atime = make_unix_date2(p+8);
1694 finfo->mtime = make_unix_date2(p+12);
1695 finfo->size = IVAL(p,16);
1696 finfo->mode = CVAL(p,24);
1697 pstrcpy(finfo->name,p+27);
1699 return(28 + CVAL(p,26));
1701 case 2: /* this is what OS/2 uses mostly */
1703 /* these dates are converted to GMT by make_unix_date */
1704 finfo->ctime = make_unix_date2(p+4);
1705 finfo->atime = make_unix_date2(p+8);
1706 finfo->mtime = make_unix_date2(p+12);
1707 finfo->size = IVAL(p,16);
1708 finfo->mode = CVAL(p,24);
1709 pstrcpy(finfo->name,p+31);
1711 return(32 + CVAL(p,30));
1713 /* levels 3 and 4 are untested */
1716 /* these dates are probably like the other ones */
1717 finfo->ctime = make_unix_date2(p+8);
1718 finfo->atime = make_unix_date2(p+12);
1719 finfo->mtime = make_unix_date2(p+16);
1720 finfo->size = IVAL(p,20);
1721 finfo->mode = CVAL(p,28);
1722 pstrcpy(finfo->name,p+33);
1724 return(SVAL(p,4)+4);
1728 /* these dates are probably like the other ones */
1729 finfo->ctime = make_unix_date2(p+8);
1730 finfo->atime = make_unix_date2(p+12);
1731 finfo->mtime = make_unix_date2(p+16);
1732 finfo->size = IVAL(p,20);
1733 finfo->mode = CVAL(p,28);
1734 pstrcpy(finfo->name,p+37);
1736 return(SVAL(p,4)+4);
1738 case 260: /* NT uses this, but also accepts 2 */
1740 int ret = SVAL(p,0);
1742 p += 4; /* next entry offset */
1743 p += 4; /* fileindex */
1745 /* these dates appear to arrive in a
1746 weird way. It seems to be localtime
1747 plus the serverzone given in the
1748 initial connect. This is GMT when
1749 DST is not in effect and one hour
1750 from GMT otherwise. Can this really
1753 I suppose this could be called
1754 kludge-GMT. Is is the GMT you get
1755 by using the current DST setting on
1756 a different localtime. It will be
1757 cheap to calculate, I suppose, as
1758 no DST tables will be needed */
1760 finfo->ctime = interpret_long_date(p); p += 8;
1761 finfo->atime = interpret_long_date(p); p += 8;
1762 finfo->mtime = interpret_long_date(p); p += 8; p += 8;
1763 finfo->size = IVAL(p,0); p += 8;
1764 p += 8; /* alloc size */
1765 finfo->mode = CVAL(p,0); p += 4;
1766 namelen = IVAL(p,0); p += 4;
1767 p += 4; /* EA size */
1768 p += 2; /* short name len? */
1769 p += 24; /* short name? */
1770 StrnCpy(finfo->name,p,namelen);
1776 DEBUG(1,("Unknown long filename format %d\n",level));
1781 /****************************************************************************
1782 do a directory listing, calling fn on each file found
1783 ****************************************************************************/
1784 int cli_list(struct cli_state *cli,char *Mask,int attribute,void (*fn)(file_info *))
1786 int max_matches = 512;
1787 /* NT uses 260, OS/2 uses 2. Both accept 1. */
1788 int info_level = cli->protocol<PROTOCOL_NT1?1:260;
1793 char *dirlist = NULL;
1794 int dirlist_len = 0;
1795 int total_received = -1;
1797 int ff_resume_key = 0;
1798 int ff_searchcount=0;
1801 int ff_dir_handle=0;
1803 char *rparam=NULL, *rdata=NULL;
1804 int param_len, data_len;
1811 while (ff_eos == 0) {
1813 if (loop_count > 200) {
1814 DEBUG(0,("Error: Looping in FIND_NEXT??\n"));
1818 param_len = 12+strlen(mask)+1;
1821 setup = TRANSACT2_FINDFIRST;
1822 SSVAL(param,0,attribute); /* attribute */
1823 SSVAL(param,2,max_matches); /* max count */
1824 SSVAL(param,4,8+4+2); /* resume required + close on end + continue */
1825 SSVAL(param,6,info_level);
1827 pstrcpy(param+12,mask);
1829 setup = TRANSACT2_FINDNEXT;
1830 SSVAL(param,0,ff_dir_handle);
1831 SSVAL(param,2,max_matches); /* max count */
1832 SSVAL(param,4,info_level);
1833 SIVAL(param,6,ff_resume_key); /* ff_resume_key */
1834 SSVAL(param,10,8+4+2); /* resume required + close on end + continue */
1835 pstrcpy(param+12,mask);
1837 DEBUG(5,("hand=0x%X resume=%d ff_lastname=%d mask=%s\n",
1838 ff_dir_handle,ff_resume_key,ff_lastname,mask));
1841 if (!cli_send_trans(cli, SMBtrans2,
1842 NULL, 0, /* Name, length */
1843 -1, 0, /* fid, flags */
1844 &setup, 1, 0, /* setup, length, max */
1845 param, param_len, 10, /* param, length, max */
1847 cli->max_xmit /* data, length, max */
1852 if (!cli_receive_trans(cli, SMBtrans2,
1853 &rparam, ¶m_len,
1854 &rdata, &data_len)) {
1855 /* we need to work around a Win95 bug - sometimes
1856 it gives ERRSRV/ERRerror temprarily */
1859 cli_error(cli, &eclass, &ecode);
1860 if (eclass != ERRSRV || ecode != ERRerror) break;
1865 if (total_received == -1) total_received = 0;
1867 /* parse out some important return info */
1870 ff_dir_handle = SVAL(p,0);
1871 ff_searchcount = SVAL(p,2);
1873 ff_lastname = SVAL(p,8);
1875 ff_searchcount = SVAL(p,0);
1877 ff_lastname = SVAL(p,6);
1880 if (ff_searchcount == 0)
1883 /* point to the data bytes */
1886 /* we might need the lastname for continuations */
1887 if (ff_lastname > 0) {
1892 StrnCpy(mask,p+ff_lastname,
1893 data_len-ff_lastname);
1896 pstrcpy(mask,p + ff_lastname + 1);
1904 /* and add them to the dirlist pool */
1905 dirlist = Realloc(dirlist,dirlist_len + data_len);
1908 DEBUG(0,("Failed to expand dirlist\n"));
1912 /* put in a length for the last entry, to ensure we can chain entries
1913 into the next packet */
1914 for (p2=p,i=0;i<(ff_searchcount-1);i++)
1915 p2 += interpret_long_filename(info_level,p2,NULL);
1916 SSVAL(p2,0,data_len - PTR_DIFF(p2,p));
1918 /* grab the data for later use */
1919 memcpy(dirlist+dirlist_len,p,data_len);
1920 dirlist_len += data_len;
1922 total_received += ff_searchcount;
1924 if (rdata) free(rdata); rdata = NULL;
1925 if (rparam) free(rparam); rparam = NULL;
1927 DEBUG(3,("received %d entries (eos=%d resume=%d)\n",
1928 ff_searchcount,ff_eos,ff_resume_key));
1933 for (p=dirlist,i=0;i<total_received;i++) {
1934 p += interpret_long_filename(info_level,p,&finfo);
1938 /* free up the dirlist buffer */
1939 if (dirlist) free(dirlist);
1940 return(total_received);
1944 /****************************************************************************
1945 Send a SamOEMChangePassword command
1946 ****************************************************************************/
1948 BOOL cli_oem_change_password(struct cli_state *cli, char *user, char *new_password,
1951 char param[16+sizeof(fstring)];
1954 fstring upper_case_old_pw;
1955 fstring upper_case_new_pw;
1956 unsigned char old_pw_hash[16];
1957 unsigned char new_pw_hash[16];
1960 int new_pw_len = strlen(new_password);
1961 char *rparam = NULL;
1965 if (strlen(user) >= sizeof(fstring)-1) {
1966 DEBUG(0,("cli_oem_change_password: user name %s is too long.\n", user));
1970 if (new_pw_len > 512) {
1971 DEBUG(0,("cli_oem_change_password: new password for user %s is too long.\n", user));
1975 SSVAL(p,0,214); /* SamOEMChangePassword command. */
1978 p = skip_string(p,1);
1979 pstrcpy(p, "B516B16");
1980 p = skip_string(p,1);
1982 p = skip_string(p,1);
1986 param_len = PTR_DIFF(p,param);
1989 * Now setup the data area.
1990 * We need to generate a random fill
1991 * for this area to make it harder to
1994 generate_random_buffer((unsigned char *)data, sizeof(data), False);
1995 fstrcpy( &data[512 - new_pw_len], new_password);
1996 SIVAL(data, 512, new_pw_len);
1999 * Get the Lanman hash of the old password, we
2000 * use this as the key to SamOEMHash().
2002 memset(upper_case_old_pw, '\0', sizeof(upper_case_old_pw));
2003 fstrcpy(upper_case_old_pw, old_password);
2004 strupper(upper_case_old_pw);
2005 E_P16((uchar *)upper_case_old_pw, old_pw_hash);
2007 SamOEMhash( (unsigned char *)data, (unsigned char *)old_pw_hash, True);
2010 * Now place the old password hash in the data.
2012 memset(upper_case_new_pw, '\0', sizeof(upper_case_new_pw));
2013 fstrcpy(upper_case_new_pw, new_password);
2014 strupper(upper_case_new_pw);
2016 E_P16((uchar *)upper_case_new_pw, new_pw_hash);
2018 E_old_pw_hash( new_pw_hash, old_pw_hash, (uchar *)&data[516]);
2022 if (cli_send_trans(cli,SMBtrans,
2023 PIPE_LANMAN,strlen(PIPE_LANMAN), /* name, length */
2024 0,0, /* fid, flags */
2025 NULL,0,0, /* setup, length, max */
2026 param,param_len,2, /* param, length, max */
2027 data,data_len,0 /* data, length, max */
2029 DEBUG(0,("cli_oem_change_password: Failed to send password change for user %s\n",
2034 if (cli_receive_trans(cli,SMBtrans,
2038 cli->rap_error = SVAL(rparam,0);
2046 return (cli->rap_error == 0);
2049 /****************************************************************************
2050 send a negprot command
2051 ****************************************************************************/
2052 BOOL cli_negprot(struct cli_state *cli)
2058 bzero(cli->outbuf,smb_size);
2060 /* setup the protocol strings */
2061 for (plength=0,numprots=0;
2062 prots[numprots].name && prots[numprots].prot<=cli->protocol;
2064 plength += strlen(prots[numprots].name)+2;
2066 set_message(cli->outbuf,0,plength,True);
2068 p = smb_buf(cli->outbuf);
2070 prots[numprots].name && prots[numprots].prot<=cli->protocol;
2073 pstrcpy(p,prots[numprots].name);
2077 CVAL(cli->outbuf,smb_com) = SMBnegprot;
2078 cli_setup_packet(cli);
2080 CVAL(smb_buf(cli->outbuf),0) = 2;
2082 send_smb(cli->fd,cli->outbuf);
2083 if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout))
2086 show_msg(cli->inbuf);
2088 if (CVAL(cli->inbuf,smb_rcls) != 0 ||
2089 ((int)SVAL(cli->inbuf,smb_vwv0) >= numprots)) {
2093 cli->protocol = prots[SVAL(cli->inbuf,smb_vwv0)].prot;
2096 if (cli->protocol >= PROTOCOL_NT1) {
2098 cli->sec_mode = CVAL(cli->inbuf,smb_vwv1);
2099 cli->max_mux = SVAL(cli->inbuf, smb_vwv1+1);
2100 cli->max_xmit = IVAL(cli->inbuf,smb_vwv3+1);
2101 cli->sesskey = IVAL(cli->inbuf,smb_vwv7+1);
2102 cli->serverzone = SVALS(cli->inbuf,smb_vwv15+1)*60;
2103 /* this time arrives in real GMT */
2104 cli->servertime = interpret_long_date(cli->inbuf+smb_vwv11+1);
2105 memcpy(cli->cryptkey,smb_buf(cli->inbuf),8);
2106 cli->capabilities = IVAL(cli->inbuf,smb_vwv9+1);
2107 if (cli->capabilities & 1) {
2108 cli->readbraw_supported = True;
2109 cli->writebraw_supported = True;
2111 } else if (cli->protocol >= PROTOCOL_LANMAN1) {
2112 cli->sec_mode = SVAL(cli->inbuf,smb_vwv1);
2113 cli->max_xmit = SVAL(cli->inbuf,smb_vwv2);
2114 cli->sesskey = IVAL(cli->inbuf,smb_vwv6);
2115 cli->serverzone = SVALS(cli->inbuf,smb_vwv10)*60;
2116 /* this time is converted to GMT by make_unix_date */
2117 cli->servertime = make_unix_date(cli->inbuf+smb_vwv8);
2118 cli->readbraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x1) != 0);
2119 cli->writebraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x2) != 0);
2120 memcpy(cli->cryptkey,smb_buf(cli->inbuf),8);
2122 /* the old core protocol */
2124 cli->serverzone = TimeDiff(time(NULL));
2127 cli->max_xmit = MIN(cli->max_xmit, CLI_BUFFER_SIZE);
2133 /****************************************************************************
2134 send a session request. see rfc1002.txt 4.3 and 4.3.2
2135 ****************************************************************************/
2136 BOOL cli_session_request(struct cli_state *cli,
2137 struct nmb_name *calling, struct nmb_name *called)
2141 /* send a session request (RFC 1002) */
2143 memcpy(&(cli->calling), calling, sizeof(*calling));
2144 memcpy(&(cli->called ), called , sizeof(*called ));
2146 /* put in the destination name */
2147 p = cli->outbuf+len;
2148 name_mangle(cli->called .name, p, cli->called .name_type);
2152 p = cli->outbuf+len;
2153 name_mangle(cli->calling.name, p, cli->calling.name_type);
2156 /* setup the packet length */
2157 _smb_setlen(cli->outbuf,len);
2158 CVAL(cli->outbuf,0) = 0x81;
2162 #endif /* WITH_SSL */
2164 send_smb(cli->fd,cli->outbuf);
2165 DEBUG(5,("Sent session request\n"));
2167 if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout))
2171 if (CVAL(cli->inbuf,0) == 0x83 && CVAL(cli->inbuf,4) == 0x8e){ /* use ssl */
2172 if (!sslutil_fd_is_ssl(cli->fd)){
2173 if (sslutil_connect(cli->fd) == 0)
2177 #endif /* WITH_SSL */
2179 if (CVAL(cli->inbuf,0) != 0x82) {
2180 /* This is the wrong place to put the error... JRA. */
2181 cli->rap_error = CVAL(cli->inbuf,0);
2188 /****************************************************************************
2189 open the client sockets
2190 ****************************************************************************/
2191 BOOL cli_connect(struct cli_state *cli, char *host, struct in_addr *ip)
2193 struct in_addr dest_ip;
2194 extern struct in_addr ipzero;
2196 fstrcpy(cli->desthost, host);
2198 if (!ip || ip_equal(*ip, ipzero)) {
2199 if (!resolve_name( cli->desthost, &dest_ip)) {
2207 cli->fd = open_socket_out(SOCK_STREAM, &dest_ip, 139, cli->timeout);
2215 /****************************************************************************
2216 initialise a client structure
2217 ****************************************************************************/
2218 BOOL cli_initialise(struct cli_state *cli)
2220 if (cli->initialised)
2223 memset(cli, 0, sizeof(*cli));
2226 cli->pid = (uint16)getpid();
2228 cli->vuid = UID_FIELD_INVALID;
2229 cli->protocol = PROTOCOL_NT1;
2230 cli->timeout = 20000;
2231 cli->bufsize = CLI_BUFFER_SIZE+4;
2232 cli->max_xmit = cli->bufsize;
2233 cli->outbuf = (char *)malloc(cli->bufsize);
2234 cli->inbuf = (char *)malloc(cli->bufsize);
2235 if (!cli->outbuf || !cli->inbuf)
2237 cli->initialised = 1;
2241 /****************************************************************************
2242 shutdown a client structure
2243 ****************************************************************************/
2244 void cli_shutdown(struct cli_state *cli)
2252 sslutil_disconnect(cli->fd);
2253 #endif /* WITH_SSL */
2256 memset(cli, 0, sizeof(*cli));
2260 /****************************************************************************
2261 return error codes for the last packet
2262 returns 0 if there was no error and the bext approx of a unix errno
2264 ****************************************************************************/
2265 int cli_error(struct cli_state *cli, uint8 *eclass, uint32 *num)
2267 int flgs2 = SVAL(cli->inbuf,smb_flg2);
2271 if (eclass) *eclass = 0;
2274 if (flgs2 & FLAGS2_32_BIT_ERROR_CODES) {
2275 /* 32 bit error codes detected */
2276 uint32 nt_err = IVAL(cli->inbuf,smb_rcls);
2277 if (num) *num = nt_err;
2278 DEBUG(10,("cli_error: 32 bit codes: code=%08x\n", nt_err));
2279 if (!IS_BITS_SET_ALL(nt_err, 0xc0000000)) return 0;
2281 switch (nt_err & 0xFFFFFF) {
2282 case NT_STATUS_ACCESS_VIOLATION: return EACCES;
2283 case NT_STATUS_NO_SUCH_FILE: return ENOENT;
2284 case NT_STATUS_NO_SUCH_DEVICE: return ENODEV;
2285 case NT_STATUS_INVALID_HANDLE: return EBADF;
2286 case NT_STATUS_NO_MEMORY: return ENOMEM;
2287 case NT_STATUS_ACCESS_DENIED: return EACCES;
2288 case NT_STATUS_OBJECT_NAME_NOT_FOUND: return ENOENT;
2289 case NT_STATUS_SHARING_VIOLATION: return EBUSY;
2292 /* for all other cases - a default code */
2296 rcls = CVAL(cli->inbuf,smb_rcls);
2297 code = SVAL(cli->inbuf,smb_err);
2298 if (rcls == 0) return 0;
2300 if (eclass) *eclass = rcls;
2301 if (num ) *num = code;
2303 if (rcls == ERRDOS) {
2305 case ERRbadfile: return ENOENT;
2306 case ERRnoaccess: return EACCES;
2309 if (rcls == ERRSRV) {
2311 case ERRbadpw: return EPERM;
2314 /* for other cases */
2318 /****************************************************************************
2319 set socket options on a open connection
2320 ****************************************************************************/
2321 void cli_sockopt(struct cli_state *cli, char *options)
2323 set_socket_options(cli->fd, options);
2326 /****************************************************************************
2327 set the PID to use for smb messages. Return the old pid.
2328 ****************************************************************************/
2329 uint16 cli_setpid(struct cli_state *cli, uint16 pid)
2331 uint16 ret = cli->pid;
2336 /****************************************************************************
2337 establishes a connection right up to doing tconX, reading in a password.
2338 ****************************************************************************/
2339 BOOL cli_reestablish_connection(struct cli_state *cli)
2341 struct nmb_name calling;
2342 struct nmb_name called;
2344 struct in_addr dest_ip;
2347 BOOL do_tcon = False;
2349 if (!cli->initialised || cli->fd == -1)
2351 DEBUG(3,("cli_reestablish_connection: not connected\n"));
2355 /* copy the parameters necessary to re-establish the connection */
2359 fstrcpy(share, cli->share);
2360 fstrcpy(dev , cli->dev);
2364 memcpy(&called , &(cli->called ), sizeof(called ));
2365 memcpy(&calling, &(cli->calling), sizeof(calling));
2366 fstrcpy(dest_host, cli->full_dest_host_name);
2367 dest_ip = cli->dest_ip;
2369 DEBUG(5,("cli_reestablish_connection: %s connecting to %s (ip %s) - %s [%s]\n",
2370 namestr(&calling), namestr(&called), inet_ntoa(dest_ip),
2371 cli->user_name, cli->domain));
2373 return cli_establish_connection(cli,
2374 dest_host, &dest_ip,
2376 share, dev, False, do_tcon);
2379 /****************************************************************************
2380 establishes a connection right up to doing tconX, reading in a password.
2381 ****************************************************************************/
2382 BOOL cli_establish_connection(struct cli_state *cli,
2383 char *dest_host, struct in_addr *dest_ip,
2384 struct nmb_name *calling, struct nmb_name *called,
2385 char *service, char *service_type,
2386 BOOL do_shutdown, BOOL do_tcon)
2388 DEBUG(5,("cli_establish_connection: %s connecting to %s (%s) - %s [%s]\n",
2389 namestr(calling), namestr(called), inet_ntoa(*dest_ip),
2390 cli->user_name, cli->domain));
2392 /* establish connection */
2394 if ((!cli->initialised))
2401 if (!cli_connect(cli, dest_host, dest_ip))
2403 DEBUG(1,("cli_establish_connection: failed to connect to %s (%s)\n",
2404 namestr(calling), inet_ntoa(*dest_ip)));
2409 if (!cli_session_request(cli, calling, called))
2411 DEBUG(1,("failed session request\n"));
2417 if (!cli_negprot(cli))
2419 DEBUG(1,("failed negprot\n"));
2425 if (cli->pwd.cleartext || cli->pwd.null_pwd)
2427 /* attempt clear-text session */
2431 pwd_get_cleartext(&(cli->pwd), passwd);
2433 /* attempt clear-text session */
2434 if (!cli_session_setup(cli, cli->user_name,
2435 passwd, strlen(passwd),
2439 DEBUG(1,("failed session setup\n"));
2446 if (!cli_send_tconX(cli, service, service_type,
2447 (char*)passwd, strlen(passwd)))
2449 DEBUG(1,("failed tcon_X\n"));
2458 /* attempt encrypted session */
2459 unsigned char nt_sess_pwd[24];
2460 unsigned char lm_sess_pwd[24];
2462 /* creates (storing a copy of) and then obtains a 24 byte password OWF */
2463 pwd_make_lm_nt_owf(&(cli->pwd), cli->cryptkey);
2464 pwd_get_lm_nt_owf(&(cli->pwd), lm_sess_pwd, nt_sess_pwd);
2466 /* attempt encrypted session */
2467 if (!cli_session_setup(cli, cli->user_name,
2468 (char*)lm_sess_pwd, sizeof(lm_sess_pwd),
2469 (char*)nt_sess_pwd, sizeof(nt_sess_pwd),
2472 DEBUG(1,("failed session setup\n"));
2480 if (!cli_send_tconX(cli, service, service_type,
2481 (char*)nt_sess_pwd, sizeof(nt_sess_pwd)))
2483 DEBUG(1,("failed tcon_X\n"));
2498 /****************************************************************************
2500 ****************************************************************************/
2501 int cli_printjob_del(struct cli_state *cli, int job)
2503 char *rparam = NULL;
2506 int rdrcnt,rprcnt, ret = -1;
2509 bzero(param,sizeof(param));
2512 SSVAL(p,0,81); /* DosPrintJobDel() */
2515 p = skip_string(p,1);
2517 p = skip_string(p,1);
2522 param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */
2523 NULL, 0, CLI_BUFFER_SIZE, /* data, length, maxlen */
2524 &rparam, &rprcnt, /* return params, length */
2525 &rdata, &rdrcnt)) { /* return data, length */
2526 ret = SVAL(rparam,0);
2529 if (rparam) free(rparam);
2530 if (rdata) free(rdata);
2536 /****************************************************************************
2537 call fn() on each entry in a print queue
2538 ****************************************************************************/
2539 int cli_print_queue(struct cli_state *cli,
2540 void (*fn)(struct print_job_info *))
2542 char *rparam = NULL;
2550 bzero(param,sizeof(param));
2553 SSVAL(p,0,76); /* API function number 76 (DosPrintJobEnum) */
2555 pstrcpy(p,"zWrLeh"); /* parameter description? */
2556 p = skip_string(p,1);
2557 pstrcpy(p,"WWzWWDDzz"); /* returned data format */
2558 p = skip_string(p,1);
2559 pstrcpy(p,cli->share); /* name of queue */
2560 p = skip_string(p,1);
2561 SSVAL(p,0,2); /* API function level 2, PRJINFO_2 data structure */
2562 SSVAL(p,2,1000); /* size of bytes of returned data buffer */
2564 pstrcpy(p,""); /* subformat */
2565 p = skip_string(p,1);
2567 DEBUG(4,("doing cli_print_queue for %s\n", cli->share));
2570 param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */
2571 NULL, 0, CLI_BUFFER_SIZE, /* data, length, maxlen */
2572 &rparam, &rprcnt, /* return params, length */
2573 &rdata, &rdrcnt)) { /* return data, length */
2575 result_code = SVAL(rparam,0);
2576 converter = SVAL(rparam,2); /* conversion factor */
2578 if (result_code == 0) {
2579 struct print_job_info job;
2583 for (i = 0; i < SVAL(rparam,4); ++i) {
2585 job.priority = SVAL(p,2);
2587 fix_char_ptr(SVAL(p,4), converter,
2589 job.t = make_unix_date3(p + 12);
2590 job.size = IVAL(p,16);
2591 fstrcpy(job.name,fix_char_ptr(SVAL(p,24),
2600 /* If any parameters or data were returned, free the storage. */
2601 if(rparam) free(rparam);
2602 if(rdata) free(rdata);