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;
29 extern pstring user_socket_options;
31 static void cli_process_oplock(struct cli_state *cli);
34 * Change the port number used to call on
36 int cli_set_port(struct cli_state *cli, int port)
44 /****************************************************************************
46 ****************************************************************************/
47 static BOOL cli_receive_smb(struct cli_state *cli)
51 ret = client_receive_smb(cli->fd,cli->inbuf,cli->timeout);
54 /* it might be an oplock break request */
55 if (!(CVAL(cli->inbuf, smb_flg) & FLAG_REPLY) &&
56 CVAL(cli->inbuf,smb_com) == SMBlockingX &&
57 SVAL(cli->inbuf,smb_vwv6) == 0 &&
58 SVAL(cli->inbuf,smb_vwv7) == 0) {
59 if (cli->use_oplocks) cli_process_oplock(cli);
60 /* try to prevent loops */
61 CVAL(cli->inbuf,smb_com) = 0xFF;
69 /****************************************************************************
70 send an smb to a fd and re-establish if necessary
71 ****************************************************************************/
72 static BOOL cli_send_smb(struct cli_state *cli)
77 BOOL reestablished=False;
79 len = smb_len(cli->outbuf) + 4;
81 while (nwritten < len) {
82 ret = write_socket(cli->fd,cli->outbuf+nwritten,len - nwritten);
83 if (ret <= 0 && errno == EPIPE && !reestablished) {
84 if (cli_reestablish_connection(cli)) {
91 DEBUG(0,("Error writing %d bytes to client. %d. Exiting\n",
102 /****************************************************************************
103 setup basics in a outgoing packet
104 ****************************************************************************/
105 static void cli_setup_packet(struct cli_state *cli)
109 SSVAL(cli->outbuf,smb_pid,cli->pid);
110 SSVAL(cli->outbuf,smb_uid,cli->vuid);
111 SSVAL(cli->outbuf,smb_mid,cli->mid);
112 if (cli->protocol > PROTOCOL_CORE) {
113 SCVAL(cli->outbuf,smb_flg,0x8);
114 SSVAL(cli->outbuf,smb_flg2,0x1);
120 /****************************************************************************
121 process an oplock break request from the server
122 ****************************************************************************/
123 static void cli_process_oplock(struct cli_state *cli)
125 char *oldbuf = cli->outbuf;
129 fnum = SVAL(cli->inbuf,smb_vwv2);
131 /* damn, we really need to keep a record of open files so we
132 can detect a oplock break and a close crossing on the
133 wire. for now this swallows the errors */
134 if (fnum == 0) return;
138 memset(buf,'\0',smb_size);
139 set_message(buf,8,0,True);
141 CVAL(buf,smb_com) = SMBlockingX;
142 SSVAL(buf,smb_tid, cli->cnum);
143 cli_setup_packet(cli);
144 SSVAL(buf,smb_vwv0,0xFF);
145 SSVAL(buf,smb_vwv1,0);
146 SSVAL(buf,smb_vwv2,fnum);
147 SSVAL(buf,smb_vwv3,2); /* oplock break ack */
148 SIVAL(buf,smb_vwv4,0); /* timoeut */
149 SSVAL(buf,smb_vwv6,0); /* unlockcount */
150 SSVAL(buf,smb_vwv7,0); /* lockcount */
154 cli->outbuf = oldbuf;
158 /*****************************************************
159 RAP error codes - a small start but will be extended.
160 *******************************************************/
168 {5, "User has insufficient privilege" },
169 {86, "The specified password is invalid" },
170 {2226, "Operation only permitted on a Primary Domain Controller" },
171 {2242, "The password of this user has expired." },
172 {2243, "The password of this user cannot change." },
173 {2244, "This password cannot be used now (password history conflict)." },
174 {2245, "The password is shorter than required." },
175 {2246, "The password of this user is too recent to change."},
177 /* these really shouldn't be here ... */
178 {0x80, "Not listening on called name"},
179 {0x81, "Not listening for calling name"},
180 {0x82, "Called name not present"},
181 {0x83, "Called name present, but insufficient resources"},
186 /****************************************************************************
187 return a description of an SMB error
188 ****************************************************************************/
189 static char *cli_smb_errstr(struct cli_state *cli)
191 return smb_errstr(cli->inbuf);
194 /******************************************************
195 Return an error message - either an SMB error or a RAP
197 *******************************************************/
199 char *cli_errstr(struct cli_state *cli)
201 static fstring error_message;
208 * Errors are of three kinds - smb errors,
209 * dealt with by cli_smb_errstr, NT errors,
210 * whose code is in cli.nt_error, and rap
211 * errors, whose error code is in cli.rap_error.
214 cli_error(cli, &errclass, &errnum, &nt_rpc_error);
218 return cli_smb_errstr(cli);
222 * Was it an NT error ?
227 char *nt_msg = get_nt_error_msg(nt_rpc_error);
231 slprintf(error_message, sizeof(fstring) - 1, "NT code %d", nt_rpc_error);
235 fstrcpy(error_message, nt_msg);
238 return error_message;
242 * Must have been a rap error.
245 slprintf(error_message, sizeof(error_message) - 1, "code %d", cli->rap_error);
247 for (i = 0; rap_errmap[i].message != NULL; i++)
249 if (rap_errmap[i].err == cli->rap_error)
251 fstrcpy( error_message, rap_errmap[i].message);
256 return error_message;
259 /*****************************************************************************
260 Convert a character pointer in a cli_call_api() response to a form we can use.
261 This function contains code to prevent core dumps if the server returns
263 *****************************************************************************/
264 static char *fix_char_ptr(unsigned int datap, unsigned int converter,
265 char *rdata, int rdrcnt)
267 if (datap == 0) { /* turn NULL pointers into zero length strings */
270 unsigned int offset = datap - converter;
272 if (offset >= rdrcnt) {
273 DEBUG(1,("bad char ptr: datap=%u, converter=%u rdrcnt=%d>",
274 datap, converter, rdrcnt));
277 return &rdata[offset];
282 /****************************************************************************
283 send a SMB trans or trans2 request
284 ****************************************************************************/
285 static BOOL cli_send_trans(struct cli_state *cli, int trans,
286 char *name, int pipe_name_len,
288 uint16 *setup, int lsetup, int msetup,
289 char *param, int lparam, int mparam,
290 char *data, int ldata, int mdata)
293 int this_ldata,this_lparam;
294 int tot_data=0,tot_param=0;
295 char *outdata,*outparam;
298 this_lparam = MIN(lparam,cli->max_xmit - (500+lsetup*2)); /* hack */
299 this_ldata = MIN(ldata,cli->max_xmit - (500+lsetup*2+this_lparam));
301 memset(cli->outbuf,'\0',smb_size);
302 set_message(cli->outbuf,14+lsetup,0,True);
303 CVAL(cli->outbuf,smb_com) = trans;
304 SSVAL(cli->outbuf,smb_tid, cli->cnum);
305 cli_setup_packet(cli);
307 outparam = smb_buf(cli->outbuf)+(trans==SMBtrans ? pipe_name_len+1 : 3);
308 outdata = outparam+this_lparam;
310 /* primary request */
311 SSVAL(cli->outbuf,smb_tpscnt,lparam); /* tpscnt */
312 SSVAL(cli->outbuf,smb_tdscnt,ldata); /* tdscnt */
313 SSVAL(cli->outbuf,smb_mprcnt,mparam); /* mprcnt */
314 SSVAL(cli->outbuf,smb_mdrcnt,mdata); /* mdrcnt */
315 SCVAL(cli->outbuf,smb_msrcnt,msetup); /* msrcnt */
316 SSVAL(cli->outbuf,smb_flags,flags); /* flags */
317 SIVAL(cli->outbuf,smb_timeout,0); /* timeout */
318 SSVAL(cli->outbuf,smb_pscnt,this_lparam); /* pscnt */
319 SSVAL(cli->outbuf,smb_psoff,smb_offset(outparam,cli->outbuf)); /* psoff */
320 SSVAL(cli->outbuf,smb_dscnt,this_ldata); /* dscnt */
321 SSVAL(cli->outbuf,smb_dsoff,smb_offset(outdata,cli->outbuf)); /* dsoff */
322 SCVAL(cli->outbuf,smb_suwcnt,lsetup); /* suwcnt */
323 for (i=0;i<lsetup;i++) /* setup[] */
324 SSVAL(cli->outbuf,smb_setup+i*2,setup[i]);
325 p = smb_buf(cli->outbuf);
326 if (trans==SMBtrans) {
327 memcpy(p,name, pipe_name_len + 1); /* name[] */
329 *p++ = 0; /* put in a null smb_name */
330 *p++ = 'D'; *p++ = ' '; /* observed in OS/2 */
332 if (this_lparam) /* param[] */
333 memcpy(outparam,param,this_lparam);
334 if (this_ldata) /* data[] */
335 memcpy(outdata,data,this_ldata);
336 set_message(cli->outbuf,14+lsetup, /* wcnt, bcc */
337 PTR_DIFF(outdata+this_ldata,smb_buf(cli->outbuf)),False);
339 show_msg(cli->outbuf);
342 if (this_ldata < ldata || this_lparam < lparam) {
343 /* receive interim response */
344 if (!cli_receive_smb(cli) ||
345 CVAL(cli->inbuf,smb_rcls) != 0) {
349 tot_data = this_ldata;
350 tot_param = this_lparam;
352 while (tot_data < ldata || tot_param < lparam) {
353 this_lparam = MIN(lparam-tot_param,cli->max_xmit - 500); /* hack */
354 this_ldata = MIN(ldata-tot_data,cli->max_xmit - (500+this_lparam));
356 set_message(cli->outbuf,trans==SMBtrans?8:9,0,True);
357 CVAL(cli->outbuf,smb_com) = trans==SMBtrans ? SMBtranss : SMBtranss2;
359 outparam = smb_buf(cli->outbuf);
360 outdata = outparam+this_lparam;
362 /* secondary request */
363 SSVAL(cli->outbuf,smb_tpscnt,lparam); /* tpscnt */
364 SSVAL(cli->outbuf,smb_tdscnt,ldata); /* tdscnt */
365 SSVAL(cli->outbuf,smb_spscnt,this_lparam); /* pscnt */
366 SSVAL(cli->outbuf,smb_spsoff,smb_offset(outparam,cli->outbuf)); /* psoff */
367 SSVAL(cli->outbuf,smb_spsdisp,tot_param); /* psdisp */
368 SSVAL(cli->outbuf,smb_sdscnt,this_ldata); /* dscnt */
369 SSVAL(cli->outbuf,smb_sdsoff,smb_offset(outdata,cli->outbuf)); /* dsoff */
370 SSVAL(cli->outbuf,smb_sdsdisp,tot_data); /* dsdisp */
371 if (trans==SMBtrans2)
372 SSVALS(cli->outbuf,smb_sfid,fid); /* fid */
373 if (this_lparam) /* param[] */
374 memcpy(outparam,param+tot_param,this_lparam);
375 if (this_ldata) /* data[] */
376 memcpy(outdata,data+tot_data,this_ldata);
377 set_message(cli->outbuf,trans==SMBtrans?8:9, /* wcnt, bcc */
378 PTR_DIFF(outdata+this_ldata,smb_buf(cli->outbuf)),False);
380 show_msg(cli->outbuf);
383 tot_data += this_ldata;
384 tot_param += this_lparam;
392 /****************************************************************************
393 receive a SMB trans or trans2 response allocating the necessary memory
394 ****************************************************************************/
395 static BOOL cli_receive_trans(struct cli_state *cli,int trans,
396 char **param, int *param_len,
397 char **data, int *data_len)
401 int this_data,this_param;
405 *data_len = *param_len = 0;
407 if (!cli_receive_smb(cli))
410 show_msg(cli->inbuf);
413 if (CVAL(cli->inbuf,smb_com) != trans) {
414 DEBUG(0,("Expected %s response, got command 0x%02x\n",
415 trans==SMBtrans?"SMBtrans":"SMBtrans2",
416 CVAL(cli->inbuf,smb_com)));
421 * An NT RPC pipe call can return ERRDOS, ERRmoredata
422 * to a trans call. This is not an error and should not
423 * be treated as such.
426 if (cli_error(cli, &eclass, &ecode, NULL))
428 if(cli->nt_pipe_fnum == 0 || !(eclass == ERRDOS && ecode == ERRmoredata))
432 /* parse out the lengths */
433 total_data = SVAL(cli->inbuf,smb_tdrcnt);
434 total_param = SVAL(cli->inbuf,smb_tprcnt);
437 *data = Realloc(*data,total_data);
438 *param = Realloc(*param,total_param);
441 this_data = SVAL(cli->inbuf,smb_drcnt);
442 this_param = SVAL(cli->inbuf,smb_prcnt);
444 if (this_data + *data_len > total_data ||
445 this_param + *param_len > total_param) {
446 DEBUG(1,("Data overflow in cli_receive_trans\n"));
451 memcpy(*data + SVAL(cli->inbuf,smb_drdisp),
452 smb_base(cli->inbuf) + SVAL(cli->inbuf,smb_droff),
455 memcpy(*param + SVAL(cli->inbuf,smb_prdisp),
456 smb_base(cli->inbuf) + SVAL(cli->inbuf,smb_proff),
458 *data_len += this_data;
459 *param_len += this_param;
461 /* parse out the total lengths again - they can shrink! */
462 total_data = SVAL(cli->inbuf,smb_tdrcnt);
463 total_param = SVAL(cli->inbuf,smb_tprcnt);
465 if (total_data <= *data_len && total_param <= *param_len)
468 if (!cli_receive_smb(cli))
471 show_msg(cli->inbuf);
474 if (CVAL(cli->inbuf,smb_com) != trans) {
475 DEBUG(0,("Expected %s response, got command 0x%02x\n",
476 trans==SMBtrans?"SMBtrans":"SMBtrans2",
477 CVAL(cli->inbuf,smb_com)));
480 if (cli_error(cli, &eclass, &ecode, NULL))
482 if(cli->nt_pipe_fnum == 0 || !(eclass == ERRDOS && ecode == ERRmoredata))
490 /****************************************************************************
491 Call a remote api on an arbitrary pipe. takes param, data and setup buffers.
492 ****************************************************************************/
493 BOOL cli_api_pipe(struct cli_state *cli, char *pipe_name, int pipe_name_len,
494 uint16 *setup, uint32 setup_count, uint32 max_setup_count,
495 char *params, uint32 param_count, uint32 max_param_count,
496 char *data, uint32 data_count, uint32 max_data_count,
497 char **rparam, uint32 *rparam_count,
498 char **rdata, uint32 *rdata_count)
500 if (pipe_name_len == 0)
501 pipe_name_len = strlen(pipe_name);
503 cli_send_trans(cli, SMBtrans,
504 pipe_name, pipe_name_len,
505 0,0, /* fid, flags */
506 setup, setup_count, max_setup_count,
507 params, param_count, max_param_count,
508 data, data_count, max_data_count);
510 return (cli_receive_trans(cli, SMBtrans,
511 rparam, (int *)rparam_count,
512 rdata, (int *)rdata_count));
515 /****************************************************************************
517 ****************************************************************************/
518 BOOL cli_api(struct cli_state *cli,
519 char *param, int prcnt, int mprcnt,
520 char *data, int drcnt, int mdrcnt,
521 char **rparam, int *rprcnt,
522 char **rdata, int *rdrcnt)
524 cli_send_trans(cli,SMBtrans,
525 PIPE_LANMAN,strlen(PIPE_LANMAN), /* Name, length */
526 0,0, /* fid, flags */
527 NULL,0,0, /* Setup, length, max */
528 param, prcnt, mprcnt, /* Params, length, max */
529 data, drcnt, mdrcnt /* Data, length, max */
532 return (cli_receive_trans(cli,SMBtrans,
538 /****************************************************************************
539 perform a NetWkstaUserLogon
540 ****************************************************************************/
541 BOOL cli_NetWkstaUserLogon(struct cli_state *cli,char *user, char *workstation)
549 memset(param, 0, sizeof(param));
551 /* send a SMBtrans command with api NetWkstaUserLogon */
553 SSVAL(p,0,132); /* api number */
555 pstrcpy(p,"OOWb54WrLh");
556 p = skip_string(p,1);
557 pstrcpy(p,"WB21BWDWWDDDDDDDzzzD");
558 p = skip_string(p,1);
567 pstrcpy(p, workstation);
570 SSVAL(p, 0, CLI_BUFFER_SIZE);
572 SSVAL(p, 0, CLI_BUFFER_SIZE);
576 param, PTR_DIFF(p,param),1024, /* param, length, max */
577 NULL, 0, CLI_BUFFER_SIZE, /* data, length, max */
578 &rparam, &rprcnt, /* return params, return size */
579 &rdata, &rdrcnt /* return data, return size */
581 cli->rap_error = SVAL(rparam,0);
584 if (cli->rap_error == 0) {
585 DEBUG(4,("NetWkstaUserLogon success\n"));
586 cli->privileges = SVAL(p, 24);
587 fstrcpy(cli->eff_name,p+2);
589 DEBUG(1,("NetwkstaUserLogon gave error %d\n", cli->rap_error));
597 return (cli->rap_error == 0);
600 /****************************************************************************
601 call a NetShareEnum - try and browse available connections on a host
602 ****************************************************************************/
603 BOOL cli_RNetShareEnum(struct cli_state *cli, void (*fn)(const char *, uint32, const char *))
612 /* now send a SMBtrans command with api RNetShareEnum */
614 SSVAL(p,0,0); /* api number */
617 p = skip_string(p,1);
619 p = skip_string(p,1);
625 param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */
626 NULL, 0, 0xFFFF, /* data, length, maxlen */
627 &rparam, &rprcnt, /* return params, length */
628 &rdata, &rdrcnt)) /* return data, length */
630 int res = SVAL(rparam,0);
631 int converter=SVAL(rparam,2);
634 if (res == 0 || res == ERRmoredata) {
635 count=SVAL(rparam,4);
638 for (i=0;i<count;i++,p+=20) {
640 int type = SVAL(p,14);
641 int comment_offset = IVAL(p,16) & 0xFFFF;
642 char *cmnt = comment_offset?(rdata+comment_offset-converter):"";
643 dos_to_unix(sname,True);
644 dos_to_unix(cmnt,True);
645 fn(sname, type, cmnt);
648 DEBUG(4,("NetShareEnum res=%d\n", res));
651 DEBUG(4,("NetShareEnum failed\n"));
663 /****************************************************************************
664 call a NetServerEnum for the specified workgroup and servertype mask.
665 This function then calls the specified callback function for each name returned.
667 The callback function takes 3 arguments: the machine name, the server type and
669 ****************************************************************************/
670 BOOL cli_NetServerEnum(struct cli_state *cli, char *workgroup, uint32 stype,
671 void (*fn)(const char *, uint32, const char *))
681 /* send a SMBtrans command with api NetServerEnum */
683 SSVAL(p,0,0x68); /* api number */
685 pstrcpy(p,"WrLehDz");
686 p = skip_string(p,1);
688 pstrcpy(p,"B16BBDz");
690 p = skip_string(p,1);
692 SSVAL(p,2,CLI_BUFFER_SIZE);
697 pstrcpy(p, workgroup);
698 p = skip_string(p,1);
701 param, PTR_DIFF(p,param), 8, /* params, length, max */
702 NULL, 0, CLI_BUFFER_SIZE, /* data, length, max */
703 &rparam, &rprcnt, /* return params, return size */
704 &rdata, &rdrcnt /* return data, return size */
706 int res = SVAL(rparam,0);
707 int converter=SVAL(rparam,2);
710 if (res == 0 || res == ERRmoredata) {
711 count=SVAL(rparam,4);
714 for (i = 0;i < count;i++, p += 26) {
716 int comment_offset = (IVAL(p,22) & 0xFFFF)-converter;
717 char *cmnt = comment_offset?(rdata+comment_offset):"";
718 if (comment_offset < 0 || comment_offset > rdrcnt) continue;
720 stype = IVAL(p,18) & ~SV_TYPE_LOCAL_LIST_ONLY;
722 dos_to_unix(sname, True);
723 dos_to_unix(cmnt, True);
724 fn(sname, stype, cmnt);
746 {PROTOCOL_CORE,"PC NETWORK PROGRAM 1.0"},
747 {PROTOCOL_COREPLUS,"MICROSOFT NETWORKS 1.03"},
748 {PROTOCOL_LANMAN1,"MICROSOFT NETWORKS 3.0"},
749 {PROTOCOL_LANMAN1,"LANMAN1.0"},
750 {PROTOCOL_LANMAN2,"LM1.2X002"},
751 {PROTOCOL_LANMAN2,"Samba"},
752 {PROTOCOL_NT1,"NT LANMAN 1.0"},
753 {PROTOCOL_NT1,"NT LM 0.12"},
758 /****************************************************************************
759 Send a session setup. The username is in UNIX character format and must be
760 converted to DOS codepage format before sending. If the password is in
761 plaintext, the same should be done.
762 ****************************************************************************/
764 BOOL cli_session_setup(struct cli_state *cli,
766 char *pass, int passlen,
767 char *ntpass, int ntpasslen,
771 fstring pword, ntpword;
773 if (cli->protocol < PROTOCOL_LANMAN1)
776 if (passlen > sizeof(pword)-1 || ntpasslen > sizeof(ntpword)-1) {
780 if (((passlen == 0) || (passlen == 1)) && (pass[0] == '\0')) {
781 /* Null session connect. */
785 if ((cli->sec_mode & 2) && passlen != 24) {
787 * Encrypted mode needed, and non encrypted password supplied.
791 fstrcpy(pword, pass);
792 unix_to_dos(pword,True);
793 fstrcpy(ntpword, ntpass);;
794 unix_to_dos(ntpword,True);
795 SMBencrypt((uchar *)pword,(uchar *)cli->cryptkey,(uchar *)pword);
796 SMBNTencrypt((uchar *)ntpword,(uchar *)cli->cryptkey,(uchar *)ntpword);
797 } else if ((cli->sec_mode & 2) && passlen == 24) {
799 * Encrypted mode needed, and encrypted password supplied.
801 memcpy(pword, pass, passlen);
802 if(ntpasslen == 24) {
803 memcpy(ntpword, ntpass, ntpasslen);
805 fstrcpy(ntpword, "");
810 * Plaintext mode needed, assume plaintext supplied.
812 fstrcpy(pword, pass);
813 unix_to_dos(pword,True);
814 fstrcpy(ntpword, "");
819 /* if in share level security then don't send a password now */
820 if (!(cli->sec_mode & 1)) {
823 fstrcpy(ntpword, "");
827 /* send a session setup command */
828 memset(cli->outbuf,'\0',smb_size);
830 if (cli->protocol < PROTOCOL_NT1)
832 set_message(cli->outbuf,10,1 + strlen(user) + passlen,True);
833 CVAL(cli->outbuf,smb_com) = SMBsesssetupX;
834 cli_setup_packet(cli);
836 CVAL(cli->outbuf,smb_vwv0) = 0xFF;
837 SSVAL(cli->outbuf,smb_vwv2,cli->max_xmit);
838 SSVAL(cli->outbuf,smb_vwv3,2);
839 SSVAL(cli->outbuf,smb_vwv4,1);
840 SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
841 SSVAL(cli->outbuf,smb_vwv7,passlen);
842 p = smb_buf(cli->outbuf);
843 memcpy(p,pword,passlen);
851 set_message(cli->outbuf,13,0,True);
852 CVAL(cli->outbuf,smb_com) = SMBsesssetupX;
853 cli_setup_packet(cli);
855 CVAL(cli->outbuf,smb_vwv0) = 0xFF;
856 SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
857 SSVAL(cli->outbuf,smb_vwv3,2);
858 SSVAL(cli->outbuf,smb_vwv4,cli->pid);
859 SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
860 SSVAL(cli->outbuf,smb_vwv7,passlen);
861 SSVAL(cli->outbuf,smb_vwv8,ntpasslen);
862 SSVAL(cli->outbuf,smb_vwv11,0);
863 p = smb_buf(cli->outbuf);
864 memcpy(p,pword,passlen);
865 p += SVAL(cli->outbuf,smb_vwv7);
866 memcpy(p,ntpword,ntpasslen);
867 p += SVAL(cli->outbuf,smb_vwv8);
871 p = skip_string(p,1);
872 pstrcpy(p,workgroup);
874 p = skip_string(p,1);
875 pstrcpy(p,"Unix");p = skip_string(p,1);
876 pstrcpy(p,"Samba");p = skip_string(p,1);
877 set_message(cli->outbuf,13,PTR_DIFF(p,smb_buf(cli->outbuf)),False);
881 if (!cli_receive_smb(cli))
884 show_msg(cli->inbuf);
886 if (CVAL(cli->inbuf,smb_rcls) != 0) {
890 /* use the returned vuid from now on */
891 cli->vuid = SVAL(cli->inbuf,smb_uid);
893 if (cli->protocol >= PROTOCOL_NT1) {
895 * Save off some of the connected server
898 char *server_domain,*server_os,*server_type;
899 server_os = smb_buf(cli->inbuf);
900 server_type = skip_string(server_os,1);
901 server_domain = skip_string(server_type,1);
902 fstrcpy(cli->server_os, server_os);
903 dos_to_unix(cli->server_os, True);
904 fstrcpy(cli->server_type, server_type);
905 dos_to_unix(cli->server_type, True);
906 fstrcpy(cli->server_domain, server_domain);
907 dos_to_unix(cli->server_domain, True);
910 fstrcpy(cli->user_name, user);
911 dos_to_unix(cli->user_name, True);
916 /****************************************************************************
918 *****************************************************************************/
920 BOOL cli_ulogoff(struct cli_state *cli)
922 memset(cli->outbuf,'\0',smb_size);
923 set_message(cli->outbuf,2,0,True);
924 CVAL(cli->outbuf,smb_com) = SMBulogoffX;
925 cli_setup_packet(cli);
926 SSVAL(cli->outbuf,smb_vwv0,0xFF);
927 SSVAL(cli->outbuf,smb_vwv2,0); /* no additional info */
930 if (!cli_receive_smb(cli))
933 return CVAL(cli->inbuf,smb_rcls) == 0;
936 /****************************************************************************
938 ****************************************************************************/
939 BOOL cli_send_tconX(struct cli_state *cli,
940 char *share, char *dev, char *pass, int passlen)
942 fstring fullshare, pword, dos_pword;
944 memset(cli->outbuf,'\0',smb_size);
945 memset(cli->inbuf,'\0',smb_size);
947 fstrcpy(cli->share, share);
949 /* in user level security don't send a password now */
950 if (cli->sec_mode & 1) {
955 if ((cli->sec_mode & 2) && *pass && passlen != 24) {
957 * Non-encrypted passwords - convert to DOS codepage before encryption.
960 fstrcpy(dos_pword,pass);
961 unix_to_dos(dos_pword,True);
962 SMBencrypt((uchar *)dos_pword,(uchar *)cli->cryptkey,(uchar *)pword);
964 if(!(cli->sec_mode & 2)) {
966 * Non-encrypted passwords - convert to DOS codepage before using.
969 unix_to_dos(pword,True);
971 memcpy(pword, pass, passlen);
975 slprintf(fullshare, sizeof(fullshare)-1,
976 "\\\\%s\\%s", cli->desthost, share);
977 unix_to_dos(fullshare, True);
980 set_message(cli->outbuf,4,
981 2 + strlen(fullshare) + passlen + strlen(dev),True);
982 CVAL(cli->outbuf,smb_com) = SMBtconX;
983 cli_setup_packet(cli);
985 SSVAL(cli->outbuf,smb_vwv0,0xFF);
986 SSVAL(cli->outbuf,smb_vwv3,passlen);
988 p = smb_buf(cli->outbuf);
989 memcpy(p,pword,passlen);
991 fstrcpy(p,fullshare);
992 p = skip_string(p,1);
996 SCVAL(cli->inbuf,smb_rcls, 1);
999 if (!cli_receive_smb(cli))
1002 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1006 fstrcpy(cli->dev, "A:");
1008 if (cli->protocol >= PROTOCOL_NT1) {
1009 fstrcpy(cli->dev, smb_buf(cli->inbuf));
1012 if (strcasecmp(share,"IPC$")==0) {
1013 fstrcpy(cli->dev, "IPC");
1016 /* only grab the device if we have a recent protocol level */
1017 if (cli->protocol >= PROTOCOL_NT1 &&
1018 smb_buflen(cli->inbuf) == 3) {
1019 /* almost certainly win95 - enable bug fixes */
1023 cli->cnum = SVAL(cli->inbuf,smb_tid);
1028 /****************************************************************************
1029 send a tree disconnect
1030 ****************************************************************************/
1031 BOOL cli_tdis(struct cli_state *cli)
1033 memset(cli->outbuf,'\0',smb_size);
1034 set_message(cli->outbuf,0,0,True);
1035 CVAL(cli->outbuf,smb_com) = SMBtdis;
1036 SSVAL(cli->outbuf,smb_tid,cli->cnum);
1037 cli_setup_packet(cli);
1040 if (!cli_receive_smb(cli))
1043 return CVAL(cli->inbuf,smb_rcls) == 0;
1046 /****************************************************************************
1048 ****************************************************************************/
1049 BOOL cli_rename(struct cli_state *cli, char *fname_src, char *fname_dst)
1053 memset(cli->outbuf,'\0',smb_size);
1054 memset(cli->inbuf,'\0',smb_size);
1056 set_message(cli->outbuf,1, 4 + strlen(fname_src) + strlen(fname_dst), True);
1058 CVAL(cli->outbuf,smb_com) = SMBmv;
1059 SSVAL(cli->outbuf,smb_tid,cli->cnum);
1060 cli_setup_packet(cli);
1062 SSVAL(cli->outbuf,smb_vwv0,aSYSTEM | aHIDDEN | aDIR);
1064 p = smb_buf(cli->outbuf);
1066 pstrcpy(p,fname_src);
1067 unix_to_dos(p,True);
1068 p = skip_string(p,1);
1070 pstrcpy(p,fname_dst);
1071 unix_to_dos(p,True);
1074 if (!cli_receive_smb(cli)) {
1078 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1085 /****************************************************************************
1087 ****************************************************************************/
1088 BOOL cli_unlink(struct cli_state *cli, char *fname)
1092 memset(cli->outbuf,'\0',smb_size);
1093 memset(cli->inbuf,'\0',smb_size);
1095 set_message(cli->outbuf,1, 2 + strlen(fname),True);
1097 CVAL(cli->outbuf,smb_com) = SMBunlink;
1098 SSVAL(cli->outbuf,smb_tid,cli->cnum);
1099 cli_setup_packet(cli);
1101 SSVAL(cli->outbuf,smb_vwv0,aSYSTEM | aHIDDEN);
1103 p = smb_buf(cli->outbuf);
1106 unix_to_dos(p,True);
1109 if (!cli_receive_smb(cli)) {
1113 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1120 /****************************************************************************
1122 ****************************************************************************/
1123 BOOL cli_mkdir(struct cli_state *cli, char *dname)
1127 memset(cli->outbuf,'\0',smb_size);
1128 memset(cli->inbuf,'\0',smb_size);
1130 set_message(cli->outbuf,0, 2 + strlen(dname),True);
1132 CVAL(cli->outbuf,smb_com) = SMBmkdir;
1133 SSVAL(cli->outbuf,smb_tid,cli->cnum);
1134 cli_setup_packet(cli);
1136 p = smb_buf(cli->outbuf);
1139 unix_to_dos(p,True);
1142 if (!cli_receive_smb(cli)) {
1146 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1153 /****************************************************************************
1155 ****************************************************************************/
1156 BOOL cli_rmdir(struct cli_state *cli, char *dname)
1160 memset(cli->outbuf,'\0',smb_size);
1161 memset(cli->inbuf,'\0',smb_size);
1163 set_message(cli->outbuf,0, 2 + strlen(dname),True);
1165 CVAL(cli->outbuf,smb_com) = SMBrmdir;
1166 SSVAL(cli->outbuf,smb_tid,cli->cnum);
1167 cli_setup_packet(cli);
1169 p = smb_buf(cli->outbuf);
1172 unix_to_dos(p,True);
1175 if (!cli_receive_smb(cli)) {
1179 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1188 /****************************************************************************
1190 ****************************************************************************/
1191 int cli_nt_create(struct cli_state *cli, char *fname)
1195 memset(cli->outbuf,'\0',smb_size);
1196 memset(cli->inbuf,'\0',smb_size);
1198 set_message(cli->outbuf,24,1 + strlen(fname),True);
1200 CVAL(cli->outbuf,smb_com) = SMBntcreateX;
1201 SSVAL(cli->outbuf,smb_tid,cli->cnum);
1202 cli_setup_packet(cli);
1204 SSVAL(cli->outbuf,smb_vwv0,0xFF);
1205 SIVAL(cli->outbuf,smb_ntcreate_Flags, 0x06);
1206 SIVAL(cli->outbuf,smb_ntcreate_RootDirectoryFid, 0x0);
1207 SIVAL(cli->outbuf,smb_ntcreate_DesiredAccess, 0x2019f);
1208 SIVAL(cli->outbuf,smb_ntcreate_FileAttributes, 0x0);
1209 SIVAL(cli->outbuf,smb_ntcreate_ShareAccess, 0x03);
1210 SIVAL(cli->outbuf,smb_ntcreate_CreateDisposition, 0x01);
1211 SIVAL(cli->outbuf,smb_ntcreate_CreateOptions, 0x0);
1212 SIVAL(cli->outbuf,smb_ntcreate_ImpersonationLevel, 0x02);
1213 SSVAL(cli->outbuf,smb_ntcreate_NameLength, strlen(fname));
1215 p = smb_buf(cli->outbuf);
1217 unix_to_dos(p,True);
1218 p = skip_string(p,1);
1221 if (!cli_receive_smb(cli)) {
1225 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1229 return SVAL(cli->inbuf,smb_vwv2 + 1);
1233 /****************************************************************************
1235 WARNING: if you open with O_WRONLY then getattrE won't work!
1236 ****************************************************************************/
1237 int cli_open(struct cli_state *cli, char *fname, int flags, int share_mode)
1241 unsigned accessmode=0;
1243 if (flags & O_CREAT)
1245 if (!(flags & O_EXCL)) {
1246 if (flags & O_TRUNC)
1252 accessmode = (share_mode<<4);
1254 if ((flags & O_ACCMODE) == O_RDWR) {
1256 } else if ((flags & O_ACCMODE) == O_WRONLY) {
1261 if ((flags & O_SYNC) == O_SYNC) {
1262 accessmode |= (1<<14);
1266 if (share_mode == DENY_FCB) {
1270 memset(cli->outbuf,'\0',smb_size);
1271 memset(cli->inbuf,'\0',smb_size);
1273 set_message(cli->outbuf,15,1 + strlen(fname),True);
1275 CVAL(cli->outbuf,smb_com) = SMBopenX;
1276 SSVAL(cli->outbuf,smb_tid,cli->cnum);
1277 cli_setup_packet(cli);
1279 SSVAL(cli->outbuf,smb_vwv0,0xFF);
1280 SSVAL(cli->outbuf,smb_vwv2,0); /* no additional info */
1281 SSVAL(cli->outbuf,smb_vwv3,accessmode);
1282 SSVAL(cli->outbuf,smb_vwv4,aSYSTEM | aHIDDEN);
1283 SSVAL(cli->outbuf,smb_vwv5,0);
1284 SSVAL(cli->outbuf,smb_vwv8,openfn);
1286 if (cli->use_oplocks) {
1287 /* if using oplocks then ask for a batch oplock via
1288 core and extended methods */
1289 CVAL(cli->outbuf,smb_flg) |=
1290 FLAG_REQUEST_OPLOCK|FLAG_REQUEST_BATCH_OPLOCK;
1291 SSVAL(cli->outbuf,smb_vwv2,SVAL(cli->outbuf,smb_vwv2) | 6);
1294 p = smb_buf(cli->outbuf);
1296 unix_to_dos(p,True);
1297 p = skip_string(p,1);
1300 if (!cli_receive_smb(cli)) {
1304 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1308 return SVAL(cli->inbuf,smb_vwv2);
1314 /****************************************************************************
1316 ****************************************************************************/
1317 BOOL cli_close(struct cli_state *cli, int fnum)
1319 memset(cli->outbuf,'\0',smb_size);
1320 memset(cli->inbuf,'\0',smb_size);
1322 set_message(cli->outbuf,3,0,True);
1324 CVAL(cli->outbuf,smb_com) = SMBclose;
1325 SSVAL(cli->outbuf,smb_tid,cli->cnum);
1326 cli_setup_packet(cli);
1328 SSVAL(cli->outbuf,smb_vwv0,fnum);
1329 SIVALS(cli->outbuf,smb_vwv1,-1);
1332 if (!cli_receive_smb(cli)) {
1336 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1344 /****************************************************************************
1346 ****************************************************************************/
1347 BOOL cli_lock(struct cli_state *cli, int fnum,
1348 uint32 offset, uint32 len, int timeout, enum brl_type lock_type)
1351 int saved_timeout = cli->timeout;
1353 memset(cli->outbuf,'\0',smb_size);
1354 memset(cli->inbuf,'\0', smb_size);
1356 set_message(cli->outbuf,8,10,True);
1358 CVAL(cli->outbuf,smb_com) = SMBlockingX;
1359 SSVAL(cli->outbuf,smb_tid,cli->cnum);
1360 cli_setup_packet(cli);
1362 CVAL(cli->outbuf,smb_vwv0) = 0xFF;
1363 SSVAL(cli->outbuf,smb_vwv2,fnum);
1364 CVAL(cli->outbuf,smb_vwv3) = (lock_type == READ_LOCK? 1 : 0);
1365 SIVALS(cli->outbuf, smb_vwv4, timeout);
1366 SSVAL(cli->outbuf,smb_vwv6,0);
1367 SSVAL(cli->outbuf,smb_vwv7,1);
1369 p = smb_buf(cli->outbuf);
1370 SSVAL(p, 0, cli->pid);
1371 SIVAL(p, 2, offset);
1375 cli->timeout = (timeout == -1) ? 0x7FFFFFFF : (timeout + 2*1000);
1377 if (!cli_receive_smb(cli)) {
1378 cli->timeout = saved_timeout;
1382 cli->timeout = saved_timeout;
1384 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1391 /****************************************************************************
1393 ****************************************************************************/
1394 BOOL cli_unlock(struct cli_state *cli, int fnum, uint32 offset, uint32 len)
1398 memset(cli->outbuf,'\0',smb_size);
1399 memset(cli->inbuf,'\0',smb_size);
1401 set_message(cli->outbuf,8,10,True);
1403 CVAL(cli->outbuf,smb_com) = SMBlockingX;
1404 SSVAL(cli->outbuf,smb_tid,cli->cnum);
1405 cli_setup_packet(cli);
1407 CVAL(cli->outbuf,smb_vwv0) = 0xFF;
1408 SSVAL(cli->outbuf,smb_vwv2,fnum);
1409 CVAL(cli->outbuf,smb_vwv3) = 0;
1410 SIVALS(cli->outbuf, smb_vwv4, 0);
1411 SSVAL(cli->outbuf,smb_vwv6,1);
1412 SSVAL(cli->outbuf,smb_vwv7,0);
1414 p = smb_buf(cli->outbuf);
1415 SSVAL(p, 0, cli->pid);
1416 SIVAL(p, 2, offset);
1420 if (!cli_receive_smb(cli)) {
1424 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1433 /****************************************************************************
1434 issue a single SMBread and don't wait for a reply
1435 ****************************************************************************/
1436 static void cli_issue_read(struct cli_state *cli, int fnum, off_t offset,
1439 memset(cli->outbuf,'\0',smb_size);
1440 memset(cli->inbuf,'\0',smb_size);
1442 set_message(cli->outbuf,10,0,True);
1444 CVAL(cli->outbuf,smb_com) = SMBreadX;
1445 SSVAL(cli->outbuf,smb_tid,cli->cnum);
1446 cli_setup_packet(cli);
1448 CVAL(cli->outbuf,smb_vwv0) = 0xFF;
1449 SSVAL(cli->outbuf,smb_vwv2,fnum);
1450 SIVAL(cli->outbuf,smb_vwv3,offset);
1451 SSVAL(cli->outbuf,smb_vwv5,size);
1452 SSVAL(cli->outbuf,smb_vwv6,size);
1453 SSVAL(cli->outbuf,smb_mid,cli->mid + i);
1458 /****************************************************************************
1460 ****************************************************************************/
1461 size_t cli_read(struct cli_state *cli, int fnum, char *buf, off_t offset, size_t size)
1468 * There is a problem in this code when mpx is more than one.
1469 * for some reason files can get corrupted when being read.
1470 * Until we understand this fully I am serializing reads (one
1471 * read/one reply) for now. JRA.
1474 int mpx = MAX(cli->max_mux-1, 1);
1478 int block = (cli->max_xmit - (smb_size+32)) & ~1023;
1480 int blocks = (size + (block-1)) / block;
1482 if (size == 0) return 0;
1484 while (received < blocks) {
1487 while (issued - received < mpx && issued < blocks) {
1488 int size1 = MIN(block, size-issued*block);
1489 cli_issue_read(cli, fnum, offset+issued*block, size1, issued);
1493 if (!cli_receive_smb(cli)) {
1498 mid = SVAL(cli->inbuf, smb_mid) - cli->mid;
1499 size2 = SVAL(cli->inbuf, smb_vwv5);
1501 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1502 blocks = MIN(blocks, mid-1);
1507 blocks = MIN(blocks, mid-1);
1508 /* this distinguishes EOF from an error */
1509 total = MAX(total, 0);
1513 if (size2 > block) {
1514 DEBUG(0,("server returned more than we wanted!\n"));
1517 if (mid >= issued) {
1518 DEBUG(0,("invalid mid from server!\n"));
1521 p = smb_base(cli->inbuf) + SVAL(cli->inbuf,smb_vwv6);
1523 memcpy(buf+mid*block, p, size2);
1525 total = MAX(total, mid*block + size2);
1528 while (received < issued) {
1529 cli_receive_smb(cli);
1537 /****************************************************************************
1538 issue a single SMBwrite and don't wait for a reply
1539 ****************************************************************************/
1540 static void cli_issue_write(struct cli_state *cli, int fnum, off_t offset, uint16 mode, char *buf,
1545 memset(cli->outbuf,'\0',smb_size);
1546 memset(cli->inbuf,'\0',smb_size);
1548 set_message(cli->outbuf,12,size,True);
1550 CVAL(cli->outbuf,smb_com) = SMBwriteX;
1551 SSVAL(cli->outbuf,smb_tid,cli->cnum);
1552 cli_setup_packet(cli);
1554 CVAL(cli->outbuf,smb_vwv0) = 0xFF;
1555 SSVAL(cli->outbuf,smb_vwv2,fnum);
1557 SIVAL(cli->outbuf,smb_vwv3,offset);
1558 SIVAL(cli->outbuf,smb_vwv5,IS_BITS_SET_ALL(mode, 0x0008) ? 0xFFFFFFFF : 0);
1559 SSVAL(cli->outbuf,smb_vwv7,mode);
1561 SSVAL(cli->outbuf,smb_vwv8,IS_BITS_SET_ALL(mode, 0x0008) ? size : 0);
1562 SSVAL(cli->outbuf,smb_vwv10,size);
1563 SSVAL(cli->outbuf,smb_vwv11,
1564 smb_buf(cli->outbuf) - smb_base(cli->outbuf));
1566 p = smb_base(cli->outbuf) + SVAL(cli->outbuf,smb_vwv11);
1567 memcpy(p, buf, size);
1569 SSVAL(cli->outbuf,smb_mid,cli->mid + i);
1571 show_msg(cli->outbuf);
1575 /****************************************************************************
1577 write_mode: 0x0001 disallow write cacheing
1578 0x0002 return bytes remaining
1579 0x0004 use raw named pipe protocol
1580 0x0008 start of message mode named pipe protocol
1581 ****************************************************************************/
1582 ssize_t cli_write(struct cli_state *cli,
1583 int fnum, uint16 write_mode,
1584 char *buf, off_t offset, size_t size)
1589 int mpx = MAX(cli->max_mux-1, 1);
1590 int block = (cli->max_xmit - (smb_size+32)) & ~1023;
1591 int blocks = (size + (block-1)) / block;
1593 while (received < blocks) {
1595 while ((issued - received < mpx) && (issued < blocks))
1597 int bsent = issued * block;
1598 int size1 = MIN(block, size - bsent);
1600 cli_issue_write(cli, fnum, offset + bsent,
1607 if (!cli_receive_smb(cli))
1614 if (CVAL(cli->inbuf,smb_rcls) != 0)
1619 bwritten += SVAL(cli->inbuf, smb_vwv2);
1622 while (received < issued && cli_receive_smb(cli))
1631 /****************************************************************************
1632 write to a file using a SMBwrite and not bypassing 0 byte writes
1633 ****************************************************************************/
1634 ssize_t cli_smbwrite(struct cli_state *cli,
1635 int fnum, char *buf, off_t offset, size_t size1)
1641 size_t size = MIN(size1, cli->max_xmit - 48);
1643 memset(cli->outbuf,'\0',smb_size);
1644 memset(cli->inbuf,'\0',smb_size);
1646 set_message(cli->outbuf,5, 3 + size,True);
1648 CVAL(cli->outbuf,smb_com) = SMBwrite;
1649 SSVAL(cli->outbuf,smb_tid,cli->cnum);
1650 cli_setup_packet(cli);
1652 SSVAL(cli->outbuf,smb_vwv0,fnum);
1653 SSVAL(cli->outbuf,smb_vwv1,size);
1654 SIVAL(cli->outbuf,smb_vwv2,offset);
1655 SSVAL(cli->outbuf,smb_vwv4,0);
1657 p = smb_buf(cli->outbuf);
1660 memcpy(p+2, buf, size);
1663 if (!cli_receive_smb(cli)) {
1667 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1671 size = SVAL(cli->inbuf,smb_vwv0);
1672 if (size == 0) break;
1682 /****************************************************************************
1683 do a SMBgetattrE call
1684 ****************************************************************************/
1685 BOOL cli_getattrE(struct cli_state *cli, int fd,
1686 uint16 *attr, size_t *size,
1687 time_t *c_time, time_t *a_time, time_t *m_time)
1689 memset(cli->outbuf,'\0',smb_size);
1690 memset(cli->inbuf,'\0',smb_size);
1692 set_message(cli->outbuf,1,0,True);
1694 CVAL(cli->outbuf,smb_com) = SMBgetattrE;
1695 SSVAL(cli->outbuf,smb_tid,cli->cnum);
1696 cli_setup_packet(cli);
1698 SSVAL(cli->outbuf,smb_vwv0,fd);
1701 if (!cli_receive_smb(cli)) {
1705 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1710 *size = IVAL(cli->inbuf, smb_vwv6);
1714 *attr = SVAL(cli->inbuf,smb_vwv10);
1718 *c_time = make_unix_date3(cli->inbuf+smb_vwv0);
1722 *a_time = make_unix_date3(cli->inbuf+smb_vwv2);
1726 *m_time = make_unix_date3(cli->inbuf+smb_vwv4);
1733 /****************************************************************************
1735 ****************************************************************************/
1736 BOOL cli_getatr(struct cli_state *cli, char *fname,
1737 uint16 *attr, size_t *size, time_t *t)
1741 memset(cli->outbuf,'\0',smb_size);
1742 memset(cli->inbuf,'\0',smb_size);
1744 set_message(cli->outbuf,0,strlen(fname)+2,True);
1746 CVAL(cli->outbuf,smb_com) = SMBgetatr;
1747 SSVAL(cli->outbuf,smb_tid,cli->cnum);
1748 cli_setup_packet(cli);
1750 p = smb_buf(cli->outbuf);
1752 pstrcpy(p+1, fname);
1753 unix_to_dos(p+1,True);
1756 if (!cli_receive_smb(cli)) {
1760 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1765 *size = IVAL(cli->inbuf, smb_vwv3);
1769 *t = make_unix_date3(cli->inbuf+smb_vwv1);
1773 *attr = SVAL(cli->inbuf,smb_vwv0);
1781 /****************************************************************************
1783 ****************************************************************************/
1784 BOOL cli_setatr(struct cli_state *cli, char *fname, uint16 attr, time_t t)
1788 memset(cli->outbuf,'\0',smb_size);
1789 memset(cli->inbuf,'\0',smb_size);
1791 set_message(cli->outbuf,8,strlen(fname)+4,True);
1793 CVAL(cli->outbuf,smb_com) = SMBsetatr;
1794 SSVAL(cli->outbuf,smb_tid,cli->cnum);
1795 cli_setup_packet(cli);
1797 SSVAL(cli->outbuf,smb_vwv0, attr);
1798 put_dos_date3(cli->outbuf,smb_vwv1, t);
1800 p = smb_buf(cli->outbuf);
1802 pstrcpy(p+1, fname);
1803 unix_to_dos(p+1,True);
1804 p = skip_string(p,1);
1808 if (!cli_receive_smb(cli)) {
1812 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1819 /****************************************************************************
1820 send a qpathinfo call
1821 ****************************************************************************/
1822 BOOL cli_qpathinfo(struct cli_state *cli, const char *fname,
1823 time_t *c_time, time_t *a_time, time_t *m_time,
1824 size_t *size, uint16 *mode)
1828 uint16 setup = TRANSACT2_QPATHINFO;
1830 char *rparam=NULL, *rdata=NULL;
1833 time_t (*date_fn)(void *);
1835 param_len = strlen(fname) + 7;
1837 memset(param, 0, param_len);
1838 SSVAL(param, 0, SMB_INFO_STANDARD);
1839 pstrcpy(¶m[6], fname);
1840 unix_to_dos(¶m[6],True);
1843 ret = (cli_send_trans(cli, SMBtrans2,
1844 NULL, 0, /* Name, length */
1845 -1, 0, /* fid, flags */
1846 &setup, 1, 0, /* setup, length, max */
1847 param, param_len, 10, /* param, length, max */
1848 NULL, data_len, cli->max_xmit /* data, length, max */
1850 cli_receive_trans(cli, SMBtrans2,
1851 &rparam, ¶m_len,
1852 &rdata, &data_len));
1854 /* we need to work around a Win95 bug - sometimes
1855 it gives ERRSRV/ERRerror temprarily */
1858 cli_error(cli, &eclass, &ecode, NULL);
1859 if (eclass != ERRSRV || ecode != ERRerror) break;
1862 } while (count-- && ret==False);
1864 if (!ret || !rdata || data_len < 22) {
1869 date_fn = make_unix_date;
1871 date_fn = make_unix_date2;
1875 *c_time = date_fn(rdata+0);
1878 *a_time = date_fn(rdata+4);
1881 *m_time = date_fn(rdata+8);
1884 *size = IVAL(rdata, 12);
1887 *mode = SVAL(rdata,l1_attrFile);
1890 if (rdata) free(rdata);
1891 if (rparam) free(rparam);
1895 /****************************************************************************
1896 send a qpathinfo call with the SMB_QUERY_FILE_ALL_INFO info level
1897 ****************************************************************************/
1898 BOOL cli_qpathinfo2(struct cli_state *cli, const char *fname,
1899 time_t *c_time, time_t *a_time, time_t *m_time,
1900 time_t *w_time, size_t *size, uint16 *mode,
1905 uint16 setup = TRANSACT2_QPATHINFO;
1907 char *rparam=NULL, *rdata=NULL;
1909 param_len = strlen(fname) + 7;
1911 memset(param, 0, param_len);
1912 SSVAL(param, 0, SMB_QUERY_FILE_ALL_INFO);
1913 pstrcpy(¶m[6], fname);
1914 unix_to_dos(¶m[6],True);
1916 if (!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 */
1926 if (!cli_receive_trans(cli, SMBtrans2,
1927 &rparam, ¶m_len,
1928 &rdata, &data_len)) {
1932 if (!rdata || data_len < 22) {
1937 *c_time = interpret_long_date(rdata+0) - cli->serverzone;
1940 *a_time = interpret_long_date(rdata+8) - cli->serverzone;
1943 *m_time = interpret_long_date(rdata+16) - cli->serverzone;
1946 *w_time = interpret_long_date(rdata+24) - cli->serverzone;
1949 *mode = SVAL(rdata, 32);
1952 *size = IVAL(rdata, 48);
1955 *ino = IVAL(rdata, 64);
1958 if (rdata) free(rdata);
1959 if (rparam) free(rparam);
1964 /****************************************************************************
1965 send a qfileinfo call
1966 ****************************************************************************/
1967 BOOL cli_qfileinfo(struct cli_state *cli, int fnum,
1968 uint16 *mode, size_t *size,
1969 time_t *c_time, time_t *a_time, time_t *m_time,
1970 time_t *w_time, SMB_INO_T *ino)
1974 uint16 setup = TRANSACT2_QFILEINFO;
1976 char *rparam=NULL, *rdata=NULL;
1978 /* if its a win95 server then fail this - win95 totally screws it
1980 if (cli->win95) return False;
1984 memset(param, 0, param_len);
1985 SSVAL(param, 0, fnum);
1986 SSVAL(param, 2, SMB_QUERY_FILE_ALL_INFO);
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, 2, /* 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 < 68) {
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, 48);
2027 *ino = IVAL(rdata, 64);
2030 if (rdata) free(rdata);
2031 if (rparam) free(rparam);
2036 /****************************************************************************
2037 interpret a long filename structure - this is mostly guesses at the moment
2038 The length of the structure is returned
2039 The structure of a long filename depends on the info level. 260 is used
2040 by NT and 2 is used by OS/2
2041 ****************************************************************************/
2042 static int interpret_long_filename(int level,char *p,file_info *finfo)
2044 extern file_info def_finfo;
2047 memcpy(finfo,&def_finfo,sizeof(*finfo));
2051 case 1: /* OS/2 understands this */
2053 /* these dates are converted to GMT by make_unix_date */
2054 finfo->ctime = make_unix_date2(p+4);
2055 finfo->atime = make_unix_date2(p+8);
2056 finfo->mtime = make_unix_date2(p+12);
2057 finfo->size = IVAL(p,16);
2058 finfo->mode = CVAL(p,24);
2059 pstrcpy(finfo->name,p+27);
2060 dos_to_unix(finfo->name,True);
2062 return(28 + CVAL(p,26));
2064 case 2: /* this is what OS/2 uses mostly */
2066 /* these dates are converted to GMT by make_unix_date */
2067 finfo->ctime = make_unix_date2(p+4);
2068 finfo->atime = make_unix_date2(p+8);
2069 finfo->mtime = make_unix_date2(p+12);
2070 finfo->size = IVAL(p,16);
2071 finfo->mode = CVAL(p,24);
2072 pstrcpy(finfo->name,p+31);
2073 dos_to_unix(finfo->name,True);
2075 return(32 + CVAL(p,30));
2077 /* levels 3 and 4 are untested */
2080 /* these dates are probably like the other ones */
2081 finfo->ctime = make_unix_date2(p+8);
2082 finfo->atime = make_unix_date2(p+12);
2083 finfo->mtime = make_unix_date2(p+16);
2084 finfo->size = IVAL(p,20);
2085 finfo->mode = CVAL(p,28);
2086 pstrcpy(finfo->name,p+33);
2087 dos_to_unix(finfo->name,True);
2089 return(SVAL(p,4)+4);
2093 /* these dates are probably like the other ones */
2094 finfo->ctime = make_unix_date2(p+8);
2095 finfo->atime = make_unix_date2(p+12);
2096 finfo->mtime = make_unix_date2(p+16);
2097 finfo->size = IVAL(p,20);
2098 finfo->mode = CVAL(p,28);
2099 pstrcpy(finfo->name,p+37);
2100 dos_to_unix(finfo->name,True);
2102 return(SVAL(p,4)+4);
2104 case 260: /* NT uses this, but also accepts 2 */
2106 int ret = SVAL(p,0);
2108 p += 4; /* next entry offset */
2109 p += 4; /* fileindex */
2111 /* these dates appear to arrive in a
2112 weird way. It seems to be localtime
2113 plus the serverzone given in the
2114 initial connect. This is GMT when
2115 DST is not in effect and one hour
2116 from GMT otherwise. Can this really
2119 I suppose this could be called
2120 kludge-GMT. Is is the GMT you get
2121 by using the current DST setting on
2122 a different localtime. It will be
2123 cheap to calculate, I suppose, as
2124 no DST tables will be needed */
2126 finfo->ctime = interpret_long_date(p); p += 8;
2127 finfo->atime = interpret_long_date(p); p += 8;
2128 finfo->mtime = interpret_long_date(p); p += 8; p += 8;
2129 finfo->size = IVAL(p,0); p += 8;
2130 p += 8; /* alloc size */
2131 finfo->mode = CVAL(p,0); p += 4;
2132 namelen = IVAL(p,0); p += 4;
2133 p += 4; /* EA size */
2134 p += 2; /* short name len? */
2135 p += 24; /* short name? */
2136 StrnCpy(finfo->name,p,MIN(sizeof(finfo->name)-1,namelen));
2137 dos_to_unix(finfo->name,True);
2143 DEBUG(1,("Unknown long filename format %d\n",level));
2148 /****************************************************************************
2149 do a directory listing, calling fn on each file found
2150 ****************************************************************************/
2151 int cli_list(struct cli_state *cli,const char *Mask,uint16 attribute,
2152 void (*fn)(file_info *, const char *))
2154 int max_matches = 512;
2155 /* NT uses 260, OS/2 uses 2. Both accept 1. */
2156 int info_level = cli->protocol<PROTOCOL_NT1?1:260;
2161 char *dirlist = NULL;
2162 int dirlist_len = 0;
2163 int total_received = -1;
2165 int ff_searchcount=0;
2168 int ff_dir_handle=0;
2170 char *rparam=NULL, *rdata=NULL;
2171 int param_len, data_len;
2177 unix_to_dos(mask,True);
2179 while (ff_eos == 0) {
2181 if (loop_count > 200) {
2182 DEBUG(0,("Error: Looping in FIND_NEXT??\n"));
2186 param_len = 12+strlen(mask)+1;
2189 setup = TRANSACT2_FINDFIRST;
2190 SSVAL(param,0,attribute); /* attribute */
2191 SSVAL(param,2,max_matches); /* max count */
2192 SSVAL(param,4,8+4+2); /* resume required + close on end + continue */
2193 SSVAL(param,6,info_level);
2195 pstrcpy(param+12,mask);
2197 setup = TRANSACT2_FINDNEXT;
2198 SSVAL(param,0,ff_dir_handle);
2199 SSVAL(param,2,max_matches); /* max count */
2200 SSVAL(param,4,info_level);
2201 SIVAL(param,6,0); /* ff_resume_key */
2202 SSVAL(param,10,8+4+2); /* resume required + close on end + continue */
2203 pstrcpy(param+12,mask);
2205 DEBUG(5,("hand=0x%X ff_lastname=%d mask=%s\n",
2206 ff_dir_handle,ff_lastname,mask));
2209 if (!cli_send_trans(cli, SMBtrans2,
2210 NULL, 0, /* Name, length */
2211 -1, 0, /* fid, flags */
2212 &setup, 1, 0, /* setup, length, max */
2213 param, param_len, 10, /* param, length, max */
2215 cli->max_xmit /* data, length, max */
2220 if (!cli_receive_trans(cli, SMBtrans2,
2221 &rparam, ¶m_len,
2222 &rdata, &data_len)) {
2223 /* we need to work around a Win95 bug - sometimes
2224 it gives ERRSRV/ERRerror temprarily */
2227 cli_error(cli, &eclass, &ecode, NULL);
2228 if (eclass != ERRSRV || ecode != ERRerror) break;
2233 if (total_received == -1) total_received = 0;
2235 /* parse out some important return info */
2238 ff_dir_handle = SVAL(p,0);
2239 ff_searchcount = SVAL(p,2);
2241 ff_lastname = SVAL(p,8);
2243 ff_searchcount = SVAL(p,0);
2245 ff_lastname = SVAL(p,6);
2248 if (ff_searchcount == 0)
2251 /* point to the data bytes */
2254 /* we might need the lastname for continuations */
2255 if (ff_lastname > 0) {
2259 StrnCpy(mask,p+ff_lastname,
2260 MIN(sizeof(mask)-1,data_len-ff_lastname));
2263 pstrcpy(mask,p + ff_lastname + 1);
2270 dos_to_unix(mask, True);
2272 /* and add them to the dirlist pool */
2273 dirlist = Realloc(dirlist,dirlist_len + data_len);
2276 DEBUG(0,("Failed to expand dirlist\n"));
2280 /* put in a length for the last entry, to ensure we can chain entries
2281 into the next packet */
2282 for (p2=p,i=0;i<(ff_searchcount-1);i++)
2283 p2 += interpret_long_filename(info_level,p2,NULL);
2284 SSVAL(p2,0,data_len - PTR_DIFF(p2,p));
2286 /* grab the data for later use */
2287 memcpy(dirlist+dirlist_len,p,data_len);
2288 dirlist_len += data_len;
2290 total_received += ff_searchcount;
2292 if (rdata) free(rdata); rdata = NULL;
2293 if (rparam) free(rparam); rparam = NULL;
2295 DEBUG(3,("received %d entries (eos=%d)\n",
2296 ff_searchcount,ff_eos));
2298 if (ff_searchcount > 0) loop_count = 0;
2303 for (p=dirlist,i=0;i<total_received;i++) {
2304 p += interpret_long_filename(info_level,p,&finfo);
2308 /* free up the dirlist buffer */
2309 if (dirlist) free(dirlist);
2310 return(total_received);
2314 /****************************************************************************
2315 Send a SamOEMChangePassword command
2316 ****************************************************************************/
2318 BOOL cli_oem_change_password(struct cli_state *cli, const char *user, const char *new_password,
2319 const char *old_password)
2321 char param[16+sizeof(fstring)];
2324 fstring upper_case_old_pw;
2325 fstring upper_case_new_pw;
2326 unsigned char old_pw_hash[16];
2327 unsigned char new_pw_hash[16];
2330 char *rparam = NULL;
2333 pstring dos_new_password;
2335 if (strlen(user) >= sizeof(fstring)-1) {
2336 DEBUG(0,("cli_oem_change_password: user name %s is too long.\n", user));
2340 SSVAL(p,0,214); /* SamOEMChangePassword command. */
2343 p = skip_string(p,1);
2344 pstrcpy(p, "B516B16");
2345 p = skip_string(p,1);
2347 p = skip_string(p,1);
2351 param_len = PTR_DIFF(p,param);
2354 * Get the Lanman hash of the old password, we
2355 * use this as the key to make_oem_passwd_hash().
2357 memset(upper_case_old_pw, '\0', sizeof(upper_case_old_pw));
2358 fstrcpy(upper_case_old_pw, old_password);
2359 unix_to_dos(upper_case_old_pw,True);
2360 strupper(upper_case_old_pw);
2361 E_P16((uchar *)upper_case_old_pw, old_pw_hash);
2363 pstrcpy(dos_new_password, new_password);
2364 unix_to_dos(dos_new_password, True);
2366 if (!make_oem_passwd_hash( data, dos_new_password, old_pw_hash, False))
2370 * Now place the old password hash in the data.
2372 memset(upper_case_new_pw, '\0', sizeof(upper_case_new_pw));
2373 fstrcpy(upper_case_new_pw, new_password);
2374 unix_to_dos(upper_case_new_pw,True);
2375 strupper(upper_case_new_pw);
2377 E_P16((uchar *)upper_case_new_pw, new_pw_hash);
2379 E_old_pw_hash( new_pw_hash, old_pw_hash, (uchar *)&data[516]);
2383 if (cli_send_trans(cli,SMBtrans,
2384 PIPE_LANMAN,strlen(PIPE_LANMAN), /* name, length */
2385 0,0, /* fid, flags */
2386 NULL,0,0, /* setup, length, max */
2387 param,param_len,2, /* param, length, max */
2388 data,data_len,0 /* data, length, max */
2390 DEBUG(0,("cli_oem_change_password: Failed to send password change for user %s\n",
2395 if (cli_receive_trans(cli,SMBtrans,
2399 cli->rap_error = SVAL(rparam,0);
2407 return (cli->rap_error == 0);
2410 /****************************************************************************
2411 send a negprot command
2412 ****************************************************************************/
2413 BOOL cli_negprot(struct cli_state *cli)
2419 memset(cli->outbuf,'\0',smb_size);
2421 /* setup the protocol strings */
2422 for (plength=0,numprots=0;
2423 prots[numprots].name && prots[numprots].prot<=cli->protocol;
2425 plength += strlen(prots[numprots].name)+2;
2427 set_message(cli->outbuf,0,plength,True);
2429 p = smb_buf(cli->outbuf);
2431 prots[numprots].name && prots[numprots].prot<=cli->protocol;
2434 pstrcpy(p,prots[numprots].name);
2435 unix_to_dos(p,True);
2439 CVAL(cli->outbuf,smb_com) = SMBnegprot;
2440 cli_setup_packet(cli);
2442 CVAL(smb_buf(cli->outbuf),0) = 2;
2445 if (!cli_receive_smb(cli))
2448 show_msg(cli->inbuf);
2450 if (CVAL(cli->inbuf,smb_rcls) != 0 ||
2451 ((int)SVAL(cli->inbuf,smb_vwv0) >= numprots)) {
2455 cli->protocol = prots[SVAL(cli->inbuf,smb_vwv0)].prot;
2458 if (cli->protocol >= PROTOCOL_NT1) {
2460 cli->sec_mode = CVAL(cli->inbuf,smb_vwv1);
2461 cli->max_mux = SVAL(cli->inbuf, smb_vwv1+1);
2462 cli->max_xmit = IVAL(cli->inbuf,smb_vwv3+1);
2463 cli->sesskey = IVAL(cli->inbuf,smb_vwv7+1);
2464 cli->serverzone = SVALS(cli->inbuf,smb_vwv15+1);
2465 cli->serverzone *= 60;
2466 /* this time arrives in real GMT */
2467 cli->servertime = interpret_long_date(cli->inbuf+smb_vwv11+1);
2468 memcpy(cli->cryptkey,smb_buf(cli->inbuf),8);
2469 cli->capabilities = IVAL(cli->inbuf,smb_vwv9+1);
2470 if (cli->capabilities & 1) {
2471 cli->readbraw_supported = True;
2472 cli->writebraw_supported = True;
2474 } else if (cli->protocol >= PROTOCOL_LANMAN1) {
2475 cli->sec_mode = SVAL(cli->inbuf,smb_vwv1);
2476 cli->max_xmit = SVAL(cli->inbuf,smb_vwv2);
2477 cli->sesskey = IVAL(cli->inbuf,smb_vwv6);
2478 cli->serverzone = SVALS(cli->inbuf,smb_vwv10);
2479 cli->serverzone *= 60;
2480 /* this time is converted to GMT by make_unix_date */
2481 cli->servertime = make_unix_date(cli->inbuf+smb_vwv8);
2482 cli->readbraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x1) != 0);
2483 cli->writebraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x2) != 0);
2484 memcpy(cli->cryptkey,smb_buf(cli->inbuf),8);
2486 /* the old core protocol */
2488 cli->serverzone = TimeDiff(time(NULL));
2491 cli->max_xmit = MIN(cli->max_xmit, CLI_BUFFER_SIZE);
2497 /****************************************************************************
2498 send a session request. see rfc1002.txt 4.3 and 4.3.2
2499 ****************************************************************************/
2500 BOOL cli_session_request(struct cli_state *cli,
2501 struct nmb_name *calling, struct nmb_name *called)
2505 /* send a session request (RFC 1002) */
2507 memcpy(&(cli->calling), calling, sizeof(*calling));
2508 memcpy(&(cli->called ), called , sizeof(*called ));
2510 /* put in the destination name */
2511 p = cli->outbuf+len;
2512 name_mangle(cli->called .name, p, cli->called .name_type);
2516 p = cli->outbuf+len;
2517 name_mangle(cli->calling.name, p, cli->calling.name_type);
2520 /* setup the packet length */
2521 _smb_setlen(cli->outbuf,len);
2522 CVAL(cli->outbuf,0) = 0x81;
2526 #endif /* WITH_SSL */
2529 DEBUG(5,("Sent session request\n"));
2531 if (!cli_receive_smb(cli))
2534 if (CVAL(cli->inbuf,0) == 0x84) {
2535 /* C. Hoch 9/14/95 Start */
2536 /* For information, here is the response structure.
2537 * We do the byte-twiddling to for portability.
2538 struct RetargetResponse{
2540 unsigned char flags;
2546 int port = (CVAL(cli->inbuf,8)<<8)+CVAL(cli->inbuf,9);
2547 /* SESSION RETARGET */
2548 putip((char *)&cli->dest_ip,cli->inbuf+4);
2551 cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip, port, LONG_CONNECT_TIMEOUT);
2555 DEBUG(3,("Retargeted\n"));
2557 set_socket_options(cli->fd,user_socket_options);
2560 return cli_session_request(cli, calling, called);
2561 } /* C. Hoch 9/14/95 End */
2564 if (CVAL(cli->inbuf,0) == 0x83 && CVAL(cli->inbuf,4) == 0x8e){ /* use ssl */
2565 if (!sslutil_fd_is_ssl(cli->fd)){
2566 if (sslutil_connect(cli->fd) == 0)
2570 #endif /* WITH_SSL */
2572 if (CVAL(cli->inbuf,0) != 0x82) {
2573 /* This is the wrong place to put the error... JRA. */
2574 cli->rap_error = CVAL(cli->inbuf,4);
2581 /****************************************************************************
2582 open the client sockets
2583 ****************************************************************************/
2584 BOOL cli_connect(struct cli_state *cli, const char *host, struct in_addr *ip)
2586 extern struct in_addr ipzero;
2588 fstrcpy(cli->desthost, host);
2590 if (!ip || ip_equal(*ip, ipzero)) {
2591 if (!resolve_name( cli->desthost, &cli->dest_ip, 0x20)) {
2594 if (ip) *ip = cli->dest_ip;
2599 if (cli->port == 0) cli->port = 139; /* Set to default */
2601 cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip,
2602 cli->port, cli->timeout);
2606 set_socket_options(cli->fd,user_socket_options);
2612 /****************************************************************************
2613 initialise a client structure
2614 ****************************************************************************/
2615 struct cli_state *cli_initialise(struct cli_state *cli)
2618 cli = (struct cli_state *)malloc(sizeof(*cli));
2624 if (cli->initialised) {
2633 cli->pid = (uint16)getpid();
2635 cli->vuid = UID_FIELD_INVALID;
2636 cli->protocol = PROTOCOL_NT1;
2637 cli->timeout = 20000; /* Timeout is in milliseconds. */
2638 cli->bufsize = CLI_BUFFER_SIZE+4;
2639 cli->max_xmit = cli->bufsize;
2640 cli->outbuf = (char *)malloc(cli->bufsize);
2641 cli->inbuf = (char *)malloc(cli->bufsize);
2642 if (!cli->outbuf || !cli->inbuf)
2647 memset(cli->outbuf, '\0', cli->bufsize);
2648 memset(cli->inbuf, '\0', cli->bufsize);
2650 cli->initialised = 1;
2655 /****************************************************************************
2656 shutdown a client structure
2657 ****************************************************************************/
2658 void cli_shutdown(struct cli_state *cli)
2670 sslutil_disconnect(cli->fd);
2671 #endif /* WITH_SSL */
2674 memset(cli, 0, sizeof(*cli));
2678 /****************************************************************************
2679 return error codes for the last packet
2680 returns 0 if there was no error and the best approx of a unix errno
2683 for 32 bit "warnings", a return code of 0 is expected.
2685 ****************************************************************************/
2686 int cli_error(struct cli_state *cli, uint8 *eclass, uint32 *num, uint32 *nt_rpc_error)
2692 if (eclass) *eclass = 0;
2694 if (nt_rpc_error) *nt_rpc_error = 0;
2696 if(!cli->initialised)
2702 flgs2 = SVAL(cli->inbuf,smb_flg2);
2703 if (nt_rpc_error) *nt_rpc_error = cli->nt_error;
2705 if (flgs2 & FLAGS2_32_BIT_ERROR_CODES) {
2706 /* 32 bit error codes detected */
2707 uint32 nt_err = IVAL(cli->inbuf,smb_rcls);
2708 if (num) *num = nt_err;
2709 DEBUG(10,("cli_error: 32 bit codes: code=%08x\n", nt_err));
2710 if (!IS_BITS_SET_ALL(nt_err, 0xc0000000)) return 0;
2712 switch (nt_err & 0xFFFFFF) {
2713 case NT_STATUS_ACCESS_VIOLATION: return EACCES;
2714 case NT_STATUS_NO_SUCH_FILE: return ENOENT;
2715 case NT_STATUS_NO_SUCH_DEVICE: return ENODEV;
2716 case NT_STATUS_INVALID_HANDLE: return EBADF;
2717 case NT_STATUS_NO_MEMORY: return ENOMEM;
2718 case NT_STATUS_ACCESS_DENIED: return EACCES;
2719 case NT_STATUS_OBJECT_NAME_NOT_FOUND: return ENOENT;
2720 case NT_STATUS_SHARING_VIOLATION: return EBUSY;
2721 case NT_STATUS_OBJECT_PATH_INVALID: return ENOTDIR;
2722 case NT_STATUS_OBJECT_NAME_COLLISION: return EEXIST;
2725 /* for all other cases - a default code */
2729 rcls = CVAL(cli->inbuf,smb_rcls);
2730 code = SVAL(cli->inbuf,smb_err);
2731 if (rcls == 0) return 0;
2733 if (eclass) *eclass = rcls;
2734 if (num ) *num = code;
2736 if (rcls == ERRDOS) {
2738 case ERRbadfile: return ENOENT;
2739 case ERRbadpath: return ENOTDIR;
2740 case ERRnoaccess: return EACCES;
2741 case ERRfilexists: return EEXIST;
2742 case ERRrename: return EEXIST;
2743 case ERRbadshare: return EBUSY;
2744 case ERRlock: return EBUSY;
2747 if (rcls == ERRSRV) {
2749 case ERRbadpw: return EPERM;
2750 case ERRaccess: return EACCES;
2751 case ERRnoresource: return ENOMEM;
2752 case ERRinvdevice: return ENODEV;
2753 case ERRinvnetname: return ENODEV;
2756 /* for other cases */
2760 /****************************************************************************
2761 set socket options on a open connection
2762 ****************************************************************************/
2763 void cli_sockopt(struct cli_state *cli, char *options)
2765 set_socket_options(cli->fd, options);
2768 /****************************************************************************
2769 set the PID to use for smb messages. Return the old pid.
2770 ****************************************************************************/
2771 uint16 cli_setpid(struct cli_state *cli, uint16 pid)
2773 uint16 ret = cli->pid;
2778 /****************************************************************************
2779 re-establishes a connection
2780 ****************************************************************************/
2781 BOOL cli_reestablish_connection(struct cli_state *cli)
2783 struct nmb_name calling;
2784 struct nmb_name called;
2788 BOOL do_tcon = False;
2789 int oldfd = cli->fd;
2791 if (!cli->initialised || cli->fd == -1)
2793 DEBUG(3,("cli_reestablish_connection: not connected\n"));
2797 /* copy the parameters necessary to re-establish the connection */
2801 fstrcpy(share, cli->share);
2802 fstrcpy(dev , cli->dev);
2806 memcpy(&called , &(cli->called ), sizeof(called ));
2807 memcpy(&calling, &(cli->calling), sizeof(calling));
2808 fstrcpy(dest_host, cli->full_dest_host_name);
2810 DEBUG(5,("cli_reestablish_connection: %s connecting to %s (ip %s) - %s [%s]\n",
2811 nmb_namestr(&calling), nmb_namestr(&called),
2812 inet_ntoa(cli->dest_ip),
2813 cli->user_name, cli->domain));
2817 if (cli_establish_connection(cli,
2818 dest_host, &cli->dest_ip,
2820 share, dev, False, do_tcon)) {
2821 if (cli->fd != oldfd) {
2822 if (dup2(cli->fd, oldfd) == oldfd) {
2831 /****************************************************************************
2832 establishes a connection right up to doing tconX, reading in a password.
2833 ****************************************************************************/
2834 BOOL cli_establish_connection(struct cli_state *cli,
2835 char *dest_host, struct in_addr *dest_ip,
2836 struct nmb_name *calling, struct nmb_name *called,
2837 char *service, char *service_type,
2838 BOOL do_shutdown, BOOL do_tcon)
2840 DEBUG(5,("cli_establish_connection: %s connecting to %s (%s) - %s [%s]\n",
2841 nmb_namestr(calling), nmb_namestr(called), inet_ntoa(*dest_ip),
2842 cli->user_name, cli->domain));
2844 /* establish connection */
2846 if ((!cli->initialised))
2853 if (!cli_connect(cli, dest_host, dest_ip))
2855 DEBUG(1,("cli_establish_connection: failed to connect to %s (%s)\n",
2856 nmb_namestr(calling), inet_ntoa(*dest_ip)));
2861 if (!cli_session_request(cli, calling, called))
2863 DEBUG(1,("failed session request\n"));
2869 if (!cli_negprot(cli))
2871 DEBUG(1,("failed negprot\n"));
2877 if (cli->pwd.cleartext || cli->pwd.null_pwd)
2882 if (cli->pwd.null_pwd)
2884 /* attempt null session */
2890 /* attempt clear-text session */
2891 pwd_get_cleartext(&(cli->pwd), passwd);
2892 pass_len = strlen(passwd);
2895 /* attempt clear-text session */
2896 if (!cli_session_setup(cli, cli->user_name,
2901 DEBUG(1,("failed session setup\n"));
2910 if (!cli_send_tconX(cli, service, service_type,
2911 (char*)passwd, strlen(passwd)))
2913 DEBUG(1,("failed tcon_X\n"));
2924 /* attempt encrypted session */
2925 unsigned char nt_sess_pwd[24];
2926 unsigned char lm_sess_pwd[24];
2928 /* creates (storing a copy of) and then obtains a 24 byte password OWF */
2929 pwd_make_lm_nt_owf(&(cli->pwd), cli->cryptkey);
2930 pwd_get_lm_nt_owf(&(cli->pwd), lm_sess_pwd, nt_sess_pwd);
2932 /* attempt encrypted session */
2933 if (!cli_session_setup(cli, cli->user_name,
2934 (char*)lm_sess_pwd, sizeof(lm_sess_pwd),
2935 (char*)nt_sess_pwd, sizeof(nt_sess_pwd),
2938 DEBUG(1,("failed session setup\n"));
2946 if (!cli_send_tconX(cli, service, service_type,
2947 (char*)nt_sess_pwd, sizeof(nt_sess_pwd)))
2949 DEBUG(1,("failed tcon_X\n"));
2964 /****************************************************************************
2966 ****************************************************************************/
2967 int cli_printjob_del(struct cli_state *cli, int job)
2969 char *rparam = NULL;
2972 int rdrcnt,rprcnt, ret = -1;
2975 memset(param,'\0',sizeof(param));
2978 SSVAL(p,0,81); /* DosPrintJobDel() */
2981 p = skip_string(p,1);
2983 p = skip_string(p,1);
2988 param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */
2989 NULL, 0, CLI_BUFFER_SIZE, /* data, length, maxlen */
2990 &rparam, &rprcnt, /* return params, length */
2991 &rdata, &rdrcnt)) { /* return data, length */
2992 ret = SVAL(rparam,0);
2995 if (rparam) free(rparam);
2996 if (rdata) free(rdata);
3002 /****************************************************************************
3003 call fn() on each entry in a print queue
3004 ****************************************************************************/
3005 int cli_print_queue(struct cli_state *cli,
3006 void (*fn)(struct print_job_info *))
3008 char *rparam = NULL;
3016 memset(param,'\0',sizeof(param));
3019 SSVAL(p,0,76); /* API function number 76 (DosPrintJobEnum) */
3021 pstrcpy(p,"zWrLeh"); /* parameter description? */
3022 p = skip_string(p,1);
3023 pstrcpy(p,"WWzWWDDzz"); /* returned data format */
3024 p = skip_string(p,1);
3025 pstrcpy(p,cli->share); /* name of queue */
3026 p = skip_string(p,1);
3027 SSVAL(p,0,2); /* API function level 2, PRJINFO_2 data structure */
3028 SSVAL(p,2,1000); /* size of bytes of returned data buffer */
3030 pstrcpy(p,""); /* subformat */
3031 p = skip_string(p,1);
3033 DEBUG(4,("doing cli_print_queue for %s\n", cli->share));
3036 param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */
3037 NULL, 0, CLI_BUFFER_SIZE, /* data, length, maxlen */
3038 &rparam, &rprcnt, /* return params, length */
3039 &rdata, &rdrcnt)) { /* return data, length */
3041 result_code = SVAL(rparam,0);
3042 converter = SVAL(rparam,2); /* conversion factor */
3044 if (result_code == 0) {
3045 struct print_job_info job;
3049 for (i = 0; i < SVAL(rparam,4); ++i) {
3051 job.priority = SVAL(p,2);
3053 fix_char_ptr(SVAL(p,4), converter,
3055 job.t = make_unix_date3(p + 12);
3056 job.size = IVAL(p,16);
3057 fstrcpy(job.name,fix_char_ptr(SVAL(p,24),
3066 /* If any parameters or data were returned, free the storage. */
3067 if(rparam) free(rparam);
3068 if(rdata) free(rdata);
3073 /****************************************************************************
3074 check for existance of a dir
3075 ****************************************************************************/
3076 BOOL cli_chkpath(struct cli_state *cli, char *path)
3081 safe_strcpy(path2,path,sizeof(pstring));
3082 trim_string(path2,NULL,"\\");
3083 if (!*path2) *path2 = '\\';
3085 memset(cli->outbuf,'\0',smb_size);
3086 set_message(cli->outbuf,0,4 + strlen(path2),True);
3087 SCVAL(cli->outbuf,smb_com,SMBchkpth);
3088 SSVAL(cli->outbuf,smb_tid,cli->cnum);
3089 cli_setup_packet(cli);
3090 p = smb_buf(cli->outbuf);
3092 safe_strcpy(p,path2,strlen(path2));
3093 unix_to_dos(p,True);
3096 if (!cli_receive_smb(cli)) {
3100 if (cli_error(cli, NULL, NULL, NULL)) return False;
3106 /****************************************************************************
3107 start a message sequence
3108 ****************************************************************************/
3109 BOOL cli_message_start(struct cli_state *cli, char *host, char *username,
3114 /* send a SMBsendstrt command */
3115 memset(cli->outbuf,'\0',smb_size);
3116 set_message(cli->outbuf,0,0,True);
3117 CVAL(cli->outbuf,smb_com) = SMBsendstrt;
3118 SSVAL(cli->outbuf,smb_tid,cli->cnum);
3119 cli_setup_packet(cli);
3121 p = smb_buf(cli->outbuf);
3123 pstrcpy(p,username);
3124 unix_to_dos(p,True);
3125 p = skip_string(p,1);
3128 unix_to_dos(p,True);
3129 p = skip_string(p,1);
3131 set_message(cli->outbuf,0,PTR_DIFF(p,smb_buf(cli->outbuf)),False);
3135 if (!cli_receive_smb(cli)) {
3139 if (cli_error(cli, NULL, NULL, NULL)) return False;
3141 *grp = SVAL(cli->inbuf,smb_vwv0);
3147 /****************************************************************************
3149 ****************************************************************************/
3150 BOOL cli_message_text(struct cli_state *cli, char *msg, int len, int grp)
3154 memset(cli->outbuf,'\0',smb_size);
3155 set_message(cli->outbuf,1,len+3,True);
3156 CVAL(cli->outbuf,smb_com) = SMBsendtxt;
3157 SSVAL(cli->outbuf,smb_tid,cli->cnum);
3158 cli_setup_packet(cli);
3160 SSVAL(cli->outbuf,smb_vwv0,grp);
3162 p = smb_buf(cli->outbuf);
3165 memcpy(p+3,msg,len);
3168 if (!cli_receive_smb(cli)) {
3172 if (cli_error(cli, NULL, NULL, NULL)) return False;
3177 /****************************************************************************
3179 ****************************************************************************/
3180 BOOL cli_message_end(struct cli_state *cli, int grp)
3182 memset(cli->outbuf,'\0',smb_size);
3183 set_message(cli->outbuf,1,0,True);
3184 CVAL(cli->outbuf,smb_com) = SMBsendend;
3185 SSVAL(cli->outbuf,smb_tid,cli->cnum);
3187 SSVAL(cli->outbuf,smb_vwv0,grp);
3189 cli_setup_packet(cli);
3193 if (!cli_receive_smb(cli)) {
3197 if (cli_error(cli, NULL, NULL, NULL)) return False;
3203 /****************************************************************************
3205 ****************************************************************************/
3206 BOOL cli_dskattr(struct cli_state *cli, int *bsize, int *total, int *avail)
3208 memset(cli->outbuf,'\0',smb_size);
3209 set_message(cli->outbuf,0,0,True);
3210 CVAL(cli->outbuf,smb_com) = SMBdskattr;
3211 SSVAL(cli->outbuf,smb_tid,cli->cnum);
3212 cli_setup_packet(cli);
3215 if (!cli_receive_smb(cli)) {
3219 *bsize = SVAL(cli->inbuf,smb_vwv1)*SVAL(cli->inbuf,smb_vwv2);
3220 *total = SVAL(cli->inbuf,smb_vwv0);
3221 *avail = SVAL(cli->inbuf,smb_vwv3);
3226 /****************************************************************************
3227 Attempt a NetBIOS session request, falling back to *SMBSERVER if needed.
3228 ****************************************************************************/
3230 BOOL attempt_netbios_session_request(struct cli_state *cli, char *srchost, char *desthost,
3231 struct in_addr *pdest_ip)
3233 struct nmb_name calling, called;
3235 make_nmb_name(&calling, srchost, 0x0);
3238 * If the called name is an IP address
3239 * then use *SMBSERVER immediately.
3242 if(is_ipaddress(desthost))
3243 make_nmb_name(&called, "*SMBSERVER", 0x20);
3245 make_nmb_name(&called, desthost, 0x20);
3247 if (!cli_session_request(cli, &calling, &called)) {
3248 struct nmb_name smbservername;
3250 make_nmb_name(&smbservername , "*SMBSERVER", 0x20);
3253 * If the name wasn't *SMBSERVER then
3254 * try with *SMBSERVER if the first name fails.
3257 if (nmb_name_equal(&called, &smbservername)) {
3260 * The name used was *SMBSERVER, don't bother with another name.
3263 DEBUG(0,("attempt_netbios_session_request: %s rejected the session for name *SMBSERVER \
3264 with error %s.\n", desthost, cli_errstr(cli) ));
3271 if (!cli_initialise(cli) ||
3272 !cli_connect(cli, desthost, pdest_ip) ||
3273 !cli_session_request(cli, &calling, &smbservername)) {
3274 DEBUG(0,("attempt_netbios_session_request: %s rejected the session for \
3275 name *SMBSERVER with error %s\n", desthost, cli_errstr(cli) ));