r4904: sync up with 3.0 for 3.0.11pre2
[Samba.git] / source / smbd / ipc.c
blob3f21a2ac6adcdf1ff8eb072009f951575a9d3bc9
1 /*
2 Unix SMB/CIFS implementation.
3 Inter-process communication and named pipe handling
4 Copyright (C) Andrew Tridgell 1992-1998
6 SMB Version handling
7 Copyright (C) John H Terpstra 1995-1998
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 This file handles the named pipe and mailslot calls
25 in the SMBtrans protocol
28 #include "includes.h"
30 extern int max_send;
32 extern fstring local_machine;
34 #define NERR_notsupported 50
36 extern int smb_read_error;
38 /*******************************************************************
39 copies parameters and data, as needed, into the smb buffer
41 *both* the data and params sections should be aligned. this
42 is fudged in the rpc pipes by
43 at present, only the data section is. this may be a possible
44 cause of some of the ipc problems being experienced. lkcl26dec97
46 ******************************************************************/
48 static void copy_trans_params_and_data(char *outbuf, int align,
49 char *rparam, int param_offset, int param_len,
50 char *rdata, int data_offset, int data_len)
52 char *copy_into = smb_buf(outbuf)+1;
54 if(param_len < 0)
55 param_len = 0;
57 if(data_len < 0)
58 data_len = 0;
60 DEBUG(5,("copy_trans_params_and_data: params[%d..%d] data[%d..%d]\n",
61 param_offset, param_offset + param_len,
62 data_offset , data_offset + data_len));
64 if (param_len)
65 memcpy(copy_into, &rparam[param_offset], param_len);
67 copy_into += param_len + align;
69 if (data_len )
70 memcpy(copy_into, &rdata[data_offset], data_len);
73 /****************************************************************************
74 Send a trans reply.
75 ****************************************************************************/
77 void send_trans_reply(char *outbuf,
78 char *rparam, int rparam_len,
79 char *rdata, int rdata_len,
80 BOOL buffer_too_large)
82 int this_ldata,this_lparam;
83 int tot_data_sent = 0;
84 int tot_param_sent = 0;
85 int align;
87 int ldata = rdata ? rdata_len : 0;
88 int lparam = rparam ? rparam_len : 0;
90 if (buffer_too_large)
91 DEBUG(5,("send_trans_reply: buffer %d too large\n", ldata ));
93 this_lparam = MIN(lparam,max_send - 500); /* hack */
94 this_ldata = MIN(ldata,max_send - (500+this_lparam));
96 align = ((this_lparam)%4);
98 if (buffer_too_large) {
99 ERROR_BOTH(STATUS_BUFFER_OVERFLOW,ERRDOS,ERRmoredata);
102 set_message(outbuf,10,1+align+this_ldata+this_lparam,True);
104 copy_trans_params_and_data(outbuf, align,
105 rparam, tot_param_sent, this_lparam,
106 rdata, tot_data_sent, this_ldata);
108 SSVAL(outbuf,smb_vwv0,lparam);
109 SSVAL(outbuf,smb_vwv1,ldata);
110 SSVAL(outbuf,smb_vwv3,this_lparam);
111 SSVAL(outbuf,smb_vwv4,smb_offset(smb_buf(outbuf)+1,outbuf));
112 SSVAL(outbuf,smb_vwv5,0);
113 SSVAL(outbuf,smb_vwv6,this_ldata);
114 SSVAL(outbuf,smb_vwv7,smb_offset(smb_buf(outbuf)+1+this_lparam+align,outbuf));
115 SSVAL(outbuf,smb_vwv8,0);
116 SSVAL(outbuf,smb_vwv9,0);
118 show_msg(outbuf);
119 if (!send_smb(smbd_server_fd(),outbuf))
120 exit_server("send_trans_reply: send_smb failed.");
122 tot_data_sent = this_ldata;
123 tot_param_sent = this_lparam;
125 while (tot_data_sent < ldata || tot_param_sent < lparam)
127 this_lparam = MIN(lparam-tot_param_sent, max_send - 500); /* hack */
128 this_ldata = MIN(ldata -tot_data_sent, max_send - (500+this_lparam));
130 if(this_lparam < 0)
131 this_lparam = 0;
133 if(this_ldata < 0)
134 this_ldata = 0;
136 align = (this_lparam%4);
138 set_message(outbuf,10,1+this_ldata+this_lparam+align,False);
140 copy_trans_params_and_data(outbuf, align,
141 rparam, tot_param_sent, this_lparam,
142 rdata, tot_data_sent, this_ldata);
144 SSVAL(outbuf,smb_vwv3,this_lparam);
145 SSVAL(outbuf,smb_vwv4,smb_offset(smb_buf(outbuf)+1,outbuf));
146 SSVAL(outbuf,smb_vwv5,tot_param_sent);
147 SSVAL(outbuf,smb_vwv6,this_ldata);
148 SSVAL(outbuf,smb_vwv7,smb_offset(smb_buf(outbuf)+1+this_lparam+align,outbuf));
149 SSVAL(outbuf,smb_vwv8,tot_data_sent);
150 SSVAL(outbuf,smb_vwv9,0);
152 show_msg(outbuf);
153 if (!send_smb(smbd_server_fd(),outbuf))
154 exit_server("send_trans_reply: send_smb failed.");
156 tot_data_sent += this_ldata;
157 tot_param_sent += this_lparam;
161 /****************************************************************************
162 Start the first part of an RPC reply which began with an SMBtrans request.
163 ****************************************************************************/
165 static BOOL api_rpc_trans_reply(char *outbuf, smb_np_struct *p)
167 BOOL is_data_outstanding;
168 char *rdata = SMB_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,
177 &is_data_outstanding)) < 0) {
178 SAFE_FREE(rdata);
179 return False;
182 send_trans_reply(outbuf, NULL, 0, rdata, data_len, is_data_outstanding);
184 SAFE_FREE(rdata);
185 return True;
188 /****************************************************************************
189 WaitNamedPipeHandleState
190 ****************************************************************************/
192 static BOOL api_WNPHS(char *outbuf, smb_np_struct *p, char *param, int param_len)
194 uint16 priority;
196 if (!param || param_len < 2)
197 return False;
199 priority = SVAL(param,0);
200 DEBUG(4,("WaitNamedPipeHandleState priority %x\n", priority));
202 if (wait_rpc_pipe_hnd_state(p, priority)) {
203 /* now send the reply */
204 send_trans_reply(outbuf, NULL, 0, NULL, 0, False);
205 return True;
207 return False;
211 /****************************************************************************
212 SetNamedPipeHandleState
213 ****************************************************************************/
215 static BOOL api_SNPHS(char *outbuf, smb_np_struct *p, char *param, int param_len)
217 uint16 id;
219 if (!param || param_len < 2)
220 return False;
222 id = SVAL(param,0);
223 DEBUG(4,("SetNamedPipeHandleState to code %x\n", id));
225 if (set_rpc_pipe_hnd_state(p, id)) {
226 /* now send the reply */
227 send_trans_reply(outbuf, NULL, 0, NULL, 0, False);
228 return True;
230 return False;
234 /****************************************************************************
235 When no reply is generated, indicate unsupported.
236 ****************************************************************************/
238 static BOOL api_no_reply(char *outbuf, int max_rdata_len)
240 char rparam[4];
242 /* unsupported */
243 SSVAL(rparam,0,NERR_notsupported);
244 SSVAL(rparam,2,0); /* converter word */
246 DEBUG(3,("Unsupported API fd command\n"));
248 /* now send the reply */
249 send_trans_reply(outbuf, rparam, 4, NULL, 0, False);
251 return -1;
254 /****************************************************************************
255 Handle remote api calls delivered to a named pipe already opened.
256 ****************************************************************************/
258 static int api_fd_reply(connection_struct *conn,uint16 vuid,char *outbuf,
259 uint16 *setup,char *data,char *params,
260 int suwcnt,int tdscnt,int tpscnt,int mdrcnt,int mprcnt)
262 BOOL reply = False;
263 smb_np_struct *p = NULL;
264 int pnum;
265 int subcommand;
267 DEBUG(5,("api_fd_reply\n"));
269 /* First find out the name of this file. */
270 if (suwcnt != 2) {
271 DEBUG(0,("Unexpected named pipe transaction.\n"));
272 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
275 /* Get the file handle and hence the file name. */
277 * NB. The setup array has already been transformed
278 * via SVAL and so is in gost byte order.
280 pnum = ((int)setup[1]) & 0xFFFF;
281 subcommand = ((int)setup[0]) & 0xFFFF;
283 if(!(p = get_rpc_pipe(pnum))) {
284 if (subcommand == TRANSACT_WAITNAMEDPIPEHANDLESTATE) {
285 /* Win9x does this call with a unicode pipe name, not a pnum. */
286 /* Just return success for now... */
287 DEBUG(3,("Got TRANSACT_WAITNAMEDPIPEHANDLESTATE on text pipe name\n"));
288 send_trans_reply(outbuf, NULL, 0, NULL, 0, False);
289 return -1;
292 DEBUG(1,("api_fd_reply: INVALID PIPE HANDLE: %x\n", pnum));
293 return ERROR_NT(NT_STATUS_INVALID_HANDLE);
296 DEBUG(3,("Got API command 0x%x on pipe \"%s\" (pnum %x)\n", subcommand, p->name, pnum));
298 /* record maximum data length that can be transmitted in an SMBtrans */
299 p->max_trans_reply = mdrcnt;
301 DEBUG(10,("api_fd_reply: p:%p max_trans_reply: %d\n", p, p->max_trans_reply));
303 switch (subcommand) {
304 case TRANSACT_DCERPCCMD:
305 /* dce/rpc command */
306 reply = write_to_pipe(p, data, tdscnt);
307 if (reply)
308 reply = api_rpc_trans_reply(outbuf, p);
309 break;
310 case TRANSACT_WAITNAMEDPIPEHANDLESTATE:
311 /* Wait Named Pipe Handle state */
312 reply = api_WNPHS(outbuf, p, params, tpscnt);
313 break;
314 case TRANSACT_SETNAMEDPIPEHANDLESTATE:
315 /* Set Named Pipe Handle state */
316 reply = api_SNPHS(outbuf, p, params, tpscnt);
317 break;
318 default:
319 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
322 if (!reply)
323 return api_no_reply(outbuf, mdrcnt);
325 return -1;
328 /****************************************************************************
329 handle named pipe commands
330 ****************************************************************************/
331 static int named_pipe(connection_struct *conn,uint16 vuid, char *outbuf,char *name,
332 uint16 *setup,char *data,char *params,
333 int suwcnt,int tdscnt,int tpscnt,
334 int msrcnt,int mdrcnt,int mprcnt)
336 DEBUG(3,("named pipe command on <%s> name\n", name));
338 if (strequal(name,"LANMAN"))
339 return api_reply(conn,vuid,outbuf,data,params,tdscnt,tpscnt,mdrcnt,mprcnt);
341 if (strequal(name,"WKSSVC") ||
342 strequal(name,"SRVSVC") ||
343 strequal(name,"WINREG") ||
344 strequal(name,"SAMR") ||
345 strequal(name,"LSARPC"))
347 DEBUG(4,("named pipe command from Win95 (wow!)\n"));
348 return api_fd_reply(conn,vuid,outbuf,setup,data,params,suwcnt,tdscnt,tpscnt,mdrcnt,mprcnt);
351 if (strlen(name) < 1)
352 return api_fd_reply(conn,vuid,outbuf,setup,data,params,suwcnt,tdscnt,tpscnt,mdrcnt,mprcnt);
354 if (setup)
355 DEBUG(3,("unknown named pipe: setup 0x%X setup1=%d\n", (int)setup[0],(int)setup[1]));
357 return 0;
361 /****************************************************************************
362 Reply to a SMBtrans.
363 ****************************************************************************/
365 int reply_trans(connection_struct *conn, char *inbuf,char *outbuf, int size, int bufsize)
367 fstring name;
368 int name_offset = 0;
369 char *data=NULL,*params=NULL;
370 uint16 *setup=NULL;
371 int outsize = 0;
372 uint16 vuid = SVAL(inbuf,smb_uid);
373 unsigned int tpscnt = SVAL(inbuf,smb_vwv0);
374 unsigned int tdscnt = SVAL(inbuf,smb_vwv1);
375 unsigned int mprcnt = SVAL(inbuf,smb_vwv2);
376 unsigned int mdrcnt = SVAL(inbuf,smb_vwv3);
377 unsigned int msrcnt = CVAL(inbuf,smb_vwv4);
378 BOOL close_on_completion = BITSETW(inbuf+smb_vwv5,0);
379 BOOL one_way = BITSETW(inbuf+smb_vwv5,1);
380 unsigned int pscnt = SVAL(inbuf,smb_vwv9);
381 unsigned int psoff = SVAL(inbuf,smb_vwv10);
382 unsigned int dscnt = SVAL(inbuf,smb_vwv11);
383 unsigned int dsoff = SVAL(inbuf,smb_vwv12);
384 unsigned int suwcnt = CVAL(inbuf,smb_vwv13);
385 START_PROFILE(SMBtrans);
387 memset(name, '\0',sizeof(name));
388 srvstr_pull_buf(inbuf, name, smb_buf(inbuf), sizeof(name), STR_TERMINATE);
390 if (dscnt > tdscnt || pscnt > tpscnt)
391 goto bad_param;
393 if (tdscnt) {
394 if((data = (char *)SMB_MALLOC(tdscnt)) == NULL) {
395 DEBUG(0,("reply_trans: data malloc fail for %u bytes !\n", tdscnt));
396 END_PROFILE(SMBtrans);
397 return(ERROR_DOS(ERRDOS,ERRnomem));
399 if ((dsoff+dscnt < dsoff) || (dsoff+dscnt < dscnt))
400 goto bad_param;
401 if ((smb_base(inbuf)+dsoff+dscnt > inbuf + size) ||
402 (smb_base(inbuf)+dsoff+dscnt < smb_base(inbuf)))
403 goto bad_param;
405 memcpy(data,smb_base(inbuf)+dsoff,dscnt);
408 if (tpscnt) {
409 if((params = (char *)SMB_MALLOC(tpscnt)) == NULL) {
410 DEBUG(0,("reply_trans: param malloc fail for %u bytes !\n", tpscnt));
411 SAFE_FREE(data);
412 END_PROFILE(SMBtrans);
413 return(ERROR_DOS(ERRDOS,ERRnomem));
415 if ((psoff+pscnt < psoff) || (psoff+pscnt < pscnt))
416 goto bad_param;
417 if ((smb_base(inbuf)+psoff+pscnt > inbuf + size) ||
418 (smb_base(inbuf)+psoff+pscnt < smb_base(inbuf)))
419 goto bad_param;
421 memcpy(params,smb_base(inbuf)+psoff,pscnt);
424 if (suwcnt) {
425 unsigned int i;
426 if((setup = SMB_MALLOC_ARRAY(uint16,suwcnt)) == NULL) {
427 DEBUG(0,("reply_trans: setup malloc fail for %u bytes !\n", (unsigned int)(suwcnt * sizeof(uint16))));
428 SAFE_FREE(data);
429 SAFE_FREE(params);
430 END_PROFILE(SMBtrans);
431 return(ERROR_DOS(ERRDOS,ERRnomem));
433 if (inbuf+smb_vwv14+(suwcnt*SIZEOFWORD) > inbuf + size)
434 goto bad_param;
435 if ((smb_vwv14+(suwcnt*SIZEOFWORD) < smb_vwv14) || (smb_vwv14+(suwcnt*SIZEOFWORD) < (suwcnt*SIZEOFWORD)))
436 goto bad_param;
438 for (i=0;i<suwcnt;i++)
439 setup[i] = SVAL(inbuf,smb_vwv14+i*SIZEOFWORD);
443 srv_signing_trans_start(SVAL(inbuf,smb_mid));
445 if (pscnt < tpscnt || dscnt < tdscnt) {
446 /* We need to send an interim response then receive the rest
447 of the parameter/data bytes */
448 outsize = set_message(outbuf,0,0,True);
449 show_msg(outbuf);
450 srv_signing_trans_stop();
451 if (!send_smb(smbd_server_fd(),outbuf))
452 exit_server("reply_trans: send_smb failed.");
455 /* receive the rest of the trans packet */
456 while (pscnt < tpscnt || dscnt < tdscnt) {
457 BOOL ret;
458 unsigned int pcnt,poff,dcnt,doff,pdisp,ddisp;
460 ret = receive_next_smb(inbuf,bufsize,SMB_SECONDARY_WAIT);
463 * The sequence number for the trans reply is always
464 * based on the last secondary received.
467 srv_signing_trans_start(SVAL(inbuf,smb_mid));
469 if ((ret && (CVAL(inbuf, smb_com) != SMBtranss)) || !ret) {
470 if(ret) {
471 DEBUG(0,("reply_trans: Invalid secondary trans packet\n"));
472 } else {
473 DEBUG(0,("reply_trans: %s in getting secondary trans response.\n",
474 (smb_read_error == READ_ERROR) ? "error" : "timeout" ));
476 SAFE_FREE(params);
477 SAFE_FREE(data);
478 SAFE_FREE(setup);
479 END_PROFILE(SMBtrans);
480 srv_signing_trans_stop();
481 return(ERROR_DOS(ERRSRV,ERRerror));
484 show_msg(inbuf);
486 /* Revise total_params and total_data in case they have changed downwards */
487 if (SVAL(inbuf,smb_vwv0) < tpscnt)
488 tpscnt = SVAL(inbuf,smb_vwv0);
489 if (SVAL(inbuf,smb_vwv1) < tdscnt)
490 tdscnt = SVAL(inbuf,smb_vwv1);
492 pcnt = SVAL(inbuf,smb_vwv2);
493 poff = SVAL(inbuf,smb_vwv3);
494 pdisp = SVAL(inbuf,smb_vwv4);
496 dcnt = SVAL(inbuf,smb_vwv5);
497 doff = SVAL(inbuf,smb_vwv6);
498 ddisp = SVAL(inbuf,smb_vwv7);
500 pscnt += pcnt;
501 dscnt += dcnt;
503 if (dscnt > tdscnt || pscnt > tpscnt)
504 goto bad_param;
506 if (pcnt) {
507 if (pdisp+pcnt > tpscnt)
508 goto bad_param;
509 if ((pdisp+pcnt < pdisp) || (pdisp+pcnt < pcnt))
510 goto bad_param;
511 if (pdisp > tpscnt)
512 goto bad_param;
513 if ((smb_base(inbuf) + poff + pcnt >= inbuf + bufsize) ||
514 (smb_base(inbuf) + poff + pcnt < smb_base(inbuf)))
515 goto bad_param;
516 if (params + pdisp < params)
517 goto bad_param;
519 memcpy(params+pdisp,smb_base(inbuf)+poff,pcnt);
522 if (dcnt) {
523 if (ddisp+dcnt > tdscnt)
524 goto bad_param;
525 if ((ddisp+dcnt < ddisp) || (ddisp+dcnt < dcnt))
526 goto bad_param;
527 if (ddisp > tdscnt)
528 goto bad_param;
529 if ((smb_base(inbuf) + doff + dcnt >= inbuf + bufsize) ||
530 (smb_base(inbuf) + doff + dcnt < smb_base(inbuf)))
531 goto bad_param;
532 if (data + ddisp < data)
533 goto bad_param;
535 memcpy(data+ddisp,smb_base(inbuf)+doff,dcnt);
539 DEBUG(3,("trans <%s> data=%u params=%u setup=%u\n",
540 name,tdscnt,tpscnt,suwcnt));
543 * WinCE wierdness....
546 if (name[0] == '\\' && (StrnCaseCmp(&name[1],local_machine, strlen(local_machine)) == 0) &&
547 (name[strlen(local_machine)+1] == '\\'))
548 name_offset = strlen(local_machine)+1;
550 if (strnequal(&name[name_offset], "\\PIPE", strlen("\\PIPE"))) {
551 name_offset += strlen("\\PIPE");
553 /* Win9x weirdness. When talking to a unicode server Win9x
554 only sends \PIPE instead of \PIPE\ */
556 if (name[name_offset] == '\\')
557 name_offset++;
559 DEBUG(5,("calling named_pipe\n"));
560 outsize = named_pipe(conn,vuid,outbuf,
561 name+name_offset,setup,data,params,
562 suwcnt,tdscnt,tpscnt,msrcnt,mdrcnt,mprcnt);
563 } else {
564 DEBUG(3,("invalid pipe name\n"));
565 outsize = 0;
569 SAFE_FREE(data);
570 SAFE_FREE(params);
571 SAFE_FREE(setup);
573 srv_signing_trans_stop();
575 if (close_on_completion)
576 close_cnum(conn,vuid);
578 if (one_way) {
579 END_PROFILE(SMBtrans);
580 return(-1);
583 if (outsize == 0) {
584 END_PROFILE(SMBtrans);
585 return(ERROR_DOS(ERRSRV,ERRnosupport));
588 END_PROFILE(SMBtrans);
589 return(outsize);
592 bad_param:
594 srv_signing_trans_stop();
595 DEBUG(0,("reply_trans: invalid trans parameters\n"));
596 SAFE_FREE(data);
597 SAFE_FREE(params);
598 SAFE_FREE(setup);
599 END_PROFILE(SMBtrans);
600 return ERROR_NT(NT_STATUS_INVALID_PARAMETER);