preparing for release of 3.0-alpha11
[Samba/ekacnet.git] / source / smbd / ipc.c
blob4047ffa8d7043c89fe9e26acdfa198b5dd743d59
1 /*
2 Unix SMB/Netbios implementation.
3 Version 1.9.
4 Inter-process communication and named pipe handling
5 Copyright (C) Andrew Tridgell 1992-1998
7 SMB Version handling
8 Copyright (C) John H Terpstra 1995-1998
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 This file handles the named pipe and mailslot calls
26 in the SMBtrans protocol
29 #include "includes.h"
31 extern int max_send;
33 extern fstring local_machine;
35 #define NERR_notsupported 50
37 extern int smb_read_error;
39 /*******************************************************************
40 copies parameters and data, as needed, into the smb buffer
42 *both* the data and params sections should be aligned. this
43 is fudged in the rpc pipes by
44 at present, only the data section is. this may be a possible
45 cause of some of the ipc problems being experienced. lkcl26dec97
47 ******************************************************************/
49 static void copy_trans_params_and_data(char *outbuf, int align,
50 char *rparam, int param_offset, int param_len,
51 char *rdata, int data_offset, int data_len)
53 char *copy_into = smb_buf(outbuf)+1;
55 if(param_len < 0)
56 param_len = 0;
58 if(data_len < 0)
59 data_len = 0;
61 DEBUG(5,("copy_trans_params_and_data: params[%d..%d] data[%d..%d]\n",
62 param_offset, param_offset + param_len,
63 data_offset , data_offset + data_len));
65 if (param_len)
66 memcpy(copy_into, &rparam[param_offset], param_len);
68 copy_into += param_len + align;
70 if (data_len )
71 memcpy(copy_into, &rdata[data_offset], data_len);
74 /****************************************************************************
75 Send a trans reply.
76 ****************************************************************************/
78 void send_trans_reply(char *outbuf,
79 char *rparam, int rparam_len,
80 char *rdata, int rdata_len,
81 BOOL buffer_too_large)
83 int this_ldata,this_lparam;
84 int tot_data_sent = 0;
85 int tot_param_sent = 0;
86 int align;
88 int ldata = rdata ? rdata_len : 0;
89 int lparam = rparam ? rparam_len : 0;
91 if (buffer_too_large)
92 DEBUG(5,("send_trans_reply: buffer %d too large\n", ldata ));
94 this_lparam = MIN(lparam,max_send - 500); /* hack */
95 this_ldata = MIN(ldata,max_send - (500+this_lparam));
97 align = ((this_lparam)%4);
99 if (buffer_too_large) {
100 ERROR_NT(STATUS_BUFFER_OVERFLOW);
103 set_message(outbuf,10,1+align+this_ldata+this_lparam,True);
105 copy_trans_params_and_data(outbuf, align,
106 rparam, tot_param_sent, this_lparam,
107 rdata, tot_data_sent, this_ldata);
109 SSVAL(outbuf,smb_vwv0,lparam);
110 SSVAL(outbuf,smb_vwv1,ldata);
111 SSVAL(outbuf,smb_vwv3,this_lparam);
112 SSVAL(outbuf,smb_vwv4,smb_offset(smb_buf(outbuf)+1,outbuf));
113 SSVAL(outbuf,smb_vwv5,0);
114 SSVAL(outbuf,smb_vwv6,this_ldata);
115 SSVAL(outbuf,smb_vwv7,smb_offset(smb_buf(outbuf)+1+this_lparam+align,outbuf));
116 SSVAL(outbuf,smb_vwv8,0);
117 SSVAL(outbuf,smb_vwv9,0);
119 show_msg(outbuf);
120 if (!send_smb(smbd_server_fd(),outbuf))
121 exit_server("send_trans_reply: send_smb failed.");
123 tot_data_sent = this_ldata;
124 tot_param_sent = this_lparam;
126 while (tot_data_sent < ldata || tot_param_sent < lparam)
128 this_lparam = MIN(lparam-tot_param_sent, max_send - 500); /* hack */
129 this_ldata = MIN(ldata -tot_data_sent, max_send - (500+this_lparam));
131 if(this_lparam < 0)
132 this_lparam = 0;
134 if(this_ldata < 0)
135 this_ldata = 0;
137 align = (this_lparam%4);
139 set_message(outbuf,10,1+this_ldata+this_lparam+align,False);
141 copy_trans_params_and_data(outbuf, align,
142 rparam, tot_param_sent, this_lparam,
143 rdata, tot_data_sent, this_ldata);
145 SSVAL(outbuf,smb_vwv3,this_lparam);
146 SSVAL(outbuf,smb_vwv4,smb_offset(smb_buf(outbuf)+1,outbuf));
147 SSVAL(outbuf,smb_vwv5,tot_param_sent);
148 SSVAL(outbuf,smb_vwv6,this_ldata);
149 SSVAL(outbuf,smb_vwv7,smb_offset(smb_buf(outbuf)+1+this_lparam+align,outbuf));
150 SSVAL(outbuf,smb_vwv8,tot_data_sent);
151 SSVAL(outbuf,smb_vwv9,0);
153 show_msg(outbuf);
154 if (!send_smb(smbd_server_fd(),outbuf))
155 exit_server("send_trans_reply: send_smb failed.");
157 tot_data_sent += this_ldata;
158 tot_param_sent += this_lparam;
162 /****************************************************************************
163 Start the first part of an RPC reply which began with an SMBtrans request.
164 ****************************************************************************/
166 static BOOL api_rpc_trans_reply(char *outbuf, pipes_struct *p)
168 char *rdata = malloc(p->max_trans_reply);
169 int data_len;
171 if(rdata == NULL) {
172 DEBUG(0,("api_rpc_trans_reply: malloc fail.\n"));
173 return False;
176 if((data_len = read_from_pipe( p, rdata, p->max_trans_reply)) < 0) {
177 SAFE_FREE(rdata);
178 return False;
181 send_trans_reply(outbuf, NULL, 0, rdata, data_len, p->out_data.current_pdu_len > data_len);
183 SAFE_FREE(rdata);
184 return True;
187 /****************************************************************************
188 WaitNamedPipeHandleState
189 ****************************************************************************/
191 static BOOL api_WNPHS(char *outbuf, pipes_struct *p, char *param, int param_len)
193 uint16 priority;
195 if (!param || param_len < 2)
196 return False;
198 priority = SVAL(param,0);
199 DEBUG(4,("WaitNamedPipeHandleState priority %x\n", priority));
201 if (wait_rpc_pipe_hnd_state(p, priority)) {
202 /* now send the reply */
203 send_trans_reply(outbuf, NULL, 0, NULL, 0, False);
204 return True;
206 return False;
210 /****************************************************************************
211 SetNamedPipeHandleState
212 ****************************************************************************/
214 static BOOL api_SNPHS(char *outbuf, pipes_struct *p, char *param, int param_len)
216 uint16 id;
218 if (!param || param_len < 2)
219 return False;
221 id = SVAL(param,0);
222 DEBUG(4,("SetNamedPipeHandleState to code %x\n", id));
224 if (set_rpc_pipe_hnd_state(p, id)) {
225 /* now send the reply */
226 send_trans_reply(outbuf, NULL, 0, NULL, 0, False);
227 return True;
229 return False;
233 /****************************************************************************
234 When no reply is generated, indicate unsupported.
235 ****************************************************************************/
237 static BOOL api_no_reply(char *outbuf, int max_rdata_len)
239 char rparam[4];
241 /* unsupported */
242 SSVAL(rparam,0,NERR_notsupported);
243 SSVAL(rparam,2,0); /* converter word */
245 DEBUG(3,("Unsupported API fd command\n"));
247 /* now send the reply */
248 send_trans_reply(outbuf, rparam, 4, NULL, 0, False);
250 return -1;
253 /****************************************************************************
254 Handle remote api calls delivered to a named pipe already opened.
255 ****************************************************************************/
257 static int api_fd_reply(connection_struct *conn,uint16 vuid,char *outbuf,
258 uint16 *setup,char *data,char *params,
259 int suwcnt,int tdscnt,int tpscnt,int mdrcnt,int mprcnt)
261 BOOL reply = False;
262 pipes_struct *p = NULL;
263 int pnum;
264 int subcommand;
266 DEBUG(5,("api_fd_reply\n"));
268 /* First find out the name of this file. */
269 if (suwcnt != 2) {
270 DEBUG(0,("Unexpected named pipe transaction.\n"));
271 return(-1);
274 /* Get the file handle and hence the file name. */
276 * NB. The setup array has already been transformed
277 * via SVAL and so is in gost byte order.
279 pnum = ((int)setup[1]) & 0xFFFF;
280 subcommand = ((int)setup[0]) & 0xFFFF;
282 if(!(p = get_rpc_pipe(pnum))) {
283 DEBUG(1,("api_fd_reply: INVALID PIPE HANDLE: %x\n", pnum));
284 return api_no_reply(outbuf, mdrcnt);
287 DEBUG(3,("Got API command 0x%x on pipe \"%s\" (pnum %x)", subcommand, p->name, pnum));
289 /* record maximum data length that can be transmitted in an SMBtrans */
290 p->max_trans_reply = mdrcnt;
292 DEBUG(10,("api_fd_reply: p:%p max_trans_reply: %d\n", p, p->max_trans_reply));
294 switch (subcommand) {
295 case 0x26:
296 /* dce/rpc command */
297 reply = write_to_pipe(p, data, tdscnt);
298 if (reply)
299 reply = api_rpc_trans_reply(outbuf, p);
300 break;
301 case 0x53:
302 /* Wait Named Pipe Handle state */
303 reply = api_WNPHS(outbuf, p, params, tpscnt);
304 break;
305 case 0x01:
306 /* Set Named Pipe Handle state */
307 reply = api_SNPHS(outbuf, p, params, tpscnt);
308 break;
311 if (!reply)
312 return api_no_reply(outbuf, mdrcnt);
314 return -1;
317 /****************************************************************************
318 handle named pipe commands
319 ****************************************************************************/
320 static int named_pipe(connection_struct *conn,uint16 vuid, char *outbuf,char *name,
321 uint16 *setup,char *data,char *params,
322 int suwcnt,int tdscnt,int tpscnt,
323 int msrcnt,int mdrcnt,int mprcnt)
325 DEBUG(3,("named pipe command on <%s> name\n", name));
327 if (strequal(name,"LANMAN"))
328 return api_reply(conn,vuid,outbuf,data,params,tdscnt,tpscnt,mdrcnt,mprcnt);
330 if (strequal(name,"WKSSVC") ||
331 strequal(name,"SRVSVC") ||
332 strequal(name,"WINREG") ||
333 strequal(name,"SAMR") ||
334 strequal(name,"LSARPC"))
336 DEBUG(4,("named pipe command from Win95 (wow!)\n"));
337 return api_fd_reply(conn,vuid,outbuf,setup,data,params,suwcnt,tdscnt,tpscnt,mdrcnt,mprcnt);
340 if (strlen(name) < 1)
341 return api_fd_reply(conn,vuid,outbuf,setup,data,params,suwcnt,tdscnt,tpscnt,mdrcnt,mprcnt);
343 if (setup)
344 DEBUG(3,("unknown named pipe: setup 0x%X setup1=%d\n", (int)setup[0],(int)setup[1]));
346 return 0;
350 /****************************************************************************
351 Reply to a SMBtrans.
352 ****************************************************************************/
354 int reply_trans(connection_struct *conn, char *inbuf,char *outbuf, int size, int bufsize)
356 fstring name;
357 int name_offset = 0;
358 char *data=NULL,*params=NULL;
359 uint16 *setup=NULL;
360 int outsize = 0;
361 uint16 vuid = SVAL(inbuf,smb_uid);
362 int tpscnt = SVAL(inbuf,smb_vwv0);
363 int tdscnt = SVAL(inbuf,smb_vwv1);
364 int mprcnt = SVAL(inbuf,smb_vwv2);
365 int mdrcnt = SVAL(inbuf,smb_vwv3);
366 int msrcnt = CVAL(inbuf,smb_vwv4);
367 BOOL close_on_completion = BITSETW(inbuf+smb_vwv5,0);
368 BOOL one_way = BITSETW(inbuf+smb_vwv5,1);
369 int pscnt = SVAL(inbuf,smb_vwv9);
370 int psoff = SVAL(inbuf,smb_vwv10);
371 int dscnt = SVAL(inbuf,smb_vwv11);
372 int dsoff = SVAL(inbuf,smb_vwv12);
373 int suwcnt = CVAL(inbuf,smb_vwv13);
374 START_PROFILE(SMBtrans);
376 memset(name, '\0',sizeof(name));
377 srvstr_pull(inbuf, name, smb_buf(inbuf), sizeof(name), -1, STR_TERMINATE);
379 if (dscnt > tdscnt || pscnt > tpscnt) {
380 exit_server("invalid trans parameters");
383 if (tdscnt) {
384 if((data = (char *)malloc(tdscnt)) == NULL) {
385 DEBUG(0,("reply_trans: data malloc fail for %d bytes !\n", tdscnt));
386 END_PROFILE(SMBtrans);
387 return(ERROR_DOS(ERRDOS,ERRnomem));
389 memcpy(data,smb_base(inbuf)+dsoff,dscnt);
392 if (tpscnt) {
393 if((params = (char *)malloc(tpscnt)) == NULL) {
394 DEBUG(0,("reply_trans: param malloc fail for %d bytes !\n", tpscnt));
395 END_PROFILE(SMBtrans);
396 return(ERROR_DOS(ERRDOS,ERRnomem));
398 memcpy(params,smb_base(inbuf)+psoff,pscnt);
401 if (suwcnt) {
402 int i;
403 if((setup = (uint16 *)malloc(suwcnt*sizeof(uint16))) == NULL) {
404 DEBUG(0,("reply_trans: setup malloc fail for %d bytes !\n", (int)(suwcnt * sizeof(uint16))));
405 END_PROFILE(SMBtrans);
406 return(ERROR_DOS(ERRDOS,ERRnomem));
408 for (i=0;i<suwcnt;i++)
409 setup[i] = SVAL(inbuf,smb_vwv14+i*SIZEOFWORD);
413 if (pscnt < tpscnt || dscnt < tdscnt) {
414 /* We need to send an interim response then receive the rest
415 of the parameter/data bytes */
416 outsize = set_message(outbuf,0,0,True);
417 show_msg(outbuf);
418 if (!send_smb(smbd_server_fd(),outbuf))
419 exit_server("reply_trans: send_smb failed.");
422 /* receive the rest of the trans packet */
423 while (pscnt < tpscnt || dscnt < tdscnt) {
424 BOOL ret;
425 int pcnt,poff,dcnt,doff,pdisp,ddisp;
427 ret = receive_next_smb(inbuf,bufsize,SMB_SECONDARY_WAIT);
429 if ((ret && (CVAL(inbuf, smb_com) != SMBtranss)) || !ret) {
430 if(ret) {
431 DEBUG(0,("reply_trans: Invalid secondary trans packet\n"));
432 } else {
433 DEBUG(0,("reply_trans: %s in getting secondary trans response.\n",
434 (smb_read_error == READ_ERROR) ? "error" : "timeout" ));
436 SAFE_FREE(params);
437 SAFE_FREE(data);
438 SAFE_FREE(setup);
439 END_PROFILE(SMBtrans);
440 return(ERROR_DOS(ERRSRV,ERRerror));
443 show_msg(inbuf);
445 tpscnt = SVAL(inbuf,smb_vwv0);
446 tdscnt = SVAL(inbuf,smb_vwv1);
448 pcnt = SVAL(inbuf,smb_vwv2);
449 poff = SVAL(inbuf,smb_vwv3);
450 pdisp = SVAL(inbuf,smb_vwv4);
452 dcnt = SVAL(inbuf,smb_vwv5);
453 doff = SVAL(inbuf,smb_vwv6);
454 ddisp = SVAL(inbuf,smb_vwv7);
456 pscnt += pcnt;
457 dscnt += dcnt;
459 if (dscnt > tdscnt || pscnt > tpscnt) {
460 exit_server("invalid trans parameters");
463 if (pcnt)
464 memcpy(params+pdisp,smb_base(inbuf)+poff,pcnt);
465 if (dcnt)
466 memcpy(data+ddisp,smb_base(inbuf)+doff,dcnt);
470 DEBUG(3,("trans <%s> data=%d params=%d setup=%d\n",
471 name,tdscnt,tpscnt,suwcnt));
474 * WinCE wierdness....
477 if (name[0] == '\\' && (StrnCaseCmp(&name[1],local_machine, strlen(local_machine)) == 0) &&
478 (name[strlen(local_machine)+1] == '\\'))
479 name_offset = strlen(local_machine)+1;
481 if (strnequal(&name[name_offset], "\\PIPE", strlen("\\PIPE"))) {
482 name_offset += strlen("\\PIPE");
484 /* Win9x weirdness. When talking to a unicode server Win9x
485 only sends \PIPE instead of \PIPE\ */
487 if (name[name_offset] == '\\')
488 name_offset++;
490 DEBUG(5,("calling named_pipe\n"));
491 outsize = named_pipe(conn,vuid,outbuf,
492 name+name_offset,setup,data,params,
493 suwcnt,tdscnt,tpscnt,msrcnt,mdrcnt,mprcnt);
494 } else {
495 DEBUG(3,("invalid pipe name\n"));
496 outsize = 0;
500 SAFE_FREE(data);
501 SAFE_FREE(params);
502 SAFE_FREE(setup);
504 if (close_on_completion)
505 close_cnum(conn,vuid);
507 if (one_way) {
508 END_PROFILE(SMBtrans);
509 return(-1);
512 if (outsize == 0) {
513 END_PROFILE(SMBtrans);
514 return(ERROR_DOS(ERRSRV,ERRnosupport));
517 END_PROFILE(SMBtrans);
518 return(outsize);