2 Unix SMB/Netbios implementation.
4 SMB client generic functions
5 Copyright (C) Andrew Tridgell 1994-1999
6 Copyright (C) Luke Kenneth Casson Leighton 1996-1999
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29 extern int DEBUGLEVEL;
32 * set the port that will be used for connections by the client
35 int cli_set_port(struct cli_state *cli, int port)
41 return cli->port; /* return it incase caller wants it */
45 /****************************************************************************
46 copy a string (unicode or otherwise) into an SMB buffer. skips a string
48 ****************************************************************************/
49 static char *cli_put_string(struct cli_state *cli, char *p, const char *str,
52 uint16 flgs2 = SVAL(cli->outbuf, smb_flg2);
53 if (IS_BITS_SET_ALL(flgs2, FLAGS2_UNICODE_STRINGS))
55 p = align2(p, cli->outbuf);
56 p = ascii_to_unibuf(p, str, 1024);
67 p = skip_string(p, 1);
76 /****************************************************************************
77 copy a string (unicode or otherwise) into an SMB buffer. skips a string
79 ****************************************************************************/
80 static const char *cli_get_string(struct cli_state *cli, char *p,
81 char *str, size_t str_len)
83 uint16 flgs2 = SVAL(cli->inbuf,smb_flg2);
84 if (IS_BITS_SET_ALL(flgs2, FLAGS2_UNICODE_STRINGS))
86 return unibuf_to_ascii(str, p, str_len);
90 safe_strcpy(str, p, str_len-1);
91 return skip_string(p, 1);
95 /****************************************************************************
97 ****************************************************************************/
98 static BOOL cli_receive_smb(struct cli_state *cli)
100 return client_receive_smb(cli->fd,cli->inbuf,cli->timeout);
103 /****************************************************************************
104 send an smb to a fd and re-establish if necessary
105 ****************************************************************************/
106 static BOOL cli_send_smb(struct cli_state *cli, BOOL show)
111 BOOL reestablished=False;
113 len = smb_len(cli->outbuf) + 4;
117 uint8 msg_type = CVAL(cli->outbuf, 0);
120 show_msg(cli->outbuf);
124 dump_data(10, cli->outbuf, len);
128 while (nwritten < len) {
129 ret = write_socket(cli->fd,cli->outbuf+nwritten,len - nwritten);
130 if (ret <= 0 && errno == EPIPE && !reestablished)
132 DEBUG(5,("cli_send_smb: write error (%s) - reconnecting\n",
135 if (cli_reestablish_connection(cli)) {
136 reestablished = True;
142 DEBUG(0,("Error writing %d bytes to client. %d. Exiting\n",
152 /******************************************************
153 Return an error message - either an SMB error or a RAP
155 *******************************************************/
157 char *cli_errstr(struct cli_state *cli)
159 static fstring error_message;
160 cli_safe_errstr(cli, error_message, sizeof(error_message));
161 return error_message;
164 /****************************************************************************
165 return a description of an SMB error
166 ****************************************************************************/
167 void cli_safe_smb_errstr(struct cli_state *cli, char *msg, size_t len)
169 smb_safe_errstr(cli->inbuf, msg, len);
172 /*****************************************************
173 RAP error codes - a small start but will be extended.
174 *******************************************************/
182 {5, "User has insufficient privilege" },
183 {86, "The specified password is invalid" },
184 {2226, "Operation only permitted on a Primary Domain Controller" },
185 {2242, "The password of this user has expired." },
186 {2243, "The password of this user cannot change." },
187 {2244, "This password cannot be used now (password history conflict)." },
188 {2245, "The password is shorter than required." },
189 {2246, "The password of this user is too recent to change."},
193 /****************************************************************************
194 return a description of a RAP error
195 ****************************************************************************/
196 BOOL get_safe_rap_errstr(int rap_error, char *err_msg, size_t msglen)
200 slprintf(err_msg, msglen - 1, "RAP code %d", rap_error);
202 for (i = 0; rap_errmap[i].message != NULL; i++)
204 if (rap_errmap[i].err == rap_error)
206 safe_strcpy( err_msg, rap_errmap[i].message, msglen);
213 /****************************************************************************
214 return a description of an SMB error
215 ****************************************************************************/
216 void cli_safe_errstr(struct cli_state *cli, char *err_msg, size_t msglen)
222 * Errors are of three kinds - smb errors,
223 * dealt with by cli_smb_errstr, NT errors,
224 * whose code is in cli.nt_error, and rap
225 * errors, whose error code is in cli.rap_error.
228 cli_error(cli, &errclass, &errnum);
232 cli_safe_smb_errstr(cli, err_msg, msglen);
234 else if (cli->nt_error)
237 * Was it an NT error ?
240 (void)get_safe_nt_error_msg(cli->nt_error, err_msg, msglen);
245 * Must have been a rap error.
247 (void)get_safe_rap_errstr(cli->rap_error, err_msg, msglen);
250 /****************************************************************************
251 setup basics in a outgoing packet
252 ****************************************************************************/
253 static void cli_setup_packet(struct cli_state *cli)
256 flgs2 |= FLAGS2_LONG_PATH_COMPONENTS;
257 flgs2 |= FLAGS2_32_BIT_ERROR_CODES;
259 flgs2 |= FLAGS2_UNICODE_STRINGS;
261 flgs2 |= FLAGS2_EXT_SEC;
265 SSVAL(cli->outbuf,smb_pid,cli->pid);
266 SSVAL(cli->outbuf,smb_uid,cli->vuid);
267 SSVAL(cli->outbuf,smb_mid,cli->mid);
269 if (cli->protocol > PROTOCOL_CORE)
271 SCVAL(cli->outbuf,smb_flg,0x8);
272 SSVAL(cli->outbuf,smb_flg2,flgs2);
277 /*****************************************************************************
278 Convert a character pointer in a cli_call_api() response to a form we can use.
279 This function contains code to prevent core dumps if the server returns
281 *****************************************************************************/
282 static char *fix_char_ptr(unsigned int datap, unsigned int converter,
283 char *rdata, int rdrcnt)
285 if (datap == 0) { /* turn NULL pointers into zero length strings */
288 unsigned int offset = datap - converter;
290 if (offset >= rdrcnt) {
291 DEBUG(1,("bad char ptr: datap=%u, converter=%u rdrcnt=%d>",
292 datap, converter, rdrcnt));
295 return &rdata[offset];
300 /****************************************************************************
301 send a SMB trans or trans2 request
302 ****************************************************************************/
303 BOOL cli_send_trans(struct cli_state *cli, int trans,
304 char *name, int pipe_name_len,
306 uint16 *setup, int lsetup, int msetup,
307 char *param, int lparam, int mparam,
308 char *data, int ldata, int mdata)
311 int this_ldata,this_lparam;
312 int tot_data=0,tot_param=0;
313 char *outdata,*outparam;
316 this_lparam = MIN(lparam,cli->max_xmit - (500+lsetup*2)); /* hack */
317 this_ldata = MIN(ldata,cli->max_xmit - (500+lsetup*2+this_lparam));
319 bzero(cli->outbuf,smb_size);
320 set_message(cli->outbuf,14+lsetup,0,True);
321 CVAL(cli->outbuf,smb_com) = trans;
322 SSVAL(cli->outbuf,smb_tid, cli->cnum);
323 cli_setup_packet(cli);
325 outparam = smb_buf(cli->outbuf)+(trans==SMBtrans ? pipe_name_len+1 : 3);
326 outdata = outparam+this_lparam;
328 /* primary request */
329 SSVAL(cli->outbuf,smb_tpscnt,lparam); /* tpscnt */
330 SSVAL(cli->outbuf,smb_tdscnt,ldata); /* tdscnt */
331 SSVAL(cli->outbuf,smb_mprcnt,mparam); /* mprcnt */
332 SSVAL(cli->outbuf,smb_mdrcnt,mdata); /* mdrcnt */
333 SCVAL(cli->outbuf,smb_msrcnt,msetup); /* msrcnt */
334 SSVAL(cli->outbuf,smb_flags,flags); /* flags */
335 SIVAL(cli->outbuf,smb_timeout,0); /* timeout */
336 SSVAL(cli->outbuf,smb_pscnt,this_lparam); /* pscnt */
337 SSVAL(cli->outbuf,smb_psoff,smb_offset(outparam,cli->outbuf)); /* psoff */
338 SSVAL(cli->outbuf,smb_dscnt,this_ldata); /* dscnt */
339 SSVAL(cli->outbuf,smb_dsoff,smb_offset(outdata,cli->outbuf)); /* dsoff */
340 SCVAL(cli->outbuf,smb_suwcnt,lsetup); /* suwcnt */
341 for (i=0;i<lsetup;i++) /* setup[] */
342 SSVAL(cli->outbuf,smb_setup+i*2,setup[i]);
343 p = smb_buf(cli->outbuf);
344 if (trans==SMBtrans) {
345 memcpy(p,name, pipe_name_len + 1); /* name[] */
347 *p++ = 0; /* put in a null smb_name */
348 *p++ = 'D'; *p++ = ' '; /* observed in OS/2 */
350 if (this_lparam) /* param[] */
351 memcpy(outparam,param,this_lparam);
352 if (this_ldata) /* data[] */
353 memcpy(outdata,data,this_ldata);
354 set_message(cli->outbuf,14+lsetup, /* wcnt, bcc */
355 PTR_DIFF(outdata+this_ldata,smb_buf(cli->outbuf)),False);
357 cli_send_smb(cli, True);
359 if (this_ldata < ldata || this_lparam < lparam) {
360 /* receive interim response */
361 if (!cli_receive_smb(cli) ||
362 CVAL(cli->inbuf,smb_rcls) != 0) {
366 tot_data = this_ldata;
367 tot_param = this_lparam;
369 while (tot_data < ldata || tot_param < lparam) {
370 this_lparam = MIN(lparam-tot_param,cli->max_xmit - 500); /* hack */
371 this_ldata = MIN(ldata-tot_data,cli->max_xmit - (500+this_lparam));
373 set_message(cli->outbuf,trans==SMBtrans?8:9,0,True);
374 CVAL(cli->outbuf,smb_com) = trans==SMBtrans ? SMBtranss : SMBtranss2;
376 outparam = smb_buf(cli->outbuf);
377 outdata = outparam+this_lparam;
379 /* secondary request */
380 SSVAL(cli->outbuf,smb_tpscnt,lparam); /* tpscnt */
381 SSVAL(cli->outbuf,smb_tdscnt,ldata); /* tdscnt */
382 SSVAL(cli->outbuf,smb_spscnt,this_lparam); /* pscnt */
383 SSVAL(cli->outbuf,smb_spsoff,smb_offset(outparam,cli->outbuf)); /* psoff */
384 SSVAL(cli->outbuf,smb_spsdisp,tot_param); /* psdisp */
385 SSVAL(cli->outbuf,smb_sdscnt,this_ldata); /* dscnt */
386 SSVAL(cli->outbuf,smb_sdsoff,smb_offset(outdata,cli->outbuf)); /* dsoff */
387 SSVAL(cli->outbuf,smb_sdsdisp,tot_data); /* dsdisp */
388 if (trans==SMBtrans2)
389 SSVALS(cli->outbuf,smb_sfid,fid); /* fid */
390 if (this_lparam) /* param[] */
391 memcpy(outparam,param,this_lparam);
392 if (this_ldata) /* data[] */
393 memcpy(outdata,data,this_ldata);
394 set_message(cli->outbuf,trans==SMBtrans?8:9, /* wcnt, bcc */
395 PTR_DIFF(outdata+this_ldata,smb_buf(cli->outbuf)),False);
397 cli_send_smb(cli, True);
399 tot_data += this_ldata;
400 tot_param += this_lparam;
408 /****************************************************************************
409 receive a SMB trans or trans2 response allocating the necessary memory
410 ****************************************************************************/
411 static BOOL cli_receive_trans(struct cli_state *cli,int trans,
412 char **param, int *param_len,
413 char **data, int *data_len)
417 int this_data,this_param;
419 *data_len = *param_len = 0;
421 if (!cli_receive_smb(cli))
425 if (CVAL(cli->inbuf,smb_com) != trans) {
426 DEBUG(0,("Expected %s response, got command 0x%02x\n",
427 trans==SMBtrans?"SMBtrans":"SMBtrans2",
428 CVAL(cli->inbuf,smb_com)));
432 if (cli_error(cli, NULL, NULL))
437 /* parse out the lengths */
438 total_data = SVAL(cli->inbuf,smb_tdrcnt);
439 total_param = SVAL(cli->inbuf,smb_tprcnt);
442 *data = Realloc(*data,total_data);
443 *param = Realloc(*param,total_param);
446 this_data = SVAL(cli->inbuf,smb_drcnt);
447 this_param = SVAL(cli->inbuf,smb_prcnt);
449 if (this_data + *data_len > total_data ||
450 this_param + *param_len > total_param) {
451 DEBUG(1,("Data overflow in cli_receive_trans\n"));
456 memcpy(*data + SVAL(cli->inbuf,smb_drdisp),
457 smb_base(cli->inbuf) + SVAL(cli->inbuf,smb_droff),
460 memcpy(*param + SVAL(cli->inbuf,smb_prdisp),
461 smb_base(cli->inbuf) + SVAL(cli->inbuf,smb_proff),
463 *data_len += this_data;
464 *param_len += this_param;
466 /* parse out the total lengths again - they can shrink! */
467 total_data = SVAL(cli->inbuf,smb_tdrcnt);
468 total_param = SVAL(cli->inbuf,smb_tprcnt);
470 if (total_data <= *data_len && total_param <= *param_len)
473 if (!cli_receive_smb(cli))
477 if (CVAL(cli->inbuf,smb_com) != trans) {
478 DEBUG(0,("Expected %s response, got command 0x%02x\n",
479 trans==SMBtrans?"SMBtrans":"SMBtrans2",
480 CVAL(cli->inbuf,smb_com)));
484 if (cli_error(cli, NULL, NULL))
493 /****************************************************************************
494 Call a remote api on an arbitrary pipe. takes param, data and setup buffers.
495 ****************************************************************************/
496 BOOL cli_api_pipe(struct cli_state *cli, char *pipe_name, int pipe_name_len,
497 uint16 *setup, uint32 setup_count, uint32 max_setup_count,
498 char *params, uint32 param_count, uint32 max_param_count,
499 char *data, uint32 data_count, uint32 max_data_count,
500 char **rparam, uint32 *rparam_count,
501 char **rdata, uint32 *rdata_count)
503 if (pipe_name_len == 0)
504 pipe_name_len = strlen(pipe_name);
506 cli_send_trans(cli, SMBtrans,
507 pipe_name, pipe_name_len,
508 0,0, /* fid, flags */
509 setup, setup_count, max_setup_count,
510 params, param_count, max_param_count,
511 data, data_count, max_data_count);
513 return (cli_receive_trans(cli, SMBtrans,
514 rparam, (int *)rparam_count,
515 rdata, (int *)rdata_count));
518 /****************************************************************************
520 ****************************************************************************/
521 BOOL cli_api(struct cli_state *cli,
522 char *param, int prcnt, int mprcnt,
523 char *data, int drcnt, int mdrcnt,
524 char **rparam, int *rprcnt,
525 char **rdata, int *rdrcnt)
527 cli_send_trans(cli,SMBtrans,
528 PIPE_LANMAN,strlen(PIPE_LANMAN), /* Name, length */
529 0,0, /* fid, flags */
530 NULL,0,0, /* Setup, length, max */
531 param, prcnt, mprcnt, /* Params, length, max */
532 data, drcnt, mdrcnt /* Data, length, max */
535 return (cli_receive_trans(cli,SMBtrans,
541 /****************************************************************************
542 perform a NetWkstaUserLogon
543 ****************************************************************************/
544 BOOL cli_NetWkstaUserLogon(struct cli_state *cli,char *user, char *workstation)
552 memset(param, 0, sizeof(param));
554 /* send a SMBtrans command with api NetWkstaUserLogon */
556 SSVAL(p,0,132); /* api number */
558 pstrcpy(p,"OOWb54WrLh");
559 p = skip_string(p,1);
560 pstrcpy(p,"WB21BWDWWDDDDDDDzzzD");
561 p = skip_string(p,1);
570 pstrcpy(p, workstation);
573 SSVAL(p, 0, CLI_BUFFER_SIZE);
575 SSVAL(p, 0, CLI_BUFFER_SIZE);
579 param, PTR_DIFF(p,param),1024, /* param, length, max */
580 NULL, 0, CLI_BUFFER_SIZE, /* data, length, max */
581 &rparam, &rprcnt, /* return params, return size */
582 &rdata, &rdrcnt /* return data, return size */
584 cli->rap_error = SVAL(rparam,0);
587 if (cli->rap_error == 0) {
588 DEBUG(4,("NetWkstaUserLogon success\n"));
589 cli->privilages = SVAL(p, 24);
590 fstrcpy(cli->eff_name,p+2);
592 DEBUG(1,("NetwkstaUserLogon gave error %d\n", cli->rap_error));
600 return (cli->rap_error == 0);
603 /****************************************************************************
604 call a NetShareEnum - try and browse available connections on a host
605 ****************************************************************************/
606 BOOL cli_RNetShareEnum(struct cli_state *cli, void (*fn)(const char *, uint32, const char *))
615 /* now send a SMBtrans command with api RNetShareEnum */
617 SSVAL(p,0,0); /* api number */
620 p = skip_string(p,1);
622 p = skip_string(p,1);
628 param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */
629 NULL, 0, 0xFFFF, /* data, length, maxlen */
630 &rparam, &rprcnt, /* return params, length */
631 &rdata, &rdrcnt)) /* return data, length */
633 int res = SVAL(rparam,0);
634 int converter=SVAL(rparam,2);
637 if (res == 0 || res == ERRmoredata) {
638 count=SVAL(rparam,4);
641 for (i=0;i<count;i++,p+=20) {
643 int type = SVAL(p,14);
644 int comment_offset = IVAL(p,16) & 0xFFFF;
645 char *cmnt = comment_offset?(rdata+comment_offset-converter):"";
646 fn(sname, type, cmnt);
649 DEBUG(4,("NetShareEnum res=%d\n", res));
652 DEBUG(4,("NetShareEnum failed\n"));
664 /****************************************************************************
665 call a NetServerEnum for the specified workgroup and servertype mask.
666 This function then calls the specified callback function for each name returned.
668 The callback function takes 3 arguments: the machine name, the server type and
670 ****************************************************************************/
671 BOOL cli_NetServerEnum(struct cli_state *cli, char *workgroup, uint32 stype,
672 void (*fn)(const char *, uint32, const char *))
682 /* send a SMBtrans command with api NetServerEnum */
684 SSVAL(p,0,0x68); /* api number */
686 pstrcpy(p,"WrLehDz");
687 p = skip_string(p,1);
689 pstrcpy(p,"B16BBDz");
691 p = skip_string(p,1);
693 SSVAL(p,2,CLI_BUFFER_SIZE);
698 pstrcpy(p, workgroup);
699 p = skip_string(p,1);
702 param, PTR_DIFF(p,param), 8, /* params, length, max */
703 NULL, 0, CLI_BUFFER_SIZE, /* data, length, max */
704 &rparam, &rprcnt, /* return params, return size */
705 &rdata, &rdrcnt /* return data, return size */
707 int res = SVAL(rparam,0);
708 int converter=SVAL(rparam,2);
711 if (res == 0 || res == ERRmoredata) {
712 count=SVAL(rparam,4);
715 for (i = 0;i < count;i++, p += 26) {
717 int comment_offset = (IVAL(p,22) & 0xFFFF)-converter;
718 char *cmnt = comment_offset?(rdata+comment_offset):"";
719 if (comment_offset < 0 || comment_offset > rdrcnt) continue;
721 stype = IVAL(p,18) & ~SV_TYPE_LOCAL_LIST_ONLY;
723 fn(sname, stype, cmnt);
745 {PROTOCOL_CORE,"PC NETWORK PROGRAM 1.0"},
746 {PROTOCOL_COREPLUS,"MICROSOFT NETWORKS 1.03"},
747 {PROTOCOL_LANMAN1,"MICROSOFT NETWORKS 3.0"},
748 {PROTOCOL_LANMAN1,"LANMAN1.0"},
749 {PROTOCOL_LANMAN2,"LM1.2X002"},
750 {PROTOCOL_LANMAN2,"Samba"},
751 {PROTOCOL_NT1,"NT LANMAN 1.0"},
752 {PROTOCOL_NT1,"NT LM 0.12"},
759 /****************************************************************************
761 ****************************************************************************/
762 BOOL cli_session_setup_x(struct cli_state *cli,
764 char *pass, int passlen,
765 char *ntpass, int ntpasslen,
771 BOOL esec = cli->capabilities & CAP_EXTENDED_SECURITY;
773 DEBUG(100,("cli_session_setup. extended security: %s\n",
776 #ifdef DEBUG_PASSWORD
777 DEBUG(100,("cli_session_setup. pass, ntpass\n"));
778 dump_data(100, pass, passlen);
779 dump_data(100, ntpass, ntpasslen);
782 if (cli->protocol < PROTOCOL_LANMAN1)
787 /* send a session setup command */
788 bzero(cli->outbuf,smb_size);
790 if (cli->protocol < PROTOCOL_NT1)
792 set_message(cli->outbuf,10,1 + strlen(user) + passlen,True);
793 CVAL(cli->outbuf,smb_com) = SMBsesssetupX;
794 cli_setup_packet(cli);
796 CVAL(cli->outbuf,smb_vwv0) = 0xFF;
797 SSVAL(cli->outbuf,smb_vwv2,cli->max_xmit);
798 SSVAL(cli->outbuf,smb_vwv3,2);
799 SSVAL(cli->outbuf,smb_vwv4,1);
800 SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
801 SSVAL(cli->outbuf,smb_vwv7,passlen);
802 p = smb_buf(cli->outbuf);
803 memcpy(p,pass,passlen);
810 set_message(cli->outbuf,12,0,True);
811 CVAL(cli->outbuf,smb_com) = SMBsesssetupX;
812 cli_setup_packet(cli);
814 CVAL(cli->outbuf,smb_vwv0) = 0xFF;
815 SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
816 SSVAL(cli->outbuf,smb_vwv3,2);
817 SSVAL(cli->outbuf,smb_vwv4,cli->pid);
818 SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
819 SSVAL(cli->outbuf,smb_vwv7,passlen);
820 SIVAL(cli->outbuf,smb_vwv10, CAP_EXTENDED_SECURITY|CAP_STATUS32|CAP_UNICODE);
821 p = smb_buf(cli->outbuf);
822 memcpy(p,pass,passlen);
825 p = cli_put_string(cli, p, "Unix", False);
826 p = cli_put_string(cli, p, "Samba", False);
827 p = cli_put_string(cli, p, "", False);
830 set_message(cli->outbuf,12,PTR_DIFF(p,smb_buf(cli->outbuf)),False);
834 set_message(cli->outbuf,13,0,True);
835 CVAL(cli->outbuf,smb_com) = SMBsesssetupX;
836 cli_setup_packet(cli);
838 CVAL(cli->outbuf,smb_vwv0) = 0xFF;
839 SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
840 SSVAL(cli->outbuf,smb_vwv3,2);
841 SSVAL(cli->outbuf,smb_vwv4,cli->pid);
842 SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
843 SSVAL(cli->outbuf,smb_vwv7,passlen);
844 SSVAL(cli->outbuf,smb_vwv8,ntpasslen);
845 SSVAL(cli->outbuf,smb_vwv11,0);
846 p = smb_buf(cli->outbuf);
847 memcpy(p,pass,passlen);
848 p += SVAL(cli->outbuf,smb_vwv7);
849 memcpy(p,ntpass,ntpasslen);
850 p += SVAL(cli->outbuf,smb_vwv8);
852 p = cli_put_string(cli, p, user, False);
853 strupper(user_domain);
854 p = cli_put_string(cli, p, user_domain, False);
855 p = cli_put_string(cli, p, "Unix", True);
856 p = cli_put_string(cli, p, "Samba", False);
858 set_message(cli->outbuf,13,PTR_DIFF(p,smb_buf(cli->outbuf)),False);
861 cli_send_smb(cli, True);
862 if (!cli_receive_smb(cli))
864 DEBUG(10,("cli_session_setup_x: receive smb failed\n"));
868 if (cli_error(cli, &eclass, &ecode))
870 uint16 flgs2 = SVAL(cli->inbuf,smb_flg2);
871 if (IS_BITS_CLR_ALL(flgs2, FLAGS2_32_BIT_ERROR_CODES))
873 if (ecode != ERRmoredata || !esec)
878 else if (ecode != 0xC0000016) /* STATUS_MORE_PROCESSING_REQD */
884 /* use the returned vuid from now on */
885 cli->vuid = SVAL(cli->inbuf,smb_uid);
887 if (cli->protocol >= PROTOCOL_NT1)
895 * Save off some of the connected server
902 server_os = smb_buf(cli->inbuf);
903 server_type = skip_string(server_os,1);
904 server_domain = skip_string(server_type,1);
906 fstrcpy(cli->server_os, server_os);
907 fstrcpy(cli->server_type, server_type);
908 fstrcpy(cli->server_domain, server_domain);
915 static BOOL cli_calc_session_pwds(struct cli_state *cli,
916 char *pword, char *ntpword,
917 char *pass, int *passlen,
918 char *ntpass, int *ntpasslen,
921 BOOL ntpass_ok = ntpass != NULL && ntpasslen != NULL;
923 if (pass == NULL || passlen == NULL)
925 DEBUG(0,("cli_calc_session_pwds: pass and passlen are NULL\n"));
928 if ((ntpass != NULL || ntpasslen != NULL) &&
929 (ntpass == NULL || ntpasslen == NULL))
931 DEBUG(0,("cli_calc_session_pwds: ntpasswd pointers invalid\n"));
935 #ifdef DEBUG_PASSWORD
936 DEBUG(100,("cli_calc_session_pwds. pass, ntpass\n"));
937 dump_data(100, pass, *passlen);
940 dump_data(100, ntpass, *ntpasslen);
943 if (!IS_BITS_SET_ALL(cli->sec_mode, 1))
945 /* if in share level security then don't send a password now */
955 else if ((*passlen == 0 || *passlen == 1) && (pass[0] == '\0'))
957 /* Null session connect. */
973 if (*passlen == 24 && *ntpasslen >= 24)
975 if (IS_BITS_SET_ALL(cli->sec_mode, 2))
977 /* encrypted password, implicit from 24-byte lengths */
978 memcpy(pword , pass , *passlen);
979 memcpy(ntpword, ntpass, *ntpasslen);
983 DEBUG(0,("cli_calc_session_pwds: encrypted passwords not supported by server\n"));
987 else if (*ntpasslen == 0 || !IS_BITS_SET_ALL(cli->sec_mode, 2))
989 /* plain-text password: server doesn't support encrypted. */
990 fstrcpy(pword, pass);
991 fstrcpy(ntpword, "");
994 else if (ntpasslen != NULL)
996 /* passlen != 0, ntpasslen != 0 && server supports encryption */
999 /* plain-text password requesting to be encrypted */
1000 uchar *srv_key = (uchar *)cli->cryptkey;
1004 SMBgenclientchals(cli->lm_cli_chal,
1006 &cli->nt_cli_chal_len,
1010 nt_owf_gen(pword, nt_owf);
1011 ntv2_owf_gen(nt_owf, cli->user_name, cli->domain, kr);
1014 memcpy(pword, cli->lm_cli_chal, 8);
1015 SMBOWFencrypt_ntv2(kr,
1017 cli->lm_cli_chal, 8,
1022 memcpy(ntpword, cli->lm_cli_chal, cli->nt_cli_chal_len);
1023 SMBOWFencrypt_ntv2(kr,
1025 cli->nt_cli_chal, cli->nt_cli_chal_len,
1026 &ntpword[cli->nt_cli_chal_len]);
1027 *ntpasslen = cli->nt_cli_chal_len + 16;
1031 /* plain-text password requesting to be encrypted */
1032 uchar *key = (uchar *)cli->cryptkey;
1033 SMBencrypt ((uchar *)pass , key,(uchar *)pword );
1034 SMBNTencrypt((uchar *)ntpass, key,(uchar *)ntpword);
1042 /****************************************************************************
1043 send a session setup
1044 ****************************************************************************/
1045 BOOL cli_session_setup(struct cli_state *cli,
1047 char *pass, int passlen,
1048 char *ntpass, int ntpasslen,
1051 fstring pword, ntpword;
1053 if (passlen > sizeof(pword)-1 || ntpasslen > sizeof(ntpword)-1)
1058 fstrcpy(cli->user_name, user);
1060 return cli_calc_session_pwds(cli, pword, ntpword,
1062 ntpass, &ntpasslen, cli->use_ntlmv2) &&
1063 cli_session_setup_x(cli, user, pass, passlen, ntpass, ntpasslen,
1067 /****************************************************************************
1069 *****************************************************************************/
1071 BOOL cli_ulogoff(struct cli_state *cli)
1073 bzero(cli->outbuf,smb_size);
1074 set_message(cli->outbuf,2,0,True);
1075 CVAL(cli->outbuf,smb_com) = SMBulogoffX;
1076 cli_setup_packet(cli);
1077 SSVAL(cli->outbuf,smb_vwv0,0xFF);
1078 SSVAL(cli->outbuf,smb_vwv2,0); /* no additional info */
1080 cli_send_smb(cli, True);
1081 if (!cli_receive_smb(cli))
1084 return CVAL(cli->inbuf,smb_rcls) == 0;
1087 /****************************************************************************
1089 ****************************************************************************/
1090 BOOL cli_send_tconX(struct cli_state *cli,
1091 char *share, char *dev, char *pass, int passlen)
1093 fstring fullshare, pword;
1095 bzero(cli->outbuf,smb_size);
1096 bzero(cli->inbuf,smb_size);
1098 fstrcpy(cli->share, share);
1100 /* in user level security don't send a password now */
1101 if (cli->sec_mode & 1) {
1106 if ((cli->sec_mode & 2) && *pass && passlen != 24) {
1108 SMBencrypt((uchar *)pass,(uchar *)cli->cryptkey,(uchar *)pword);
1110 memcpy(pword, pass, passlen);
1113 slprintf(fullshare, sizeof(fullshare)-1,
1114 "\\\\%s\\%s", cli->desthost, share);
1115 strupper(fullshare);
1117 set_message(cli->outbuf,4, 0, True);
1118 CVAL(cli->outbuf,smb_com) = SMBtconX;
1119 cli_setup_packet(cli);
1121 SSVAL(cli->outbuf,smb_vwv0,0xFF);
1122 SSVAL(cli->outbuf,smb_vwv3,passlen);
1124 p = smb_buf(cli->outbuf);
1125 memcpy(p,pword,passlen);
1127 p = cli_put_string(cli, p, fullshare, False);
1129 p = skip_string(p, 1);
1131 set_message(cli->outbuf,4,PTR_DIFF(p, smb_buf(cli->outbuf)),False);
1133 SCVAL(cli->inbuf,smb_rcls, 1);
1135 cli_send_smb(cli, True);
1136 if (!cli_receive_smb(cli))
1139 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1143 fstrcpy(cli->dev, "A:");
1145 if (cli->protocol >= PROTOCOL_NT1)
1147 cli_get_string(cli, smb_buf(cli->inbuf),
1148 cli->dev, sizeof(cli->dev));
1151 if (strcasecmp(share,"IPC$")==0) {
1152 fstrcpy(cli->dev, "IPC");
1155 /* only grab the device if we have a recent protocol level */
1156 if (cli->protocol >= PROTOCOL_NT1 && smb_buflen(cli->inbuf) == 3)
1158 /* almost certainly win95 - enable bug fixes */
1162 cli->cnum = SVAL(cli->inbuf,smb_tid);
1167 /****************************************************************************
1168 send a tree disconnect
1169 ****************************************************************************/
1170 BOOL cli_tdis(struct cli_state *cli)
1172 bzero(cli->outbuf,smb_size);
1173 set_message(cli->outbuf,0,0,True);
1174 CVAL(cli->outbuf,smb_com) = SMBtdis;
1175 SSVAL(cli->outbuf,smb_tid,cli->cnum);
1176 cli_setup_packet(cli);
1178 cli_send_smb(cli, True);
1179 if (!cli_receive_smb(cli))
1182 return CVAL(cli->inbuf,smb_rcls) == 0;
1185 /****************************************************************************
1187 ****************************************************************************/
1188 BOOL cli_rename(struct cli_state *cli, char *fname_src, char *fname_dst)
1192 bzero(cli->outbuf,smb_size);
1193 bzero(cli->inbuf,smb_size);
1195 set_message(cli->outbuf,1, 4 + strlen(fname_src) + strlen(fname_dst), True);
1197 CVAL(cli->outbuf,smb_com) = SMBmv;
1198 SSVAL(cli->outbuf,smb_tid,cli->cnum);
1199 cli_setup_packet(cli);
1201 SSVAL(cli->outbuf,smb_vwv0,aSYSTEM | aHIDDEN);
1203 p = smb_buf(cli->outbuf);
1205 pstrcpy(p,fname_src);
1206 p = skip_string(p,1);
1208 pstrcpy(p,fname_dst);
1210 cli_send_smb(cli, True);
1211 if (!cli_receive_smb(cli)) {
1215 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1222 /****************************************************************************
1224 ****************************************************************************/
1225 BOOL cli_unlink(struct cli_state *cli, char *fname)
1229 bzero(cli->outbuf,smb_size);
1230 bzero(cli->inbuf,smb_size);
1232 set_message(cli->outbuf,1, 2 + strlen(fname),True);
1234 CVAL(cli->outbuf,smb_com) = SMBunlink;
1235 SSVAL(cli->outbuf,smb_tid,cli->cnum);
1236 cli_setup_packet(cli);
1238 SSVAL(cli->outbuf,smb_vwv0,aSYSTEM | aHIDDEN);
1240 p = smb_buf(cli->outbuf);
1244 cli_send_smb(cli, True);
1245 if (!cli_receive_smb(cli)) {
1249 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1256 /****************************************************************************
1258 ****************************************************************************/
1259 BOOL cli_mkdir(struct cli_state *cli, char *dname)
1263 bzero(cli->outbuf,smb_size);
1264 bzero(cli->inbuf,smb_size);
1266 set_message(cli->outbuf,0, 2 + strlen(dname),True);
1268 CVAL(cli->outbuf,smb_com) = SMBmkdir;
1269 SSVAL(cli->outbuf,smb_tid,cli->cnum);
1270 cli_setup_packet(cli);
1272 p = smb_buf(cli->outbuf);
1276 cli_send_smb(cli, True);
1277 if (!cli_receive_smb(cli)) {
1281 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1288 /****************************************************************************
1290 ****************************************************************************/
1291 BOOL cli_rmdir(struct cli_state *cli, char *dname)
1295 bzero(cli->outbuf,smb_size);
1296 bzero(cli->inbuf,smb_size);
1298 set_message(cli->outbuf,0, 2 + strlen(dname),True);
1300 CVAL(cli->outbuf,smb_com) = SMBrmdir;
1301 SSVAL(cli->outbuf,smb_tid,cli->cnum);
1302 cli_setup_packet(cli);
1304 p = smb_buf(cli->outbuf);
1308 cli_send_smb(cli, True);
1309 if (!cli_receive_smb(cli)) {
1313 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1322 /****************************************************************************
1324 ****************************************************************************/
1325 int cli_nt_create(struct cli_state *cli, char *fname)
1329 bzero(cli->outbuf,smb_size);
1330 bzero(cli->inbuf,smb_size);
1332 set_message(cli->outbuf,24,1 + strlen(fname),True);
1334 CVAL(cli->outbuf,smb_com) = SMBntcreateX;
1335 SSVAL(cli->outbuf,smb_tid,cli->cnum);
1336 cli_setup_packet(cli);
1338 SSVAL(cli->outbuf,smb_vwv0,0xFF);
1339 SIVAL(cli->outbuf,smb_ntcreate_Flags, 0x06);
1340 SIVAL(cli->outbuf,smb_ntcreate_RootDirectoryFid, 0x0);
1341 SIVAL(cli->outbuf,smb_ntcreate_DesiredAccess, 0x2019f);
1342 SIVAL(cli->outbuf,smb_ntcreate_FileAttributes, 0x0);
1343 SIVAL(cli->outbuf,smb_ntcreate_ShareAccess, 0x03);
1344 SIVAL(cli->outbuf,smb_ntcreate_CreateDisposition, 0x01);
1345 SIVAL(cli->outbuf,smb_ntcreate_CreateOptions, 0x0);
1346 SIVAL(cli->outbuf,smb_ntcreate_ImpersonationLevel, 0x02);
1347 SSVAL(cli->outbuf,smb_ntcreate_NameLength, strlen(fname));
1349 p = smb_buf(cli->outbuf);
1351 p = skip_string(p,1);
1353 cli_send_smb(cli, True);
1354 if (!cli_receive_smb(cli)) {
1358 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1362 return SVAL(cli->inbuf,smb_vwv2 + 1);
1366 /****************************************************************************
1368 ****************************************************************************/
1369 int cli_open(struct cli_state *cli, char *fname, int flags, int share_mode)
1373 unsigned accessmode=0;
1375 /* you must open for RW not just write - otherwise getattrE doesn't
1377 if ((flags & O_ACCMODE) == O_WRONLY && strncmp(cli->dev, "LPT", 3)) {
1378 flags = (flags & ~O_ACCMODE) | O_RDWR;
1381 if (flags & O_CREAT)
1383 if (!(flags & O_EXCL)) {
1384 if (flags & O_TRUNC)
1390 accessmode = (share_mode<<4);
1392 if ((flags & O_ACCMODE) == O_RDWR) {
1394 } else if ((flags & O_ACCMODE) == O_WRONLY) {
1399 if ((flags & O_SYNC) == O_SYNC) {
1400 accessmode |= (1<<14);
1404 bzero(cli->outbuf,smb_size);
1405 bzero(cli->inbuf,smb_size);
1407 set_message(cli->outbuf,15,1 + strlen(fname),True);
1409 CVAL(cli->outbuf,smb_com) = SMBopenX;
1410 SSVAL(cli->outbuf,smb_tid,cli->cnum);
1411 cli_setup_packet(cli);
1413 SSVAL(cli->outbuf,smb_vwv0,0xFF);
1414 SSVAL(cli->outbuf,smb_vwv2,0); /* no additional info */
1415 SSVAL(cli->outbuf,smb_vwv3,accessmode);
1416 SSVAL(cli->outbuf,smb_vwv4,aSYSTEM | aHIDDEN);
1417 SSVAL(cli->outbuf,smb_vwv5,0);
1418 SSVAL(cli->outbuf,smb_vwv8,openfn);
1420 p = smb_buf(cli->outbuf);
1421 p = cli_put_string(cli, p, fname, False);
1423 set_message(cli->outbuf,15,PTR_DIFF(p, smb_buf(cli->outbuf)),False);
1425 cli_send_smb(cli, True);
1426 if (!cli_receive_smb(cli)) {
1430 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1434 return SVAL(cli->inbuf,smb_vwv2);
1440 /****************************************************************************
1442 ****************************************************************************/
1443 BOOL cli_close(struct cli_state *cli, int fnum)
1445 bzero(cli->outbuf,smb_size);
1446 bzero(cli->inbuf,smb_size);
1448 set_message(cli->outbuf,3,0,True);
1450 CVAL(cli->outbuf,smb_com) = SMBclose;
1451 SSVAL(cli->outbuf,smb_tid,cli->cnum);
1452 cli_setup_packet(cli);
1454 SSVAL(cli->outbuf,smb_vwv0,fnum);
1455 SIVALS(cli->outbuf,smb_vwv1,-1);
1457 cli_send_smb(cli, True);
1458 if (!cli_receive_smb(cli)) {
1462 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1470 /****************************************************************************
1472 ****************************************************************************/
1473 BOOL cli_lock(struct cli_state *cli, int fnum, uint32 offset, uint32 len, int timeout)
1476 int saved_timeout = cli->timeout;
1478 bzero(cli->outbuf,smb_size);
1479 bzero(cli->inbuf,smb_size);
1481 set_message(cli->outbuf,8,10,True);
1483 CVAL(cli->outbuf,smb_com) = SMBlockingX;
1484 SSVAL(cli->outbuf,smb_tid,cli->cnum);
1485 cli_setup_packet(cli);
1487 CVAL(cli->outbuf,smb_vwv0) = 0xFF;
1488 SSVAL(cli->outbuf,smb_vwv2,fnum);
1489 CVAL(cli->outbuf,smb_vwv3) = 0;
1490 SIVALS(cli->outbuf, smb_vwv4, timeout);
1491 SSVAL(cli->outbuf,smb_vwv6,0);
1492 SSVAL(cli->outbuf,smb_vwv7,1);
1494 p = smb_buf(cli->outbuf);
1495 SSVAL(p, 0, cli->pid);
1496 SIVAL(p, 2, offset);
1498 cli_send_smb(cli, True);
1500 cli->timeout = (timeout == -1) ? 0x7FFFFFFF : timeout;
1502 if (!cli_receive_smb(cli)) {
1503 cli->timeout = saved_timeout;
1507 cli->timeout = saved_timeout;
1509 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1516 /****************************************************************************
1518 ****************************************************************************/
1519 BOOL cli_unlock(struct cli_state *cli, int fnum, uint32 offset, uint32 len, int timeout)
1523 bzero(cli->outbuf,smb_size);
1524 bzero(cli->inbuf,smb_size);
1526 set_message(cli->outbuf,8,10,True);
1528 CVAL(cli->outbuf,smb_com) = SMBlockingX;
1529 SSVAL(cli->outbuf,smb_tid,cli->cnum);
1530 cli_setup_packet(cli);
1532 CVAL(cli->outbuf,smb_vwv0) = 0xFF;
1533 SSVAL(cli->outbuf,smb_vwv2,fnum);
1534 CVAL(cli->outbuf,smb_vwv3) = 0;
1535 SIVALS(cli->outbuf, smb_vwv4, timeout);
1536 SSVAL(cli->outbuf,smb_vwv6,1);
1537 SSVAL(cli->outbuf,smb_vwv7,0);
1539 p = smb_buf(cli->outbuf);
1540 SSVAL(p, 0, cli->pid);
1541 SIVAL(p, 2, offset);
1544 cli_send_smb(cli, True);
1545 if (!cli_receive_smb(cli)) {
1549 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1558 /****************************************************************************
1559 issue a single SMBread and don't wait for a reply
1560 ****************************************************************************/
1561 static void cli_issue_read(struct cli_state *cli, int fnum, off_t offset,
1564 bzero(cli->outbuf,smb_size);
1565 bzero(cli->inbuf,smb_size);
1567 set_message(cli->outbuf,10,0,True);
1569 CVAL(cli->outbuf,smb_com) = SMBreadX;
1570 SSVAL(cli->outbuf,smb_tid,cli->cnum);
1571 cli_setup_packet(cli);
1573 CVAL(cli->outbuf,smb_vwv0) = 0xFF;
1574 SSVAL(cli->outbuf,smb_vwv2,fnum);
1575 SIVAL(cli->outbuf,smb_vwv3,offset);
1576 SSVAL(cli->outbuf,smb_vwv5,size);
1577 SSVAL(cli->outbuf,smb_vwv6,size);
1578 SSVAL(cli->outbuf,smb_mid,cli->mid + i);
1580 cli_send_smb(cli, True);
1583 /****************************************************************************
1585 ****************************************************************************/
1586 size_t cli_read(struct cli_state *cli, int fnum, char *buf, off_t offset, size_t size)
1592 int mpx = MAX(cli->max_mux-1, 1);
1593 int block = (cli->max_xmit - (smb_size+32)) & ~1023;
1595 int blocks = (size + (block-1)) / block;
1597 if (size == 0) return 0;
1599 while (received < blocks)
1603 while (issued - received < mpx && issued < blocks) {
1604 int size1 = MIN(block, size-issued*block);
1605 cli_issue_read(cli, fnum, offset+issued*block, size1, issued);
1609 if (!cli_receive_smb(cli)) {
1614 mid = SVAL(cli->inbuf, smb_mid) - cli->mid;
1615 size2 = SVAL(cli->inbuf, smb_vwv5);
1617 if (cli_error(cli, NULL, NULL))
1619 blocks = MIN(blocks, mid-1);
1624 blocks = MIN(blocks, mid-1);
1625 /* this distinguishes EOF from an error */
1626 total = MAX(total, 0);
1630 if (size2 > block) {
1631 DEBUG(0,("server returned more than we wanted!\n"));
1634 if (mid >= issued) {
1635 DEBUG(0,("invalid mid from server!\n"));
1638 p = smb_base(cli->inbuf) + SVAL(cli->inbuf,smb_vwv6);
1640 memcpy(buf+mid*block, p, size2);
1642 total = MAX(total, mid*block + size2);
1645 while (received < issued) {
1646 cli_receive_smb(cli);
1654 /****************************************************************************
1655 issue a single SMBwrite and don't wait for a reply
1656 ****************************************************************************/
1657 static void cli_issue_write(struct cli_state *cli, int fnum, off_t offset, uint16 mode, char *buf,
1662 bzero(cli->outbuf,smb_size);
1663 bzero(cli->inbuf,smb_size);
1665 set_message(cli->outbuf,12,size,True);
1667 CVAL(cli->outbuf,smb_com) = SMBwriteX;
1668 SSVAL(cli->outbuf,smb_tid,cli->cnum);
1669 cli_setup_packet(cli);
1671 CVAL(cli->outbuf,smb_vwv0) = 0xFF;
1672 SSVAL(cli->outbuf,smb_vwv2,fnum);
1674 SIVAL(cli->outbuf,smb_vwv3,offset);
1675 SIVAL(cli->outbuf,smb_vwv5,IS_BITS_SET_ALL(mode, 0x0008) ? 0xFFFFFFFF : 0);
1676 SSVAL(cli->outbuf,smb_vwv7,mode);
1678 SSVAL(cli->outbuf,smb_vwv8,IS_BITS_SET_ALL(mode, 0x0008) ? size : 0);
1679 SSVAL(cli->outbuf,smb_vwv10,size);
1680 SSVAL(cli->outbuf,smb_vwv11,
1681 smb_buf(cli->outbuf) - smb_base(cli->outbuf));
1683 p = smb_base(cli->outbuf) + SVAL(cli->outbuf,smb_vwv11);
1684 memcpy(p, buf, size);
1686 SSVAL(cli->outbuf,smb_mid,cli->mid + i);
1688 cli_send_smb(cli, True);
1691 /****************************************************************************
1693 write_mode: 0x0001 disallow write cacheing
1694 0x0002 return bytes remaining
1695 0x0004 use raw named pipe protocol
1696 0x0008 start of message mode named pipe protocol
1697 ****************************************************************************/
1698 ssize_t cli_write(struct cli_state *cli,
1699 int fnum, uint16 write_mode,
1700 char *buf, off_t offset, size_t size)
1705 int mpx = MAX(cli->max_mux-1, 1);
1706 int block = (cli->max_xmit - (smb_size+32)) & ~1023;
1708 int blocks = (size + (block-1)) / block;
1710 if (size == 0) return 0;
1712 while (received < blocks) {
1715 while (issued - received < mpx && issued < blocks) {
1716 int size1 = MIN(block, size-issued*block);
1717 cli_issue_write(cli, fnum, offset+issued*block,
1724 if (!cli_receive_smb(cli)) {
1729 mid = SVAL(cli->inbuf, smb_mid) - cli->mid;
1730 size2 = SVAL(cli->inbuf, smb_vwv2);
1732 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1733 blocks = MIN(blocks, mid-1);
1738 blocks = MIN(blocks, mid-1);
1739 /* this distinguishes EOF from an error */
1740 total = MAX(total, 0);
1746 total = MAX(total, mid*block + size2);
1749 while (received < issued) {
1750 cli_receive_smb(cli);
1758 /****************************************************************************
1759 do a SMBgetattrE call
1760 ****************************************************************************/
1761 BOOL cli_getattrE(struct cli_state *cli, int fd,
1762 uint16 *attr, size_t *size,
1763 time_t *c_time, time_t *a_time, time_t *m_time)
1765 bzero(cli->outbuf,smb_size);
1766 bzero(cli->inbuf,smb_size);
1768 set_message(cli->outbuf,2,0,True);
1770 CVAL(cli->outbuf,smb_com) = SMBgetattrE;
1771 SSVAL(cli->outbuf,smb_tid,cli->cnum);
1772 cli_setup_packet(cli);
1774 SSVAL(cli->outbuf,smb_vwv0,fd);
1776 cli_send_smb(cli, True);
1777 if (!cli_receive_smb(cli)) {
1781 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1786 *size = IVAL(cli->inbuf, smb_vwv6);
1790 *attr = SVAL(cli->inbuf,smb_vwv10);
1794 *c_time = make_unix_date3(cli->inbuf+smb_vwv0);
1798 *a_time = make_unix_date3(cli->inbuf+smb_vwv2);
1802 *m_time = make_unix_date3(cli->inbuf+smb_vwv4);
1809 /****************************************************************************
1811 ****************************************************************************/
1812 BOOL cli_getatr(struct cli_state *cli, char *fname,
1813 uint16 *attr, size_t *size, time_t *t)
1817 bzero(cli->outbuf,smb_size);
1818 bzero(cli->inbuf,smb_size);
1820 set_message(cli->outbuf,0,strlen(fname)+2,True);
1822 CVAL(cli->outbuf,smb_com) = SMBgetatr;
1823 SSVAL(cli->outbuf,smb_tid,cli->cnum);
1824 cli_setup_packet(cli);
1826 p = smb_buf(cli->outbuf);
1828 pstrcpy(p+1, fname);
1830 cli_send_smb(cli, True);
1831 if (!cli_receive_smb(cli)) {
1835 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1840 *size = IVAL(cli->inbuf, smb_vwv3);
1844 *t = make_unix_date3(cli->inbuf+smb_vwv1);
1848 *attr = SVAL(cli->inbuf,smb_vwv0);
1856 /****************************************************************************
1858 ****************************************************************************/
1859 BOOL cli_setatr(struct cli_state *cli, char *fname, uint16 attr, time_t t)
1863 bzero(cli->outbuf,smb_size);
1864 bzero(cli->inbuf,smb_size);
1866 set_message(cli->outbuf,8,strlen(fname)+4,True);
1868 CVAL(cli->outbuf,smb_com) = SMBsetatr;
1869 SSVAL(cli->outbuf,smb_tid,cli->cnum);
1870 cli_setup_packet(cli);
1872 SSVAL(cli->outbuf,smb_vwv0, attr);
1873 put_dos_date3(cli->outbuf,smb_vwv1, t);
1875 p = smb_buf(cli->outbuf);
1877 pstrcpy(p+1, fname);
1878 p = skip_string(p,1);
1881 cli_send_smb(cli, True);
1882 if (!cli_receive_smb(cli)) {
1886 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1893 /****************************************************************************
1894 send a qpathinfo call
1895 ****************************************************************************/
1896 BOOL cli_qpathinfo(struct cli_state *cli, const char *fname,
1897 time_t *c_time, time_t *a_time, time_t *m_time,
1898 size_t *size, uint16 *mode)
1902 uint16 setup = TRANSACT2_QPATHINFO;
1904 char *rparam=NULL, *rdata=NULL;
1907 time_t (*date_fn)(void *);
1909 param_len = strlen(fname) + 7;
1911 memset(param, 0, param_len);
1912 SSVAL(param, 0, SMB_INFO_STANDARD);
1913 pstrcpy(¶m[6], fname);
1916 ret = (cli_send_trans(cli, SMBtrans2,
1917 NULL, 0, /* Name, length */
1918 -1, 0, /* fid, flags */
1919 &setup, 1, 0, /* setup, length, max */
1920 param, param_len, 10, /* param, length, max */
1921 NULL, data_len, cli->max_xmit /* data, length, max */
1923 cli_receive_trans(cli, SMBtrans2,
1924 &rparam, ¶m_len,
1925 &rdata, &data_len));
1927 /* we need to work around a Win95 bug - sometimes
1928 it gives ERRSRV/ERRerror temprarily */
1931 cli_error(cli, &eclass, &ecode);
1932 if (eclass != ERRSRV || ecode != ERRerror) break;
1935 } while (count-- && ret==False);
1937 if (!ret || !rdata || data_len < 22) {
1942 date_fn = make_unix_date;
1944 date_fn = make_unix_date2;
1948 *c_time = date_fn(rdata+0);
1951 *a_time = date_fn(rdata+4);
1954 *m_time = date_fn(rdata+8);
1957 *size = IVAL(rdata, 12);
1960 *mode = SVAL(rdata,l1_attrFile);
1963 if (rdata) free(rdata);
1964 if (rparam) free(rparam);
1968 /****************************************************************************
1969 send a qpathinfo call with the SMB_QUERY_FILE_ALL_INFO info level
1970 ****************************************************************************/
1971 BOOL cli_qpathinfo2(struct cli_state *cli, const char *fname,
1972 time_t *c_time, time_t *a_time, time_t *m_time,
1973 time_t *w_time, size_t *size, uint16 *mode,
1978 uint16 setup = TRANSACT2_QPATHINFO;
1980 char *rparam=NULL, *rdata=NULL;
1982 param_len = strlen(fname) + 7;
1984 memset(param, 0, param_len);
1985 SSVAL(param, 0, SMB_QUERY_FILE_ALL_INFO);
1986 pstrcpy(¶m[6], fname);
1988 if (!cli_send_trans(cli, SMBtrans2,
1989 NULL, 0, /* name, length */
1990 -1, 0, /* fid, flags */
1991 &setup, 1, 0, /* setup, length, max */
1992 param, param_len, 10, /* param, length, max */
1993 NULL, data_len, cli->max_xmit /* data, length, max */
1998 if (!cli_receive_trans(cli, SMBtrans2,
1999 &rparam, ¶m_len,
2000 &rdata, &data_len)) {
2004 if (!rdata || data_len < 22) {
2009 *c_time = interpret_long_date(rdata+0) - cli->serverzone;
2012 *a_time = interpret_long_date(rdata+8) - cli->serverzone;
2015 *m_time = interpret_long_date(rdata+16) - cli->serverzone;
2018 *w_time = interpret_long_date(rdata+24) - cli->serverzone;
2021 *mode = SVAL(rdata, 32);
2024 *size = IVAL(rdata, 40);
2027 *ino = IVAL(rdata, 64);
2030 if (rdata) free(rdata);
2031 if (rparam) free(rparam);
2036 /****************************************************************************
2037 send a qfileinfo call
2038 ****************************************************************************/
2039 BOOL cli_qfileinfo(struct cli_state *cli, int fnum,
2040 uint16 *mode, size_t *size,
2041 time_t *c_time, time_t *a_time, time_t *m_time,
2042 time_t *w_time, SMB_INO_T *ino)
2046 uint16 setup = TRANSACT2_QFILEINFO;
2048 char *rparam=NULL, *rdata=NULL;
2050 /* if its a win95 server then fail this - win95 totally screws it
2052 if (cli->win95) return False;
2056 memset(param, 0, param_len);
2057 SSVAL(param, 0, fnum);
2058 SSVAL(param, 2, SMB_QUERY_FILE_ALL_INFO);
2060 if (!cli_send_trans(cli, SMBtrans2,
2061 NULL, 0, /* name, length */
2062 -1, 0, /* fid, flags */
2063 &setup, 1, 0, /* setup, length, max */
2064 param, param_len, 2, /* param, length, max */
2065 NULL, data_len, cli->max_xmit /* data, length, max */
2070 if (!cli_receive_trans(cli, SMBtrans2,
2071 &rparam, ¶m_len,
2072 &rdata, &data_len)) {
2076 if (!rdata || data_len < 68) {
2081 *c_time = interpret_long_date(rdata+0) - cli->serverzone;
2084 *a_time = interpret_long_date(rdata+8) - cli->serverzone;
2087 *m_time = interpret_long_date(rdata+16) - cli->serverzone;
2090 *w_time = interpret_long_date(rdata+24) - cli->serverzone;
2093 *mode = SVAL(rdata, 32);
2096 *size = IVAL(rdata, 40);
2099 *ino = IVAL(rdata, 64);
2102 if (rdata) free(rdata);
2103 if (rparam) free(rparam);
2108 /****************************************************************************
2109 interpret a long filename structure - this is mostly guesses at the moment
2110 The length of the structure is returned
2111 The structure of a long filename depends on the info level. 260 is used
2112 by NT and 2 is used by OS/2
2113 ****************************************************************************/
2114 static int interpret_long_filename(int level,char *p,file_info *finfo)
2116 extern file_info def_finfo;
2119 memcpy(finfo,&def_finfo,sizeof(*finfo));
2123 case 1: /* OS/2 understands this */
2125 /* these dates are converted to GMT by make_unix_date */
2126 finfo->ctime = make_unix_date2(p+4);
2127 finfo->atime = make_unix_date2(p+8);
2128 finfo->mtime = make_unix_date2(p+12);
2129 finfo->size = IVAL(p,16);
2130 finfo->mode = CVAL(p,24);
2131 pstrcpy(finfo->name,p+27);
2133 return(28 + CVAL(p,26));
2135 case 2: /* this is what OS/2 uses mostly */
2137 /* these dates are converted to GMT by make_unix_date */
2138 finfo->ctime = make_unix_date2(p+4);
2139 finfo->atime = make_unix_date2(p+8);
2140 finfo->mtime = make_unix_date2(p+12);
2141 finfo->size = IVAL(p,16);
2142 finfo->mode = CVAL(p,24);
2143 pstrcpy(finfo->name,p+31);
2145 return(32 + CVAL(p,30));
2147 /* levels 3 and 4 are untested */
2150 /* these dates are probably like the other ones */
2151 finfo->ctime = make_unix_date2(p+8);
2152 finfo->atime = make_unix_date2(p+12);
2153 finfo->mtime = make_unix_date2(p+16);
2154 finfo->size = IVAL(p,20);
2155 finfo->mode = CVAL(p,28);
2156 pstrcpy(finfo->name,p+33);
2158 return(SVAL(p,4)+4);
2162 /* these dates are probably like the other ones */
2163 finfo->ctime = make_unix_date2(p+8);
2164 finfo->atime = make_unix_date2(p+12);
2165 finfo->mtime = make_unix_date2(p+16);
2166 finfo->size = IVAL(p,20);
2167 finfo->mode = CVAL(p,28);
2168 pstrcpy(finfo->name,p+37);
2170 return(SVAL(p,4)+4);
2172 case 260: /* NT uses this, but also accepts 2 */
2174 int ret = SVAL(p,0);
2176 p += 4; /* next entry offset */
2177 p += 4; /* fileindex */
2179 /* these dates appear to arrive in a
2180 weird way. It seems to be localtime
2181 plus the serverzone given in the
2182 initial connect. This is GMT when
2183 DST is not in effect and one hour
2184 from GMT otherwise. Can this really
2187 I suppose this could be called
2188 kludge-GMT. Is is the GMT you get
2189 by using the current DST setting on
2190 a different localtime. It will be
2191 cheap to calculate, I suppose, as
2192 no DST tables will be needed */
2194 finfo->ctime = interpret_long_date(p); p += 8;
2195 finfo->atime = interpret_long_date(p); p += 8;
2196 finfo->mtime = interpret_long_date(p); p += 8; p += 8;
2197 finfo->size = IVAL(p,0); p += 8;
2198 p += 8; /* alloc size */
2199 finfo->mode = CVAL(p,0); p += 4;
2200 namelen = IVAL(p,0); p += 4;
2201 p += 4; /* EA size */
2202 p += 2; /* short name len? */
2203 p += 24; /* short name? */
2204 StrnCpy(finfo->name,p,namelen);
2210 DEBUG(1,("Unknown long filename format %d\n",level));
2215 /****************************************************************************
2216 do a directory listing, calling fn on each file found
2217 ****************************************************************************/
2218 int cli_list(struct cli_state *cli,const char *Mask,uint16 attribute,
2219 void (*fn)(file_info *, const char *))
2221 int max_matches = 512;
2222 /* NT uses 260, OS/2 uses 2. Both accept 1. */
2223 int info_level = cli->protocol<PROTOCOL_NT1?1:260;
2228 char *dirlist = NULL;
2229 int dirlist_len = 0;
2230 int total_received = -1;
2232 int ff_resume_key = 0;
2233 int ff_searchcount=0;
2236 int ff_dir_handle=0;
2238 char *rparam=NULL, *rdata=NULL;
2239 int param_len, data_len;
2246 while (ff_eos == 0) {
2248 if (loop_count > 200) {
2249 DEBUG(0,("Error: Looping in FIND_NEXT??\n"));
2253 param_len = 12+strlen(mask)+1;
2256 setup = TRANSACT2_FINDFIRST;
2257 SSVAL(param,0,attribute); /* attribute */
2258 SSVAL(param,2,max_matches); /* max count */
2259 SSVAL(param,4,8+4+2); /* resume required + close on end + continue */
2260 SSVAL(param,6,info_level);
2262 pstrcpy(param+12,mask);
2264 setup = TRANSACT2_FINDNEXT;
2265 SSVAL(param,0,ff_dir_handle);
2266 SSVAL(param,2,max_matches); /* max count */
2267 SSVAL(param,4,info_level);
2268 SIVAL(param,6,ff_resume_key); /* ff_resume_key */
2269 SSVAL(param,10,8+4+2); /* resume required + close on end + continue */
2270 pstrcpy(param+12,mask);
2272 DEBUG(5,("hand=0x%X resume=%d ff_lastname=%d mask=%s\n",
2273 ff_dir_handle,ff_resume_key,ff_lastname,mask));
2276 if (!cli_send_trans(cli, SMBtrans2,
2277 NULL, 0, /* Name, length */
2278 -1, 0, /* fid, flags */
2279 &setup, 1, 0, /* setup, length, max */
2280 param, param_len, 10, /* param, length, max */
2282 cli->max_xmit /* data, length, max */
2287 if (!cli_receive_trans(cli, SMBtrans2,
2288 &rparam, ¶m_len,
2289 &rdata, &data_len)) {
2290 /* we need to work around a Win95 bug - sometimes
2291 it gives ERRSRV/ERRerror temprarily */
2294 cli_error(cli, &eclass, &ecode);
2295 if (eclass != ERRSRV || ecode != ERRerror) break;
2300 if (total_received == -1) total_received = 0;
2302 /* parse out some important return info */
2305 ff_dir_handle = SVAL(p,0);
2306 ff_searchcount = SVAL(p,2);
2308 ff_lastname = SVAL(p,8);
2310 ff_searchcount = SVAL(p,0);
2312 ff_lastname = SVAL(p,6);
2315 if (ff_searchcount == 0)
2318 /* point to the data bytes */
2321 /* we might need the lastname for continuations */
2322 if (ff_lastname > 0) {
2327 StrnCpy(mask,p+ff_lastname,
2328 data_len-ff_lastname);
2331 pstrcpy(mask,p + ff_lastname + 1);
2339 /* and add them to the dirlist pool */
2340 dirlist = Realloc(dirlist,dirlist_len + data_len);
2343 DEBUG(0,("Failed to expand dirlist\n"));
2347 /* put in a length for the last entry, to ensure we can chain entries
2348 into the next packet */
2349 for (p2=p,i=0;i<(ff_searchcount-1);i++)
2350 p2 += interpret_long_filename(info_level,p2,NULL);
2351 SSVAL(p2,0,data_len - PTR_DIFF(p2,p));
2353 /* grab the data for later use */
2354 memcpy(dirlist+dirlist_len,p,data_len);
2355 dirlist_len += data_len;
2357 total_received += ff_searchcount;
2359 if (rdata) free(rdata); rdata = NULL;
2360 if (rparam) free(rparam); rparam = NULL;
2362 DEBUG(3,("received %d entries (eos=%d resume=%d)\n",
2363 ff_searchcount,ff_eos,ff_resume_key));
2368 for (p=dirlist,i=0;i<total_received;i++) {
2369 p += interpret_long_filename(info_level,p,&finfo);
2373 /* free up the dirlist buffer */
2374 if (dirlist) free(dirlist);
2375 return(total_received);
2379 /****************************************************************************
2380 Send a SamOEMChangePassword command
2381 ****************************************************************************/
2383 BOOL cli_oem_change_password(struct cli_state *cli, const char *user, const char *new_password,
2384 const char *old_password)
2386 char param[16+sizeof(fstring)];
2389 fstring upper_case_old_pw;
2390 fstring upper_case_new_pw;
2391 unsigned char old_pw_hash[16];
2392 unsigned char new_pw_hash[16];
2395 char *rparam = NULL;
2399 if (strlen(user) >= sizeof(fstring)-1) {
2400 DEBUG(0,("cli_oem_change_password: user name %s is too long.\n", user));
2404 SSVAL(p,0,214); /* SamOEMChangePassword command. */
2407 p = skip_string(p,1);
2408 pstrcpy(p, "B516B16");
2409 p = skip_string(p,1);
2411 p = skip_string(p,1);
2415 param_len = PTR_DIFF(p,param);
2418 * Get the Lanman hash of the old password, we
2419 * use this as the key to make_oem_passwd_hash().
2421 memset(upper_case_old_pw, '\0', sizeof(upper_case_old_pw));
2422 fstrcpy(upper_case_old_pw, old_password);
2423 strupper(upper_case_old_pw);
2424 E_P16((uchar *)upper_case_old_pw, old_pw_hash);
2426 if (!make_oem_passwd_hash( data, new_password, old_pw_hash, False))
2432 * Now place the old password hash in the data.
2434 memset(upper_case_new_pw, '\0', sizeof(upper_case_new_pw));
2435 fstrcpy(upper_case_new_pw, new_password);
2436 strupper(upper_case_new_pw);
2438 E_P16((uchar *)upper_case_new_pw, new_pw_hash);
2440 E_old_pw_hash( new_pw_hash, old_pw_hash, (uchar *)&data[516]);
2444 if (!cli_send_trans(cli,SMBtrans,
2445 PIPE_LANMAN,strlen(PIPE_LANMAN), /* name, length */
2446 0,0, /* fid, flags */
2447 NULL,0,0, /* setup, length, max */
2448 param,param_len,2, /* param, length, max */
2449 data,data_len,0 /* data, length, max */
2452 DEBUG(0,("cli_oem_change_password: Failed to send password change for user %s\n",
2457 if (cli_receive_trans(cli,SMBtrans,
2461 cli->rap_error = SVAL(rparam,0);
2469 return (cli->rap_error == 0);
2472 /****************************************************************************
2473 send a negprot command
2474 ****************************************************************************/
2475 BOOL cli_negprot(struct cli_state *cli)
2481 bzero(cli->outbuf,smb_size);
2483 /* setup the protocol strings */
2484 for (plength=0,numprots=0;
2485 prots[numprots].name && prots[numprots].prot<=cli->protocol;
2487 plength += strlen(prots[numprots].name)+2;
2489 set_message(cli->outbuf,0,plength,True);
2491 p = smb_buf(cli->outbuf);
2493 prots[numprots].name && prots[numprots].prot<=cli->protocol;
2496 pstrcpy(p,prots[numprots].name);
2500 CVAL(cli->outbuf,smb_com) = SMBnegprot;
2501 cli_setup_packet(cli);
2503 CVAL(smb_buf(cli->outbuf),0) = 2;
2505 cli_send_smb(cli, True);
2506 if (!cli_receive_smb(cli))
2511 if (CVAL(cli->inbuf,smb_rcls) != 0 ||
2512 ((int)SVAL(cli->inbuf,smb_vwv0) >= numprots)) {
2516 cli->protocol = prots[SVAL(cli->inbuf,smb_vwv0)].prot;
2519 if (cli->protocol >= PROTOCOL_NT1)
2521 char *buf = smb_buf(cli->inbuf);
2522 int bcc = SVAL(cli->inbuf,smb_vwv+2*(CVAL(cli->inbuf,smb_wct)));
2524 cli->sec_mode = CVAL(cli->inbuf,smb_vwv1);
2525 cli->max_mux = SVAL(cli->inbuf, smb_vwv1+1);
2526 cli->max_xmit = IVAL(cli->inbuf,smb_vwv3+1);
2527 cli->sesskey = IVAL(cli->inbuf,smb_vwv7+1);
2528 cli->serverzone = SVALS(cli->inbuf,smb_vwv15+1)*60;
2529 /* this time arrives in real GMT */
2530 cli->servertime = interpret_long_date(cli->inbuf+smb_vwv11+1);
2532 cli->capabilities = IVAL(cli->inbuf,smb_vwv9+1);
2533 if (IS_BITS_SET_ALL(cli->capabilities, CAP_RAW_MODE))
2535 cli->readbraw_supported = True;
2536 cli->writebraw_supported = True;
2539 if (IS_BITS_SET_ALL(cli->capabilities, CAP_EXTENDED_SECURITY))
2541 /* oops, some kerberos-related nonsense. */
2542 /* expect to have to use NTLMSSP-over-SMB */
2543 DEBUG(10,("unknown kerberos-related (?) blob\n"));
2544 memset(cli->cryptkey, 0, 8);
2545 cli->server_domain[0] = 0;
2549 memcpy(cli->cryptkey, buf,8);
2552 unibuf_to_ascii(cli->server_domain, buf+8,
2553 sizeof(cli->server_domain));
2557 cli->server_domain[0] = 0;
2559 DEBUG(5,("server's domain: %s bcc: %d\n",
2560 cli->server_domain, bcc));
2563 else if (cli->protocol >= PROTOCOL_LANMAN1)
2565 cli->sec_mode = SVAL(cli->inbuf,smb_vwv1);
2566 cli->max_xmit = SVAL(cli->inbuf,smb_vwv2);
2567 cli->sesskey = IVAL(cli->inbuf,smb_vwv6);
2568 cli->serverzone = SVALS(cli->inbuf,smb_vwv10)*60;
2569 /* this time is converted to GMT by make_unix_date */
2570 cli->servertime = make_unix_date(cli->inbuf+smb_vwv8);
2571 cli->readbraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x1) != 0);
2572 cli->writebraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x2) != 0);
2573 memcpy(cli->cryptkey,smb_buf(cli->inbuf),8);
2575 /* the old core protocol */
2577 cli->serverzone = TimeDiff(time(NULL));
2580 cli->max_xmit = MIN(cli->max_xmit, CLI_BUFFER_SIZE);
2586 /****************************************************************************
2587 send a session request. see rfc1002.txt 4.3 and 4.3.2
2588 ****************************************************************************/
2589 BOOL cli_session_request(struct cli_state *cli,
2590 struct nmb_name *calling, struct nmb_name *called)
2594 /* send a session request (RFC 1002) */
2596 memcpy(&(cli->calling), calling, sizeof(*calling));
2597 memcpy(&(cli->called ), called , sizeof(*called ));
2599 if (cli->port == 445)
2604 /* put in the destination name */
2605 p = cli->outbuf+len;
2606 name_mangle(cli->called .name, p, cli->called .name_type);
2610 p = cli->outbuf+len;
2611 name_mangle(cli->calling.name, p, cli->calling.name_type);
2614 /* setup the packet length */
2615 _smb_setlen(cli->outbuf,len);
2616 CVAL(cli->outbuf,0) = 0x81;
2620 #endif /* WITH_SSL */
2622 cli_send_smb(cli, True);
2623 DEBUG(5,("Sent session request\n"));
2625 if (!cli_receive_smb(cli))
2629 if (CVAL(cli->inbuf,0) == 0x83 && CVAL(cli->inbuf,4) == 0x8e){ /* use ssl */
2630 if (!sslutil_fd_is_ssl(cli->fd)){
2631 if (sslutil_connect(cli->fd) == 0)
2635 #endif /* WITH_SSL */
2637 if (CVAL(cli->inbuf,0) != 0x82) {
2638 /* This is the wrong place to put the error... JRA. */
2639 cli->rap_error = CVAL(cli->inbuf,0);
2646 /****************************************************************************
2647 open the client sockets
2648 ****************************************************************************/
2649 BOOL cli_connect(struct cli_state *cli, const char *host, struct in_addr *ip)
2651 extern struct in_addr ipzero;
2652 int port = cli->port;
2654 fstrcpy(cli->desthost, host);
2656 if (!ip || ip_equal(*ip, ipzero)) {
2657 if (!resolve_name( cli->desthost, &cli->dest_ip, 0x20)) {
2660 if (ip) *ip = cli->dest_ip;
2666 if (port == 0) port = SMB_PORT2;
2668 cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip,
2669 port, cli->timeout);
2678 cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip,
2679 port, cli->timeout);
2680 if (cli->fd == -1) return False;
2689 /****************************************************************************
2690 initialise a client structure
2691 ****************************************************************************/
2692 struct cli_state *cli_initialise(struct cli_state *cli)
2695 cli = (struct cli_state *)malloc(sizeof(*cli));
2701 if (cli->initialised) {
2710 cli->pid = (uint16)getpid();
2712 cli->vuid = UID_FIELD_INVALID;
2713 cli->protocol = PROTOCOL_NT1;
2714 cli->timeout = 20000;
2715 cli->bufsize = CLI_BUFFER_SIZE+4;
2716 cli->max_xmit = cli->bufsize;
2717 cli->outbuf = (char *)malloc(cli->bufsize);
2718 cli->inbuf = (char *)malloc(cli->bufsize);
2719 if (!cli->outbuf || !cli->inbuf)
2724 cli->initialised = 1;
2725 cli->capabilities = CAP_DFS;
2730 /****************************************************************************
2731 close the socket descriptor
2732 ****************************************************************************/
2733 void cli_close_socket(struct cli_state *cli)
2738 sslutil_disconnect(cli->fd);
2740 #endif /* WITH_SSL */
2748 /****************************************************************************
2749 shutdown a client structure
2750 ****************************************************************************/
2751 void cli_shutdown(struct cli_state *cli)
2753 DEBUG(10,("cli_shutdown\n"));
2762 cli_close_socket(cli);
2763 memset(cli, 0, sizeof(*cli));
2767 /****************************************************************************
2768 return error codes for the last packet
2769 returns 0 if there was no error and the best approx of a unix errno
2772 for 32 bit "warnings", a return code of 0 is expected.
2774 ****************************************************************************/
2775 int cli_error(struct cli_state *cli, uint8 *eclass, uint32 *num)
2781 if (!cli->initialised)
2783 DEBUG(0,("cli_error: client state uninitialised!\n"));
2787 flgs2 = SVAL(cli->inbuf,smb_flg2);
2789 if (eclass) *eclass = 0;
2792 if (flgs2 & FLAGS2_32_BIT_ERROR_CODES)
2794 /* 32 bit error codes detected */
2795 uint32 nt_err = IVAL(cli->inbuf,smb_rcls);
2796 if (num) *num = nt_err;
2797 DEBUG(10,("cli_error: 32 bit codes: code=%08x\n", nt_err));
2798 if (!IS_BITS_SET_ALL(nt_err, 0xc0000000)) return 0;
2800 switch (nt_err & 0xFFFFFF)
2802 case NT_STATUS_ACCESS_VIOLATION : return EACCES;
2803 case NT_STATUS_NO_SUCH_FILE : return ENOENT;
2804 case NT_STATUS_NO_SUCH_DEVICE : return ENODEV;
2805 case NT_STATUS_INVALID_HANDLE : return EBADF;
2806 case NT_STATUS_NO_MEMORY : return ENOMEM;
2807 case NT_STATUS_ACCESS_DENIED : return EACCES;
2808 case NT_STATUS_OBJECT_NAME_NOT_FOUND: return ENOENT;
2809 case NT_STATUS_SHARING_VIOLATION : return EBUSY;
2810 case NT_STATUS_OBJECT_PATH_INVALID : return ENOTDIR;
2811 case NT_STATUS_OBJECT_NAME_COLLISION: return EEXIST;
2814 /* for all other cases - a default code */
2818 rcls = CVAL(cli->inbuf,smb_rcls);
2819 code = SVAL(cli->inbuf,smb_err);
2820 if (rcls == 0) return 0;
2822 if (eclass) *eclass = rcls;
2823 if (num ) *num = code;
2825 if (rcls == ERRDOS) {
2827 case ERRbadfile: return ENOENT;
2828 case ERRbadpath: return ENOTDIR;
2829 case ERRnoaccess: return EACCES;
2830 case ERRfilexists: return EEXIST;
2831 case ERRrename: return EEXIST;
2832 case ERRbadshare: return EBUSY;
2833 case ERRlock: return EBUSY;
2834 case ERRmoredata: return 0; /* Informational only */
2837 if (rcls == ERRSRV) {
2839 case ERRbadpw: return EPERM;
2840 case ERRaccess: return EACCES;
2841 case ERRnoresource: return ENOMEM;
2842 case ERRinvdevice: return ENODEV;
2843 case ERRinvnetname: return ENODEV;
2846 /* for other cases */
2850 /****************************************************************************
2851 set socket options on a open connection
2852 ****************************************************************************/
2853 void cli_sockopt(struct cli_state *cli, char *options)
2855 set_socket_options(cli->fd, options);
2858 /****************************************************************************
2859 set the PID to use for smb messages. Return the old pid.
2860 ****************************************************************************/
2861 uint16 cli_setpid(struct cli_state *cli, uint16 pid)
2863 uint16 ret = cli->pid;
2868 /****************************************************************************
2869 re-establishes a connection
2870 ****************************************************************************/
2871 BOOL cli_reestablish_connection(struct cli_state *cli)
2873 struct nmb_name calling;
2874 struct nmb_name called;
2878 BOOL do_tcon = False;
2879 int oldfd = cli->fd;
2881 if (!cli->initialised || cli->fd == -1)
2883 DEBUG(3,("cli_reestablish_connection: not connected\n"));
2887 /* copy the parameters necessary to re-establish the connection */
2896 fstrcpy(share, cli->share);
2897 fstrcpy(dev , cli->dev);
2900 memcpy(&called , &(cli->called ), sizeof(called ));
2901 memcpy(&calling, &(cli->calling), sizeof(calling));
2902 fstrcpy(dest_host, cli->desthost);
2904 DEBUG(5,("cli_reestablish_connection: %s connecting to %s (ip %s) - %s [%s]\n",
2905 nmb_namestr(&calling), nmb_namestr(&called),
2906 inet_ntoa(cli->dest_ip),
2907 cli->user_name, cli->domain));
2911 if (cli_establish_connection(cli,
2912 dest_host, &cli->dest_ip,
2914 share, dev, False, do_tcon))
2916 if (cli->fd != oldfd)
2918 if (dup2(cli->fd, oldfd) == oldfd)
2920 cli_close_socket(cli);
2928 /****************************************************************************
2929 establishes a connection right up to doing tconX, reading in a password.
2930 ****************************************************************************/
2931 BOOL cli_establish_connection(struct cli_state *cli,
2932 char *dest_host, struct in_addr *dest_ip,
2933 struct nmb_name *calling, struct nmb_name *called,
2934 char *service, char *service_type,
2935 BOOL do_shutdown, BOOL do_tcon)
2940 nmb_safe_namestr(calling, callingstr, sizeof(callingstr));
2941 nmb_safe_namestr(called , calledstr , sizeof(calledstr ));
2943 DEBUG(5,("cli_establish_connection: %s connecting to %s (%s) - %s [%s] with NTLM%s\n",
2944 callingstr, calledstr, inet_ntoa(*dest_ip),
2945 cli->user_name, cli->domain,
2946 cli->use_ntlmv2 ? "v2" : "v1"));
2948 /* establish connection */
2950 if ((!cli->initialised))
2957 if (!cli_connect(cli, dest_host, dest_ip))
2959 DEBUG(1,("cli_establish_connection: failed to connect to %s (%s)\n",
2960 callingstr, inet_ntoa(*dest_ip)));
2965 if (!cli_session_request(cli, calling, called))
2967 DEBUG(1,("failed session request\n"));
2975 if (!cli_negprot(cli))
2977 DEBUG(1,("failed negprot\n"));
2985 if (cli->domain[0] == 0)
2987 safe_strcpy(cli->domain, cli->server_domain,
2988 sizeof(cli->domain));
2991 if (IS_BITS_SET_ALL(cli->capabilities, CAP_EXTENDED_SECURITY))
2993 /* common to both session setups */
2997 char *e = pwd_buf + sizeof(pwd_buf);
2999 /* 1st session setup */
3002 0x60, 0x40, 0x06, 0x06, 0x2b, 0x06, 0x01, 0x05,
3003 0x05, 0x02, 0xa0, 0x36, 0x30, 0x34, 0xa0, 0x0e,
3004 0x30, 0x0c, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04,
3005 0x01, 0x82, 0x37, 0x02, 0x02, 0x0a, 0xa2, 0x22,
3008 /* 2nd session setup */
3010 char pwd_data_2[8] =
3012 0xa1, 0x51, 0x30, 0x4f, 0xa2, 0x4d, 0x04, 0x4b
3015 char pwd_data_2[8] =
3017 0xa1, 0x51, 0x30, 0x4f, 0xa2, 0x4d, 0x04, 0x4b
3019 prs_struct auth_resp;
3026 memset(pwd_buf, 0, sizeof(pwd_buf));
3027 memcpy(pwd_buf, pwd_data, sizeof(pwd_data));
3028 p = pwd_buf + sizeof(pwd_data);
3030 safe_strcpy(p, "NTLMSSP", PTR_DIFF(e, p) - 1);
3031 p = skip_string(p, 1);
3034 if (cli->ntlmssp_cli_flgs == 0)
3036 cli->ntlmssp_cli_flgs =
3037 NTLMSSP_NEGOTIATE_UNICODE |
3038 NTLMSSP_NEGOTIATE_OEM |
3039 NTLMSSP_NEGOTIATE_SIGN |
3040 NTLMSSP_NEGOTIATE_SEAL |
3041 NTLMSSP_NEGOTIATE_LM_KEY |
3042 NTLMSSP_NEGOTIATE_NTLM |
3043 NTLMSSP_NEGOTIATE_ALWAYS_SIGN |
3044 NTLMSSP_NEGOTIATE_00001000 |
3045 NTLMSSP_NEGOTIATE_00002000;
3047 cli->ntlmssp_cli_flgs = 0x80008207;
3050 SIVAL(p, 0, cli->ntlmssp_cli_flgs);
3052 p += 16; /* skip some NULL space */
3053 CVAL(p, 0) = 0; p++; /* alignment */
3055 buf_len = PTR_DIFF(p, pwd_buf);
3057 /* first session negotiation stage */
3058 if (!cli_session_setup_x(cli, cli->user_name,
3063 DEBUG(1,("failed session setup\n"));
3071 DEBUG(1,("1st session setup ok\n"));
3073 if (*cli->server_domain || *cli->server_os || *cli->server_type)
3075 DEBUG(1,("Domain=[%s] OS=[%s] Server=[%s]\n",
3081 p = smb_buf(cli->inbuf) + 0x2f;
3082 cli->ntlmssp_cli_flgs = IVAL(p, 0); /* 0x80808a05; */
3084 memcpy(cli->cryptkey, p, 8);
3085 #ifdef DEBUG_PASSWORD
3086 DEBUG(100,("cli_session_setup_x: ntlmssp %8x\n",
3087 cli->ntlmssp_cli_flgs));
3089 DEBUG(100,("cli_session_setup_x: crypt key\n"));
3090 dump_data(100, cli->cryptkey, 8);
3092 prs_init(&auth_resp, 1024, 4, SAFETY_MARGIN, False);
3094 pwd_make_lm_nt_owf(&cli->pwd, cli->cryptkey);
3096 create_ntlmssp_resp(&cli->pwd, cli->domain,
3097 cli->user_name, cli->calling.name,
3098 cli->ntlmssp_cli_flgs,
3100 prs_link(NULL, &auth_resp, NULL);
3102 memset(pwd_buf, 0, sizeof(pwd_buf));
3105 CVAL(p, 0) = 0xa1; p++;
3106 CVAL(p, 0) = 0x82; p++;
3107 p_gssapi = p; p+= 2;
3108 CVAL(p, 0) = 0x30; p++;
3109 CVAL(p, 0) = 0x82; p++;
3112 CVAL(p, 0) = 0xa2; p++;
3113 CVAL(p, 0) = 0x82; p++;
3115 CVAL(p, 0) = 0x04; p++;
3116 CVAL(p, 0) = 0x82; p++;
3121 safe_strcpy(p, "NTLMSSP", PTR_DIFF(e, p) - 1);
3122 p = skip_string(p, 1);
3126 resp_len = mem_buf_len(auth_resp.data);
3127 mem_buf_copy(p, auth_resp.data, 0, resp_len);
3128 prs_mem_free(&auth_resp);
3132 buf_len = PTR_DIFF(p, pwd_buf);
3133 gssapi_len = PTR_DIFF(p, p_gssapi_end) + 12;
3135 *p_gssapi++ = (gssapi_len >> 8) & 0xff;
3136 *p_gssapi++ = gssapi_len & 0xff;
3141 *p_gssapi++ = (gssapi_len >> 8) & 0xff;
3142 *p_gssapi++ = gssapi_len & 0xff;
3146 *p_oem++ = (gssapi_len >> 8) & 0xff;
3147 *p_oem++ = gssapi_len & 0xff;
3152 *p_oem++ = (gssapi_len >> 8) & 0xff;
3153 *p_oem++ = gssapi_len & 0xff;
3155 /* second session negotiation stage */
3156 if (!cli_session_setup_x(cli, cli->user_name,
3161 DEBUG(1,("failed session setup\n"));
3169 DEBUG(1,("2nd session setup ok\n"));
3173 if (!cli_send_tconX(cli, service, service_type,
3177 DEBUG(1,("failed tcon_X\n"));
3186 else if (cli->pwd.cleartext || cli->pwd.null_pwd)
3188 fstring passwd, ntpasswd;
3189 int pass_len = 0, ntpass_len = 0;
3191 if (cli->pwd.null_pwd)
3193 /* attempt null session */
3194 passwd[0] = ntpasswd[0] = 0;
3195 pass_len = ntpass_len = 1;
3199 /* attempt clear-text session */
3200 pwd_get_cleartext(&(cli->pwd), passwd);
3201 pass_len = strlen(passwd);
3204 /* attempt clear-text session */
3205 if (!cli_session_setup(cli, cli->user_name,
3207 ntpasswd, ntpass_len,
3210 DEBUG(1,("failed session setup\n"));
3219 if (!cli_send_tconX(cli, service, service_type,
3220 (char*)passwd, strlen(passwd)))
3222 DEBUG(1,("failed tcon_X\n"));
3233 /* attempt encrypted session */
3234 unsigned char lm_sess_pwd[24];
3235 unsigned char nt_sess_pwd[128];
3236 size_t nt_sess_pwd_len;
3238 if (cli->use_ntlmv2 != False)
3240 DEBUG(10,("cli_establish_connection: NTLMv2\n"));
3241 pwd_make_lm_nt_owf2(&(cli->pwd), cli->cryptkey,
3242 cli->user_name, calling->name, cli->domain);
3246 DEBUG(10,("cli_establish_connection: NTLMv1\n"));
3247 pwd_make_lm_nt_owf(&(cli->pwd), cli->cryptkey);
3250 pwd_get_lm_nt_owf(&(cli->pwd), lm_sess_pwd, nt_sess_pwd,
3253 /* attempt encrypted session */
3254 if (!cli_session_setup_x(cli, cli->user_name,
3255 (char*)lm_sess_pwd, sizeof(lm_sess_pwd),
3256 (char*)nt_sess_pwd, nt_sess_pwd_len,
3259 DEBUG(1,("failed session setup\n"));
3261 if (cli->use_ntlmv2 == Auto)
3263 DEBUG(10,("NTLMv2 failed. Using NTLMv1\n"));
3264 cli->use_ntlmv2 = False;
3267 fstrcpy(cli->share, service);
3268 fstrcpy(cli->dev, service_type);
3270 fstrcpy(cli->desthost, dest_host);
3271 cli_close_socket(cli);
3272 return cli_establish_connection(cli,
3275 service, service_type,
3276 do_shutdown, do_tcon);
3286 DEBUG(1,("session setup ok\n"));
3288 if (*cli->server_domain || *cli->server_os || *cli->server_type)
3290 DEBUG(1,("Domain=[%s] OS=[%s] Server=[%s]\n",
3298 if (!cli_send_tconX(cli, service, service_type,
3299 (char*)nt_sess_pwd, sizeof(nt_sess_pwd)))
3301 DEBUG(1,("failed tcon_X\n"));
3319 /****************************************************************************
3320 connect to one of multiple servers: don't care which
3321 ****************************************************************************/
3322 BOOL cli_connect_serverlist(struct cli_state *cli, char *p)
3324 extern pstring global_myname;
3325 extern pstring scope;
3326 fstring remote_machine;
3327 struct in_addr dest_ip;
3328 struct nmb_name calling, called, stupid_smbserver_called;
3329 BOOL connected_ok = False;
3332 * Treat each name in the 'password server =' line as a potential
3333 * PDC/BDC. Contact each in turn and try and authenticate.
3336 while(p && next_token(&p,remote_machine,LIST_SEP,sizeof(remote_machine)))
3340 if (!cli_initialise(cli))
3342 DEBUG(0,("cli_connect_serverlist: unable to initialize client connection.\n"));
3346 standard_sub_basic(remote_machine);
3347 strupper(remote_machine);
3349 if (!resolve_name( remote_machine, &dest_ip, 0x20))
3351 DEBUG(1,("cli_connect_serverlist: Can't resolve address for %s\n", remote_machine));
3355 if ((lp_security() != SEC_USER) && (ismyip(dest_ip)))
3357 DEBUG(1,("cli_connect_serverlist: Password server loop - not using password server %s\n", remote_machine));
3361 make_nmb_name(&calling, global_myname , 0x0 , scope);
3362 make_nmb_name(&called , remote_machine, 0x20, scope);
3363 /* stupid microsoft destruction of the ability of netbios
3364 * to provide multiple netbios servers on one host.
3366 make_nmb_name(&stupid_smbserver_called , "*SMBSERVER", 0x20, scope);
3368 pwd_set_nullpwd(&cli->pwd);
3370 if (!cli_establish_connection(cli, remote_machine, &dest_ip,
3374 !cli_establish_connection(cli, remote_machine, &dest_ip,
3375 &calling, &stupid_smbserver_called,
3383 if (cli->protocol < PROTOCOL_LANMAN2 ||
3384 !IS_BITS_SET_ALL(cli->sec_mode, 1))
3386 DEBUG(1,("cli_connect_serverlist: machine %s isn't in user level security mode\n",
3393 * We have an anonymous connection to IPC$.
3396 connected_ok = True;
3402 DEBUG(0,("cli_connect_serverlist: Domain password server not available.\n"));
3406 return connected_ok;
3409 /****************************************************************************
3411 ****************************************************************************/
3412 int cli_printjob_del(struct cli_state *cli, int job)
3414 char *rparam = NULL;
3417 int rdrcnt,rprcnt, ret = -1;
3420 bzero(param,sizeof(param));
3423 SSVAL(p,0,81); /* DosPrintJobDel() */
3426 p = skip_string(p,1);
3428 p = skip_string(p,1);
3433 param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */
3434 NULL, 0, CLI_BUFFER_SIZE, /* data, length, maxlen */
3435 &rparam, &rprcnt, /* return params, length */
3436 &rdata, &rdrcnt)) { /* return data, length */
3437 ret = SVAL(rparam,0);
3440 if (rparam) free(rparam);
3441 if (rdata) free(rdata);
3447 /****************************************************************************
3448 call fn() on each entry in a print queue
3449 ****************************************************************************/
3450 int cli_print_queue(struct cli_state *cli,
3451 void (*fn)(struct print_job_info *))
3453 char *rparam = NULL;
3461 bzero(param,sizeof(param));
3464 SSVAL(p,0,76); /* API function number 76 (DosPrintJobEnum) */
3466 pstrcpy(p,"zWrLeh"); /* parameter description? */
3467 p = skip_string(p,1);
3468 pstrcpy(p,"WWzWWDDzz"); /* returned data format */
3469 p = skip_string(p,1);
3470 pstrcpy(p,cli->share); /* name of queue */
3471 p = skip_string(p,1);
3472 SSVAL(p,0,2); /* API function level 2, PRJINFO_2 data structure */
3473 SSVAL(p,2,1000); /* size of bytes of returned data buffer */
3475 pstrcpy(p,""); /* subformat */
3476 p = skip_string(p,1);
3478 DEBUG(4,("doing cli_print_queue for %s\n", cli->share));
3481 param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */
3482 NULL, 0, CLI_BUFFER_SIZE, /* data, length, maxlen */
3483 &rparam, &rprcnt, /* return params, length */
3484 &rdata, &rdrcnt)) { /* return data, length */
3486 result_code = SVAL(rparam,0);
3487 converter = SVAL(rparam,2); /* conversion factor */
3489 if (result_code == 0) {
3490 struct print_job_info job;
3494 for (i = 0; i < SVAL(rparam,4); ++i) {
3496 job.priority = SVAL(p,2);
3498 fix_char_ptr(SVAL(p,4), converter,
3500 job.t = make_unix_date3(p + 12);
3501 job.size = IVAL(p,16);
3502 fstrcpy(job.name,fix_char_ptr(SVAL(p,24),
3511 /* If any parameters or data were returned, free the storage. */
3512 if(rparam) free(rparam);
3513 if(rdata) free(rdata);
3518 /****************************************************************************
3519 check for existance of a dir
3520 ****************************************************************************/
3521 BOOL cli_chkpath(struct cli_state *cli, char *path)
3526 fstrcpy(path2,path);
3527 trim_string(path2,NULL,"\\");
3528 if (!*path2) *path2 = '\\';
3530 bzero(cli->outbuf,smb_size);
3531 set_message(cli->outbuf,0,4 + strlen(path2),True);
3532 SCVAL(cli->outbuf,smb_com,SMBchkpth);
3533 SSVAL(cli->outbuf,smb_tid,cli->cnum);
3534 cli_setup_packet(cli);
3536 p = smb_buf(cli->outbuf);
3540 cli_send_smb(cli, True);
3541 if (!cli_receive_smb(cli)) {
3545 if (cli_error(cli, NULL, NULL)) return False;
3551 /****************************************************************************
3552 start a message sequence
3553 ****************************************************************************/
3554 BOOL cli_message_start(struct cli_state *cli, char *host, char *username,
3559 /* send a SMBsendstrt command */
3560 bzero(cli->outbuf,smb_size);
3561 set_message(cli->outbuf,0,0,True);
3562 CVAL(cli->outbuf,smb_com) = SMBsendstrt;
3563 SSVAL(cli->outbuf,smb_tid,cli->cnum);
3564 cli_setup_packet(cli);
3566 p = smb_buf(cli->outbuf);
3568 pstrcpy(p,username);
3569 p = skip_string(p,1);
3572 p = skip_string(p,1);
3574 set_message(cli->outbuf,0,PTR_DIFF(p,smb_buf(cli->outbuf)),False);
3576 cli_send_smb(cli, True);
3578 if (!cli_receive_smb(cli)) {
3582 if (cli_error(cli, NULL, NULL)) return False;
3584 *grp = SVAL(cli->inbuf,smb_vwv0);
3590 /****************************************************************************
3592 ****************************************************************************/
3593 BOOL cli_message_text(struct cli_state *cli, char *msg, int len, int grp)
3597 bzero(cli->outbuf,smb_size);
3598 set_message(cli->outbuf,1,len+3,True);
3599 CVAL(cli->outbuf,smb_com) = SMBsendtxt;
3600 SSVAL(cli->outbuf,smb_tid,cli->cnum);
3601 cli_setup_packet(cli);
3603 SSVAL(cli->outbuf,smb_vwv0,grp);
3605 p = smb_buf(cli->outbuf);
3608 memcpy(p+3,msg,len);
3609 cli_send_smb(cli, True);
3611 if (!cli_receive_smb(cli)) {
3615 if (cli_error(cli, NULL, NULL)) return False;
3620 /****************************************************************************
3622 ****************************************************************************/
3623 BOOL cli_message_end(struct cli_state *cli, int grp)
3625 bzero(cli->outbuf,smb_size);
3626 set_message(cli->outbuf,1,0,True);
3627 CVAL(cli->outbuf,smb_com) = SMBsendend;
3628 SSVAL(cli->outbuf,smb_tid,cli->cnum);
3630 SSVAL(cli->outbuf,smb_vwv0,grp);
3632 cli_setup_packet(cli);
3634 cli_send_smb(cli, True);
3636 if (!cli_receive_smb(cli)) {
3640 if (cli_error(cli, NULL, NULL)) return False;
3646 /****************************************************************************
3648 ****************************************************************************/
3649 BOOL cli_dskattr(struct cli_state *cli, int *bsize, int *total, int *avail)
3651 bzero(cli->outbuf,smb_size);
3652 set_message(cli->outbuf,0,0,True);
3653 CVAL(cli->outbuf,smb_com) = SMBdskattr;
3654 SSVAL(cli->outbuf,smb_tid,cli->cnum);
3655 cli_setup_packet(cli);
3657 cli_send_smb(cli, True);
3658 if (!cli_receive_smb(cli)) {
3662 *bsize = SVAL(cli->inbuf,smb_vwv1)*SVAL(cli->inbuf,smb_vwv2);
3663 *total = SVAL(cli->inbuf,smb_vwv0);
3664 *avail = SVAL(cli->inbuf,smb_vwv3);