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\n",
101 /****************************************************************************
102 setup basics in a outgoing packet
103 ****************************************************************************/
104 static void cli_setup_packet(struct cli_state *cli)
108 SSVAL(cli->outbuf,smb_pid,cli->pid);
109 SSVAL(cli->outbuf,smb_uid,cli->vuid);
110 SSVAL(cli->outbuf,smb_mid,cli->mid);
111 if (cli->protocol > PROTOCOL_CORE) {
112 SCVAL(cli->outbuf,smb_flg,0x8);
113 SSVAL(cli->outbuf,smb_flg2,0x1);
119 /****************************************************************************
120 process an oplock break request from the server
121 ****************************************************************************/
122 static void cli_process_oplock(struct cli_state *cli)
124 char *oldbuf = cli->outbuf;
128 fnum = SVAL(cli->inbuf,smb_vwv2);
130 /* damn, we really need to keep a record of open files so we
131 can detect a oplock break and a close crossing on the
132 wire. for now this swallows the errors */
133 if (fnum == 0) return;
137 memset(buf,'\0',smb_size);
138 set_message(buf,8,0,True);
140 CVAL(buf,smb_com) = SMBlockingX;
141 SSVAL(buf,smb_tid, cli->cnum);
142 cli_setup_packet(cli);
143 SSVAL(buf,smb_vwv0,0xFF);
144 SSVAL(buf,smb_vwv1,0);
145 SSVAL(buf,smb_vwv2,fnum);
146 SSVAL(buf,smb_vwv3,2); /* oplock break ack */
147 SIVAL(buf,smb_vwv4,0); /* timoeut */
148 SSVAL(buf,smb_vwv6,0); /* unlockcount */
149 SSVAL(buf,smb_vwv7,0); /* lockcount */
153 cli->outbuf = oldbuf;
157 /*****************************************************
158 RAP error codes - a small start but will be extended.
159 *******************************************************/
167 {5, "User has insufficient privilege" },
168 {86, "The specified password is invalid" },
169 {2226, "Operation only permitted on a Primary Domain Controller" },
170 {2242, "The password of this user has expired." },
171 {2243, "The password of this user cannot change." },
172 {2244, "This password cannot be used now (password history conflict)." },
173 {2245, "The password is shorter than required." },
174 {2246, "The password of this user is too recent to change."},
176 /* these really shouldn't be here ... */
177 {0x80, "Not listening on called name"},
178 {0x81, "Not listening for calling name"},
179 {0x82, "Called name not present"},
180 {0x83, "Called name present, but insufficient resources"},
185 /****************************************************************************
186 return a description of an SMB error
187 ****************************************************************************/
188 static char *cli_smb_errstr(struct cli_state *cli)
190 return smb_errstr(cli->inbuf);
193 /******************************************************
194 Return an error message - either an SMB error or a RAP
196 *******************************************************/
198 char *cli_errstr(struct cli_state *cli)
200 static fstring error_message;
207 * Errors are of three kinds - smb errors,
208 * dealt with by cli_smb_errstr, NT errors,
209 * whose code is in cli.nt_error, and rap
210 * errors, whose error code is in cli.rap_error.
213 cli_error(cli, &errclass, &errnum, &nt_rpc_error);
217 return cli_smb_errstr(cli);
221 * Was it an NT error ?
226 char *nt_msg = get_nt_error_msg(nt_rpc_error);
230 slprintf(error_message, sizeof(fstring) - 1, "NT code %d", nt_rpc_error);
234 fstrcpy(error_message, nt_msg);
237 return error_message;
241 * Must have been a rap error.
244 slprintf(error_message, sizeof(error_message) - 1, "code %d", cli->rap_error);
246 for (i = 0; rap_errmap[i].message != NULL; i++)
248 if (rap_errmap[i].err == cli->rap_error)
250 fstrcpy( error_message, rap_errmap[i].message);
255 return error_message;
258 /*****************************************************************************
259 Convert a character pointer in a cli_call_api() response to a form we can use.
260 This function contains code to prevent core dumps if the server returns
262 *****************************************************************************/
263 static char *fix_char_ptr(unsigned int datap, unsigned int converter,
264 char *rdata, int rdrcnt)
266 if (datap == 0) { /* turn NULL pointers into zero length strings */
269 unsigned int offset = datap - converter;
271 if (offset >= rdrcnt) {
272 DEBUG(1,("bad char ptr: datap=%u, converter=%u rdrcnt=%d>",
273 datap, converter, rdrcnt));
276 return &rdata[offset];
281 /****************************************************************************
282 send a SMB trans or trans2 request
283 ****************************************************************************/
284 static BOOL cli_send_trans(struct cli_state *cli, int trans,
285 char *name, int pipe_name_len,
287 uint16 *setup, int lsetup, int msetup,
288 char *param, int lparam, int mparam,
289 char *data, int ldata, int mdata)
292 int this_ldata,this_lparam;
293 int tot_data=0,tot_param=0;
294 char *outdata,*outparam;
297 this_lparam = MIN(lparam,cli->max_xmit - (500+lsetup*2)); /* hack */
298 this_ldata = MIN(ldata,cli->max_xmit - (500+lsetup*2+this_lparam));
300 memset(cli->outbuf,'\0',smb_size);
301 set_message(cli->outbuf,14+lsetup,0,True);
302 CVAL(cli->outbuf,smb_com) = trans;
303 SSVAL(cli->outbuf,smb_tid, cli->cnum);
304 cli_setup_packet(cli);
306 outparam = smb_buf(cli->outbuf)+(trans==SMBtrans ? pipe_name_len+1 : 3);
307 outdata = outparam+this_lparam;
309 /* primary request */
310 SSVAL(cli->outbuf,smb_tpscnt,lparam); /* tpscnt */
311 SSVAL(cli->outbuf,smb_tdscnt,ldata); /* tdscnt */
312 SSVAL(cli->outbuf,smb_mprcnt,mparam); /* mprcnt */
313 SSVAL(cli->outbuf,smb_mdrcnt,mdata); /* mdrcnt */
314 SCVAL(cli->outbuf,smb_msrcnt,msetup); /* msrcnt */
315 SSVAL(cli->outbuf,smb_flags,flags); /* flags */
316 SIVAL(cli->outbuf,smb_timeout,0); /* timeout */
317 SSVAL(cli->outbuf,smb_pscnt,this_lparam); /* pscnt */
318 SSVAL(cli->outbuf,smb_psoff,smb_offset(outparam,cli->outbuf)); /* psoff */
319 SSVAL(cli->outbuf,smb_dscnt,this_ldata); /* dscnt */
320 SSVAL(cli->outbuf,smb_dsoff,smb_offset(outdata,cli->outbuf)); /* dsoff */
321 SCVAL(cli->outbuf,smb_suwcnt,lsetup); /* suwcnt */
322 for (i=0;i<lsetup;i++) /* setup[] */
323 SSVAL(cli->outbuf,smb_setup+i*2,setup[i]);
324 p = smb_buf(cli->outbuf);
325 if (trans==SMBtrans) {
326 memcpy(p,name, pipe_name_len + 1); /* name[] */
328 *p++ = 0; /* put in a null smb_name */
329 *p++ = 'D'; *p++ = ' '; /* observed in OS/2 */
331 if (this_lparam) /* param[] */
332 memcpy(outparam,param,this_lparam);
333 if (this_ldata) /* data[] */
334 memcpy(outdata,data,this_ldata);
335 set_message(cli->outbuf,14+lsetup, /* wcnt, bcc */
336 PTR_DIFF(outdata+this_ldata,smb_buf(cli->outbuf)),False);
338 show_msg(cli->outbuf);
341 if (this_ldata < ldata || this_lparam < lparam) {
342 /* receive interim response */
343 if (!cli_receive_smb(cli) ||
344 CVAL(cli->inbuf,smb_rcls) != 0) {
348 tot_data = this_ldata;
349 tot_param = this_lparam;
351 while (tot_data < ldata || tot_param < lparam) {
352 this_lparam = MIN(lparam-tot_param,cli->max_xmit - 500); /* hack */
353 this_ldata = MIN(ldata-tot_data,cli->max_xmit - (500+this_lparam));
355 set_message(cli->outbuf,trans==SMBtrans?8:9,0,True);
356 CVAL(cli->outbuf,smb_com) = trans==SMBtrans ? SMBtranss : SMBtranss2;
358 outparam = smb_buf(cli->outbuf);
359 outdata = outparam+this_lparam;
361 /* secondary request */
362 SSVAL(cli->outbuf,smb_tpscnt,lparam); /* tpscnt */
363 SSVAL(cli->outbuf,smb_tdscnt,ldata); /* tdscnt */
364 SSVAL(cli->outbuf,smb_spscnt,this_lparam); /* pscnt */
365 SSVAL(cli->outbuf,smb_spsoff,smb_offset(outparam,cli->outbuf)); /* psoff */
366 SSVAL(cli->outbuf,smb_spsdisp,tot_param); /* psdisp */
367 SSVAL(cli->outbuf,smb_sdscnt,this_ldata); /* dscnt */
368 SSVAL(cli->outbuf,smb_sdsoff,smb_offset(outdata,cli->outbuf)); /* dsoff */
369 SSVAL(cli->outbuf,smb_sdsdisp,tot_data); /* dsdisp */
370 if (trans==SMBtrans2)
371 SSVALS(cli->outbuf,smb_sfid,fid); /* fid */
372 if (this_lparam) /* param[] */
373 memcpy(outparam,param+tot_param,this_lparam);
374 if (this_ldata) /* data[] */
375 memcpy(outdata,data+tot_data,this_ldata);
376 set_message(cli->outbuf,trans==SMBtrans?8:9, /* wcnt, bcc */
377 PTR_DIFF(outdata+this_ldata,smb_buf(cli->outbuf)),False);
379 show_msg(cli->outbuf);
382 tot_data += this_ldata;
383 tot_param += this_lparam;
391 /****************************************************************************
392 receive a SMB trans or trans2 response allocating the necessary memory
393 ****************************************************************************/
394 static BOOL cli_receive_trans(struct cli_state *cli,int trans,
395 char **param, int *param_len,
396 char **data, int *data_len)
400 int this_data,this_param;
404 *data_len = *param_len = 0;
406 if (!cli_receive_smb(cli))
409 show_msg(cli->inbuf);
412 if (CVAL(cli->inbuf,smb_com) != trans) {
413 DEBUG(0,("Expected %s response, got command 0x%02x\n",
414 trans==SMBtrans?"SMBtrans":"SMBtrans2",
415 CVAL(cli->inbuf,smb_com)));
420 * An NT RPC pipe call can return ERRDOS, ERRmoredata
421 * to a trans call. This is not an error and should not
422 * be treated as such.
425 if (cli_error(cli, &eclass, &ecode, NULL))
427 if(cli->nt_pipe_fnum == 0 || !(eclass == ERRDOS && ecode == ERRmoredata))
431 /* parse out the lengths */
432 total_data = SVAL(cli->inbuf,smb_tdrcnt);
433 total_param = SVAL(cli->inbuf,smb_tprcnt);
436 *data = Realloc(*data,total_data);
437 *param = Realloc(*param,total_param);
440 this_data = SVAL(cli->inbuf,smb_drcnt);
441 this_param = SVAL(cli->inbuf,smb_prcnt);
443 if (this_data + *data_len > total_data ||
444 this_param + *param_len > total_param) {
445 DEBUG(1,("Data overflow in cli_receive_trans\n"));
450 memcpy(*data + SVAL(cli->inbuf,smb_drdisp),
451 smb_base(cli->inbuf) + SVAL(cli->inbuf,smb_droff),
454 memcpy(*param + SVAL(cli->inbuf,smb_prdisp),
455 smb_base(cli->inbuf) + SVAL(cli->inbuf,smb_proff),
457 *data_len += this_data;
458 *param_len += this_param;
460 /* parse out the total lengths again - they can shrink! */
461 total_data = SVAL(cli->inbuf,smb_tdrcnt);
462 total_param = SVAL(cli->inbuf,smb_tprcnt);
464 if (total_data <= *data_len && total_param <= *param_len)
467 if (!cli_receive_smb(cli))
470 show_msg(cli->inbuf);
473 if (CVAL(cli->inbuf,smb_com) != trans) {
474 DEBUG(0,("Expected %s response, got command 0x%02x\n",
475 trans==SMBtrans?"SMBtrans":"SMBtrans2",
476 CVAL(cli->inbuf,smb_com)));
479 if (cli_error(cli, &eclass, &ecode, NULL))
481 if(cli->nt_pipe_fnum == 0 || !(eclass == ERRDOS && ecode == ERRmoredata))
489 /****************************************************************************
490 Call a remote api on an arbitrary pipe. takes param, data and setup buffers.
491 ****************************************************************************/
492 BOOL cli_api_pipe(struct cli_state *cli, char *pipe_name, int pipe_name_len,
493 uint16 *setup, uint32 setup_count, uint32 max_setup_count,
494 char *params, uint32 param_count, uint32 max_param_count,
495 char *data, uint32 data_count, uint32 max_data_count,
496 char **rparam, uint32 *rparam_count,
497 char **rdata, uint32 *rdata_count)
499 if (pipe_name_len == 0)
500 pipe_name_len = strlen(pipe_name);
502 cli_send_trans(cli, SMBtrans,
503 pipe_name, pipe_name_len,
504 0,0, /* fid, flags */
505 setup, setup_count, max_setup_count,
506 params, param_count, max_param_count,
507 data, data_count, max_data_count);
509 return (cli_receive_trans(cli, SMBtrans,
510 rparam, (int *)rparam_count,
511 rdata, (int *)rdata_count));
514 /****************************************************************************
516 ****************************************************************************/
517 BOOL cli_api(struct cli_state *cli,
518 char *param, int prcnt, int mprcnt,
519 char *data, int drcnt, int mdrcnt,
520 char **rparam, int *rprcnt,
521 char **rdata, int *rdrcnt)
523 cli_send_trans(cli,SMBtrans,
524 PIPE_LANMAN,strlen(PIPE_LANMAN), /* Name, length */
525 0,0, /* fid, flags */
526 NULL,0,0, /* Setup, length, max */
527 param, prcnt, mprcnt, /* Params, length, max */
528 data, drcnt, mdrcnt /* Data, length, max */
531 return (cli_receive_trans(cli,SMBtrans,
537 /****************************************************************************
538 perform a NetWkstaUserLogon
539 ****************************************************************************/
540 BOOL cli_NetWkstaUserLogon(struct cli_state *cli,char *user, char *workstation)
548 memset(param, 0, sizeof(param));
550 /* send a SMBtrans command with api NetWkstaUserLogon */
552 SSVAL(p,0,132); /* api number */
554 pstrcpy(p,"OOWb54WrLh");
555 p = skip_string(p,1);
556 pstrcpy(p,"WB21BWDWWDDDDDDDzzzD");
557 p = skip_string(p,1);
566 pstrcpy(p, workstation);
569 SSVAL(p, 0, CLI_BUFFER_SIZE);
571 SSVAL(p, 0, CLI_BUFFER_SIZE);
575 param, PTR_DIFF(p,param),1024, /* param, length, max */
576 NULL, 0, CLI_BUFFER_SIZE, /* data, length, max */
577 &rparam, &rprcnt, /* return params, return size */
578 &rdata, &rdrcnt /* return data, return size */
580 cli->rap_error = SVAL(rparam,0);
583 if (cli->rap_error == 0) {
584 DEBUG(4,("NetWkstaUserLogon success\n"));
585 cli->privileges = SVAL(p, 24);
586 fstrcpy(cli->eff_name,p+2);
588 DEBUG(1,("NetwkstaUserLogon gave error %d\n", cli->rap_error));
596 return (cli->rap_error == 0);
599 /****************************************************************************
600 call a NetShareEnum - try and browse available connections on a host
601 ****************************************************************************/
602 int cli_RNetShareEnum(struct cli_state *cli, void (*fn)(const char *, uint32, const char *))
611 /* now send a SMBtrans command with api RNetShareEnum */
613 SSVAL(p,0,0); /* api number */
616 p = skip_string(p,1);
618 p = skip_string(p,1);
621 * Win2k needs a *smaller* buffer than 0xFFFF here -
622 * it returns "out of server memory" with 0xFFFF !!! JRA.
628 param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */
629 NULL, 0, 0xFFE0, /* data, length, maxlen - Win2k needs a small buffer here too ! */
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 dos_to_unix(sname,True);
647 dos_to_unix(cmnt,True);
648 fn(sname, type, cmnt);
651 DEBUG(4,("NetShareEnum res=%d\n", res));
654 DEBUG(4,("NetShareEnum failed\n"));
666 /****************************************************************************
667 call a NetServerEnum for the specified workgroup and servertype mask.
668 This function then calls the specified callback function for each name returned.
670 The callback function takes 3 arguments: the machine name, the server type and
672 ****************************************************************************/
673 BOOL cli_NetServerEnum(struct cli_state *cli, char *workgroup, uint32 stype,
674 void (*fn)(const char *, uint32, const char *))
684 /* send a SMBtrans command with api NetServerEnum */
686 SSVAL(p,0,0x68); /* api number */
688 pstrcpy(p,"WrLehDz");
689 p = skip_string(p,1);
691 pstrcpy(p,"B16BBDz");
693 p = skip_string(p,1);
695 SSVAL(p,2,CLI_BUFFER_SIZE);
700 pstrcpy(p, workgroup);
701 p = skip_string(p,1);
704 param, PTR_DIFF(p,param), 8, /* params, length, max */
705 NULL, 0, CLI_BUFFER_SIZE, /* data, length, max */
706 &rparam, &rprcnt, /* return params, return size */
707 &rdata, &rdrcnt /* return data, return size */
709 int res = SVAL(rparam,0);
710 int converter=SVAL(rparam,2);
713 if (res == 0 || res == ERRmoredata) {
714 count=SVAL(rparam,4);
717 for (i = 0;i < count;i++, p += 26) {
719 int comment_offset = (IVAL(p,22) & 0xFFFF)-converter;
720 char *cmnt = comment_offset?(rdata+comment_offset):"";
721 if (comment_offset < 0 || comment_offset > rdrcnt) continue;
723 stype = IVAL(p,18) & ~SV_TYPE_LOCAL_LIST_ONLY;
725 dos_to_unix(sname, True);
726 dos_to_unix(cmnt, True);
727 fn(sname, stype, cmnt);
749 {PROTOCOL_CORE,"PC NETWORK PROGRAM 1.0"},
750 {PROTOCOL_COREPLUS,"MICROSOFT NETWORKS 1.03"},
751 {PROTOCOL_LANMAN1,"MICROSOFT NETWORKS 3.0"},
752 {PROTOCOL_LANMAN1,"LANMAN1.0"},
753 {PROTOCOL_LANMAN2,"LM1.2X002"},
754 {PROTOCOL_LANMAN2,"Samba"},
755 {PROTOCOL_NT1,"NT LANMAN 1.0"},
756 {PROTOCOL_NT1,"NT LM 0.12"},
761 /****************************************************************************
762 Send a session setup. The username is in UNIX character format and must be
763 converted to DOS codepage format before sending. If the password is in
764 plaintext, the same should be done.
765 ****************************************************************************/
767 BOOL cli_session_setup(struct cli_state *cli,
769 char *pass, int passlen,
770 char *ntpass, int ntpasslen,
774 fstring pword, ntpword;
776 if (cli->protocol < PROTOCOL_LANMAN1)
779 if (passlen > sizeof(pword)-1 || ntpasslen > sizeof(ntpword)-1) {
783 if (((passlen == 0) || (passlen == 1)) && (pass[0] == '\0')) {
784 /* Null session connect. */
788 if ((cli->sec_mode & 2) && passlen != 24) {
790 * Encrypted mode needed, and non encrypted password supplied.
794 fstrcpy(pword, pass);
795 unix_to_dos(pword,True);
796 fstrcpy(ntpword, ntpass);;
797 unix_to_dos(ntpword,True);
798 SMBencrypt((uchar *)pword,(uchar *)cli->cryptkey,(uchar *)pword);
799 SMBNTencrypt((uchar *)ntpword,(uchar *)cli->cryptkey,(uchar *)ntpword);
800 } else if ((cli->sec_mode & 2) && passlen == 24) {
802 * Encrypted mode needed, and encrypted password supplied.
804 memcpy(pword, pass, passlen);
805 if(ntpasslen == 24) {
806 memcpy(ntpword, ntpass, ntpasslen);
808 fstrcpy(ntpword, "");
813 * Plaintext mode needed, assume plaintext supplied.
815 fstrcpy(pword, pass);
816 unix_to_dos(pword,True);
817 fstrcpy(ntpword, "");
822 /* if in share level security then don't send a password now */
823 if (!(cli->sec_mode & 1)) {
826 fstrcpy(ntpword, "");
830 /* send a session setup command */
831 memset(cli->outbuf,'\0',smb_size);
833 if (cli->protocol < PROTOCOL_NT1)
835 set_message(cli->outbuf,10,1 + strlen(user) + passlen,True);
836 CVAL(cli->outbuf,smb_com) = SMBsesssetupX;
837 cli_setup_packet(cli);
839 CVAL(cli->outbuf,smb_vwv0) = 0xFF;
840 SSVAL(cli->outbuf,smb_vwv2,cli->max_xmit);
841 SSVAL(cli->outbuf,smb_vwv3,2);
842 SSVAL(cli->outbuf,smb_vwv4,1);
843 SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
844 SSVAL(cli->outbuf,smb_vwv7,passlen);
845 p = smb_buf(cli->outbuf);
846 memcpy(p,pword,passlen);
854 set_message(cli->outbuf,13,0,True);
855 CVAL(cli->outbuf,smb_com) = SMBsesssetupX;
856 cli_setup_packet(cli);
858 CVAL(cli->outbuf,smb_vwv0) = 0xFF;
859 SSVAL(cli->outbuf,smb_vwv2,CLI_BUFFER_SIZE);
860 SSVAL(cli->outbuf,smb_vwv3,2);
861 SSVAL(cli->outbuf,smb_vwv4,cli->pid);
862 SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
863 SSVAL(cli->outbuf,smb_vwv7,passlen);
864 SSVAL(cli->outbuf,smb_vwv8,ntpasslen);
865 SSVAL(cli->outbuf,smb_vwv11,0);
866 p = smb_buf(cli->outbuf);
867 memcpy(p,pword,passlen);
868 p += SVAL(cli->outbuf,smb_vwv7);
869 memcpy(p,ntpword,ntpasslen);
870 p += SVAL(cli->outbuf,smb_vwv8);
874 p = skip_string(p,1);
875 pstrcpy(p,workgroup);
877 p = skip_string(p,1);
878 pstrcpy(p,"Unix");p = skip_string(p,1);
879 pstrcpy(p,"Samba");p = skip_string(p,1);
880 set_message(cli->outbuf,13,PTR_DIFF(p,smb_buf(cli->outbuf)),False);
884 if (!cli_receive_smb(cli))
887 show_msg(cli->inbuf);
889 if (CVAL(cli->inbuf,smb_rcls) != 0) {
893 /* use the returned vuid from now on */
894 cli->vuid = SVAL(cli->inbuf,smb_uid);
896 if (cli->protocol >= PROTOCOL_NT1) {
898 * Save off some of the connected server
901 char *server_domain,*server_os,*server_type;
902 server_os = smb_buf(cli->inbuf);
903 server_type = skip_string(server_os,1);
904 server_domain = skip_string(server_type,1);
905 fstrcpy(cli->server_os, server_os);
906 dos_to_unix(cli->server_os, True);
907 fstrcpy(cli->server_type, server_type);
908 dos_to_unix(cli->server_type, True);
909 fstrcpy(cli->server_domain, server_domain);
910 dos_to_unix(cli->server_domain, True);
913 fstrcpy(cli->user_name, user);
914 dos_to_unix(cli->user_name, True);
919 /****************************************************************************
921 *****************************************************************************/
923 BOOL cli_ulogoff(struct cli_state *cli)
925 memset(cli->outbuf,'\0',smb_size);
926 set_message(cli->outbuf,2,0,True);
927 CVAL(cli->outbuf,smb_com) = SMBulogoffX;
928 cli_setup_packet(cli);
929 SSVAL(cli->outbuf,smb_vwv0,0xFF);
930 SSVAL(cli->outbuf,smb_vwv2,0); /* no additional info */
933 if (!cli_receive_smb(cli))
936 return CVAL(cli->inbuf,smb_rcls) == 0;
939 /****************************************************************************
941 ****************************************************************************/
942 BOOL cli_send_tconX(struct cli_state *cli,
943 char *share, char *dev, char *pass, int passlen)
945 fstring fullshare, pword, dos_pword;
947 memset(cli->outbuf,'\0',smb_size);
948 memset(cli->inbuf,'\0',smb_size);
950 fstrcpy(cli->share, share);
952 /* in user level security don't send a password now */
953 if (cli->sec_mode & 1) {
958 if ((cli->sec_mode & 2) && *pass && passlen != 24) {
960 * Non-encrypted passwords - convert to DOS codepage before encryption.
963 fstrcpy(dos_pword,pass);
964 unix_to_dos(dos_pword,True);
965 SMBencrypt((uchar *)dos_pword,(uchar *)cli->cryptkey,(uchar *)pword);
967 if(!(cli->sec_mode & 2)) {
969 * Non-encrypted passwords - convert to DOS codepage before using.
972 unix_to_dos(pword,True);
974 memcpy(pword, pass, passlen);
978 slprintf(fullshare, sizeof(fullshare)-1,
979 "\\\\%s\\%s", cli->desthost, share);
980 unix_to_dos(fullshare, True);
983 set_message(cli->outbuf,4,
984 2 + strlen(fullshare) + passlen + strlen(dev),True);
985 CVAL(cli->outbuf,smb_com) = SMBtconX;
986 cli_setup_packet(cli);
988 SSVAL(cli->outbuf,smb_vwv0,0xFF);
989 SSVAL(cli->outbuf,smb_vwv3,passlen);
991 p = smb_buf(cli->outbuf);
992 memcpy(p,pword,passlen);
994 fstrcpy(p,fullshare);
995 p = skip_string(p,1);
999 SCVAL(cli->inbuf,smb_rcls, 1);
1002 if (!cli_receive_smb(cli))
1005 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1009 fstrcpy(cli->dev, "A:");
1011 if (cli->protocol >= PROTOCOL_NT1) {
1012 fstrcpy(cli->dev, smb_buf(cli->inbuf));
1015 if (strcasecmp(share,"IPC$")==0) {
1016 fstrcpy(cli->dev, "IPC");
1019 /* only grab the device if we have a recent protocol level */
1020 if (cli->protocol >= PROTOCOL_NT1 &&
1021 smb_buflen(cli->inbuf) == 3) {
1022 /* almost certainly win95 - enable bug fixes */
1026 cli->cnum = SVAL(cli->inbuf,smb_tid);
1031 /****************************************************************************
1032 send a tree disconnect
1033 ****************************************************************************/
1034 BOOL cli_tdis(struct cli_state *cli)
1036 memset(cli->outbuf,'\0',smb_size);
1037 set_message(cli->outbuf,0,0,True);
1038 CVAL(cli->outbuf,smb_com) = SMBtdis;
1039 SSVAL(cli->outbuf,smb_tid,cli->cnum);
1040 cli_setup_packet(cli);
1043 if (!cli_receive_smb(cli))
1046 return CVAL(cli->inbuf,smb_rcls) == 0;
1049 /****************************************************************************
1051 ****************************************************************************/
1052 BOOL cli_rename(struct cli_state *cli, char *fname_src, char *fname_dst)
1056 memset(cli->outbuf,'\0',smb_size);
1057 memset(cli->inbuf,'\0',smb_size);
1059 set_message(cli->outbuf,1, 4 + strlen(fname_src) + strlen(fname_dst), True);
1061 CVAL(cli->outbuf,smb_com) = SMBmv;
1062 SSVAL(cli->outbuf,smb_tid,cli->cnum);
1063 cli_setup_packet(cli);
1065 SSVAL(cli->outbuf,smb_vwv0,aSYSTEM | aHIDDEN | aDIR);
1067 p = smb_buf(cli->outbuf);
1069 pstrcpy(p,fname_src);
1070 unix_to_dos(p,True);
1071 p = skip_string(p,1);
1073 pstrcpy(p,fname_dst);
1074 unix_to_dos(p,True);
1077 if (!cli_receive_smb(cli)) {
1081 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1088 /****************************************************************************
1090 ****************************************************************************/
1091 BOOL cli_unlink(struct cli_state *cli, char *fname)
1095 memset(cli->outbuf,'\0',smb_size);
1096 memset(cli->inbuf,'\0',smb_size);
1098 set_message(cli->outbuf,1, 2 + strlen(fname),True);
1100 CVAL(cli->outbuf,smb_com) = SMBunlink;
1101 SSVAL(cli->outbuf,smb_tid,cli->cnum);
1102 cli_setup_packet(cli);
1104 SSVAL(cli->outbuf,smb_vwv0,aSYSTEM | aHIDDEN);
1106 p = smb_buf(cli->outbuf);
1109 unix_to_dos(p,True);
1112 if (!cli_receive_smb(cli)) {
1116 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1123 /****************************************************************************
1125 ****************************************************************************/
1126 BOOL cli_mkdir(struct cli_state *cli, char *dname)
1130 memset(cli->outbuf,'\0',smb_size);
1131 memset(cli->inbuf,'\0',smb_size);
1133 set_message(cli->outbuf,0, 2 + strlen(dname),True);
1135 CVAL(cli->outbuf,smb_com) = SMBmkdir;
1136 SSVAL(cli->outbuf,smb_tid,cli->cnum);
1137 cli_setup_packet(cli);
1139 p = smb_buf(cli->outbuf);
1142 unix_to_dos(p,True);
1145 if (!cli_receive_smb(cli)) {
1149 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1156 /****************************************************************************
1158 ****************************************************************************/
1159 BOOL cli_rmdir(struct cli_state *cli, char *dname)
1163 memset(cli->outbuf,'\0',smb_size);
1164 memset(cli->inbuf,'\0',smb_size);
1166 set_message(cli->outbuf,0, 2 + strlen(dname),True);
1168 CVAL(cli->outbuf,smb_com) = SMBrmdir;
1169 SSVAL(cli->outbuf,smb_tid,cli->cnum);
1170 cli_setup_packet(cli);
1172 p = smb_buf(cli->outbuf);
1175 unix_to_dos(p,True);
1178 if (!cli_receive_smb(cli)) {
1182 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1191 /****************************************************************************
1193 ****************************************************************************/
1194 int cli_nt_create(struct cli_state *cli, char *fname)
1198 memset(cli->outbuf,'\0',smb_size);
1199 memset(cli->inbuf,'\0',smb_size);
1201 set_message(cli->outbuf,24,1 + strlen(fname),True);
1203 CVAL(cli->outbuf,smb_com) = SMBntcreateX;
1204 SSVAL(cli->outbuf,smb_tid,cli->cnum);
1205 cli_setup_packet(cli);
1207 SSVAL(cli->outbuf,smb_vwv0,0xFF);
1208 SIVAL(cli->outbuf,smb_ntcreate_Flags, 0x06);
1209 SIVAL(cli->outbuf,smb_ntcreate_RootDirectoryFid, 0x0);
1210 SIVAL(cli->outbuf,smb_ntcreate_DesiredAccess, 0x2019f);
1211 SIVAL(cli->outbuf,smb_ntcreate_FileAttributes, 0x0);
1212 SIVAL(cli->outbuf,smb_ntcreate_ShareAccess, 0x03);
1213 SIVAL(cli->outbuf,smb_ntcreate_CreateDisposition, 0x01);
1214 SIVAL(cli->outbuf,smb_ntcreate_CreateOptions, 0x0);
1215 SIVAL(cli->outbuf,smb_ntcreate_ImpersonationLevel, 0x02);
1216 SSVAL(cli->outbuf,smb_ntcreate_NameLength, strlen(fname));
1218 p = smb_buf(cli->outbuf);
1220 unix_to_dos(p,True);
1221 p = skip_string(p,1);
1224 if (!cli_receive_smb(cli)) {
1228 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1232 return SVAL(cli->inbuf,smb_vwv2 + 1);
1236 /****************************************************************************
1238 WARNING: if you open with O_WRONLY then getattrE won't work!
1239 ****************************************************************************/
1240 int cli_open(struct cli_state *cli, char *fname, int flags, int share_mode)
1244 unsigned accessmode=0;
1246 if (flags & O_CREAT)
1248 if (!(flags & O_EXCL)) {
1249 if (flags & O_TRUNC)
1255 accessmode = (share_mode<<4);
1257 if ((flags & O_ACCMODE) == O_RDWR) {
1259 } else if ((flags & O_ACCMODE) == O_WRONLY) {
1264 if ((flags & O_SYNC) == O_SYNC) {
1265 accessmode |= (1<<14);
1269 if (share_mode == DENY_FCB) {
1273 memset(cli->outbuf,'\0',smb_size);
1274 memset(cli->inbuf,'\0',smb_size);
1276 set_message(cli->outbuf,15,1 + strlen(fname),True);
1278 CVAL(cli->outbuf,smb_com) = SMBopenX;
1279 SSVAL(cli->outbuf,smb_tid,cli->cnum);
1280 cli_setup_packet(cli);
1282 SSVAL(cli->outbuf,smb_vwv0,0xFF);
1283 SSVAL(cli->outbuf,smb_vwv2,0); /* no additional info */
1284 SSVAL(cli->outbuf,smb_vwv3,accessmode);
1285 SSVAL(cli->outbuf,smb_vwv4,aSYSTEM | aHIDDEN);
1286 SSVAL(cli->outbuf,smb_vwv5,0);
1287 SSVAL(cli->outbuf,smb_vwv8,openfn);
1289 if (cli->use_oplocks) {
1290 /* if using oplocks then ask for a batch oplock via
1291 core and extended methods */
1292 CVAL(cli->outbuf,smb_flg) |=
1293 FLAG_REQUEST_OPLOCK|FLAG_REQUEST_BATCH_OPLOCK;
1294 SSVAL(cli->outbuf,smb_vwv2,SVAL(cli->outbuf,smb_vwv2) | 6);
1297 p = smb_buf(cli->outbuf);
1299 unix_to_dos(p,True);
1300 p = skip_string(p,1);
1303 if (!cli_receive_smb(cli)) {
1307 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1311 return SVAL(cli->inbuf,smb_vwv2);
1317 /****************************************************************************
1319 ****************************************************************************/
1320 BOOL cli_close(struct cli_state *cli, int fnum)
1322 memset(cli->outbuf,'\0',smb_size);
1323 memset(cli->inbuf,'\0',smb_size);
1325 set_message(cli->outbuf,3,0,True);
1327 CVAL(cli->outbuf,smb_com) = SMBclose;
1328 SSVAL(cli->outbuf,smb_tid,cli->cnum);
1329 cli_setup_packet(cli);
1331 SSVAL(cli->outbuf,smb_vwv0,fnum);
1332 SIVALS(cli->outbuf,smb_vwv1,-1);
1335 if (!cli_receive_smb(cli)) {
1339 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1347 /****************************************************************************
1349 ****************************************************************************/
1350 BOOL cli_lock(struct cli_state *cli, int fnum,
1351 uint32 offset, uint32 len, int timeout, enum brl_type lock_type)
1354 int saved_timeout = cli->timeout;
1356 memset(cli->outbuf,'\0',smb_size);
1357 memset(cli->inbuf,'\0', smb_size);
1359 set_message(cli->outbuf,8,10,True);
1361 CVAL(cli->outbuf,smb_com) = SMBlockingX;
1362 SSVAL(cli->outbuf,smb_tid,cli->cnum);
1363 cli_setup_packet(cli);
1365 CVAL(cli->outbuf,smb_vwv0) = 0xFF;
1366 SSVAL(cli->outbuf,smb_vwv2,fnum);
1367 CVAL(cli->outbuf,smb_vwv3) = (lock_type == READ_LOCK? 1 : 0);
1368 SIVALS(cli->outbuf, smb_vwv4, timeout);
1369 SSVAL(cli->outbuf,smb_vwv6,0);
1370 SSVAL(cli->outbuf,smb_vwv7,1);
1372 p = smb_buf(cli->outbuf);
1373 SSVAL(p, 0, cli->pid);
1374 SIVAL(p, 2, offset);
1378 cli->timeout = (timeout == -1) ? 0x7FFFFFFF : (timeout + 2*1000);
1380 if (!cli_receive_smb(cli)) {
1381 cli->timeout = saved_timeout;
1385 cli->timeout = saved_timeout;
1387 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1394 /****************************************************************************
1396 ****************************************************************************/
1397 BOOL cli_unlock(struct cli_state *cli, int fnum, uint32 offset, uint32 len)
1401 memset(cli->outbuf,'\0',smb_size);
1402 memset(cli->inbuf,'\0',smb_size);
1404 set_message(cli->outbuf,8,10,True);
1406 CVAL(cli->outbuf,smb_com) = SMBlockingX;
1407 SSVAL(cli->outbuf,smb_tid,cli->cnum);
1408 cli_setup_packet(cli);
1410 CVAL(cli->outbuf,smb_vwv0) = 0xFF;
1411 SSVAL(cli->outbuf,smb_vwv2,fnum);
1412 CVAL(cli->outbuf,smb_vwv3) = 0;
1413 SIVALS(cli->outbuf, smb_vwv4, 0);
1414 SSVAL(cli->outbuf,smb_vwv6,1);
1415 SSVAL(cli->outbuf,smb_vwv7,0);
1417 p = smb_buf(cli->outbuf);
1418 SSVAL(p, 0, cli->pid);
1419 SIVAL(p, 2, offset);
1423 if (!cli_receive_smb(cli)) {
1427 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1436 /****************************************************************************
1437 issue a single SMBread and don't wait for a reply
1438 ****************************************************************************/
1439 static void cli_issue_read(struct cli_state *cli, int fnum, off_t offset,
1442 memset(cli->outbuf,'\0',smb_size);
1443 memset(cli->inbuf,'\0',smb_size);
1445 set_message(cli->outbuf,10,0,True);
1447 CVAL(cli->outbuf,smb_com) = SMBreadX;
1448 SSVAL(cli->outbuf,smb_tid,cli->cnum);
1449 cli_setup_packet(cli);
1451 CVAL(cli->outbuf,smb_vwv0) = 0xFF;
1452 SSVAL(cli->outbuf,smb_vwv2,fnum);
1453 SIVAL(cli->outbuf,smb_vwv3,offset);
1454 SSVAL(cli->outbuf,smb_vwv5,size);
1455 SSVAL(cli->outbuf,smb_vwv6,size);
1456 SSVAL(cli->outbuf,smb_mid,cli->mid + i);
1461 /****************************************************************************
1463 ****************************************************************************/
1464 size_t cli_read(struct cli_state *cli, int fnum, char *buf, off_t offset, size_t size)
1471 * There is a problem in this code when mpx is more than one.
1472 * for some reason files can get corrupted when being read.
1473 * Until we understand this fully I am serializing reads (one
1474 * read/one reply) for now. JRA.
1477 int mpx = MAX(cli->max_mux-1, 1);
1481 int block = (cli->max_xmit - (smb_size+32)) & ~1023;
1483 int blocks = (size + (block-1)) / block;
1485 if (size == 0) return 0;
1487 while (received < blocks) {
1490 while (issued - received < mpx && issued < blocks) {
1491 int size1 = MIN(block, size-issued*block);
1492 cli_issue_read(cli, fnum, offset+issued*block, size1, issued);
1496 if (!cli_receive_smb(cli)) {
1501 mid = SVAL(cli->inbuf, smb_mid) - cli->mid;
1502 size2 = SVAL(cli->inbuf, smb_vwv5);
1504 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1505 blocks = MIN(blocks, mid-1);
1510 blocks = MIN(blocks, mid-1);
1511 /* this distinguishes EOF from an error */
1512 total = MAX(total, 0);
1516 if (size2 > block) {
1517 DEBUG(0,("server returned more than we wanted!\n"));
1520 if (mid >= issued) {
1521 DEBUG(0,("invalid mid from server!\n"));
1524 p = smb_base(cli->inbuf) + SVAL(cli->inbuf,smb_vwv6);
1526 memcpy(buf+mid*block, p, size2);
1528 total = MAX(total, mid*block + size2);
1531 while (received < issued) {
1532 cli_receive_smb(cli);
1540 /****************************************************************************
1541 issue a single SMBwrite and don't wait for a reply
1542 ****************************************************************************/
1543 static void cli_issue_write(struct cli_state *cli, int fnum, off_t offset, uint16 mode, char *buf,
1548 memset(cli->outbuf,'\0',smb_size);
1549 memset(cli->inbuf,'\0',smb_size);
1551 set_message(cli->outbuf,12,size,True);
1553 CVAL(cli->outbuf,smb_com) = SMBwriteX;
1554 SSVAL(cli->outbuf,smb_tid,cli->cnum);
1555 cli_setup_packet(cli);
1557 CVAL(cli->outbuf,smb_vwv0) = 0xFF;
1558 SSVAL(cli->outbuf,smb_vwv2,fnum);
1560 SIVAL(cli->outbuf,smb_vwv3,offset);
1561 SIVAL(cli->outbuf,smb_vwv5,IS_BITS_SET_ALL(mode, 0x0008) ? 0xFFFFFFFF : 0);
1562 SSVAL(cli->outbuf,smb_vwv7,mode);
1564 SSVAL(cli->outbuf,smb_vwv8,IS_BITS_SET_ALL(mode, 0x0008) ? size : 0);
1565 SSVAL(cli->outbuf,smb_vwv10,size);
1566 SSVAL(cli->outbuf,smb_vwv11,
1567 smb_buf(cli->outbuf) - smb_base(cli->outbuf));
1569 p = smb_base(cli->outbuf) + SVAL(cli->outbuf,smb_vwv11);
1570 memcpy(p, buf, size);
1572 SSVAL(cli->outbuf,smb_mid,cli->mid + i);
1574 show_msg(cli->outbuf);
1578 /****************************************************************************
1580 write_mode: 0x0001 disallow write cacheing
1581 0x0002 return bytes remaining
1582 0x0004 use raw named pipe protocol
1583 0x0008 start of message mode named pipe protocol
1584 ****************************************************************************/
1585 ssize_t cli_write(struct cli_state *cli,
1586 int fnum, uint16 write_mode,
1587 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;
1594 int blocks = (size + (block-1)) / block;
1596 while (received < blocks) {
1598 while ((issued - received < mpx) && (issued < blocks))
1600 int bsent = issued * block;
1601 int size1 = MIN(block, size - bsent);
1603 cli_issue_write(cli, fnum, offset + bsent,
1610 if (!cli_receive_smb(cli))
1617 if (CVAL(cli->inbuf,smb_rcls) != 0)
1622 bwritten += SVAL(cli->inbuf, smb_vwv2);
1625 while (received < issued && cli_receive_smb(cli))
1634 /****************************************************************************
1635 write to a file using a SMBwrite and not bypassing 0 byte writes
1636 ****************************************************************************/
1637 ssize_t cli_smbwrite(struct cli_state *cli,
1638 int fnum, char *buf, off_t offset, size_t size1)
1644 size_t size = MIN(size1, cli->max_xmit - 48);
1646 memset(cli->outbuf,'\0',smb_size);
1647 memset(cli->inbuf,'\0',smb_size);
1649 set_message(cli->outbuf,5, 3 + size,True);
1651 CVAL(cli->outbuf,smb_com) = SMBwrite;
1652 SSVAL(cli->outbuf,smb_tid,cli->cnum);
1653 cli_setup_packet(cli);
1655 SSVAL(cli->outbuf,smb_vwv0,fnum);
1656 SSVAL(cli->outbuf,smb_vwv1,size);
1657 SIVAL(cli->outbuf,smb_vwv2,offset);
1658 SSVAL(cli->outbuf,smb_vwv4,0);
1660 p = smb_buf(cli->outbuf);
1663 memcpy(p+2, buf, size);
1666 if (!cli_receive_smb(cli)) {
1670 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1674 size = SVAL(cli->inbuf,smb_vwv0);
1675 if (size == 0) break;
1685 /****************************************************************************
1686 do a SMBgetattrE call
1687 ****************************************************************************/
1688 BOOL cli_getattrE(struct cli_state *cli, int fd,
1689 uint16 *attr, size_t *size,
1690 time_t *c_time, time_t *a_time, time_t *m_time)
1692 memset(cli->outbuf,'\0',smb_size);
1693 memset(cli->inbuf,'\0',smb_size);
1695 set_message(cli->outbuf,1,0,True);
1697 CVAL(cli->outbuf,smb_com) = SMBgetattrE;
1698 SSVAL(cli->outbuf,smb_tid,cli->cnum);
1699 cli_setup_packet(cli);
1701 SSVAL(cli->outbuf,smb_vwv0,fd);
1704 if (!cli_receive_smb(cli)) {
1708 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1713 *size = IVAL(cli->inbuf, smb_vwv6);
1717 *attr = SVAL(cli->inbuf,smb_vwv10);
1721 *c_time = make_unix_date3(cli->inbuf+smb_vwv0);
1725 *a_time = make_unix_date3(cli->inbuf+smb_vwv2);
1729 *m_time = make_unix_date3(cli->inbuf+smb_vwv4);
1736 /****************************************************************************
1738 ****************************************************************************/
1739 BOOL cli_getatr(struct cli_state *cli, char *fname,
1740 uint16 *attr, size_t *size, time_t *t)
1744 memset(cli->outbuf,'\0',smb_size);
1745 memset(cli->inbuf,'\0',smb_size);
1747 set_message(cli->outbuf,0,strlen(fname)+2,True);
1749 CVAL(cli->outbuf,smb_com) = SMBgetatr;
1750 SSVAL(cli->outbuf,smb_tid,cli->cnum);
1751 cli_setup_packet(cli);
1753 p = smb_buf(cli->outbuf);
1755 pstrcpy(p+1, fname);
1756 unix_to_dos(p+1,True);
1759 if (!cli_receive_smb(cli)) {
1763 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1768 *size = IVAL(cli->inbuf, smb_vwv3);
1772 *t = make_unix_date3(cli->inbuf+smb_vwv1);
1776 *attr = SVAL(cli->inbuf,smb_vwv0);
1784 /****************************************************************************
1786 ****************************************************************************/
1787 BOOL cli_setatr(struct cli_state *cli, char *fname, uint16 attr, time_t t)
1791 memset(cli->outbuf,'\0',smb_size);
1792 memset(cli->inbuf,'\0',smb_size);
1794 set_message(cli->outbuf,8,strlen(fname)+4,True);
1796 CVAL(cli->outbuf,smb_com) = SMBsetatr;
1797 SSVAL(cli->outbuf,smb_tid,cli->cnum);
1798 cli_setup_packet(cli);
1800 SSVAL(cli->outbuf,smb_vwv0, attr);
1801 put_dos_date3(cli->outbuf,smb_vwv1, t);
1803 p = smb_buf(cli->outbuf);
1805 pstrcpy(p+1, fname);
1806 unix_to_dos(p+1,True);
1807 p = skip_string(p,1);
1811 if (!cli_receive_smb(cli)) {
1815 if (CVAL(cli->inbuf,smb_rcls) != 0) {
1822 /****************************************************************************
1823 send a qpathinfo call
1824 ****************************************************************************/
1825 BOOL cli_qpathinfo(struct cli_state *cli, const char *fname,
1826 time_t *c_time, time_t *a_time, time_t *m_time,
1827 size_t *size, uint16 *mode)
1831 uint16 setup = TRANSACT2_QPATHINFO;
1833 char *rparam=NULL, *rdata=NULL;
1836 time_t (*date_fn)(void *);
1838 param_len = strlen(fname) + 7;
1840 memset(param, 0, param_len);
1841 SSVAL(param, 0, SMB_INFO_STANDARD);
1842 pstrcpy(¶m[6], fname);
1843 unix_to_dos(¶m[6],True);
1846 ret = (cli_send_trans(cli, SMBtrans2,
1847 NULL, 0, /* Name, length */
1848 -1, 0, /* fid, flags */
1849 &setup, 1, 0, /* setup, length, max */
1850 param, param_len, 10, /* param, length, max */
1851 NULL, data_len, cli->max_xmit /* data, length, max */
1853 cli_receive_trans(cli, SMBtrans2,
1854 &rparam, ¶m_len,
1855 &rdata, &data_len));
1857 /* we need to work around a Win95 bug - sometimes
1858 it gives ERRSRV/ERRerror temprarily */
1861 cli_error(cli, &eclass, &ecode, NULL);
1862 if (eclass != ERRSRV || ecode != ERRerror) break;
1865 } while (count-- && ret==False);
1867 if (!ret || !rdata || data_len < 22) {
1872 date_fn = make_unix_date;
1874 date_fn = make_unix_date2;
1878 *c_time = date_fn(rdata+0);
1881 *a_time = date_fn(rdata+4);
1884 *m_time = date_fn(rdata+8);
1887 *size = IVAL(rdata, 12);
1890 *mode = SVAL(rdata,l1_attrFile);
1893 if (rdata) free(rdata);
1894 if (rparam) free(rparam);
1898 /****************************************************************************
1899 send a qpathinfo call with the SMB_QUERY_FILE_ALL_INFO info level
1900 ****************************************************************************/
1901 BOOL cli_qpathinfo2(struct cli_state *cli, const char *fname,
1902 time_t *c_time, time_t *a_time, time_t *m_time,
1903 time_t *w_time, size_t *size, uint16 *mode,
1908 uint16 setup = TRANSACT2_QPATHINFO;
1910 char *rparam=NULL, *rdata=NULL;
1912 param_len = strlen(fname) + 7;
1914 memset(param, 0, param_len);
1915 SSVAL(param, 0, SMB_QUERY_FILE_ALL_INFO);
1916 pstrcpy(¶m[6], fname);
1917 unix_to_dos(¶m[6],True);
1919 if (!cli_send_trans(cli, SMBtrans2,
1920 NULL, 0, /* name, length */
1921 -1, 0, /* fid, flags */
1922 &setup, 1, 0, /* setup, length, max */
1923 param, param_len, 10, /* param, length, max */
1924 NULL, data_len, cli->max_xmit /* data, length, max */
1929 if (!cli_receive_trans(cli, SMBtrans2,
1930 &rparam, ¶m_len,
1931 &rdata, &data_len)) {
1935 if (!rdata || data_len < 22) {
1940 *c_time = interpret_long_date(rdata+0) - cli->serverzone;
1943 *a_time = interpret_long_date(rdata+8) - cli->serverzone;
1946 *m_time = interpret_long_date(rdata+16) - cli->serverzone;
1949 *w_time = interpret_long_date(rdata+24) - cli->serverzone;
1952 *mode = SVAL(rdata, 32);
1955 *size = IVAL(rdata, 48);
1958 *ino = IVAL(rdata, 64);
1961 if (rdata) free(rdata);
1962 if (rparam) free(rparam);
1967 /****************************************************************************
1968 send a qfileinfo call
1969 ****************************************************************************/
1970 BOOL cli_qfileinfo(struct cli_state *cli, int fnum,
1971 uint16 *mode, size_t *size,
1972 time_t *c_time, time_t *a_time, time_t *m_time,
1973 time_t *w_time, SMB_INO_T *ino)
1977 uint16 setup = TRANSACT2_QFILEINFO;
1979 char *rparam=NULL, *rdata=NULL;
1981 /* if its a win95 server then fail this - win95 totally screws it
1983 if (cli->win95) return False;
1987 memset(param, 0, param_len);
1988 SSVAL(param, 0, fnum);
1989 SSVAL(param, 2, SMB_QUERY_FILE_ALL_INFO);
1991 if (!cli_send_trans(cli, SMBtrans2,
1992 NULL, 0, /* name, length */
1993 -1, 0, /* fid, flags */
1994 &setup, 1, 0, /* setup, length, max */
1995 param, param_len, 2, /* param, length, max */
1996 NULL, data_len, cli->max_xmit /* data, length, max */
2001 if (!cli_receive_trans(cli, SMBtrans2,
2002 &rparam, ¶m_len,
2003 &rdata, &data_len)) {
2007 if (!rdata || data_len < 68) {
2012 *c_time = interpret_long_date(rdata+0) - cli->serverzone;
2015 *a_time = interpret_long_date(rdata+8) - cli->serverzone;
2018 *m_time = interpret_long_date(rdata+16) - cli->serverzone;
2021 *w_time = interpret_long_date(rdata+24) - cli->serverzone;
2024 *mode = SVAL(rdata, 32);
2027 *size = IVAL(rdata, 48);
2030 *ino = IVAL(rdata, 64);
2033 if (rdata) free(rdata);
2034 if (rparam) free(rparam);
2039 /****************************************************************************
2040 interpret a long filename structure - this is mostly guesses at the moment
2041 The length of the structure is returned
2042 The structure of a long filename depends on the info level. 260 is used
2043 by NT and 2 is used by OS/2
2044 ****************************************************************************/
2045 static int interpret_long_filename(int level,char *p,file_info *finfo)
2047 extern file_info def_finfo;
2050 memcpy(finfo,&def_finfo,sizeof(*finfo));
2054 case 1: /* OS/2 understands this */
2056 /* these dates are converted to GMT by make_unix_date */
2057 finfo->ctime = make_unix_date2(p+4);
2058 finfo->atime = make_unix_date2(p+8);
2059 finfo->mtime = make_unix_date2(p+12);
2060 finfo->size = IVAL(p,16);
2061 finfo->mode = CVAL(p,24);
2062 pstrcpy(finfo->name,p+27);
2063 dos_to_unix(finfo->name,True);
2065 return(28 + CVAL(p,26));
2067 case 2: /* this is what OS/2 uses mostly */
2069 /* these dates are converted to GMT by make_unix_date */
2070 finfo->ctime = make_unix_date2(p+4);
2071 finfo->atime = make_unix_date2(p+8);
2072 finfo->mtime = make_unix_date2(p+12);
2073 finfo->size = IVAL(p,16);
2074 finfo->mode = CVAL(p,24);
2075 pstrcpy(finfo->name,p+31);
2076 dos_to_unix(finfo->name,True);
2078 return(32 + CVAL(p,30));
2080 /* levels 3 and 4 are untested */
2083 /* these dates are probably like the other ones */
2084 finfo->ctime = make_unix_date2(p+8);
2085 finfo->atime = make_unix_date2(p+12);
2086 finfo->mtime = make_unix_date2(p+16);
2087 finfo->size = IVAL(p,20);
2088 finfo->mode = CVAL(p,28);
2089 pstrcpy(finfo->name,p+33);
2090 dos_to_unix(finfo->name,True);
2092 return(SVAL(p,4)+4);
2096 /* these dates are probably like the other ones */
2097 finfo->ctime = make_unix_date2(p+8);
2098 finfo->atime = make_unix_date2(p+12);
2099 finfo->mtime = make_unix_date2(p+16);
2100 finfo->size = IVAL(p,20);
2101 finfo->mode = CVAL(p,28);
2102 pstrcpy(finfo->name,p+37);
2103 dos_to_unix(finfo->name,True);
2105 return(SVAL(p,4)+4);
2107 case 260: /* NT uses this, but also accepts 2 */
2109 int ret = SVAL(p,0);
2111 p += 4; /* next entry offset */
2112 p += 4; /* fileindex */
2114 /* these dates appear to arrive in a
2115 weird way. It seems to be localtime
2116 plus the serverzone given in the
2117 initial connect. This is GMT when
2118 DST is not in effect and one hour
2119 from GMT otherwise. Can this really
2122 I suppose this could be called
2123 kludge-GMT. Is is the GMT you get
2124 by using the current DST setting on
2125 a different localtime. It will be
2126 cheap to calculate, I suppose, as
2127 no DST tables will be needed */
2129 finfo->ctime = interpret_long_date(p); p += 8;
2130 finfo->atime = interpret_long_date(p); p += 8;
2131 finfo->mtime = interpret_long_date(p); p += 8; p += 8;
2132 finfo->size = IVAL(p,0); p += 8;
2133 p += 8; /* alloc size */
2134 finfo->mode = CVAL(p,0); p += 4;
2135 namelen = IVAL(p,0); p += 4;
2136 p += 4; /* EA size */
2137 p += 2; /* short name len? */
2138 p += 24; /* short name? */
2139 StrnCpy(finfo->name,p,MIN(sizeof(finfo->name)-1,namelen));
2140 dos_to_unix(finfo->name,True);
2146 DEBUG(1,("Unknown long filename format %d\n",level));
2151 /****************************************************************************
2152 do a directory listing, calling fn on each file found
2153 ****************************************************************************/
2154 int cli_list(struct cli_state *cli,const char *Mask,uint16 attribute,
2155 void (*fn)(file_info *, const char *))
2157 int max_matches = 512;
2158 /* NT uses 260, OS/2 uses 2. Both accept 1. */
2159 int info_level = cli->protocol<PROTOCOL_NT1?1:260;
2164 char *dirlist = NULL;
2165 int dirlist_len = 0;
2166 int total_received = -1;
2168 int ff_searchcount=0;
2171 int ff_dir_handle=0;
2173 char *rparam=NULL, *rdata=NULL;
2174 int param_len, data_len;
2180 unix_to_dos(mask,True);
2182 while (ff_eos == 0) {
2184 if (loop_count > 200) {
2185 DEBUG(0,("Error: Looping in FIND_NEXT??\n"));
2189 param_len = 12+strlen(mask)+1;
2192 setup = TRANSACT2_FINDFIRST;
2193 SSVAL(param,0,attribute); /* attribute */
2194 SSVAL(param,2,max_matches); /* max count */
2195 SSVAL(param,4,4+2); /* resume required + close on end */
2196 SSVAL(param,6,info_level);
2198 pstrcpy(param+12,mask);
2200 setup = TRANSACT2_FINDNEXT;
2201 SSVAL(param,0,ff_dir_handle);
2202 SSVAL(param,2,max_matches); /* max count */
2203 SSVAL(param,4,info_level);
2204 SIVAL(param,6,0); /* ff_resume_key */
2205 SSVAL(param,10,8+4+2); /* continue + resume required + close on end */
2206 pstrcpy(param+12,mask);
2208 DEBUG(5,("hand=0x%X ff_lastname=%d mask=%s\n",
2209 ff_dir_handle,ff_lastname,mask));
2212 if (!cli_send_trans(cli, SMBtrans2,
2213 NULL, 0, /* Name, length */
2214 -1, 0, /* fid, flags */
2215 &setup, 1, 0, /* setup, length, max */
2216 param, param_len, 10, /* param, length, max */
2218 cli->max_xmit /* data, length, max */
2223 if (!cli_receive_trans(cli, SMBtrans2,
2224 &rparam, ¶m_len,
2225 &rdata, &data_len)) {
2226 /* we need to work around a Win95 bug - sometimes
2227 it gives ERRSRV/ERRerror temprarily */
2230 cli_error(cli, &eclass, &ecode, NULL);
2231 if (eclass != ERRSRV || ecode != ERRerror) break;
2236 if (total_received == -1) total_received = 0;
2238 /* parse out some important return info */
2241 ff_dir_handle = SVAL(p,0);
2242 ff_searchcount = SVAL(p,2);
2244 ff_lastname = SVAL(p,8);
2246 ff_searchcount = SVAL(p,0);
2248 ff_lastname = SVAL(p,6);
2251 if (ff_searchcount == 0)
2254 /* point to the data bytes */
2257 /* we might need the lastname for continuations */
2258 if (ff_lastname > 0) {
2262 StrnCpy(mask,p+ff_lastname,
2263 MIN(sizeof(mask)-1,data_len-ff_lastname));
2266 pstrcpy(mask,p + ff_lastname + 1);
2273 dos_to_unix(mask, True);
2275 /* and add them to the dirlist pool */
2276 dirlist = Realloc(dirlist,dirlist_len + data_len);
2279 DEBUG(0,("Failed to expand dirlist\n"));
2283 /* put in a length for the last entry, to ensure we can chain entries
2284 into the next packet */
2285 for (p2=p,i=0;i<(ff_searchcount-1);i++)
2286 p2 += interpret_long_filename(info_level,p2,NULL);
2287 SSVAL(p2,0,data_len - PTR_DIFF(p2,p));
2289 /* grab the data for later use */
2290 memcpy(dirlist+dirlist_len,p,data_len);
2291 dirlist_len += data_len;
2293 total_received += ff_searchcount;
2295 if (rdata) free(rdata); rdata = NULL;
2296 if (rparam) free(rparam); rparam = NULL;
2298 DEBUG(3,("received %d entries (eos=%d)\n",
2299 ff_searchcount,ff_eos));
2301 if (ff_searchcount > 0) loop_count = 0;
2306 for (p=dirlist,i=0;i<total_received;i++) {
2307 p += interpret_long_filename(info_level,p,&finfo);
2311 /* free up the dirlist buffer */
2312 if (dirlist) free(dirlist);
2313 return(total_received);
2317 /****************************************************************************
2318 Send a SamOEMChangePassword command
2319 ****************************************************************************/
2321 BOOL cli_oem_change_password(struct cli_state *cli, const char *user, const char *new_password,
2322 const char *old_password)
2324 char param[16+sizeof(fstring)];
2327 fstring upper_case_old_pw;
2328 fstring upper_case_new_pw;
2329 unsigned char old_pw_hash[16];
2330 unsigned char new_pw_hash[16];
2333 char *rparam = NULL;
2336 pstring dos_new_password;
2338 if (strlen(user) >= sizeof(fstring)-1) {
2339 DEBUG(0,("cli_oem_change_password: user name %s is too long.\n", user));
2343 SSVAL(p,0,214); /* SamOEMChangePassword command. */
2346 p = skip_string(p,1);
2347 pstrcpy(p, "B516B16");
2348 p = skip_string(p,1);
2350 p = skip_string(p,1);
2354 param_len = PTR_DIFF(p,param);
2357 * Get the Lanman hash of the old password, we
2358 * use this as the key to make_oem_passwd_hash().
2360 memset(upper_case_old_pw, '\0', sizeof(upper_case_old_pw));
2361 fstrcpy(upper_case_old_pw, old_password);
2362 unix_to_dos(upper_case_old_pw,True);
2363 strupper(upper_case_old_pw);
2364 E_P16((uchar *)upper_case_old_pw, old_pw_hash);
2366 pstrcpy(dos_new_password, new_password);
2367 unix_to_dos(dos_new_password, True);
2369 if (!make_oem_passwd_hash( data, dos_new_password, old_pw_hash, False))
2373 * Now place the old password hash in the data.
2375 memset(upper_case_new_pw, '\0', sizeof(upper_case_new_pw));
2376 fstrcpy(upper_case_new_pw, new_password);
2377 unix_to_dos(upper_case_new_pw,True);
2378 strupper(upper_case_new_pw);
2380 E_P16((uchar *)upper_case_new_pw, new_pw_hash);
2382 E_old_pw_hash( new_pw_hash, old_pw_hash, (uchar *)&data[516]);
2386 if (cli_send_trans(cli,SMBtrans,
2387 PIPE_LANMAN,strlen(PIPE_LANMAN), /* name, length */
2388 0,0, /* fid, flags */
2389 NULL,0,0, /* setup, length, max */
2390 param,param_len,2, /* param, length, max */
2391 data,data_len,0 /* data, length, max */
2393 DEBUG(0,("cli_oem_change_password: Failed to send password change for user %s\n",
2398 if (cli_receive_trans(cli,SMBtrans,
2402 cli->rap_error = SVAL(rparam,0);
2410 return (cli->rap_error == 0);
2413 /****************************************************************************
2414 send a negprot command
2415 ****************************************************************************/
2416 BOOL cli_negprot(struct cli_state *cli)
2422 memset(cli->outbuf,'\0',smb_size);
2424 /* setup the protocol strings */
2425 for (plength=0,numprots=0;
2426 prots[numprots].name && prots[numprots].prot<=cli->protocol;
2428 plength += strlen(prots[numprots].name)+2;
2430 set_message(cli->outbuf,0,plength,True);
2432 p = smb_buf(cli->outbuf);
2434 prots[numprots].name && prots[numprots].prot<=cli->protocol;
2437 pstrcpy(p,prots[numprots].name);
2438 unix_to_dos(p,True);
2442 CVAL(cli->outbuf,smb_com) = SMBnegprot;
2443 cli_setup_packet(cli);
2445 CVAL(smb_buf(cli->outbuf),0) = 2;
2448 if (!cli_receive_smb(cli))
2451 show_msg(cli->inbuf);
2453 if (CVAL(cli->inbuf,smb_rcls) != 0 ||
2454 ((int)SVAL(cli->inbuf,smb_vwv0) >= numprots)) {
2458 cli->protocol = prots[SVAL(cli->inbuf,smb_vwv0)].prot;
2461 if (cli->protocol >= PROTOCOL_NT1) {
2463 cli->sec_mode = CVAL(cli->inbuf,smb_vwv1);
2464 cli->max_mux = SVAL(cli->inbuf, smb_vwv1+1);
2465 cli->max_xmit = IVAL(cli->inbuf,smb_vwv3+1);
2466 cli->sesskey = IVAL(cli->inbuf,smb_vwv7+1);
2467 cli->serverzone = SVALS(cli->inbuf,smb_vwv15+1);
2468 cli->serverzone *= 60;
2469 /* this time arrives in real GMT */
2470 cli->servertime = interpret_long_date(cli->inbuf+smb_vwv11+1);
2471 memcpy(cli->cryptkey,smb_buf(cli->inbuf),8);
2472 cli->capabilities = IVAL(cli->inbuf,smb_vwv9+1);
2473 if (cli->capabilities & 1) {
2474 cli->readbraw_supported = True;
2475 cli->writebraw_supported = True;
2477 } else if (cli->protocol >= PROTOCOL_LANMAN1) {
2478 cli->sec_mode = SVAL(cli->inbuf,smb_vwv1);
2479 cli->max_xmit = SVAL(cli->inbuf,smb_vwv2);
2480 cli->sesskey = IVAL(cli->inbuf,smb_vwv6);
2481 cli->serverzone = SVALS(cli->inbuf,smb_vwv10);
2482 cli->serverzone *= 60;
2483 /* this time is converted to GMT by make_unix_date */
2484 cli->servertime = make_unix_date(cli->inbuf+smb_vwv8);
2485 cli->readbraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x1) != 0);
2486 cli->writebraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x2) != 0);
2487 memcpy(cli->cryptkey,smb_buf(cli->inbuf),8);
2489 /* the old core protocol */
2491 cli->serverzone = TimeDiff(time(NULL));
2494 cli->max_xmit = MIN(cli->max_xmit, CLI_BUFFER_SIZE);
2500 /****************************************************************************
2501 send a session request. see rfc1002.txt 4.3 and 4.3.2
2502 ****************************************************************************/
2503 BOOL cli_session_request(struct cli_state *cli,
2504 struct nmb_name *calling, struct nmb_name *called)
2508 /* send a session request (RFC 1002) */
2510 memcpy(&(cli->calling), calling, sizeof(*calling));
2511 memcpy(&(cli->called ), called , sizeof(*called ));
2513 /* put in the destination name */
2514 p = cli->outbuf+len;
2515 name_mangle(cli->called .name, p, cli->called .name_type);
2519 p = cli->outbuf+len;
2520 name_mangle(cli->calling.name, p, cli->calling.name_type);
2523 /* setup the packet length */
2524 _smb_setlen(cli->outbuf,len);
2525 CVAL(cli->outbuf,0) = 0x81;
2529 #endif /* WITH_SSL */
2532 DEBUG(5,("Sent session request\n"));
2534 if (!cli_receive_smb(cli))
2537 if (CVAL(cli->inbuf,0) == 0x84) {
2538 /* C. Hoch 9/14/95 Start */
2539 /* For information, here is the response structure.
2540 * We do the byte-twiddling to for portability.
2541 struct RetargetResponse{
2543 unsigned char flags;
2549 int port = (CVAL(cli->inbuf,8)<<8)+CVAL(cli->inbuf,9);
2550 /* SESSION RETARGET */
2551 putip((char *)&cli->dest_ip,cli->inbuf+4);
2553 cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip, port, LONG_CONNECT_TIMEOUT);
2557 DEBUG(3,("Retargeted\n"));
2559 set_socket_options(cli->fd,user_socket_options);
2566 DEBUG(0,("Retarget recursion - failing\n"));
2570 ret = cli_session_request(cli, calling, called);
2574 } /* C. Hoch 9/14/95 End */
2577 if (CVAL(cli->inbuf,0) == 0x83 && CVAL(cli->inbuf,4) == 0x8e){ /* use ssl */
2578 if (!sslutil_fd_is_ssl(cli->fd)){
2579 if (sslutil_connect(cli->fd) == 0)
2583 #endif /* WITH_SSL */
2585 if (CVAL(cli->inbuf,0) != 0x82) {
2586 /* This is the wrong place to put the error... JRA. */
2587 cli->rap_error = CVAL(cli->inbuf,4);
2594 /****************************************************************************
2595 open the client sockets
2596 ****************************************************************************/
2597 BOOL cli_connect(struct cli_state *cli, const char *host, struct in_addr *ip)
2599 extern struct in_addr ipzero;
2601 fstrcpy(cli->desthost, host);
2603 if (!ip || ip_equal(*ip, ipzero)) {
2604 if (!resolve_name( cli->desthost, &cli->dest_ip, 0x20)) {
2607 if (ip) *ip = cli->dest_ip;
2612 if (cli->port == 0) cli->port = 139; /* Set to default */
2614 cli->fd = open_socket_out(SOCK_STREAM, &cli->dest_ip,
2615 cli->port, cli->timeout);
2619 set_socket_options(cli->fd,user_socket_options);
2625 /****************************************************************************
2626 initialise a client structure
2627 ****************************************************************************/
2628 struct cli_state *cli_initialise(struct cli_state *cli)
2631 cli = (struct cli_state *)malloc(sizeof(*cli));
2637 if (cli->initialised) {
2646 cli->pid = (uint16)getpid();
2648 cli->vuid = UID_FIELD_INVALID;
2649 cli->protocol = PROTOCOL_NT1;
2650 cli->timeout = 20000; /* Timeout is in milliseconds. */
2651 cli->bufsize = CLI_BUFFER_SIZE+4;
2652 cli->max_xmit = cli->bufsize;
2653 cli->outbuf = (char *)malloc(cli->bufsize);
2654 cli->inbuf = (char *)malloc(cli->bufsize);
2655 if (!cli->outbuf || !cli->inbuf)
2660 memset(cli->outbuf, '\0', cli->bufsize);
2661 memset(cli->inbuf, '\0', cli->bufsize);
2663 cli->initialised = 1;
2668 /****************************************************************************
2669 shutdown a client structure
2670 ****************************************************************************/
2671 void cli_shutdown(struct cli_state *cli)
2683 sslutil_disconnect(cli->fd);
2684 #endif /* WITH_SSL */
2687 memset(cli, 0, sizeof(*cli));
2691 /****************************************************************************
2692 return error codes for the last packet
2693 returns 0 if there was no error and the best approx of a unix errno
2696 for 32 bit "warnings", a return code of 0 is expected.
2698 ****************************************************************************/
2699 int cli_error(struct cli_state *cli, uint8 *eclass, uint32 *num, uint32 *nt_rpc_error)
2705 if (eclass) *eclass = 0;
2707 if (nt_rpc_error) *nt_rpc_error = 0;
2709 if(!cli->initialised)
2715 flgs2 = SVAL(cli->inbuf,smb_flg2);
2716 if (nt_rpc_error) *nt_rpc_error = cli->nt_error;
2718 if (flgs2 & FLAGS2_32_BIT_ERROR_CODES) {
2719 /* 32 bit error codes detected */
2720 uint32 nt_err = IVAL(cli->inbuf,smb_rcls);
2721 if (num) *num = nt_err;
2722 DEBUG(10,("cli_error: 32 bit codes: code=%08x\n", nt_err));
2723 if (!IS_BITS_SET_ALL(nt_err, 0xc0000000)) return 0;
2725 switch (nt_err & 0xFFFFFF) {
2726 case NT_STATUS_ACCESS_VIOLATION: return EACCES;
2727 case NT_STATUS_NO_SUCH_FILE: return ENOENT;
2728 case NT_STATUS_NO_SUCH_DEVICE: return ENODEV;
2729 case NT_STATUS_INVALID_HANDLE: return EBADF;
2730 case NT_STATUS_NO_MEMORY: return ENOMEM;
2731 case NT_STATUS_ACCESS_DENIED: return EACCES;
2732 case NT_STATUS_OBJECT_NAME_NOT_FOUND: return ENOENT;
2733 case NT_STATUS_SHARING_VIOLATION: return EBUSY;
2734 case NT_STATUS_OBJECT_PATH_INVALID: return ENOTDIR;
2735 case NT_STATUS_OBJECT_NAME_COLLISION: return EEXIST;
2738 /* for all other cases - a default code */
2742 rcls = CVAL(cli->inbuf,smb_rcls);
2743 code = SVAL(cli->inbuf,smb_err);
2744 if (rcls == 0) return 0;
2746 if (eclass) *eclass = rcls;
2747 if (num ) *num = code;
2749 if (rcls == ERRDOS) {
2751 case ERRbadfile: return ENOENT;
2752 case ERRbadpath: return ENOTDIR;
2753 case ERRnoaccess: return EACCES;
2754 case ERRfilexists: return EEXIST;
2755 case ERRrename: return EEXIST;
2756 case ERRbadshare: return EBUSY;
2757 case ERRlock: return EBUSY;
2760 if (rcls == ERRSRV) {
2762 case ERRbadpw: return EPERM;
2763 case ERRaccess: return EACCES;
2764 case ERRnoresource: return ENOMEM;
2765 case ERRinvdevice: return ENODEV;
2766 case ERRinvnetname: return ENODEV;
2769 /* for other cases */
2773 /****************************************************************************
2774 set socket options on a open connection
2775 ****************************************************************************/
2776 void cli_sockopt(struct cli_state *cli, char *options)
2778 set_socket_options(cli->fd, options);
2781 /****************************************************************************
2782 set the PID to use for smb messages. Return the old pid.
2783 ****************************************************************************/
2784 uint16 cli_setpid(struct cli_state *cli, uint16 pid)
2786 uint16 ret = cli->pid;
2791 /****************************************************************************
2792 re-establishes a connection
2793 ****************************************************************************/
2794 BOOL cli_reestablish_connection(struct cli_state *cli)
2796 struct nmb_name calling;
2797 struct nmb_name called;
2801 BOOL do_tcon = False;
2802 int oldfd = cli->fd;
2804 if (!cli->initialised || cli->fd == -1)
2806 DEBUG(3,("cli_reestablish_connection: not connected\n"));
2810 /* copy the parameters necessary to re-establish the connection */
2814 fstrcpy(share, cli->share);
2815 fstrcpy(dev , cli->dev);
2819 memcpy(&called , &(cli->called ), sizeof(called ));
2820 memcpy(&calling, &(cli->calling), sizeof(calling));
2821 fstrcpy(dest_host, cli->full_dest_host_name);
2823 DEBUG(5,("cli_reestablish_connection: %s connecting to %s (ip %s) - %s [%s]\n",
2824 nmb_namestr(&calling), nmb_namestr(&called),
2825 inet_ntoa(cli->dest_ip),
2826 cli->user_name, cli->domain));
2830 if (cli_establish_connection(cli,
2831 dest_host, &cli->dest_ip,
2833 share, dev, False, do_tcon)) {
2834 if (cli->fd != oldfd) {
2835 if (dup2(cli->fd, oldfd) == oldfd) {
2844 /****************************************************************************
2845 establishes a connection right up to doing tconX, reading in a password.
2846 ****************************************************************************/
2847 BOOL cli_establish_connection(struct cli_state *cli,
2848 char *dest_host, struct in_addr *dest_ip,
2849 struct nmb_name *calling, struct nmb_name *called,
2850 char *service, char *service_type,
2851 BOOL do_shutdown, BOOL do_tcon)
2853 DEBUG(5,("cli_establish_connection: %s connecting to %s (%s) - %s [%s]\n",
2854 nmb_namestr(calling), nmb_namestr(called), inet_ntoa(*dest_ip),
2855 cli->user_name, cli->domain));
2857 /* establish connection */
2859 if ((!cli->initialised))
2866 if (!cli_connect(cli, dest_host, dest_ip))
2868 DEBUG(1,("cli_establish_connection: failed to connect to %s (%s)\n",
2869 nmb_namestr(calling), inet_ntoa(*dest_ip)));
2874 if (!cli_session_request(cli, calling, called))
2876 DEBUG(1,("failed session request\n"));
2882 if (!cli_negprot(cli))
2884 DEBUG(1,("failed negprot\n"));
2890 if (cli->pwd.cleartext || cli->pwd.null_pwd)
2895 if (cli->pwd.null_pwd)
2897 /* attempt null session */
2903 /* attempt clear-text session */
2904 pwd_get_cleartext(&(cli->pwd), passwd);
2905 pass_len = strlen(passwd);
2908 /* attempt clear-text session */
2909 if (!cli_session_setup(cli, cli->user_name,
2914 DEBUG(1,("failed session setup\n"));
2923 if (!cli_send_tconX(cli, service, service_type,
2924 (char*)passwd, strlen(passwd)))
2926 DEBUG(1,("failed tcon_X\n"));
2937 /* attempt encrypted session */
2938 unsigned char nt_sess_pwd[24];
2939 unsigned char lm_sess_pwd[24];
2941 /* creates (storing a copy of) and then obtains a 24 byte password OWF */
2942 pwd_make_lm_nt_owf(&(cli->pwd), cli->cryptkey);
2943 pwd_get_lm_nt_owf(&(cli->pwd), lm_sess_pwd, nt_sess_pwd);
2945 /* attempt encrypted session */
2946 if (!cli_session_setup(cli, cli->user_name,
2947 (char*)lm_sess_pwd, sizeof(lm_sess_pwd),
2948 (char*)nt_sess_pwd, sizeof(nt_sess_pwd),
2951 DEBUG(1,("failed session setup\n"));
2959 if (!cli_send_tconX(cli, service, service_type,
2960 (char*)nt_sess_pwd, sizeof(nt_sess_pwd)))
2962 DEBUG(1,("failed tcon_X\n"));
2977 /****************************************************************************
2979 ****************************************************************************/
2980 int cli_printjob_del(struct cli_state *cli, int job)
2982 char *rparam = NULL;
2985 int rdrcnt,rprcnt, ret = -1;
2988 memset(param,'\0',sizeof(param));
2991 SSVAL(p,0,81); /* DosPrintJobDel() */
2994 p = skip_string(p,1);
2996 p = skip_string(p,1);
3001 param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */
3002 NULL, 0, CLI_BUFFER_SIZE, /* data, length, maxlen */
3003 &rparam, &rprcnt, /* return params, length */
3004 &rdata, &rdrcnt)) { /* return data, length */
3005 ret = SVAL(rparam,0);
3008 if (rparam) free(rparam);
3009 if (rdata) free(rdata);
3015 /****************************************************************************
3016 call fn() on each entry in a print queue
3017 ****************************************************************************/
3018 int cli_print_queue(struct cli_state *cli,
3019 void (*fn)(struct print_job_info *))
3021 char *rparam = NULL;
3029 memset(param,'\0',sizeof(param));
3032 SSVAL(p,0,76); /* API function number 76 (DosPrintJobEnum) */
3034 pstrcpy(p,"zWrLeh"); /* parameter description? */
3035 p = skip_string(p,1);
3036 pstrcpy(p,"WWzWWDDzz"); /* returned data format */
3037 p = skip_string(p,1);
3038 pstrcpy(p,cli->share); /* name of queue */
3039 p = skip_string(p,1);
3040 SSVAL(p,0,2); /* API function level 2, PRJINFO_2 data structure */
3041 SSVAL(p,2,1000); /* size of bytes of returned data buffer */
3043 pstrcpy(p,""); /* subformat */
3044 p = skip_string(p,1);
3046 DEBUG(4,("doing cli_print_queue for %s\n", cli->share));
3049 param, PTR_DIFF(p,param), 1024, /* Param, length, maxlen */
3050 NULL, 0, CLI_BUFFER_SIZE, /* data, length, maxlen */
3051 &rparam, &rprcnt, /* return params, length */
3052 &rdata, &rdrcnt)) { /* return data, length */
3054 result_code = SVAL(rparam,0);
3055 converter = SVAL(rparam,2); /* conversion factor */
3057 if (result_code == 0) {
3058 struct print_job_info job;
3062 for (i = 0; i < SVAL(rparam,4); ++i) {
3064 job.priority = SVAL(p,2);
3066 fix_char_ptr(SVAL(p,4), converter,
3068 job.t = make_unix_date3(p + 12);
3069 job.size = IVAL(p,16);
3070 fstrcpy(job.name,fix_char_ptr(SVAL(p,24),
3079 /* If any parameters or data were returned, free the storage. */
3080 if(rparam) free(rparam);
3081 if(rdata) free(rdata);
3086 /****************************************************************************
3087 check for existance of a dir
3088 ****************************************************************************/
3089 BOOL cli_chkpath(struct cli_state *cli, char *path)
3094 safe_strcpy(path2,path,sizeof(pstring));
3095 trim_string(path2,NULL,"\\");
3096 if (!*path2) *path2 = '\\';
3098 memset(cli->outbuf,'\0',smb_size);
3099 set_message(cli->outbuf,0,4 + strlen(path2),True);
3100 SCVAL(cli->outbuf,smb_com,SMBchkpth);
3101 SSVAL(cli->outbuf,smb_tid,cli->cnum);
3102 cli_setup_packet(cli);
3103 p = smb_buf(cli->outbuf);
3105 safe_strcpy(p,path2,strlen(path2));
3106 unix_to_dos(p,True);
3109 if (!cli_receive_smb(cli)) {
3113 if (cli_error(cli, NULL, NULL, NULL)) return False;
3119 /****************************************************************************
3120 start a message sequence
3121 ****************************************************************************/
3122 BOOL cli_message_start(struct cli_state *cli, char *host, char *username,
3127 /* send a SMBsendstrt command */
3128 memset(cli->outbuf,'\0',smb_size);
3129 set_message(cli->outbuf,0,0,True);
3130 CVAL(cli->outbuf,smb_com) = SMBsendstrt;
3131 SSVAL(cli->outbuf,smb_tid,cli->cnum);
3132 cli_setup_packet(cli);
3134 p = smb_buf(cli->outbuf);
3136 pstrcpy(p,username);
3137 unix_to_dos(p,True);
3138 p = skip_string(p,1);
3141 unix_to_dos(p,True);
3142 p = skip_string(p,1);
3144 set_message(cli->outbuf,0,PTR_DIFF(p,smb_buf(cli->outbuf)),False);
3148 if (!cli_receive_smb(cli)) {
3152 if (cli_error(cli, NULL, NULL, NULL)) return False;
3154 *grp = SVAL(cli->inbuf,smb_vwv0);
3160 /****************************************************************************
3162 ****************************************************************************/
3163 BOOL cli_message_text(struct cli_state *cli, char *msg, int len, int grp)
3167 memset(cli->outbuf,'\0',smb_size);
3168 set_message(cli->outbuf,1,len+3,True);
3169 CVAL(cli->outbuf,smb_com) = SMBsendtxt;
3170 SSVAL(cli->outbuf,smb_tid,cli->cnum);
3171 cli_setup_packet(cli);
3173 SSVAL(cli->outbuf,smb_vwv0,grp);
3175 p = smb_buf(cli->outbuf);
3178 memcpy(p+3,msg,len);
3181 if (!cli_receive_smb(cli)) {
3185 if (cli_error(cli, NULL, NULL, NULL)) return False;
3190 /****************************************************************************
3192 ****************************************************************************/
3193 BOOL cli_message_end(struct cli_state *cli, int grp)
3195 memset(cli->outbuf,'\0',smb_size);
3196 set_message(cli->outbuf,1,0,True);
3197 CVAL(cli->outbuf,smb_com) = SMBsendend;
3198 SSVAL(cli->outbuf,smb_tid,cli->cnum);
3200 SSVAL(cli->outbuf,smb_vwv0,grp);
3202 cli_setup_packet(cli);
3206 if (!cli_receive_smb(cli)) {
3210 if (cli_error(cli, NULL, NULL, NULL)) return False;
3216 /****************************************************************************
3218 ****************************************************************************/
3219 BOOL cli_dskattr(struct cli_state *cli, int *bsize, int *total, int *avail)
3221 memset(cli->outbuf,'\0',smb_size);
3222 set_message(cli->outbuf,0,0,True);
3223 CVAL(cli->outbuf,smb_com) = SMBdskattr;
3224 SSVAL(cli->outbuf,smb_tid,cli->cnum);
3225 cli_setup_packet(cli);
3228 if (!cli_receive_smb(cli)) {
3232 *bsize = SVAL(cli->inbuf,smb_vwv1)*SVAL(cli->inbuf,smb_vwv2);
3233 *total = SVAL(cli->inbuf,smb_vwv0);
3234 *avail = SVAL(cli->inbuf,smb_vwv3);
3239 /****************************************************************************
3240 Attempt a NetBIOS session request, falling back to *SMBSERVER if needed.
3241 ****************************************************************************/
3243 BOOL attempt_netbios_session_request(struct cli_state *cli, char *srchost, char *desthost,
3244 struct in_addr *pdest_ip)
3246 struct nmb_name calling, called;
3248 make_nmb_name(&calling, srchost, 0x0);
3251 * If the called name is an IP address
3252 * then use *SMBSERVER immediately.
3255 if(is_ipaddress(desthost))
3256 make_nmb_name(&called, "*SMBSERVER", 0x20);
3258 make_nmb_name(&called, desthost, 0x20);
3260 if (!cli_session_request(cli, &calling, &called)) {
3261 struct nmb_name smbservername;
3263 make_nmb_name(&smbservername , "*SMBSERVER", 0x20);
3266 * If the name wasn't *SMBSERVER then
3267 * try with *SMBSERVER if the first name fails.
3270 if (nmb_name_equal(&called, &smbservername)) {
3273 * The name used was *SMBSERVER, don't bother with another name.
3276 DEBUG(0,("attempt_netbios_session_request: %s rejected the session for name *SMBSERVER \
3277 with error %s.\n", desthost, cli_errstr(cli) ));
3284 if (!cli_initialise(cli) ||
3285 !cli_connect(cli, desthost, pdest_ip) ||
3286 !cli_session_request(cli, &calling, &smbservername)) {
3287 DEBUG(0,("attempt_netbios_session_request: %s rejected the session for \
3288 name *SMBSERVER with error %s\n", desthost, cli_errstr(cli) ));