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);
496 param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */
497 NULL, 0, 0xFFFF, /* 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);
505 if (res == 0 || res == ERRmoredata) {
506 count=SVAL(rparam,4);
509 for (i=0;i<count;i++,p+=20) {
511 int type = SVAL(p,14);
512 int comment_offset = IVAL(p,16) & 0xFFFF;
513 char *cmnt = comment_offset?(rdata+comment_offset-converter):"";
514 fn(sname, type, cmnt);
517 DEBUG(4,("NetShareEnum res=%d\n", res));
520 DEBUG(4,("NetShareEnum failed\n"));
532 /****************************************************************************
533 call a NetServerEnum for the specified workgroup and servertype mask.
534 This function then calls the specified callback function for each name returned.
536 The callback function takes 3 arguments: the machine name, the server type and
538 ****************************************************************************/
539 BOOL cli_NetServerEnum(struct cli_state *cli, char *workgroup, uint32 stype,
540 void (*fn)(const char *, uint32, const char *))
550 /* send a SMBtrans command with api NetServerEnum */
552 SSVAL(p,0,0x68); /* api number */
554 pstrcpy(p,"WrLehDz");
555 p = skip_string(p,1);
557 pstrcpy(p,"B16BBDz");
559 p = skip_string(p,1);
561 SSVAL(p,2,CLI_BUFFER_SIZE);
566 pstrcpy(p, workgroup);
567 p = skip_string(p,1);
570 param, PTR_DIFF(p,param), 8, /* params, length, max */
571 NULL, 0, CLI_BUFFER_SIZE, /* data, length, max */
572 &rparam, &rprcnt, /* return params, return size */
573 &rdata, &rdrcnt /* return data, return size */
575 int res = SVAL(rparam,0);
576 int converter=SVAL(rparam,2);
579 if (res == 0 || res == ERRmoredata) {
580 count=SVAL(rparam,4);
583 for (i = 0;i < count;i++, p += 26) {
585 int comment_offset = (IVAL(p,22) & 0xFFFF)-converter;
586 char *cmnt = comment_offset?(rdata+comment_offset):"";
587 if (comment_offset < 0 || comment_offset > rdrcnt) continue;
589 stype = IVAL(p,18) & ~SV_TYPE_LOCAL_LIST_ONLY;
591 fn(sname, stype, cmnt);
613 {PROTOCOL_CORE,"PC NETWORK PROGRAM 1.0"},
614 {PROTOCOL_COREPLUS,"MICROSOFT NETWORKS 1.03"},
615 {PROTOCOL_LANMAN1,"MICROSOFT NETWORKS 3.0"},
616 {PROTOCOL_LANMAN1,"LANMAN1.0"},
617 {PROTOCOL_LANMAN2,"LM1.2X002"},
618 {PROTOCOL_LANMAN2,"Samba"},
619 {PROTOCOL_NT1,"NT LANMAN 1.0"},
620 {PROTOCOL_NT1,"NT LM 0.12"},
625 /****************************************************************************
627 ****************************************************************************/
628 BOOL cli_session_setup(struct cli_state *cli,
630 char *pass, int passlen,
631 char *ntpass, int ntpasslen,
635 fstring pword, ntpword;
637 if (cli->protocol < PROTOCOL_LANMAN1)
640 if (passlen > sizeof(pword)-1 || ntpasslen > sizeof(ntpword)-1) {
644 if (((passlen == 0) || (passlen == 1)) && (pass[0] == '\0')) {
645 /* Null session connect. */
649 if ((cli->sec_mode & 2) && passlen != 24) {
652 SMBencrypt((uchar *)pass,(uchar *)cli->cryptkey,(uchar *)pword);
653 SMBNTencrypt((uchar *)ntpass,(uchar *)cli->cryptkey,(uchar *)ntpword);
655 fstrcpy(pword, pass);
656 fstrcpy(ntpword, "");
661 /* if in share level security then don't send a password now */
662 if (!(cli->sec_mode & 1)) {
665 fstrcpy(ntpword, "");
669 /* send a session setup command */
670 bzero(cli->outbuf,smb_size);
672 if (cli->protocol < PROTOCOL_NT1)
674 set_message(cli->outbuf,10,1 + strlen(user) + passlen,True);
675 CVAL(cli->outbuf,smb_com) = SMBsesssetupX;
676 cli_setup_packet(cli);
678 CVAL(cli->outbuf,smb_vwv0) = 0xFF;
679 SSVAL(cli->outbuf,smb_vwv2,cli->max_xmit);
680 SSVAL(cli->outbuf,smb_vwv3,2);
681 SSVAL(cli->outbuf,smb_vwv4,1);
682 SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
683 SSVAL(cli->outbuf,smb_vwv7,passlen);
684 p = smb_buf(cli->outbuf);
685 memcpy(p,pword,passlen);
692 set_message(cli->outbuf,13,0,True);
693 CVAL(cli->outbuf,smb_com) = SMBsesssetupX;
694 cli_setup_packet(cli);
696 CVAL(cli->outbuf,smb_vwv0) = 0xFF;
697 SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
698 SSVAL(cli->outbuf,smb_vwv3,2);
699 SSVAL(cli->outbuf,smb_vwv4,cli->pid);
700 SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
701 SSVAL(cli->outbuf,smb_vwv7,passlen);
702 SSVAL(cli->outbuf,smb_vwv8,ntpasslen);
703 SSVAL(cli->outbuf,smb_vwv11,0);
704 p = smb_buf(cli->outbuf);
705 memcpy(p,pword,passlen);
706 p += SVAL(cli->outbuf,smb_vwv7);
707 memcpy(p,ntpword,ntpasslen);
708 p += SVAL(cli->outbuf,smb_vwv8);
711 p = skip_string(p,1);
712 pstrcpy(p,workgroup);
714 p = skip_string(p,1);
715 pstrcpy(p,"Unix");p = skip_string(p,1);
716 pstrcpy(p,"Samba");p = skip_string(p,1);
717 set_message(cli->outbuf,13,PTR_DIFF(p,smb_buf(cli->outbuf)),False);
720 send_smb(cli->fd,cli->outbuf);
721 if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout))
724 show_msg(cli->inbuf);
726 if (CVAL(cli->inbuf,smb_rcls) != 0) {
730 /* use the returned vuid from now on */
731 cli->vuid = SVAL(cli->inbuf,smb_uid);
736 /****************************************************************************
738 *****************************************************************************/
740 BOOL cli_ulogoff(struct cli_state *cli)
742 bzero(cli->outbuf,smb_size);
743 set_message(cli->outbuf,2,0,True);
744 CVAL(cli->outbuf,smb_com) = SMBulogoffX;
745 cli_setup_packet(cli);
746 SSVAL(cli->outbuf,smb_vwv0,0xFF);
747 SSVAL(cli->outbuf,smb_vwv2,0); /* no additional info */
749 send_smb(cli->fd,cli->outbuf);
750 if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout))
753 return CVAL(cli->inbuf,smb_rcls) == 0;
756 /****************************************************************************
758 ****************************************************************************/
759 BOOL cli_send_tconX(struct cli_state *cli,
760 char *share, char *dev, char *pass, int passlen)
762 fstring fullshare, pword;
764 bzero(cli->outbuf,smb_size);
765 bzero(cli->inbuf,smb_size);
767 fstrcpy(cli->share, share);
769 /* in user level security don't send a password now */
770 if (cli->sec_mode & 1) {
775 if ((cli->sec_mode & 2) && *pass && passlen != 24) {
777 SMBencrypt((uchar *)pass,(uchar *)cli->cryptkey,(uchar *)pword);
779 memcpy(pword, pass, passlen);
782 slprintf(fullshare, sizeof(fullshare)-1,
783 "\\\\%s\\%s", cli->desthost, share);
785 set_message(cli->outbuf,4,
786 2 + strlen(fullshare) + passlen + strlen(dev),True);
787 CVAL(cli->outbuf,smb_com) = SMBtconX;
788 cli_setup_packet(cli);
790 SSVAL(cli->outbuf,smb_vwv0,0xFF);
791 SSVAL(cli->outbuf,smb_vwv3,passlen);
793 p = smb_buf(cli->outbuf);
794 memcpy(p,pword,passlen);
796 fstrcpy(p,fullshare);
797 p = skip_string(p,1);
800 SCVAL(cli->inbuf,smb_rcls, 1);
802 send_smb(cli->fd,cli->outbuf);
803 if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout))
806 if (CVAL(cli->inbuf,smb_rcls) != 0) {
810 fstrcpy(cli->dev, "A:");
812 if (cli->protocol >= PROTOCOL_NT1) {
813 fstrcpy(cli->dev, smb_buf(cli->inbuf));
816 if (strcasecmp(share,"IPC$")==0) {
817 fstrcpy(cli->dev, "IPC");
820 /* only grab the device if we have a recent protocol level */
821 if (cli->protocol >= PROTOCOL_NT1 &&
822 smb_buflen(cli->inbuf) == 3) {
823 /* almost certainly win95 - enable bug fixes */
827 cli->cnum = SVAL(cli->inbuf,smb_tid);
832 /****************************************************************************
833 send a tree disconnect
834 ****************************************************************************/
835 BOOL cli_tdis(struct cli_state *cli)
837 bzero(cli->outbuf,smb_size);
838 set_message(cli->outbuf,0,0,True);
839 CVAL(cli->outbuf,smb_com) = SMBtdis;
840 SSVAL(cli->outbuf,smb_tid,cli->cnum);
841 cli_setup_packet(cli);
843 send_smb(cli->fd,cli->outbuf);
844 if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout))
847 return CVAL(cli->inbuf,smb_rcls) == 0;
850 /****************************************************************************
852 ****************************************************************************/
853 BOOL cli_rename(struct cli_state *cli, char *fname_src, char *fname_dst)
857 bzero(cli->outbuf,smb_size);
858 bzero(cli->inbuf,smb_size);
860 set_message(cli->outbuf,1, 4 + strlen(fname_src) + strlen(fname_dst), True);
862 CVAL(cli->outbuf,smb_com) = SMBmv;
863 SSVAL(cli->outbuf,smb_tid,cli->cnum);
864 cli_setup_packet(cli);
866 SSVAL(cli->outbuf,smb_vwv0,aSYSTEM | aHIDDEN);
868 p = smb_buf(cli->outbuf);
870 pstrcpy(p,fname_src);
871 p = skip_string(p,1);
873 pstrcpy(p,fname_dst);
875 send_smb(cli->fd,cli->outbuf);
876 if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) {
880 if (CVAL(cli->inbuf,smb_rcls) != 0) {
887 /****************************************************************************
889 ****************************************************************************/
890 BOOL cli_unlink(struct cli_state *cli, char *fname)
894 bzero(cli->outbuf,smb_size);
895 bzero(cli->inbuf,smb_size);
897 set_message(cli->outbuf,1, 2 + strlen(fname),True);
899 CVAL(cli->outbuf,smb_com) = SMBunlink;
900 SSVAL(cli->outbuf,smb_tid,cli->cnum);
901 cli_setup_packet(cli);
903 SSVAL(cli->outbuf,smb_vwv0,aSYSTEM | aHIDDEN);
905 p = smb_buf(cli->outbuf);
909 send_smb(cli->fd,cli->outbuf);
910 if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) {
914 if (CVAL(cli->inbuf,smb_rcls) != 0) {
921 /****************************************************************************
923 ****************************************************************************/
924 BOOL cli_mkdir(struct cli_state *cli, char *dname)
928 bzero(cli->outbuf,smb_size);
929 bzero(cli->inbuf,smb_size);
931 set_message(cli->outbuf,0, 2 + strlen(dname),True);
933 CVAL(cli->outbuf,smb_com) = SMBmkdir;
934 SSVAL(cli->outbuf,smb_tid,cli->cnum);
935 cli_setup_packet(cli);
937 p = smb_buf(cli->outbuf);
941 send_smb(cli->fd,cli->outbuf);
942 if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) {
946 if (CVAL(cli->inbuf,smb_rcls) != 0) {
953 /****************************************************************************
955 ****************************************************************************/
956 BOOL cli_rmdir(struct cli_state *cli, char *dname)
960 bzero(cli->outbuf,smb_size);
961 bzero(cli->inbuf,smb_size);
963 set_message(cli->outbuf,0, 2 + strlen(dname),True);
965 CVAL(cli->outbuf,smb_com) = SMBrmdir;
966 SSVAL(cli->outbuf,smb_tid,cli->cnum);
967 cli_setup_packet(cli);
969 p = smb_buf(cli->outbuf);
973 send_smb(cli->fd,cli->outbuf);
974 if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) {
978 if (CVAL(cli->inbuf,smb_rcls) != 0) {
987 /****************************************************************************
989 ****************************************************************************/
990 int cli_nt_create(struct cli_state *cli, char *fname)
994 bzero(cli->outbuf,smb_size);
995 bzero(cli->inbuf,smb_size);
997 set_message(cli->outbuf,24,1 + strlen(fname),True);
999 CVAL(cli->outbuf,smb_com) = SMBntcreateX;
1000 SSVAL(cli->outbuf,smb_tid,cli->cnum);
1001 cli_setup_packet(cli);
1003 SSVAL(cli->outbuf,smb_vwv0,0xFF);
1004 SIVAL(cli->outbuf,smb_ntcreate_Flags, 0x06);
1005 SIVAL(cli->outbuf,smb_ntcreate_RootDirectoryFid, 0x0);
1006 SIVAL(cli->outbuf,smb_ntcreate_DesiredAccess, 0x2019f);
1007 SIVAL(cli->outbuf,smb_ntcreate_FileAttributes, 0x0);
1008 SIVAL(cli->outbuf,smb_ntcreate_ShareAccess, 0x03);
1009 SIVAL(cli->outbuf,smb_ntcreate_CreateDisposition, 0x01);
1010 SIVAL(cli->outbuf,smb_ntcreate_CreateOptions, 0x0);
1011 SIVAL(cli->outbuf,smb_ntcreate_ImpersonationLevel, 0x02);
1012 SSVAL(cli->outbuf,smb_ntcreate_NameLength, strlen(fname));
1014 p = smb_buf(cli->outbuf);
1016 p = skip_string(p,1);
1018 send_smb(cli->fd,cli->outbuf);
1019 if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) {
1023 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1027 return SVAL(cli->inbuf,smb_vwv2 + 1);
1031 /****************************************************************************
1033 ****************************************************************************/
1034 int cli_open(struct cli_state *cli, char *fname, int flags, int share_mode)
1038 unsigned accessmode=0;
1040 /* you must open for RW not just write - otherwise getattrE doesn't
1042 if ((flags & O_ACCMODE) == O_WRONLY) {
1043 flags = (flags & ~O_ACCMODE) | O_RDWR;
1046 if (flags & O_CREAT)
1048 if (!(flags & O_EXCL)) {
1049 if (flags & O_TRUNC)
1055 accessmode = (share_mode<<4);
1057 if ((flags & O_ACCMODE) == O_RDWR) {
1059 } else if ((flags & O_ACCMODE) == O_WRONLY) {
1064 if ((flags & O_SYNC) == O_SYNC) {
1065 accessmode |= (1<<14);
1069 bzero(cli->outbuf,smb_size);
1070 bzero(cli->inbuf,smb_size);
1072 set_message(cli->outbuf,15,1 + strlen(fname),True);
1074 CVAL(cli->outbuf,smb_com) = SMBopenX;
1075 SSVAL(cli->outbuf,smb_tid,cli->cnum);
1076 cli_setup_packet(cli);
1078 SSVAL(cli->outbuf,smb_vwv0,0xFF);
1079 SSVAL(cli->outbuf,smb_vwv2,0); /* no additional info */
1080 SSVAL(cli->outbuf,smb_vwv3,accessmode);
1081 SSVAL(cli->outbuf,smb_vwv4,aSYSTEM | aHIDDEN);
1082 SSVAL(cli->outbuf,smb_vwv5,0);
1083 SSVAL(cli->outbuf,smb_vwv8,openfn);
1085 p = smb_buf(cli->outbuf);
1087 p = skip_string(p,1);
1089 send_smb(cli->fd,cli->outbuf);
1090 if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) {
1094 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1098 return SVAL(cli->inbuf,smb_vwv2);
1104 /****************************************************************************
1106 ****************************************************************************/
1107 BOOL cli_close(struct cli_state *cli, int fnum)
1109 bzero(cli->outbuf,smb_size);
1110 bzero(cli->inbuf,smb_size);
1112 set_message(cli->outbuf,3,0,True);
1114 CVAL(cli->outbuf,smb_com) = SMBclose;
1115 SSVAL(cli->outbuf,smb_tid,cli->cnum);
1116 cli_setup_packet(cli);
1118 SSVAL(cli->outbuf,smb_vwv0,fnum);
1119 SIVALS(cli->outbuf,smb_vwv1,-1);
1121 send_smb(cli->fd,cli->outbuf);
1122 if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) {
1126 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1134 /****************************************************************************
1136 ****************************************************************************/
1137 BOOL cli_lock(struct cli_state *cli, int fnum, uint32 offset, uint32 len, int timeout)
1140 int saved_timeout = cli->timeout;
1142 bzero(cli->outbuf,smb_size);
1143 bzero(cli->inbuf,smb_size);
1145 set_message(cli->outbuf,8,10,True);
1147 CVAL(cli->outbuf,smb_com) = SMBlockingX;
1148 SSVAL(cli->outbuf,smb_tid,cli->cnum);
1149 cli_setup_packet(cli);
1151 CVAL(cli->outbuf,smb_vwv0) = 0xFF;
1152 SSVAL(cli->outbuf,smb_vwv2,fnum);
1153 CVAL(cli->outbuf,smb_vwv3) = 0;
1154 SIVALS(cli->outbuf, smb_vwv4, timeout);
1155 SSVAL(cli->outbuf,smb_vwv6,0);
1156 SSVAL(cli->outbuf,smb_vwv7,1);
1158 p = smb_buf(cli->outbuf);
1159 SSVAL(p, 0, cli->pid);
1160 SIVAL(p, 2, offset);
1163 send_smb(cli->fd,cli->outbuf);
1165 cli->timeout = (timeout == -1) ? 0x7FFFFFFF : timeout;
1167 if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) {
1168 cli->timeout = saved_timeout;
1172 cli->timeout = saved_timeout;
1174 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1181 /****************************************************************************
1183 ****************************************************************************/
1184 BOOL cli_unlock(struct cli_state *cli, int fnum, uint32 offset, uint32 len, int timeout)
1188 bzero(cli->outbuf,smb_size);
1189 bzero(cli->inbuf,smb_size);
1191 set_message(cli->outbuf,8,10,True);
1193 CVAL(cli->outbuf,smb_com) = SMBlockingX;
1194 SSVAL(cli->outbuf,smb_tid,cli->cnum);
1195 cli_setup_packet(cli);
1197 CVAL(cli->outbuf,smb_vwv0) = 0xFF;
1198 SSVAL(cli->outbuf,smb_vwv2,fnum);
1199 CVAL(cli->outbuf,smb_vwv3) = 0;
1200 SIVALS(cli->outbuf, smb_vwv4, timeout);
1201 SSVAL(cli->outbuf,smb_vwv6,1);
1202 SSVAL(cli->outbuf,smb_vwv7,0);
1204 p = smb_buf(cli->outbuf);
1205 SSVAL(p, 0, cli->pid);
1206 SIVAL(p, 2, offset);
1209 send_smb(cli->fd,cli->outbuf);
1210 if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) {
1214 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1223 /****************************************************************************
1224 issue a single SMBread and don't wait for a reply
1225 ****************************************************************************/
1226 static void cli_issue_read(struct cli_state *cli, int fnum, off_t offset,
1229 bzero(cli->outbuf,smb_size);
1230 bzero(cli->inbuf,smb_size);
1232 set_message(cli->outbuf,10,0,True);
1234 CVAL(cli->outbuf,smb_com) = SMBreadX;
1235 SSVAL(cli->outbuf,smb_tid,cli->cnum);
1236 cli_setup_packet(cli);
1238 CVAL(cli->outbuf,smb_vwv0) = 0xFF;
1239 SSVAL(cli->outbuf,smb_vwv2,fnum);
1240 SIVAL(cli->outbuf,smb_vwv3,offset);
1241 SSVAL(cli->outbuf,smb_vwv5,size);
1242 SSVAL(cli->outbuf,smb_vwv6,size);
1243 SSVAL(cli->outbuf,smb_mid,cli->mid + i);
1245 send_smb(cli->fd,cli->outbuf);
1248 /****************************************************************************
1250 ****************************************************************************/
1251 size_t cli_read(struct cli_state *cli, int fnum, char *buf, off_t offset, size_t size)
1257 int mpx = MAX(cli->max_mux-1, 1);
1258 int block = (cli->max_xmit - (smb_size+32)) & ~1023;
1260 int blocks = (size + (block-1)) / block;
1262 if (size == 0) return 0;
1264 while (received < blocks) {
1267 while (issued - received < mpx && issued < blocks) {
1268 int size1 = MIN(block, size-issued*block);
1269 cli_issue_read(cli, fnum, offset+issued*block, size1, issued);
1273 if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) {
1278 mid = SVAL(cli->inbuf, smb_mid) - cli->mid;
1279 size2 = SVAL(cli->inbuf, smb_vwv5);
1281 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1282 blocks = MIN(blocks, mid-1);
1287 blocks = MIN(blocks, mid-1);
1288 /* this distinguishes EOF from an error */
1289 total = MAX(total, 0);
1293 if (size2 > block) {
1294 DEBUG(0,("server returned more than we wanted!\n"));
1297 if (mid >= issued) {
1298 DEBUG(0,("invalid mid from server!\n"));
1301 p = smb_base(cli->inbuf) + SVAL(cli->inbuf,smb_vwv6);
1303 memcpy(buf+mid*block, p, size2);
1305 total = MAX(total, mid*block + size2);
1308 while (received < issued) {
1309 client_receive_smb(cli->fd,cli->inbuf,cli->timeout);
1317 /****************************************************************************
1318 issue a single SMBwrite and don't wait for a reply
1319 ****************************************************************************/
1320 static void cli_issue_write(struct cli_state *cli, int fnum, off_t offset, uint16 mode, char *buf,
1325 bzero(cli->outbuf,smb_size);
1326 bzero(cli->inbuf,smb_size);
1328 set_message(cli->outbuf,12,size,True);
1330 CVAL(cli->outbuf,smb_com) = SMBwriteX;
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);
1337 SIVAL(cli->outbuf,smb_vwv3,offset);
1338 SIVAL(cli->outbuf,smb_vwv5,IS_BITS_SET_ALL(mode, 0x0008) ? 0xFFFFFFFF : 0);
1339 SSVAL(cli->outbuf,smb_vwv7,mode);
1341 SSVAL(cli->outbuf,smb_vwv8,IS_BITS_SET_ALL(mode, 0x0008) ? size : 0);
1342 SSVAL(cli->outbuf,smb_vwv10,size);
1343 SSVAL(cli->outbuf,smb_vwv11,
1344 smb_buf(cli->outbuf) - smb_base(cli->outbuf));
1346 p = smb_base(cli->outbuf) + SVAL(cli->outbuf,smb_vwv11);
1347 memcpy(p, buf, size);
1349 SSVAL(cli->outbuf,smb_mid,cli->mid + i);
1351 show_msg(cli->outbuf);
1352 send_smb(cli->fd,cli->outbuf);
1355 /****************************************************************************
1357 write_mode: 0x0001 disallow write cacheing
1358 0x0002 return bytes remaining
1359 0x0004 use raw named pipe protocol
1360 0x0008 start of message mode named pipe protocol
1361 ****************************************************************************/
1362 size_t cli_write(struct cli_state *cli,
1363 int fnum, uint16 write_mode,
1364 char *buf, off_t offset, size_t size)
1369 int mpx = MAX(cli->max_mux-1, 1);
1370 int block = (cli->max_xmit - (smb_size+32)) & ~1023;
1372 int blocks = (size + (block-1)) / block;
1374 if (size == 0) return 0;
1376 while (received < blocks) {
1379 while (issued - received < mpx && issued < blocks) {
1380 int size1 = MIN(block, size-issued*block);
1381 cli_issue_write(cli, fnum, offset+issued*block,
1388 if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) {
1393 mid = SVAL(cli->inbuf, smb_mid) - cli->mid;
1394 size2 = SVAL(cli->inbuf, smb_vwv2);
1396 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1397 blocks = MIN(blocks, mid-1);
1402 blocks = MIN(blocks, mid-1);
1403 /* this distinguishes EOF from an error */
1404 total = MAX(total, 0);
1410 total = MAX(total, mid*block + size2);
1413 while (received < issued) {
1414 client_receive_smb(cli->fd,cli->inbuf,cli->timeout);
1422 /****************************************************************************
1423 do a SMBgetattrE call
1424 ****************************************************************************/
1425 BOOL cli_getattrE(struct cli_state *cli, int fd,
1426 uint32 *attr, size_t *size,
1427 time_t *c_time, time_t *a_time, time_t *m_time)
1429 bzero(cli->outbuf,smb_size);
1430 bzero(cli->inbuf,smb_size);
1432 set_message(cli->outbuf,2,0,True);
1434 CVAL(cli->outbuf,smb_com) = SMBgetattrE;
1435 SSVAL(cli->outbuf,smb_tid,cli->cnum);
1436 cli_setup_packet(cli);
1438 SSVAL(cli->outbuf,smb_vwv0,fd);
1440 send_smb(cli->fd,cli->outbuf);
1441 if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) {
1445 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1450 *size = IVAL(cli->inbuf, smb_vwv6);
1454 *attr = SVAL(cli->inbuf,smb_vwv10);
1458 *c_time = make_unix_date3(cli->inbuf+smb_vwv0);
1462 *a_time = make_unix_date3(cli->inbuf+smb_vwv2);
1466 *m_time = make_unix_date3(cli->inbuf+smb_vwv4);
1473 /****************************************************************************
1475 ****************************************************************************/
1476 BOOL cli_getatr(struct cli_state *cli, char *fname,
1477 uint32 *attr, size_t *size, time_t *t)
1481 bzero(cli->outbuf,smb_size);
1482 bzero(cli->inbuf,smb_size);
1484 set_message(cli->outbuf,0,strlen(fname)+2,True);
1486 CVAL(cli->outbuf,smb_com) = SMBgetatr;
1487 SSVAL(cli->outbuf,smb_tid,cli->cnum);
1488 cli_setup_packet(cli);
1490 p = smb_buf(cli->outbuf);
1492 pstrcpy(p+1, fname);
1494 send_smb(cli->fd,cli->outbuf);
1495 if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) {
1499 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1504 *size = IVAL(cli->inbuf, smb_vwv3);
1508 *t = make_unix_date3(cli->inbuf+smb_vwv1);
1512 *attr = SVAL(cli->inbuf,smb_vwv0);
1520 /****************************************************************************
1522 ****************************************************************************/
1523 BOOL cli_setatr(struct cli_state *cli, char *fname, int attr, time_t t)
1527 bzero(cli->outbuf,smb_size);
1528 bzero(cli->inbuf,smb_size);
1530 set_message(cli->outbuf,8,strlen(fname)+4,True);
1532 CVAL(cli->outbuf,smb_com) = SMBsetatr;
1533 SSVAL(cli->outbuf,smb_tid,cli->cnum);
1534 cli_setup_packet(cli);
1536 SSVAL(cli->outbuf,smb_vwv0, attr);
1537 put_dos_date3(cli->outbuf,smb_vwv1, t);
1539 p = smb_buf(cli->outbuf);
1541 pstrcpy(p+1, fname);
1542 p = skip_string(p,1);
1545 send_smb(cli->fd,cli->outbuf);
1546 if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout)) {
1550 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1557 /****************************************************************************
1558 send a qpathinfo call
1559 ****************************************************************************/
1560 BOOL cli_qpathinfo(struct cli_state *cli, const char *fname,
1561 time_t *c_time, time_t *a_time, time_t *m_time,
1562 size_t *size, uint32 *mode)
1566 uint16 setup = TRANSACT2_QPATHINFO;
1568 char *rparam=NULL, *rdata=NULL;
1571 time_t (*date_fn)(void *);
1573 param_len = strlen(fname) + 7;
1575 memset(param, 0, param_len);
1576 SSVAL(param, 0, SMB_INFO_STANDARD);
1577 pstrcpy(¶m[6], fname);
1580 ret = (cli_send_trans(cli, SMBtrans2,
1581 NULL, 0, /* Name, length */
1582 -1, 0, /* fid, flags */
1583 &setup, 1, 0, /* setup, length, max */
1584 param, param_len, 10, /* param, length, max */
1585 NULL, data_len, cli->max_xmit /* data, length, max */
1587 cli_receive_trans(cli, SMBtrans2,
1588 &rparam, ¶m_len,
1589 &rdata, &data_len));
1591 /* we need to work around a Win95 bug - sometimes
1592 it gives ERRSRV/ERRerror temprarily */
1595 cli_error(cli, &eclass, &ecode);
1596 if (eclass != ERRSRV || ecode != ERRerror) break;
1599 } while (count-- && ret==False);
1601 if (!ret || !rdata || data_len < 22) {
1606 date_fn = make_unix_date;
1608 date_fn = make_unix_date2;
1612 *c_time = date_fn(rdata+0);
1615 *a_time = date_fn(rdata+4);
1618 *m_time = date_fn(rdata+8);
1621 *size = IVAL(rdata, 12);
1624 *mode = SVAL(rdata,l1_attrFile);
1627 if (rdata) free(rdata);
1628 if (rparam) free(rparam);
1632 /****************************************************************************
1633 send a qpathinfo call with the SMB_QUERY_FILE_ALL_INFO info level
1634 ****************************************************************************/
1635 BOOL cli_qpathinfo2(struct cli_state *cli, const char *fname,
1636 time_t *c_time, time_t *a_time, time_t *m_time,
1637 time_t *w_time, size_t *size, uint32 *mode)
1641 uint16 setup = TRANSACT2_QPATHINFO;
1643 char *rparam=NULL, *rdata=NULL;
1645 param_len = strlen(fname) + 7;
1647 memset(param, 0, param_len);
1648 SSVAL(param, 0, SMB_QUERY_FILE_ALL_INFO);
1649 pstrcpy(¶m[6], fname);
1651 if (!cli_send_trans(cli, SMBtrans2,
1652 NULL, 0, /* name, length */
1653 -1, 0, /* fid, flags */
1654 &setup, 1, 0, /* setup, length, max */
1655 param, param_len, 10, /* param, length, max */
1656 NULL, data_len, cli->max_xmit /* data, length, max */
1661 if (!cli_receive_trans(cli, SMBtrans2,
1662 &rparam, ¶m_len,
1663 &rdata, &data_len)) {
1667 if (!rdata || data_len < 22) {
1672 *c_time = interpret_long_date(rdata+0) - cli->serverzone;
1675 *a_time = interpret_long_date(rdata+8) - cli->serverzone;
1678 *m_time = interpret_long_date(rdata+16) - cli->serverzone;
1681 *w_time = interpret_long_date(rdata+24) - cli->serverzone;
1684 *size = IVAL(rdata, 40);
1687 *mode = IVAL(rdata, 32);
1690 if (rdata) free(rdata);
1691 if (rparam) free(rparam);
1696 /****************************************************************************
1697 send a qfileinfo call
1698 ****************************************************************************/
1699 BOOL cli_qfileinfo(struct cli_state *cli, int fnum,
1700 uint32 *mode, size_t *size,
1701 time_t *c_time, time_t *a_time, time_t *m_time)
1705 uint16 setup = TRANSACT2_QFILEINFO;
1707 char *rparam=NULL, *rdata=NULL;
1711 memset(param, 0, param_len);
1712 SSVAL(param, 0, fnum);
1713 SSVAL(param, 2, SMB_INFO_STANDARD);
1715 if (!cli_send_trans(cli, SMBtrans2,
1716 NULL, 0, /* name, length */
1717 -1, 0, /* fid, flags */
1718 &setup, 1, 0, /* setup, length, max */
1719 param, param_len, 2, /* param, length, max */
1720 NULL, data_len, cli->max_xmit /* data, length, max */
1725 if (!cli_receive_trans(cli, SMBtrans2,
1726 &rparam, ¶m_len,
1727 &rdata, &data_len)) {
1731 if (!rdata || data_len < 22) {
1736 *c_time = make_unix_date2(rdata+0);
1739 *a_time = make_unix_date2(rdata+4);
1742 *m_time = make_unix_date2(rdata+8);
1745 *size = IVAL(rdata, 12);
1748 *mode = SVAL(rdata,l1_attrFile);
1751 if (rdata) free(rdata);
1752 if (rparam) free(rparam);
1757 /****************************************************************************
1758 interpret a long filename structure - this is mostly guesses at the moment
1759 The length of the structure is returned
1760 The structure of a long filename depends on the info level. 260 is used
1761 by NT and 2 is used by OS/2
1762 ****************************************************************************/
1763 static int interpret_long_filename(int level,char *p,file_info *finfo)
1765 extern file_info def_finfo;
1768 memcpy(finfo,&def_finfo,sizeof(*finfo));
1772 case 1: /* OS/2 understands this */
1774 /* these dates are converted to GMT by make_unix_date */
1775 finfo->ctime = make_unix_date2(p+4);
1776 finfo->atime = make_unix_date2(p+8);
1777 finfo->mtime = make_unix_date2(p+12);
1778 finfo->size = IVAL(p,16);
1779 finfo->mode = CVAL(p,24);
1780 pstrcpy(finfo->name,p+27);
1782 return(28 + CVAL(p,26));
1784 case 2: /* this is what OS/2 uses mostly */
1786 /* these dates are converted to GMT by make_unix_date */
1787 finfo->ctime = make_unix_date2(p+4);
1788 finfo->atime = make_unix_date2(p+8);
1789 finfo->mtime = make_unix_date2(p+12);
1790 finfo->size = IVAL(p,16);
1791 finfo->mode = CVAL(p,24);
1792 pstrcpy(finfo->name,p+31);
1794 return(32 + CVAL(p,30));
1796 /* levels 3 and 4 are untested */
1799 /* these dates are probably like the other ones */
1800 finfo->ctime = make_unix_date2(p+8);
1801 finfo->atime = make_unix_date2(p+12);
1802 finfo->mtime = make_unix_date2(p+16);
1803 finfo->size = IVAL(p,20);
1804 finfo->mode = CVAL(p,28);
1805 pstrcpy(finfo->name,p+33);
1807 return(SVAL(p,4)+4);
1811 /* these dates are probably like the other ones */
1812 finfo->ctime = make_unix_date2(p+8);
1813 finfo->atime = make_unix_date2(p+12);
1814 finfo->mtime = make_unix_date2(p+16);
1815 finfo->size = IVAL(p,20);
1816 finfo->mode = CVAL(p,28);
1817 pstrcpy(finfo->name,p+37);
1819 return(SVAL(p,4)+4);
1821 case 260: /* NT uses this, but also accepts 2 */
1823 int ret = SVAL(p,0);
1825 p += 4; /* next entry offset */
1826 p += 4; /* fileindex */
1828 /* these dates appear to arrive in a
1829 weird way. It seems to be localtime
1830 plus the serverzone given in the
1831 initial connect. This is GMT when
1832 DST is not in effect and one hour
1833 from GMT otherwise. Can this really
1836 I suppose this could be called
1837 kludge-GMT. Is is the GMT you get
1838 by using the current DST setting on
1839 a different localtime. It will be
1840 cheap to calculate, I suppose, as
1841 no DST tables will be needed */
1843 finfo->ctime = interpret_long_date(p); p += 8;
1844 finfo->atime = interpret_long_date(p); p += 8;
1845 finfo->mtime = interpret_long_date(p); p += 8; p += 8;
1846 finfo->size = IVAL(p,0); p += 8;
1847 p += 8; /* alloc size */
1848 finfo->mode = CVAL(p,0); p += 4;
1849 namelen = IVAL(p,0); p += 4;
1850 p += 4; /* EA size */
1851 p += 2; /* short name len? */
1852 p += 24; /* short name? */
1853 StrnCpy(finfo->name,p,namelen);
1859 DEBUG(1,("Unknown long filename format %d\n",level));
1864 /****************************************************************************
1865 do a directory listing, calling fn on each file found
1866 ****************************************************************************/
1867 int cli_list(struct cli_state *cli,char *Mask,int attribute,void (*fn)(file_info *))
1869 int max_matches = 512;
1870 /* NT uses 260, OS/2 uses 2. Both accept 1. */
1871 int info_level = cli->protocol<PROTOCOL_NT1?1:260;
1876 char *dirlist = NULL;
1877 int dirlist_len = 0;
1878 int total_received = -1;
1880 int ff_resume_key = 0;
1881 int ff_searchcount=0;
1884 int ff_dir_handle=0;
1886 char *rparam=NULL, *rdata=NULL;
1887 int param_len, data_len;
1894 while (ff_eos == 0) {
1896 if (loop_count > 200) {
1897 DEBUG(0,("Error: Looping in FIND_NEXT??\n"));
1901 param_len = 12+strlen(mask)+1;
1904 setup = TRANSACT2_FINDFIRST;
1905 SSVAL(param,0,attribute); /* attribute */
1906 SSVAL(param,2,max_matches); /* max count */
1907 SSVAL(param,4,8+4+2); /* resume required + close on end + continue */
1908 SSVAL(param,6,info_level);
1910 pstrcpy(param+12,mask);
1912 setup = TRANSACT2_FINDNEXT;
1913 SSVAL(param,0,ff_dir_handle);
1914 SSVAL(param,2,max_matches); /* max count */
1915 SSVAL(param,4,info_level);
1916 SIVAL(param,6,ff_resume_key); /* ff_resume_key */
1917 SSVAL(param,10,8+4+2); /* resume required + close on end + continue */
1918 pstrcpy(param+12,mask);
1920 DEBUG(5,("hand=0x%X resume=%d ff_lastname=%d mask=%s\n",
1921 ff_dir_handle,ff_resume_key,ff_lastname,mask));
1924 if (!cli_send_trans(cli, SMBtrans2,
1925 NULL, 0, /* Name, length */
1926 -1, 0, /* fid, flags */
1927 &setup, 1, 0, /* setup, length, max */
1928 param, param_len, 10, /* param, length, max */
1930 cli->max_xmit /* data, length, max */
1935 if (!cli_receive_trans(cli, SMBtrans2,
1936 &rparam, ¶m_len,
1937 &rdata, &data_len)) {
1938 /* we need to work around a Win95 bug - sometimes
1939 it gives ERRSRV/ERRerror temprarily */
1942 cli_error(cli, &eclass, &ecode);
1943 if (eclass != ERRSRV || ecode != ERRerror) break;
1948 if (total_received == -1) total_received = 0;
1950 /* parse out some important return info */
1953 ff_dir_handle = SVAL(p,0);
1954 ff_searchcount = SVAL(p,2);
1956 ff_lastname = SVAL(p,8);
1958 ff_searchcount = SVAL(p,0);
1960 ff_lastname = SVAL(p,6);
1963 if (ff_searchcount == 0)
1966 /* point to the data bytes */
1969 /* we might need the lastname for continuations */
1970 if (ff_lastname > 0) {
1975 StrnCpy(mask,p+ff_lastname,
1976 data_len-ff_lastname);
1979 pstrcpy(mask,p + ff_lastname + 1);
1987 /* and add them to the dirlist pool */
1988 dirlist = Realloc(dirlist,dirlist_len + data_len);
1991 DEBUG(0,("Failed to expand dirlist\n"));
1995 /* put in a length for the last entry, to ensure we can chain entries
1996 into the next packet */
1997 for (p2=p,i=0;i<(ff_searchcount-1);i++)
1998 p2 += interpret_long_filename(info_level,p2,NULL);
1999 SSVAL(p2,0,data_len - PTR_DIFF(p2,p));
2001 /* grab the data for later use */
2002 memcpy(dirlist+dirlist_len,p,data_len);
2003 dirlist_len += data_len;
2005 total_received += ff_searchcount;
2007 if (rdata) free(rdata); rdata = NULL;
2008 if (rparam) free(rparam); rparam = NULL;
2010 DEBUG(3,("received %d entries (eos=%d resume=%d)\n",
2011 ff_searchcount,ff_eos,ff_resume_key));
2016 for (p=dirlist,i=0;i<total_received;i++) {
2017 p += interpret_long_filename(info_level,p,&finfo);
2021 /* free up the dirlist buffer */
2022 if (dirlist) free(dirlist);
2023 return(total_received);
2027 /****************************************************************************
2028 Send a SamOEMChangePassword command
2029 ****************************************************************************/
2031 BOOL cli_oem_change_password(struct cli_state *cli, char *user, char *new_password,
2034 char param[16+sizeof(fstring)];
2037 fstring upper_case_old_pw;
2038 fstring upper_case_new_pw;
2039 unsigned char old_pw_hash[16];
2040 unsigned char new_pw_hash[16];
2043 char *rparam = NULL;
2047 if (strlen(user) >= sizeof(fstring)-1) {
2048 DEBUG(0,("cli_oem_change_password: user name %s is too long.\n", user));
2052 SSVAL(p,0,214); /* SamOEMChangePassword command. */
2055 p = skip_string(p,1);
2056 pstrcpy(p, "B516B16");
2057 p = skip_string(p,1);
2059 p = skip_string(p,1);
2063 param_len = PTR_DIFF(p,param);
2066 * Get the Lanman hash of the old password, we
2067 * use this as the key to make_oem_passwd_hash().
2069 memset(upper_case_old_pw, '\0', sizeof(upper_case_old_pw));
2070 fstrcpy(upper_case_old_pw, old_password);
2071 strupper(upper_case_old_pw);
2072 E_P16((uchar *)upper_case_old_pw, old_pw_hash);
2074 if (!make_oem_passwd_hash( data, new_password, old_pw_hash, False))
2080 * Now place the old password hash in the data.
2082 memset(upper_case_new_pw, '\0', sizeof(upper_case_new_pw));
2083 fstrcpy(upper_case_new_pw, new_password);
2084 strupper(upper_case_new_pw);
2086 E_P16((uchar *)upper_case_new_pw, new_pw_hash);
2088 E_old_pw_hash( new_pw_hash, old_pw_hash, (uchar *)&data[516]);
2092 if (cli_send_trans(cli,SMBtrans,
2093 PIPE_LANMAN,strlen(PIPE_LANMAN), /* name, length */
2094 0,0, /* fid, flags */
2095 NULL,0,0, /* setup, length, max */
2096 param,param_len,2, /* param, length, max */
2097 data,data_len,0 /* data, length, max */
2099 DEBUG(0,("cli_oem_change_password: Failed to send password change for user %s\n",
2104 if (cli_receive_trans(cli,SMBtrans,
2108 cli->rap_error = SVAL(rparam,0);
2116 return (cli->rap_error == 0);
2119 /****************************************************************************
2120 send a negprot command
2121 ****************************************************************************/
2122 BOOL cli_negprot(struct cli_state *cli)
2128 bzero(cli->outbuf,smb_size);
2130 /* setup the protocol strings */
2131 for (plength=0,numprots=0;
2132 prots[numprots].name && prots[numprots].prot<=cli->protocol;
2134 plength += strlen(prots[numprots].name)+2;
2136 set_message(cli->outbuf,0,plength,True);
2138 p = smb_buf(cli->outbuf);
2140 prots[numprots].name && prots[numprots].prot<=cli->protocol;
2143 pstrcpy(p,prots[numprots].name);
2147 CVAL(cli->outbuf,smb_com) = SMBnegprot;
2148 cli_setup_packet(cli);
2150 CVAL(smb_buf(cli->outbuf),0) = 2;
2152 send_smb(cli->fd,cli->outbuf);
2153 if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout))
2156 show_msg(cli->inbuf);
2158 if (CVAL(cli->inbuf,smb_rcls) != 0 ||
2159 ((int)SVAL(cli->inbuf,smb_vwv0) >= numprots)) {
2163 cli->protocol = prots[SVAL(cli->inbuf,smb_vwv0)].prot;
2166 if (cli->protocol >= PROTOCOL_NT1) {
2168 cli->sec_mode = CVAL(cli->inbuf,smb_vwv1);
2169 cli->max_mux = SVAL(cli->inbuf, smb_vwv1+1);
2170 cli->max_xmit = IVAL(cli->inbuf,smb_vwv3+1);
2171 cli->sesskey = IVAL(cli->inbuf,smb_vwv7+1);
2172 cli->serverzone = SVALS(cli->inbuf,smb_vwv15+1)*60;
2173 /* this time arrives in real GMT */
2174 cli->servertime = interpret_long_date(cli->inbuf+smb_vwv11+1);
2175 memcpy(cli->cryptkey,smb_buf(cli->inbuf),8);
2176 cli->capabilities = IVAL(cli->inbuf,smb_vwv9+1);
2177 if (cli->capabilities & 1) {
2178 cli->readbraw_supported = True;
2179 cli->writebraw_supported = True;
2181 } else if (cli->protocol >= PROTOCOL_LANMAN1) {
2182 cli->sec_mode = SVAL(cli->inbuf,smb_vwv1);
2183 cli->max_xmit = SVAL(cli->inbuf,smb_vwv2);
2184 cli->sesskey = IVAL(cli->inbuf,smb_vwv6);
2185 cli->serverzone = SVALS(cli->inbuf,smb_vwv10)*60;
2186 /* this time is converted to GMT by make_unix_date */
2187 cli->servertime = make_unix_date(cli->inbuf+smb_vwv8);
2188 cli->readbraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x1) != 0);
2189 cli->writebraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x2) != 0);
2190 memcpy(cli->cryptkey,smb_buf(cli->inbuf),8);
2192 /* the old core protocol */
2194 cli->serverzone = TimeDiff(time(NULL));
2197 cli->max_xmit = MIN(cli->max_xmit, CLI_BUFFER_SIZE);
2203 /****************************************************************************
2204 send a session request. see rfc1002.txt 4.3 and 4.3.2
2205 ****************************************************************************/
2206 BOOL cli_session_request(struct cli_state *cli,
2207 struct nmb_name *calling, struct nmb_name *called)
2211 /* send a session request (RFC 1002) */
2213 memcpy(&(cli->calling), calling, sizeof(*calling));
2214 memcpy(&(cli->called ), called , sizeof(*called ));
2216 /* put in the destination name */
2217 p = cli->outbuf+len;
2218 name_mangle(cli->called .name, p, cli->called .name_type);
2222 p = cli->outbuf+len;
2223 name_mangle(cli->calling.name, p, cli->calling.name_type);
2226 /* setup the packet length */
2227 _smb_setlen(cli->outbuf,len);
2228 CVAL(cli->outbuf,0) = 0x81;
2232 #endif /* WITH_SSL */
2234 send_smb(cli->fd,cli->outbuf);
2235 DEBUG(5,("Sent session request\n"));
2237 if (!client_receive_smb(cli->fd,cli->inbuf,cli->timeout))
2241 if (CVAL(cli->inbuf,0) == 0x83 && CVAL(cli->inbuf,4) == 0x8e){ /* use ssl */
2242 if (!sslutil_fd_is_ssl(cli->fd)){
2243 if (sslutil_connect(cli->fd) == 0)
2247 #endif /* WITH_SSL */
2249 if (CVAL(cli->inbuf,0) != 0x82) {
2250 /* This is the wrong place to put the error... JRA. */
2251 cli->rap_error = CVAL(cli->inbuf,0);
2258 /****************************************************************************
2259 open the client sockets
2260 ****************************************************************************/
2261 BOOL cli_connect(struct cli_state *cli, char *host, struct in_addr *ip)
2263 struct in_addr dest_ip;
2264 extern struct in_addr ipzero;
2266 fstrcpy(cli->desthost, host);
2268 if (!ip || ip_equal(*ip, ipzero)) {
2269 if (!resolve_name( cli->desthost, &dest_ip, 0x20)) {
2272 if (ip) *ip = dest_ip;
2278 cli->fd = open_socket_out(SOCK_STREAM, &dest_ip, 139, cli->timeout);
2286 /****************************************************************************
2287 initialise a client structure
2288 ****************************************************************************/
2289 BOOL cli_initialise(struct cli_state *cli)
2291 if (cli->initialised)
2296 memset(cli, 0, sizeof(*cli));
2300 cli->pid = (uint16)getpid();
2302 cli->vuid = UID_FIELD_INVALID;
2303 cli->protocol = PROTOCOL_NT1;
2304 cli->timeout = 20000;
2305 cli->bufsize = CLI_BUFFER_SIZE+4;
2306 cli->max_xmit = cli->bufsize;
2307 cli->outbuf = (char *)malloc(cli->bufsize);
2308 cli->inbuf = (char *)malloc(cli->bufsize);
2309 if (!cli->outbuf || !cli->inbuf)
2314 cli->initialised = 1;
2319 /****************************************************************************
2320 shutdown a client structure
2321 ****************************************************************************/
2322 void cli_shutdown(struct cli_state *cli)
2334 sslutil_disconnect(cli->fd);
2335 #endif /* WITH_SSL */
2338 memset(cli, 0, sizeof(*cli));
2342 /****************************************************************************
2343 return error codes for the last packet
2344 returns 0 if there was no error and the best approx of a unix errno
2347 for 32 bit "warnings", a return code of 0 is expected.
2349 ****************************************************************************/
2350 int cli_error(struct cli_state *cli, uint8 *eclass, uint32 *num)
2352 int flgs2 = SVAL(cli->inbuf,smb_flg2);
2356 if (eclass) *eclass = 0;
2359 if (flgs2 & FLAGS2_32_BIT_ERROR_CODES) {
2360 /* 32 bit error codes detected */
2361 uint32 nt_err = IVAL(cli->inbuf,smb_rcls);
2362 if (num) *num = nt_err;
2363 DEBUG(10,("cli_error: 32 bit codes: code=%08x\n", nt_err));
2364 if (!IS_BITS_SET_ALL(nt_err, 0xc0000000)) return 0;
2366 switch (nt_err & 0xFFFFFF) {
2367 case NT_STATUS_ACCESS_VIOLATION: return EACCES;
2368 case NT_STATUS_NO_SUCH_FILE: return ENOENT;
2369 case NT_STATUS_NO_SUCH_DEVICE: return ENODEV;
2370 case NT_STATUS_INVALID_HANDLE: return EBADF;
2371 case NT_STATUS_NO_MEMORY: return ENOMEM;
2372 case NT_STATUS_ACCESS_DENIED: return EACCES;
2373 case NT_STATUS_OBJECT_NAME_NOT_FOUND: return ENOENT;
2374 case NT_STATUS_SHARING_VIOLATION: return EBUSY;
2375 case NT_STATUS_OBJECT_PATH_INVALID: return ENOTDIR;
2376 case NT_STATUS_OBJECT_NAME_COLLISION: return EEXIST;
2379 /* for all other cases - a default code */
2383 rcls = CVAL(cli->inbuf,smb_rcls);
2384 code = SVAL(cli->inbuf,smb_err);
2385 if (rcls == 0) return 0;
2387 if (eclass) *eclass = rcls;
2388 if (num ) *num = code;
2390 if (rcls == ERRDOS) {
2392 case ERRbadfile: return ENOENT;
2393 case ERRbadpath: return ENOTDIR;
2394 case ERRnoaccess: return EACCES;
2395 case ERRfilexists: return EEXIST;
2396 case ERRrename: return EEXIST;
2399 if (rcls == ERRSRV) {
2401 case ERRbadpw: return EPERM;
2404 /* for other cases */
2408 /****************************************************************************
2409 set socket options on a open connection
2410 ****************************************************************************/
2411 void cli_sockopt(struct cli_state *cli, char *options)
2413 set_socket_options(cli->fd, options);
2416 /****************************************************************************
2417 set the PID to use for smb messages. Return the old pid.
2418 ****************************************************************************/
2419 uint16 cli_setpid(struct cli_state *cli, uint16 pid)
2421 uint16 ret = cli->pid;
2426 /****************************************************************************
2427 establishes a connection right up to doing tconX, reading in a password.
2428 ****************************************************************************/
2429 BOOL cli_reestablish_connection(struct cli_state *cli)
2431 struct nmb_name calling;
2432 struct nmb_name called;
2434 struct in_addr dest_ip;
2437 BOOL do_tcon = False;
2439 if (!cli->initialised || cli->fd == -1)
2441 DEBUG(3,("cli_reestablish_connection: not connected\n"));
2445 /* copy the parameters necessary to re-establish the connection */
2449 fstrcpy(share, cli->share);
2450 fstrcpy(dev , cli->dev);
2454 memcpy(&called , &(cli->called ), sizeof(called ));
2455 memcpy(&calling, &(cli->calling), sizeof(calling));
2456 fstrcpy(dest_host, cli->full_dest_host_name);
2457 dest_ip = cli->dest_ip;
2459 DEBUG(5,("cli_reestablish_connection: %s connecting to %s (ip %s) - %s [%s]\n",
2460 namestr(&calling), namestr(&called), inet_ntoa(dest_ip),
2461 cli->user_name, cli->domain));
2463 return cli_establish_connection(cli,
2464 dest_host, &dest_ip,
2466 share, dev, False, do_tcon);
2469 /****************************************************************************
2470 establishes a connection right up to doing tconX, reading in a password.
2471 ****************************************************************************/
2472 BOOL cli_establish_connection(struct cli_state *cli,
2473 char *dest_host, struct in_addr *dest_ip,
2474 struct nmb_name *calling, struct nmb_name *called,
2475 char *service, char *service_type,
2476 BOOL do_shutdown, BOOL do_tcon)
2478 DEBUG(5,("cli_establish_connection: %s connecting to %s (%s) - %s [%s]\n",
2479 namestr(calling), namestr(called), inet_ntoa(*dest_ip),
2480 cli->user_name, cli->domain));
2482 /* establish connection */
2484 if ((!cli->initialised))
2491 if (!cli_connect(cli, dest_host, dest_ip))
2493 DEBUG(1,("cli_establish_connection: failed to connect to %s (%s)\n",
2494 namestr(calling), inet_ntoa(*dest_ip)));
2499 if (!cli_session_request(cli, calling, called))
2501 DEBUG(1,("failed session request\n"));
2507 if (!cli_negprot(cli))
2509 DEBUG(1,("failed negprot\n"));
2515 if (cli->pwd.cleartext || cli->pwd.null_pwd)
2520 if (cli->pwd.null_pwd)
2522 /* attempt null session */
2528 /* attempt clear-text session */
2529 pwd_get_cleartext(&(cli->pwd), passwd);
2530 pass_len = strlen(passwd);
2533 /* attempt clear-text session */
2534 if (!cli_session_setup(cli, cli->user_name,
2539 DEBUG(1,("failed session setup\n"));
2548 if (!cli_send_tconX(cli, service, service_type,
2549 (char*)passwd, strlen(passwd)))
2551 DEBUG(1,("failed tcon_X\n"));
2562 /* attempt encrypted session */
2563 unsigned char nt_sess_pwd[24];
2564 unsigned char lm_sess_pwd[24];
2566 /* creates (storing a copy of) and then obtains a 24 byte password OWF */
2567 pwd_make_lm_nt_owf(&(cli->pwd), cli->cryptkey);
2568 pwd_get_lm_nt_owf(&(cli->pwd), lm_sess_pwd, nt_sess_pwd);
2570 /* attempt encrypted session */
2571 if (!cli_session_setup(cli, cli->user_name,
2572 (char*)lm_sess_pwd, sizeof(lm_sess_pwd),
2573 (char*)nt_sess_pwd, sizeof(nt_sess_pwd),
2576 DEBUG(1,("failed session setup\n"));
2584 if (!cli_send_tconX(cli, service, service_type,
2585 (char*)nt_sess_pwd, sizeof(nt_sess_pwd)))
2587 DEBUG(1,("failed tcon_X\n"));
2602 /****************************************************************************
2604 ****************************************************************************/
2605 int cli_printjob_del(struct cli_state *cli, int job)
2607 char *rparam = NULL;
2610 int rdrcnt,rprcnt, ret = -1;
2613 bzero(param,sizeof(param));
2616 SSVAL(p,0,81); /* DosPrintJobDel() */
2619 p = skip_string(p,1);
2621 p = skip_string(p,1);
2626 param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */
2627 NULL, 0, CLI_BUFFER_SIZE, /* data, length, maxlen */
2628 &rparam, &rprcnt, /* return params, length */
2629 &rdata, &rdrcnt)) { /* return data, length */
2630 ret = SVAL(rparam,0);
2633 if (rparam) free(rparam);
2634 if (rdata) free(rdata);
2640 /****************************************************************************
2641 call fn() on each entry in a print queue
2642 ****************************************************************************/
2643 int cli_print_queue(struct cli_state *cli,
2644 void (*fn)(struct print_job_info *))
2646 char *rparam = NULL;
2654 bzero(param,sizeof(param));
2657 SSVAL(p,0,76); /* API function number 76 (DosPrintJobEnum) */
2659 pstrcpy(p,"zWrLeh"); /* parameter description? */
2660 p = skip_string(p,1);
2661 pstrcpy(p,"WWzWWDDzz"); /* returned data format */
2662 p = skip_string(p,1);
2663 pstrcpy(p,cli->share); /* name of queue */
2664 p = skip_string(p,1);
2665 SSVAL(p,0,2); /* API function level 2, PRJINFO_2 data structure */
2666 SSVAL(p,2,1000); /* size of bytes of returned data buffer */
2668 pstrcpy(p,""); /* subformat */
2669 p = skip_string(p,1);
2671 DEBUG(4,("doing cli_print_queue for %s\n", cli->share));
2674 param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */
2675 NULL, 0, CLI_BUFFER_SIZE, /* data, length, maxlen */
2676 &rparam, &rprcnt, /* return params, length */
2677 &rdata, &rdrcnt)) { /* return data, length */
2679 result_code = SVAL(rparam,0);
2680 converter = SVAL(rparam,2); /* conversion factor */
2682 if (result_code == 0) {
2683 struct print_job_info job;
2687 for (i = 0; i < SVAL(rparam,4); ++i) {
2689 job.priority = SVAL(p,2);
2691 fix_char_ptr(SVAL(p,4), converter,
2693 job.t = make_unix_date3(p + 12);
2694 job.size = IVAL(p,16);
2695 fstrcpy(job.name,fix_char_ptr(SVAL(p,24),
2704 /* If any parameters or data were returned, free the storage. */
2705 if(rparam) free(rparam);
2706 if(rdata) free(rdata);