split clientgen.c into several parts
[ira/wip.git] / source3 / libsmb / clitrans.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 3.0
4    client transaction calls
5    Copyright (C) Andrew Tridgell 1994-1998
6    
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.
11    
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.
16    
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.
20 */
21
22 #define NO_SYSLOG
23
24 #include "includes.h"
25
26
27 /****************************************************************************
28   send a SMB trans or trans2 request
29   ****************************************************************************/
30 BOOL cli_send_trans(struct cli_state *cli, int trans, 
31                     char *name, int pipe_name_len, 
32                     int fid, int flags,
33                     uint16 *setup, int lsetup, int msetup,
34                     char *param, int lparam, int mparam,
35                     char *data, int ldata, int mdata)
36 {
37         int i;
38         int this_ldata,this_lparam;
39         int tot_data=0,tot_param=0;
40         char *outdata,*outparam;
41         char *p;
42
43         this_lparam = MIN(lparam,cli->max_xmit - (500+lsetup*2)); /* hack */
44         this_ldata = MIN(ldata,cli->max_xmit - (500+lsetup*2+this_lparam));
45
46         memset(cli->outbuf,'\0',smb_size);
47         set_message(cli->outbuf,14+lsetup,0,True);
48         CVAL(cli->outbuf,smb_com) = trans;
49         SSVAL(cli->outbuf,smb_tid, cli->cnum);
50         cli_setup_packet(cli);
51
52         outparam = smb_buf(cli->outbuf)+(trans==SMBtrans ? pipe_name_len+1 : 3);
53         outdata = outparam+this_lparam;
54
55         /* primary request */
56         SSVAL(cli->outbuf,smb_tpscnt,lparam);   /* tpscnt */
57         SSVAL(cli->outbuf,smb_tdscnt,ldata);    /* tdscnt */
58         SSVAL(cli->outbuf,smb_mprcnt,mparam);   /* mprcnt */
59         SSVAL(cli->outbuf,smb_mdrcnt,mdata);    /* mdrcnt */
60         SCVAL(cli->outbuf,smb_msrcnt,msetup);   /* msrcnt */
61         SSVAL(cli->outbuf,smb_flags,flags);     /* flags */
62         SIVAL(cli->outbuf,smb_timeout,0);               /* timeout */
63         SSVAL(cli->outbuf,smb_pscnt,this_lparam);       /* pscnt */
64         SSVAL(cli->outbuf,smb_psoff,smb_offset(outparam,cli->outbuf)); /* psoff */
65         SSVAL(cli->outbuf,smb_dscnt,this_ldata);        /* dscnt */
66         SSVAL(cli->outbuf,smb_dsoff,smb_offset(outdata,cli->outbuf)); /* dsoff */
67         SCVAL(cli->outbuf,smb_suwcnt,lsetup);   /* suwcnt */
68         for (i=0;i<lsetup;i++)          /* setup[] */
69                 SSVAL(cli->outbuf,smb_setup+i*2,setup[i]);
70         p = smb_buf(cli->outbuf);
71         if (trans==SMBtrans) {
72                 memcpy(p,name, pipe_name_len + 1);  /* name[] */
73         } else {
74                 *p++ = 0;  /* put in a null smb_name */
75                 *p++ = 'D'; *p++ = ' '; /* observed in OS/2 */
76         }
77         if (this_lparam)                        /* param[] */
78                 memcpy(outparam,param,this_lparam);
79         if (this_ldata)                 /* data[] */
80                 memcpy(outdata,data,this_ldata);
81         set_message(cli->outbuf,14+lsetup,              /* wcnt, bcc */
82                     PTR_DIFF(outdata+this_ldata,smb_buf(cli->outbuf)),False);
83
84         show_msg(cli->outbuf);
85         cli_send_smb(cli);
86
87         if (this_ldata < ldata || this_lparam < lparam) {
88                 /* receive interim response */
89                 if (!cli_receive_smb(cli) || 
90                     CVAL(cli->inbuf,smb_rcls) != 0) {
91                         return(False);
92                 }      
93
94                 tot_data = this_ldata;
95                 tot_param = this_lparam;
96                 
97                 while (tot_data < ldata || tot_param < lparam)  {
98                         this_lparam = MIN(lparam-tot_param,cli->max_xmit - 500); /* hack */
99                         this_ldata = MIN(ldata-tot_data,cli->max_xmit - (500+this_lparam));
100
101                         set_message(cli->outbuf,trans==SMBtrans?8:9,0,True);
102                         CVAL(cli->outbuf,smb_com) = trans==SMBtrans ? SMBtranss : SMBtranss2;
103                         
104                         outparam = smb_buf(cli->outbuf);
105                         outdata = outparam+this_lparam;
106                         
107                         /* secondary request */
108                         SSVAL(cli->outbuf,smb_tpscnt,lparam);   /* tpscnt */
109                         SSVAL(cli->outbuf,smb_tdscnt,ldata);    /* tdscnt */
110                         SSVAL(cli->outbuf,smb_spscnt,this_lparam);      /* pscnt */
111                         SSVAL(cli->outbuf,smb_spsoff,smb_offset(outparam,cli->outbuf)); /* psoff */
112                         SSVAL(cli->outbuf,smb_spsdisp,tot_param);       /* psdisp */
113                         SSVAL(cli->outbuf,smb_sdscnt,this_ldata);       /* dscnt */
114                         SSVAL(cli->outbuf,smb_sdsoff,smb_offset(outdata,cli->outbuf)); /* dsoff */
115                         SSVAL(cli->outbuf,smb_sdsdisp,tot_data);        /* dsdisp */
116                         if (trans==SMBtrans2)
117                                 SSVALS(cli->outbuf,smb_sfid,fid);               /* fid */
118                         if (this_lparam)                        /* param[] */
119                                 memcpy(outparam,param+tot_param,this_lparam);
120                         if (this_ldata)                 /* data[] */
121                                 memcpy(outdata,data+tot_data,this_ldata);
122                         set_message(cli->outbuf,trans==SMBtrans?8:9, /* wcnt, bcc */
123                                     PTR_DIFF(outdata+this_ldata,smb_buf(cli->outbuf)),False);
124                         
125                         show_msg(cli->outbuf);
126                         cli_send_smb(cli);
127                         
128                         tot_data += this_ldata;
129                         tot_param += this_lparam;
130                 }
131         }
132
133         return(True);
134 }
135
136
137 /****************************************************************************
138   receive a SMB trans or trans2 response allocating the necessary memory
139   ****************************************************************************/
140 BOOL cli_receive_trans(struct cli_state *cli,int trans,
141                               char **param, int *param_len,
142                               char **data, int *data_len)
143 {
144         int total_data=0;
145         int total_param=0;
146         int this_data,this_param;
147         uint8 eclass;
148         uint32 ecode;
149
150         *data_len = *param_len = 0;
151
152         if (!cli_receive_smb(cli))
153                 return False;
154
155         show_msg(cli->inbuf);
156         
157         /* sanity check */
158         if (CVAL(cli->inbuf,smb_com) != trans) {
159                 DEBUG(0,("Expected %s response, got command 0x%02x\n",
160                          trans==SMBtrans?"SMBtrans":"SMBtrans2", 
161                          CVAL(cli->inbuf,smb_com)));
162                 return(False);
163         }
164
165         /*
166          * An NT RPC pipe call can return ERRDOS, ERRmoredata
167          * to a trans call. This is not an error and should not
168          * be treated as such.
169          */
170
171         if (cli_error(cli, &eclass, &ecode, NULL))
172         {
173         if(cli->nt_pipe_fnum == 0 || !(eclass == ERRDOS && ecode == ERRmoredata))
174                         return(False);
175         }
176
177         /* parse out the lengths */
178         total_data = SVAL(cli->inbuf,smb_tdrcnt);
179         total_param = SVAL(cli->inbuf,smb_tprcnt);
180
181         /* allocate it */
182         *data = Realloc(*data,total_data);
183         *param = Realloc(*param,total_param);
184
185         while (1)  {
186                 this_data = SVAL(cli->inbuf,smb_drcnt);
187                 this_param = SVAL(cli->inbuf,smb_prcnt);
188
189                 if (this_data + *data_len > total_data ||
190                     this_param + *param_len > total_param) {
191                         DEBUG(1,("Data overflow in cli_receive_trans\n"));
192                         return False;
193                 }
194
195                 if (this_data)
196                         memcpy(*data + SVAL(cli->inbuf,smb_drdisp),
197                                smb_base(cli->inbuf) + SVAL(cli->inbuf,smb_droff),
198                                this_data);
199                 if (this_param)
200                         memcpy(*param + SVAL(cli->inbuf,smb_prdisp),
201                                smb_base(cli->inbuf) + SVAL(cli->inbuf,smb_proff),
202                                this_param);
203                 *data_len += this_data;
204                 *param_len += this_param;
205
206                 /* parse out the total lengths again - they can shrink! */
207                 total_data = SVAL(cli->inbuf,smb_tdrcnt);
208                 total_param = SVAL(cli->inbuf,smb_tprcnt);
209                 
210                 if (total_data <= *data_len && total_param <= *param_len)
211                         break;
212                 
213                 if (!cli_receive_smb(cli))
214                         return False;
215
216                 show_msg(cli->inbuf);
217                 
218                 /* sanity check */
219                 if (CVAL(cli->inbuf,smb_com) != trans) {
220                         DEBUG(0,("Expected %s response, got command 0x%02x\n",
221                                  trans==SMBtrans?"SMBtrans":"SMBtrans2", 
222                                  CVAL(cli->inbuf,smb_com)));
223                         return(False);
224                 }
225                 if (cli_error(cli, &eclass, &ecode, NULL))
226                 {
227                 if(cli->nt_pipe_fnum == 0 || !(eclass == ERRDOS && ecode == ERRmoredata))
228                                 return(False);
229                 }
230         }
231         
232         return(True);
233 }