2 Unix SMB/Netbios implementation.
4 SMB client generic functions
5 Copyright (C) Andrew Tridgell 1994-1997
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.
29 extern int DEBUGLEVEL;
31 /****************************************************************************
32 setup basics in a outgoing packet
33 ****************************************************************************/
34 static void cli_setup_packet(struct cli_state *cli)
36 SSVAL(cli->outbuf,smb_pid,cli->pid);
37 SSVAL(cli->outbuf,smb_uid,cli->uid);
38 SSVAL(cli->outbuf,smb_mid,cli->mid);
39 if (cli->protocol > PROTOCOL_CORE) {
40 SCVAL(cli->outbuf,smb_flg,0x8);
41 SSVAL(cli->outbuf,smb_flg2,0x1);
46 /****************************************************************************
47 send a SMB trans or trans2 request
48 ****************************************************************************/
49 static BOOL cli_send_trans(struct cli_state *cli,
50 int trans, char *name, int fid, int flags,
51 char *data,char *param,uint16 *setup, int ldata,int lparam,
52 int lsetup,int mdata,int mparam,int msetup)
55 int this_ldata,this_lparam;
56 int tot_data=0,tot_param=0;
57 char *outdata,*outparam;
60 this_lparam = MIN(lparam,cli->max_xmit - (500+lsetup*SIZEOFWORD)); /* hack */
61 this_ldata = MIN(ldata,cli->max_xmit - (500+lsetup*SIZEOFWORD+this_lparam));
63 bzero(cli->outbuf,smb_size);
64 set_message(cli->outbuf,14+lsetup,0,True);
65 CVAL(cli->outbuf,smb_com) = trans;
66 SSVAL(cli->outbuf,smb_tid, cli->cnum);
67 cli_setup_packet(cli);
69 outparam = smb_buf(cli->outbuf)+(trans==SMBtrans ? strlen(name)+1 : 3);
70 outdata = outparam+this_lparam;
73 SSVAL(cli->outbuf,smb_tpscnt,lparam); /* tpscnt */
74 SSVAL(cli->outbuf,smb_tdscnt,ldata); /* tdscnt */
75 SSVAL(cli->outbuf,smb_mprcnt,mparam); /* mprcnt */
76 SSVAL(cli->outbuf,smb_mdrcnt,mdata); /* mdrcnt */
77 SCVAL(cli->outbuf,smb_msrcnt,msetup); /* msrcnt */
78 SSVAL(cli->outbuf,smb_flags,flags); /* flags */
79 SIVAL(cli->outbuf,smb_timeout,0); /* timeout */
80 SSVAL(cli->outbuf,smb_pscnt,this_lparam); /* pscnt */
81 SSVAL(cli->outbuf,smb_psoff,smb_offset(outparam,cli->outbuf)); /* psoff */
82 SSVAL(cli->outbuf,smb_dscnt,this_ldata); /* dscnt */
83 SSVAL(cli->outbuf,smb_dsoff,smb_offset(outdata,cli->outbuf)); /* dsoff */
84 SCVAL(cli->outbuf,smb_suwcnt,lsetup); /* suwcnt */
85 for (i=0;i<lsetup;i++) /* setup[] */
86 SSVAL(cli->outbuf,smb_setup+i*SIZEOFWORD,setup[i]);
87 p = smb_buf(cli->outbuf);
88 if (trans==SMBtrans) {
89 strcpy(p,name); /* name[] */
91 *p++ = 0; /* put in a null smb_name */
92 *p++ = 'D'; *p++ = ' '; /* observed in OS/2 */
94 if (this_lparam) /* param[] */
95 memcpy(outparam,param,this_lparam);
96 if (this_ldata) /* data[] */
97 memcpy(outdata,data,this_ldata);
98 set_message(cli->outbuf,14+lsetup, /* wcnt, bcc */
99 PTR_DIFF(outdata+this_ldata,smb_buf(cli->outbuf)),False);
101 show_msg(cli->outbuf);
102 send_smb(cli->fd,cli->outbuf);
104 if (this_ldata < ldata || this_lparam < lparam) {
105 /* receive interim response */
106 if (!receive_smb(cli->fd,cli->inbuf,cli->timeout) ||
107 cli_error(cli,NULL, NULL)) {
111 tot_data = this_ldata;
112 tot_param = this_lparam;
114 while (tot_data < ldata || tot_param < lparam) {
115 this_lparam = MIN(lparam-tot_param,cli->max_xmit - 500); /* hack */
116 this_ldata = MIN(ldata-tot_data,cli->max_xmit - (500+this_lparam));
118 set_message(cli->outbuf,trans==SMBtrans?8:9,0,True);
119 CVAL(cli->outbuf,smb_com) = trans==SMBtrans ? SMBtranss : SMBtranss2;
121 outparam = smb_buf(cli->outbuf);
122 outdata = outparam+this_lparam;
124 /* secondary request */
125 SSVAL(cli->outbuf,smb_tpscnt,lparam); /* tpscnt */
126 SSVAL(cli->outbuf,smb_tdscnt,ldata); /* tdscnt */
127 SSVAL(cli->outbuf,smb_spscnt,this_lparam); /* pscnt */
128 SSVAL(cli->outbuf,smb_spsoff,smb_offset(outparam,cli->outbuf)); /* psoff */
129 SSVAL(cli->outbuf,smb_spsdisp,tot_param); /* psdisp */
130 SSVAL(cli->outbuf,smb_sdscnt,this_ldata); /* dscnt */
131 SSVAL(cli->outbuf,smb_sdsoff,smb_offset(outdata,cli->outbuf)); /* dsoff */
132 SSVAL(cli->outbuf,smb_sdsdisp,tot_data); /* dsdisp */
133 if (trans==SMBtrans2)
134 SSVAL(cli->outbuf,smb_sfid,fid); /* fid */
135 if (this_lparam) /* param[] */
136 memcpy(outparam,param,this_lparam);
137 if (this_ldata) /* data[] */
138 memcpy(outdata,data,this_ldata);
139 set_message(cli->outbuf,trans==SMBtrans?8:9, /* wcnt, bcc */
140 PTR_DIFF(outdata+this_ldata,smb_buf(cli->outbuf)),False);
142 show_msg(cli->outbuf);
143 send_smb(cli->fd,cli->outbuf);
145 tot_data += this_ldata;
146 tot_param += this_lparam;
154 /****************************************************************************
155 receive a SMB trans or trans2 response allocating the necessary memory
156 ****************************************************************************/
157 static BOOL cli_receive_trans(struct cli_state *cli,
158 int trans,int *data_len,
159 int *param_len, char **data,char **param)
163 int this_data,this_param;
165 *data_len = *param_len = 0;
167 if (!receive_smb(cli->fd,cli->inbuf,cli->timeout))
170 show_msg(cli->inbuf);
173 if (CVAL(cli->inbuf,smb_com) != trans) {
174 DEBUG(0,("Expected %s response, got command 0x%02x\n",
175 trans==SMBtrans?"SMBtrans":"SMBtrans2",
176 CVAL(cli->inbuf,smb_com)));
179 if (cli_error(cli,NULL, NULL)) return(False);
181 /* parse out the lengths */
182 total_data = SVAL(cli->inbuf,smb_tdrcnt);
183 total_param = SVAL(cli->inbuf,smb_tprcnt);
186 *data = Realloc(*data,total_data);
187 *param = Realloc(*param,total_param);
190 this_data = SVAL(cli->inbuf,smb_drcnt);
191 this_param = SVAL(cli->inbuf,smb_prcnt);
193 if (this_data + *data_len > total_data ||
194 this_param + *param_len > total_param) {
195 DEBUG(1,("Data overflow in cli_receive_trans\n"));
200 memcpy(*data + SVAL(cli->inbuf,smb_drdisp),
201 smb_base(cli->inbuf) + SVAL(cli->inbuf,smb_droff),
204 memcpy(*param + SVAL(cli->inbuf,smb_prdisp),
205 smb_base(cli->inbuf) + SVAL(cli->inbuf,smb_proff),
207 *data_len += this_data;
208 *param_len += this_param;
210 /* parse out the total lengths again - they can shrink! */
211 total_data = SVAL(cli->inbuf,smb_tdrcnt);
212 total_param = SVAL(cli->inbuf,smb_tprcnt);
214 if (total_data <= *data_len && total_param <= *param_len)
217 if (!receive_smb(cli->fd,cli->inbuf,cli->timeout))
220 show_msg(cli->inbuf);
223 if (CVAL(cli->inbuf,smb_com) != trans) {
224 DEBUG(0,("Expected %s response, got command 0x%02x\n",
225 trans==SMBtrans?"SMBtrans":"SMBtrans2",
226 CVAL(cli->inbuf,smb_com)));
229 if (cli_error(cli,NULL, NULL)) return(False);
236 /****************************************************************************
238 ****************************************************************************/
239 static BOOL cli_api(struct cli_state *cli,
240 int prcnt,int drcnt,int mprcnt,int mdrcnt,int *rprcnt,
241 int *rdrcnt, char *param,char *data,
242 char **rparam, char **rdata)
244 cli_send_trans(cli,SMBtrans,"\\PIPE\\LANMAN",0,0,
249 return (cli_receive_trans(cli,SMBtrans,
255 /****************************************************************************
256 perform a NetWkstaUserLogon
257 ****************************************************************************/
258 BOOL cli_NetWkstaUserLogon(struct cli_state *cli,char *user, char *workstation)
266 memset(param, 0, sizeof(param));
268 /* send a SMBtrans command with api NetWkstaUserLogon */
270 SSVAL(p,0,132); /* api number */
272 strcpy(p,"OOWb54WrLh");
273 p = skip_string(p,1);
274 strcpy(p,"WB21BWDWWDDDDDDDzzzD");
275 p = skip_string(p,1);
280 p += 21; p++; p += 15; p++;
281 strcpy(p, workstation);
284 SSVAL(p, 0, BUFFER_SIZE);
286 SSVAL(p, 0, BUFFER_SIZE);
291 if (cli_api(cli, PTR_DIFF(p,param),0,
296 cli->error = SVAL(rparam,0);
299 if (cli->error == 0) {
300 DEBUG(4,("NetWkstaUserLogon success\n"));
301 cli->privileges = SVAL(p, 24);
302 fstrcpy(cli->eff_name,p+2);
304 DEBUG(1,("NetwkstaUserLogon gave error %d\n", cli->error));
308 if (rparam) free(rparam);
309 if (rdata) free(rdata);
310 return cli->error == 0;
314 /****************************************************************************
315 call a NetServerEnum for the specified workgroup and servertype mask.
316 This function then calls the specified callback function for each name returned.
318 The callback function takes 3 arguments: the machine name, the server type and
320 ****************************************************************************/
321 BOOL cli_NetServerEnum(struct cli_state *cli, char *workgroup, uint32 stype,
322 void (*fn)(char *, uint32, char *))
332 /* send a SMBtrans command with api NetServerEnum */
334 SSVAL(p,0,0x68); /* api number */
337 p = skip_string(p,1);
341 p = skip_string(p,1);
343 SSVAL(p,2,BUFFER_SIZE);
348 pstrcpy(p, workgroup);
349 p = skip_string(p,1);
352 PTR_DIFF(p,param), /* param count */
355 BUFFER_SIZE, /* mdrcount */
359 int res = SVAL(rparam,0);
360 int converter=SVAL(rparam,2);
364 count=SVAL(rparam,4);
367 for (i = 0;i < count;i++, p += 26) {
369 int comment_offset = IVAL(p,22) & 0xFFFF;
370 char *cmnt = comment_offset?(rdata+comment_offset-converter):"";
372 stype = IVAL(p,18) & ~SV_TYPE_LOCAL_LIST_ONLY;
374 fn(sname, stype, cmnt);
379 if (rparam) free(rparam);
380 if (rdata) free(rdata);
394 {PROTOCOL_CORE,"PC NETWORK PROGRAM 1.0"},
395 {PROTOCOL_COREPLUS,"MICROSOFT NETWORKS 1.03"},
396 {PROTOCOL_LANMAN1,"MICROSOFT NETWORKS 3.0"},
397 {PROTOCOL_LANMAN1,"LANMAN1.0"},
398 {PROTOCOL_LANMAN2,"LM1.2X002"},
399 {PROTOCOL_LANMAN2,"Samba"},
400 {PROTOCOL_NT1,"NT LM 0.12"},
401 {PROTOCOL_NT1,"NT LANMAN 1.0"},
406 /****************************************************************************
408 ****************************************************************************/
409 BOOL cli_session_setup(struct cli_state *cli,
411 char *pass, int passlen,
412 char *ntpass, int ntpasslen,
418 if (cli->protocol < PROTOCOL_LANMAN1)
421 if (passlen > sizeof(pword)-1) {
425 if ((cli->sec_mode & USE_CHALLENGE_RESPONSE) && *pass && passlen != 24)
428 SMBencrypt((uchar *)pass,(uchar *)cli->cryptkey,(uchar *)pword);
432 memcpy(pword, pass, passlen);
435 /* if in share level security then don't send a password now */
436 if (!(cli->sec_mode & USE_USER_LEVEL_SECURITY))
442 /* send a session setup command */
443 bzero(cli->outbuf,smb_size);
445 if (cli->protocol < PROTOCOL_NT1) {
446 set_message(cli->outbuf,10,1 + strlen(user) + passlen,True);
447 CVAL(cli->outbuf,smb_com) = SMBsesssetupX;
448 cli_setup_packet(cli);
450 CVAL(cli->outbuf,smb_vwv0) = 0xFF;
451 SSVAL(cli->outbuf,smb_vwv2,cli->max_xmit);
452 SSVAL(cli->outbuf,smb_vwv3,2);
453 SSVAL(cli->outbuf,smb_vwv4,1);
454 SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
455 SSVAL(cli->outbuf,smb_vwv7,passlen);
456 p = smb_buf(cli->outbuf);
457 memcpy(p,pword,passlen);
462 set_message(cli->outbuf,13,0,True);
463 CVAL(cli->outbuf,smb_com) = SMBsesssetupX;
464 cli_setup_packet(cli);
466 CVAL(cli->outbuf,smb_vwv0) = 0xFF;
467 SSVAL(cli->outbuf,smb_vwv2,BUFFER_SIZE);
468 SSVAL(cli->outbuf,smb_vwv3,2);
469 SSVAL(cli->outbuf,smb_vwv4,cli->pid);
470 SIVAL(cli->outbuf,smb_vwv5,cli->sesskey);
471 SSVAL(cli->outbuf,smb_vwv7,passlen);
472 SSVAL(cli->outbuf,smb_vwv8,ntpasslen);
473 p = smb_buf(cli->outbuf);
474 memcpy(p,pword,passlen);
475 p += SVAL(cli->outbuf,smb_vwv7);
476 memcpy(p,ntpass,ntpasslen);
477 p += SVAL(cli->outbuf,smb_vwv8);
480 p = skip_string(p,1);
483 p = skip_string(p,1);
484 strcpy(p,"Unix");p = skip_string(p,1);
485 strcpy(p,"Samba");p = skip_string(p,1);
486 set_message(cli->outbuf,13,PTR_DIFF(p,smb_buf(cli->outbuf)),False);
489 send_smb(cli->fd,cli->outbuf);
490 if (!receive_smb(cli->fd,cli->inbuf,cli->timeout))
493 show_msg(cli->inbuf);
495 if (cli_error(cli,NULL, NULL)) return(False);
497 /* use the returned uid from now on */
498 cli->uid = SVAL(cli->inbuf,smb_uid);
504 /****************************************************************************
506 ****************************************************************************/
507 BOOL cli_send_tconX(struct cli_state *cli,
508 char *share, char *dev, char *pass, int passlen)
510 fstring fullshare, pword;
512 bzero(cli->outbuf,smb_size);
513 bzero(cli->inbuf,smb_size);
515 if (cli->sec_mode & USE_USER_LEVEL_SECURITY) {
520 if ((cli->sec_mode & USE_CHALLENGE_RESPONSE) && *pass && passlen != 24) {
522 SMBencrypt((uchar *)pass,(uchar *)cli->cryptkey,(uchar *)pword);
524 memcpy(pword, pass, passlen);
527 sprintf(fullshare, "\\\\%s\\%s", cli->called_netbios_name, share);
529 set_message(cli->outbuf,4,
530 2 + strlen(fullshare) + passlen + strlen(dev),True);
531 CVAL(cli->outbuf,smb_com) = SMBtconX;
532 cli_setup_packet(cli);
534 SSVAL(cli->outbuf,smb_vwv0,0xFF);
535 SSVAL(cli->outbuf,smb_vwv3,passlen);
537 p = smb_buf(cli->outbuf);
538 memcpy(p,pword,passlen);
541 p = skip_string(p,1);
544 SCVAL(cli->inbuf,smb_rcls, 1);
546 send_smb(cli->fd,cli->outbuf);
547 if (!receive_smb(cli->fd,cli->inbuf,cli->timeout))
550 if (cli_error(cli,NULL, NULL)) return(False);
552 cli->cnum = SVAL(cli->inbuf,smb_tid);
557 /****************************************************************************
558 send a tree disconnect
559 ****************************************************************************/
560 BOOL cli_tdis(struct cli_state *cli)
562 bzero(cli->outbuf,smb_size);
563 set_message(cli->outbuf,0,0,True);
564 CVAL(cli->outbuf,smb_com) = SMBtdis;
565 SSVAL(cli->outbuf,smb_tid,cli->cnum);
566 cli_setup_packet(cli);
568 send_smb(cli->fd,cli->outbuf);
569 if (!receive_smb(cli->fd,cli->inbuf,cli->timeout))
572 return !cli_error(cli,NULL, NULL);
575 /****************************************************************************
577 ****************************************************************************/
578 BOOL cli_unlink(struct cli_state *cli, char *fname)
582 bzero(cli->outbuf,smb_size);
583 bzero(cli->inbuf,smb_size);
585 set_message(cli->outbuf,1, 2 + strlen(fname),True);
587 CVAL(cli->outbuf,smb_com) = SMBunlink;
588 SSVAL(cli->outbuf,smb_tid,cli->cnum);
589 cli_setup_packet(cli);
591 SSVAL(cli->outbuf,smb_vwv0,aSYSTEM | aHIDDEN);
593 p = smb_buf(cli->outbuf);
596 p = skip_string(p,1);
598 send_smb(cli->fd,cli->outbuf);
599 if (!receive_smb(cli->fd,cli->inbuf,cli->timeout)) {
603 if (cli_error(cli,NULL, NULL)) return False;
610 /****************************************************************************
612 ****************************************************************************/
613 int cli_open(struct cli_state *cli, char *fname, int flags, int share_mode)
617 unsigned accessmode=0;
621 if (!(flags & O_EXCL)) {
628 accessmode = (share_mode<<4);
630 if ((flags & O_RDWR) == O_RDWR) {
632 } else if ((flags & O_WRONLY) == O_WRONLY) {
636 bzero(cli->outbuf,smb_size);
637 bzero(cli->inbuf,smb_size);
639 set_message(cli->outbuf,15,1 + strlen(fname),True);
641 CVAL(cli->outbuf,smb_com) = SMBopenX;
642 SSVAL(cli->outbuf,smb_tid,cli->cnum);
643 cli_setup_packet(cli);
645 SSVAL(cli->outbuf,smb_vwv0,0xFF);
646 SSVAL(cli->outbuf,smb_vwv2,0); /* no additional info */
647 SSVAL(cli->outbuf,smb_vwv3,accessmode);
648 SSVAL(cli->outbuf,smb_vwv4,aSYSTEM | aHIDDEN);
649 SSVAL(cli->outbuf,smb_vwv5,aSYSTEM | aHIDDEN);
650 SSVAL(cli->outbuf,smb_vwv8,openfn);
652 p = smb_buf(cli->outbuf);
654 p = skip_string(p,1);
656 send_smb(cli->fd,cli->outbuf);
657 if (!receive_smb(cli->fd,cli->inbuf,cli->timeout)) {
661 if (cli_error(cli,NULL, NULL)) return -1;
663 return SVAL(cli->inbuf,smb_vwv2);
669 /****************************************************************************
671 ****************************************************************************/
672 BOOL cli_close(struct cli_state *cli, int fnum)
674 bzero(cli->outbuf,smb_size);
675 bzero(cli->inbuf,smb_size);
677 set_message(cli->outbuf,3,0,True);
679 CVAL(cli->outbuf,smb_com) = SMBclose;
680 SSVAL(cli->outbuf,smb_tid,cli->cnum);
681 cli_setup_packet(cli);
683 SSVAL(cli->outbuf,smb_vwv0,fnum);
684 SSVAL(cli->outbuf,smb_vwv1,0);
685 SSVAL(cli->outbuf,smb_vwv2,0);
687 send_smb(cli->fd,cli->outbuf);
688 if (!receive_smb(cli->fd,cli->inbuf,cli->timeout)) {
692 if (cli_error(cli,NULL, NULL)) return False;
698 /****************************************************************************
700 ****************************************************************************/
701 BOOL cli_lock(struct cli_state *cli, int fnum, uint32 offset, uint32 len, int timeout)
705 bzero(cli->outbuf,smb_size);
706 bzero(cli->inbuf,smb_size);
708 set_message(cli->outbuf,8,10,True);
710 CVAL(cli->outbuf,smb_com) = SMBlockingX;
711 SSVAL(cli->outbuf,smb_tid,cli->cnum);
712 cli_setup_packet(cli);
714 CVAL(cli->outbuf,smb_vwv0) = 0xFF;
715 SSVAL(cli->outbuf,smb_vwv2,fnum);
716 CVAL(cli->outbuf,smb_vwv3) = 0;
717 SIVALS(cli->outbuf, smb_vwv4, timeout);
718 SSVAL(cli->outbuf,smb_vwv6,0);
719 SSVAL(cli->outbuf,smb_vwv7,1);
721 p = smb_buf(cli->outbuf);
722 SSVAL(p, 0, cli->pid);
726 send_smb(cli->fd,cli->outbuf);
727 if (!receive_smb(cli->fd,cli->inbuf,cli->timeout)) {
731 if (cli_error(cli,NULL, NULL)) return False;
736 /****************************************************************************
738 ****************************************************************************/
739 BOOL cli_unlock(struct cli_state *cli, int fnum, uint32 offset, uint32 len, int timeout)
743 bzero(cli->outbuf,smb_size);
744 bzero(cli->inbuf,smb_size);
746 set_message(cli->outbuf,8,10,True);
748 CVAL(cli->outbuf,smb_com) = SMBlockingX;
749 SSVAL(cli->outbuf,smb_tid,cli->cnum);
750 cli_setup_packet(cli);
752 CVAL(cli->outbuf,smb_vwv0) = 0xFF;
753 SSVAL(cli->outbuf,smb_vwv2,fnum);
754 CVAL(cli->outbuf,smb_vwv3) = 0;
755 SIVALS(cli->outbuf, smb_vwv4, timeout);
756 SSVAL(cli->outbuf,smb_vwv6,1);
757 SSVAL(cli->outbuf,smb_vwv7,0);
759 p = smb_buf(cli->outbuf);
760 SSVAL(p, 0, cli->pid);
764 send_smb(cli->fd,cli->outbuf);
765 if (!receive_smb(cli->fd,cli->inbuf,cli->timeout)) {
769 if (cli_error(cli,NULL, NULL)) return False;
775 /****************************************************************************
777 ****************************************************************************/
778 int cli_read(struct cli_state *cli, int fnum, char *buf, uint32 offset, uint16 size)
782 bzero(cli->outbuf,smb_size);
783 bzero(cli->inbuf,smb_size);
785 set_message(cli->outbuf,10,0,True);
787 CVAL(cli->outbuf,smb_com) = SMBreadX;
788 SSVAL(cli->outbuf,smb_tid,cli->cnum);
789 cli_setup_packet(cli);
791 CVAL(cli->outbuf,smb_vwv0) = 0xFF;
792 SSVAL(cli->outbuf,smb_vwv2,fnum);
793 SIVAL(cli->outbuf,smb_vwv3,offset);
794 SSVAL(cli->outbuf,smb_vwv5,size);
795 SSVAL(cli->outbuf,smb_vwv6,size);
797 send_smb(cli->fd,cli->outbuf);
798 if (!receive_smb(cli->fd,cli->inbuf,cli->timeout)) {
802 if (cli_error(cli,NULL, NULL)) return -1;
804 size = SVAL(cli->inbuf, smb_vwv5);
805 p = smb_base(cli->inbuf) + SVAL(cli->inbuf,smb_vwv6);
807 memcpy(buf, p, size);
813 /****************************************************************************
815 ****************************************************************************/
816 int cli_write(struct cli_state *cli, int fnum, char *buf, uint32 offset, uint16 size)
820 bzero(cli->outbuf,smb_size);
821 bzero(cli->inbuf,smb_size);
823 set_message(cli->outbuf,12,size,True);
825 CVAL(cli->outbuf,smb_com) = SMBwriteX;
826 SSVAL(cli->outbuf,smb_tid,cli->cnum);
827 cli_setup_packet(cli);
829 CVAL(cli->outbuf,smb_vwv0) = 0xFF;
830 SSVAL(cli->outbuf,smb_vwv2,fnum);
831 SIVAL(cli->outbuf,smb_vwv3,offset);
833 SSVAL(cli->outbuf,smb_vwv10,size);
834 SSVAL(cli->outbuf,smb_vwv11,smb_buf(cli->outbuf) - smb_base(cli->outbuf));
836 p = smb_base(cli->outbuf) + SVAL(cli->outbuf,smb_vwv11);
837 memcpy(p, buf, size);
839 send_smb(cli->fd,cli->outbuf);
840 if (!receive_smb(cli->fd,cli->inbuf,cli->timeout)) {
844 if (cli_error(cli,NULL, NULL)) return -1;
846 return SVAL(cli->inbuf, smb_vwv2);
850 /****************************************************************************
851 send a negprot command
852 ****************************************************************************/
853 BOOL cli_negprot(struct cli_state *cli)
859 bzero(cli->outbuf,smb_size);
861 /* setup the protocol strings */
862 for (plength=0,numprots=0;
863 prots[numprots].name && prots[numprots].prot<=cli->protocol;
865 plength += strlen(prots[numprots].name)+2;
867 set_message(cli->outbuf,0,plength,True);
869 p = smb_buf(cli->outbuf);
871 prots[numprots].name && prots[numprots].prot<=cli->protocol;
874 strcpy(p,prots[numprots].name);
878 CVAL(cli->outbuf,smb_com) = SMBnegprot;
879 cli_setup_packet(cli);
881 CVAL(smb_buf(cli->outbuf),0) = 2;
883 send_smb(cli->fd,cli->outbuf);
884 if (!receive_smb(cli->fd,cli->inbuf,cli->timeout))
887 show_msg(cli->inbuf);
889 if (cli_error(cli,NULL, NULL)) return False;
890 if ((int)SVAL(cli->inbuf,smb_vwv0) >= numprots) return(False);
892 cli->protocol = prots[SVAL(cli->inbuf,smb_vwv0)].prot;
895 if (cli->protocol < PROTOCOL_NT1) {
896 cli->sec_mode = SVAL(cli->inbuf,smb_vwv1);
897 cli->max_xmit = SVAL(cli->inbuf,smb_vwv2);
898 cli->sesskey = IVAL(cli->inbuf,smb_vwv6);
899 cli->serverzone = SVALS(cli->inbuf,smb_vwv10)*60;
900 /* this time is converted to GMT by make_unix_date */
901 cli->servertime = make_unix_date(cli->inbuf+smb_vwv8);
902 if (cli->protocol >= PROTOCOL_COREPLUS) {
903 cli->readbraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x1) != 0);
904 cli->writebraw_supported = ((SVAL(cli->inbuf,smb_vwv5) & 0x2) != 0);
906 memcpy(cli->cryptkey,smb_buf(cli->inbuf),8);
909 cli->sec_mode = CVAL(cli->inbuf,smb_vwv1);
910 cli->max_xmit = IVAL(cli->inbuf,smb_vwv3+1);
911 cli->sesskey = IVAL(cli->inbuf,smb_vwv7+1);
912 cli->serverzone = SVALS(cli->inbuf,smb_vwv15+1)*60;
913 /* this time arrives in real GMT */
914 cli->servertime = interpret_long_date(cli->inbuf+smb_vwv11+1);
915 memcpy(cli->cryptkey,smb_buf(cli->inbuf),8);
916 if (IVAL(cli->inbuf,smb_vwv9+1) & 1)
917 cli->readbraw_supported =
918 cli->writebraw_supported = True;
924 #define TRUNCATE_NETBIOS_NAME 1
926 /****************************************************************************
927 send a session request. see rfc1002.txt 4.3 and 4.3.2
928 ****************************************************************************/
929 BOOL cli_session_request(struct cli_state *cli,
930 char *called_host_name , int called_name_type,
931 char calling_netbios_name[16], int calling_name_type)
935 /* send a session request (RFC 1002) */
937 strncpy(cli->called_netbios_name , called_host_name , sizeof(cli->called_netbios_name ));
938 strncpy(cli->calling_netbios_name, calling_netbios_name, sizeof(cli->calling_netbios_name));
940 /* sorry, don't trust strncpy to null-terminate the string... */
941 cli->called_netbios_name [sizeof(cli->called_netbios_name )-1] = 0;
942 cli->calling_netbios_name[sizeof(cli->calling_netbios_name)-1] = 0;
944 #ifdef TRUNCATE_NETBIOS_NAME
945 /* ok. this is because of a stupid microsoft-ism. if the called host
946 name contains a '.', microsoft clients expect you to truncate the
947 netbios name up to and including the '.'
949 p = strchr(cli->called_netbios_name, '.');
951 #endif /* TRUNCATE_NETBIOS_NAME */
953 /* put in the destination name */
955 name_mangle(cli->called_netbios_name, p, called_name_type);
960 name_mangle(cli->calling_netbios_name, p, calling_name_type);
963 /* setup the packet length */
964 _smb_setlen(cli->outbuf,len);
965 CVAL(cli->outbuf,0) = 0x81;
967 send_smb(cli->fd,cli->outbuf);
968 DEBUG(5,("Sent session request\n"));
970 if (!receive_smb(cli->fd,cli->inbuf,cli->timeout))
973 if (CVAL(cli->inbuf,0) != 0x82) {
974 cli->error = CVAL(cli->inbuf,0);
981 /****************************************************************************
982 open the client sockets
983 ****************************************************************************/
984 BOOL cli_connect(struct cli_state *cli, char *host, struct in_addr *ip)
986 struct in_addr dest_ip;
988 fstrcpy(cli->full_dest_host_name, host);
992 /* no ip specified - look up the name */
995 if ((hp = Get_Hostbyname(host)) == 0) {
999 putip((char *)&dest_ip,(char *)hp->h_addr);
1001 /* use the given ip address */
1005 /* open the socket */
1006 cli->fd = open_socket_out(SOCK_STREAM, &dest_ip, 139, cli->timeout);
1008 return (cli->fd != -1);
1012 /****************************************************************************
1013 initialise a client structure
1014 ****************************************************************************/
1015 BOOL cli_initialise(struct cli_state *cli)
1017 if (cli->initialised) cli_shutdown(cli);
1019 memset(cli, 0, sizeof(*cli));
1022 cli->pid = getpid();
1024 cli->uid = getuid();
1025 cli->protocol = PROTOCOL_NT1;
1026 cli->timeout = 20000;
1027 cli->bufsize = 0x10000;
1028 cli->max_xmit = cli->bufsize - 4;
1029 cli->outbuf = (char *)malloc(cli->bufsize);
1030 cli->inbuf = (char *)malloc(cli->bufsize);
1031 if (!cli->outbuf || !cli->inbuf) return False;
1032 cli->initialised = 1;
1036 /****************************************************************************
1037 shutdown a client structure
1038 ****************************************************************************/
1039 void cli_shutdown(struct cli_state *cli)
1041 if (cli->outbuf) free(cli->outbuf);
1042 if (cli->inbuf) free(cli->inbuf);
1043 if (cli->fd != -1) close(cli->fd);
1044 memset(cli, 0, sizeof(*cli));
1047 /****************************************************************************
1048 return a description of the error
1049 ****************************************************************************/
1050 char *cli_errstr(struct cli_state *cli)
1052 return smb_errstr(cli->inbuf);
1055 /****************************************************************************
1056 return error codes for the last packet
1057 ****************************************************************************/
1058 BOOL cli_error(struct cli_state *cli, uint8 *eclass, uint32 *num)
1060 int flgs2 = SVAL(cli->inbuf,smb_flg2);
1062 if (eclass) *eclass = 0;
1065 if (flgs2 & FLAGS2_32_BIT_ERROR_CODES)
1067 /* 32 bit error codes detected */
1068 uint32 nt_err = IVAL(cli->inbuf,smb_rcls);
1069 if (num) *num = nt_err;
1070 return (nt_err != 0);
1074 /* dos 16 bit error codes detected */
1075 char rcls = CVAL(cli->inbuf,smb_rcls);
1078 if (eclass) *eclass = rcls;
1079 if (num ) *num = SVAL(cli->inbuf,smb_err);
1086 /****************************************************************************
1087 set socket options on a open connection
1088 ****************************************************************************/
1089 void cli_sockopt(struct cli_state *cli, char *options)
1091 set_socket_options(cli->fd, options);
1094 /****************************************************************************
1095 set the PID to use for smb messages. Return the old pid.
1096 ****************************************************************************/
1097 int cli_setpid(struct cli_state *cli, int pid)