This commit was manufactured by cvs2svn to create branch 'SAMBA_2_2'.
[Samba.git] / source / smbd / ipc.c
blob5ade6672093f38a95a5c01b102989eb8ad367be6
1 #define OLD_NTDOMAIN 1
2 /*
3 Unix SMB/Netbios implementation.
4 Version 1.9.
5 Inter-process communication and named pipe handling
6 Copyright (C) Andrew Tridgell 1992-1998
8 SMB Version handling
9 Copyright (C) John H Terpstra 1995-1998
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2 of the License, or
14 (at your option) any later version.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 This file handles the named pipe and mailslot calls
27 in the SMBtrans protocol
30 #include "includes.h"
32 extern int DEBUGLEVEL;
33 extern int max_send;
35 extern fstring local_machine;
37 #define NERR_notsupported 50
39 extern int smb_read_error;
41 /*******************************************************************
42 copies parameters and data, as needed, into the smb buffer
44 *both* the data and params sections should be aligned. this
45 is fudged in the rpc pipes by
46 at present, only the data section is. this may be a possible
47 cause of some of the ipc problems being experienced. lkcl26dec97
49 ******************************************************************/
51 static void copy_trans_params_and_data(char *outbuf, int align,
52 char *rparam, int param_offset, int param_len,
53 char *rdata, int data_offset, int data_len)
55 char *copy_into = smb_buf(outbuf)+1;
57 if(param_len < 0)
58 param_len = 0;
60 if(data_len < 0)
61 data_len = 0;
63 DEBUG(5,("copy_trans_params_and_data: params[%d..%d] data[%d..%d]\n",
64 param_offset, param_offset + param_len,
65 data_offset , data_offset + data_len));
67 if (param_len)
68 memcpy(copy_into, &rparam[param_offset], param_len);
70 copy_into += param_len + align;
72 if (data_len )
73 memcpy(copy_into, &rdata[data_offset], data_len);
76 /****************************************************************************
77 Send a trans reply.
78 ****************************************************************************/
80 void send_trans_reply(char *outbuf,
81 char *rparam, int rparam_len,
82 char *rdata, int rdata_len,
83 BOOL buffer_too_large)
85 int this_ldata,this_lparam;
86 int tot_data_sent = 0;
87 int tot_param_sent = 0;
88 int align;
90 int ldata = rdata ? rdata_len : 0;
91 int lparam = rparam ? rparam_len : 0;
93 if (buffer_too_large)
94 DEBUG(5,("send_trans_reply: buffer %d too large\n", ldata ));
96 this_lparam = MIN(lparam,max_send - 500); /* hack */
97 this_ldata = MIN(ldata,max_send - (500+this_lparam));
99 align = ((this_lparam)%4);
101 set_message(outbuf,10,1+align+this_ldata+this_lparam,True);
103 if (buffer_too_large)
105 /* issue a buffer size warning. on a DCE/RPC pipe, expect an SMBreadX... */
106 SIVAL(outbuf, smb_flg2, FLAGS2_32_BIT_ERROR_CODES);
107 SIVAL(outbuf, smb_rcls, 0x80000000 | STATUS_BUFFER_OVERFLOW);
110 copy_trans_params_and_data(outbuf, align,
111 rparam, tot_param_sent, this_lparam,
112 rdata, tot_data_sent, this_ldata);
114 SSVAL(outbuf,smb_vwv0,lparam);
115 SSVAL(outbuf,smb_vwv1,ldata);
116 SSVAL(outbuf,smb_vwv3,this_lparam);
117 SSVAL(outbuf,smb_vwv4,smb_offset(smb_buf(outbuf)+1,outbuf));
118 SSVAL(outbuf,smb_vwv5,0);
119 SSVAL(outbuf,smb_vwv6,this_ldata);
120 SSVAL(outbuf,smb_vwv7,smb_offset(smb_buf(outbuf)+1+this_lparam+align,outbuf));
121 SSVAL(outbuf,smb_vwv8,0);
122 SSVAL(outbuf,smb_vwv9,0);
124 show_msg(outbuf);
125 send_smb(smbd_server_fd(),outbuf);
127 tot_data_sent = this_ldata;
128 tot_param_sent = this_lparam;
130 while (tot_data_sent < ldata || tot_param_sent < lparam)
132 this_lparam = MIN(lparam-tot_param_sent, max_send - 500); /* hack */
133 this_ldata = MIN(ldata -tot_data_sent, max_send - (500+this_lparam));
135 if(this_lparam < 0)
136 this_lparam = 0;
138 if(this_ldata < 0)
139 this_ldata = 0;
141 align = (this_lparam%4);
143 set_message(outbuf,10,1+this_ldata+this_lparam+align,False);
145 copy_trans_params_and_data(outbuf, align,
146 rparam, tot_param_sent, this_lparam,
147 rdata, tot_data_sent, this_ldata);
149 SSVAL(outbuf,smb_vwv3,this_lparam);
150 SSVAL(outbuf,smb_vwv4,smb_offset(smb_buf(outbuf)+1,outbuf));
151 SSVAL(outbuf,smb_vwv5,tot_param_sent);
152 SSVAL(outbuf,smb_vwv6,this_ldata);
153 SSVAL(outbuf,smb_vwv7,smb_offset(smb_buf(outbuf)+1+this_lparam+align,outbuf));
154 SSVAL(outbuf,smb_vwv8,tot_data_sent);
155 SSVAL(outbuf,smb_vwv9,0);
157 show_msg(outbuf);
158 send_smb(smbd_server_fd(),outbuf);
160 tot_data_sent += this_ldata;
161 tot_param_sent += this_lparam;
165 /****************************************************************************
166 Start the first part of an RPC reply which began with an SMBtrans request.
167 ****************************************************************************/
169 static BOOL api_rpc_trans_reply(char *outbuf, pipes_struct *p)
171 char *rdata = malloc(p->max_trans_reply);
172 int data_len;
174 if(rdata == NULL) {
175 DEBUG(0,("api_rpc_trans_reply: malloc fail.\n"));
176 return False;
179 if((data_len = read_from_pipe( p, rdata, p->max_trans_reply)) < 0) {
180 free(rdata);
181 return False;
184 send_trans_reply(outbuf, NULL, 0, rdata, data_len, p->out_data.current_pdu_len > data_len);
186 free(rdata);
187 return True;
190 /****************************************************************************
191 WaitNamedPipeHandleState
192 ****************************************************************************/
194 static BOOL api_WNPHS(char *outbuf, pipes_struct *p, char *param, int param_len)
196 uint16 priority;
198 if (!param || param_len < 2)
199 return False;
201 priority = SVAL(param,0);
202 DEBUG(4,("WaitNamedPipeHandleState priority %x\n", priority));
204 if (wait_rpc_pipe_hnd_state(p, priority)) {
205 /* now send the reply */
206 send_trans_reply(outbuf, NULL, 0, NULL, 0, False);
207 return True;
209 return False;
213 /****************************************************************************
214 SetNamedPipeHandleState
215 ****************************************************************************/
217 static BOOL api_SNPHS(char *outbuf, pipes_struct *p, char *param, int param_len)
219 uint16 id;
221 if (!param || param_len < 2)
222 return False;
224 id = SVAL(param,0);
225 DEBUG(4,("SetNamedPipeHandleState to code %x\n", id));
227 if (set_rpc_pipe_hnd_state(p, id)) {
228 /* now send the reply */
229 send_trans_reply(outbuf, NULL, 0, NULL, 0, False);
230 return True;
232 return False;
236 /****************************************************************************
237 When no reply is generated, indicate unsupported.
238 ****************************************************************************/
240 static BOOL api_no_reply(char *outbuf, int max_rdata_len)
242 char rparam[4];
244 /* unsupported */
245 SSVAL(rparam,0,NERR_notsupported);
246 SSVAL(rparam,2,0); /* converter word */
248 DEBUG(3,("Unsupported API fd command\n"));
250 /* now send the reply */
251 send_trans_reply(outbuf, rparam, 4, NULL, 0, False);
253 return -1;
256 /****************************************************************************
257 Handle remote api calls delivered to a named pipe already opened.
258 ****************************************************************************/
260 static int api_fd_reply(connection_struct *conn,uint16 vuid,char *outbuf,
261 uint16 *setup,char *data,char *params,
262 int suwcnt,int tdscnt,int tpscnt,int mdrcnt,int mprcnt)
264 BOOL reply = False;
265 pipes_struct *p = NULL;
266 int pnum;
267 int subcommand;
269 DEBUG(5,("api_fd_reply\n"));
271 /* First find out the name of this file. */
272 if (suwcnt != 2) {
273 DEBUG(0,("Unexpected named pipe transaction.\n"));
274 return(-1);
277 /* Get the file handle and hence the file name. */
279 * NB. The setup array has already been transformed
280 * via SVAL and so is in gost byte order.
282 pnum = ((int)setup[1]) & 0xFFFF;
283 subcommand = ((int)setup[0]) & 0xFFFF;
285 if(!(p = get_rpc_pipe(pnum))) {
286 DEBUG(1,("api_fd_reply: INVALID PIPE HANDLE: %x\n", pnum));
287 return api_no_reply(outbuf, mdrcnt);
290 DEBUG(3,("Got API command 0x%x on pipe \"%s\" (pnum %x)", subcommand, p->name, pnum));
292 /* record maximum data length that can be transmitted in an SMBtrans */
293 p->max_trans_reply = mdrcnt;
295 DEBUG(10,("api_fd_reply: p:%p max_trans_reply: %d\n", p, p->max_trans_reply));
297 switch (subcommand) {
298 case 0x26:
299 /* dce/rpc command */
300 reply = write_to_pipe(p, data, tdscnt);
301 if (reply)
302 reply = api_rpc_trans_reply(outbuf, p);
303 break;
304 case 0x53:
305 /* Wait Named Pipe Handle state */
306 reply = api_WNPHS(outbuf, p, params, tpscnt);
307 break;
308 case 0x01:
309 /* Set Named Pipe Handle state */
310 reply = api_SNPHS(outbuf, p, params, tpscnt);
311 break;
314 if (!reply)
315 return api_no_reply(outbuf, mdrcnt);
317 return -1;
320 /****************************************************************************
321 handle named pipe commands
322 ****************************************************************************/
323 static int named_pipe(connection_struct *conn,uint16 vuid, char *outbuf,char *name,
324 uint16 *setup,char *data,char *params,
325 int suwcnt,int tdscnt,int tpscnt,
326 int msrcnt,int mdrcnt,int mprcnt)
328 DEBUG(3,("named pipe command on <%s> name\n", name));
330 if (strequal(name,"LANMAN"))
331 return api_reply(conn,vuid,outbuf,data,params,tdscnt,tpscnt,mdrcnt,mprcnt);
333 if (strequal(name,"WKSSVC") ||
334 strequal(name,"SRVSVC") ||
335 strequal(name,"WINREG") ||
336 strequal(name,"SAMR") ||
337 strequal(name,"LSARPC"))
339 DEBUG(4,("named pipe command from Win95 (wow!)\n"));
340 return api_fd_reply(conn,vuid,outbuf,setup,data,params,suwcnt,tdscnt,tpscnt,mdrcnt,mprcnt);
343 if (strlen(name) < 1)
344 return api_fd_reply(conn,vuid,outbuf,setup,data,params,suwcnt,tdscnt,tpscnt,mdrcnt,mprcnt);
346 if (setup)
347 DEBUG(3,("unknown named pipe: setup 0x%X setup1=%d\n", (int)setup[0],(int)setup[1]));
349 return 0;
353 /****************************************************************************
354 Reply to a SMBtrans.
355 ****************************************************************************/
357 int reply_trans(connection_struct *conn, char *inbuf,char *outbuf, int size, int bufsize)
359 fstring name;
360 int name_offset = 0;
361 char *data=NULL,*params=NULL;
362 uint16 *setup=NULL;
363 int outsize = 0;
364 uint16 vuid = SVAL(inbuf,smb_uid);
365 int tpscnt = SVAL(inbuf,smb_vwv0);
366 int tdscnt = SVAL(inbuf,smb_vwv1);
367 int mprcnt = SVAL(inbuf,smb_vwv2);
368 int mdrcnt = SVAL(inbuf,smb_vwv3);
369 int msrcnt = CVAL(inbuf,smb_vwv4);
370 BOOL close_on_completion = BITSETW(inbuf+smb_vwv5,0);
371 BOOL one_way = BITSETW(inbuf+smb_vwv5,1);
372 int pscnt = SVAL(inbuf,smb_vwv9);
373 int psoff = SVAL(inbuf,smb_vwv10);
374 int dscnt = SVAL(inbuf,smb_vwv11);
375 int dsoff = SVAL(inbuf,smb_vwv12);
376 int suwcnt = CVAL(inbuf,smb_vwv13);
377 START_PROFILE(SMBtrans);
379 memset(name, '\0',sizeof(name));
380 fstrcpy(name,smb_buf(inbuf));
382 if (dscnt > tdscnt || pscnt > tpscnt) {
383 exit_server("invalid trans parameters\n");
386 if (tdscnt) {
387 if((data = (char *)malloc(tdscnt)) == NULL) {
388 DEBUG(0,("reply_trans: data malloc fail for %d bytes !\n", tdscnt));
389 END_PROFILE(SMBtrans);
390 return(ERROR(ERRDOS,ERRnomem));
392 memcpy(data,smb_base(inbuf)+dsoff,dscnt);
395 if (tpscnt) {
396 if((params = (char *)malloc(tpscnt)) == NULL) {
397 DEBUG(0,("reply_trans: param malloc fail for %d bytes !\n", tpscnt));
398 END_PROFILE(SMBtrans);
399 return(ERROR(ERRDOS,ERRnomem));
401 memcpy(params,smb_base(inbuf)+psoff,pscnt);
404 if (suwcnt) {
405 int i;
406 if((setup = (uint16 *)malloc(suwcnt*sizeof(uint16))) == NULL) {
407 DEBUG(0,("reply_trans: setup malloc fail for %d bytes !\n", (int)(suwcnt * sizeof(uint16))));
408 END_PROFILE(SMBtrans);
409 return(ERROR(ERRDOS,ERRnomem));
411 for (i=0;i<suwcnt;i++)
412 setup[i] = SVAL(inbuf,smb_vwv14+i*SIZEOFWORD);
416 if (pscnt < tpscnt || dscnt < tdscnt) {
417 /* We need to send an interim response then receive the rest
418 of the parameter/data bytes */
419 outsize = set_message(outbuf,0,0,True);
420 show_msg(outbuf);
421 send_smb(smbd_server_fd(),outbuf);
424 /* receive the rest of the trans packet */
425 while (pscnt < tpscnt || dscnt < tdscnt) {
426 BOOL ret;
427 int pcnt,poff,dcnt,doff,pdisp,ddisp;
429 ret = receive_next_smb(inbuf,bufsize,SMB_SECONDARY_WAIT);
431 if ((ret && (CVAL(inbuf, smb_com) != SMBtranss)) || !ret) {
432 if(ret) {
433 DEBUG(0,("reply_trans: Invalid secondary trans packet\n"));
434 } else {
435 DEBUG(0,("reply_trans: %s in getting secondary trans response.\n",
436 (smb_read_error == READ_ERROR) ? "error" : "timeout" ));
438 if (params)
439 free(params);
440 if (data)
441 free(data);
442 if (setup)
443 free(setup);
444 END_PROFILE(SMBtrans);
445 return(ERROR(ERRSRV,ERRerror));
448 show_msg(inbuf);
450 tpscnt = SVAL(inbuf,smb_vwv0);
451 tdscnt = SVAL(inbuf,smb_vwv1);
453 pcnt = SVAL(inbuf,smb_vwv2);
454 poff = SVAL(inbuf,smb_vwv3);
455 pdisp = SVAL(inbuf,smb_vwv4);
457 dcnt = SVAL(inbuf,smb_vwv5);
458 doff = SVAL(inbuf,smb_vwv6);
459 ddisp = SVAL(inbuf,smb_vwv7);
461 pscnt += pcnt;
462 dscnt += dcnt;
464 if (dscnt > tdscnt || pscnt > tpscnt) {
465 exit_server("invalid trans parameters\n");
468 if (pcnt)
469 memcpy(params+pdisp,smb_base(inbuf)+poff,pcnt);
470 if (dcnt)
471 memcpy(data+ddisp,smb_base(inbuf)+doff,dcnt);
475 DEBUG(3,("trans <%s> data=%d params=%d setup=%d\n",
476 name,tdscnt,tpscnt,suwcnt));
479 * WinCE wierdness....
482 if (name[0] == '\\' && (StrnCaseCmp(&name[1],local_machine, strlen(local_machine)) == 0) &&
483 (name[strlen(local_machine)+1] == '\\'))
484 name_offset = strlen(local_machine)+1;
486 if (strncmp(&name[name_offset],"\\PIPE\\",strlen("\\PIPE\\")) == 0) {
487 DEBUG(5,("calling named_pipe\n"));
488 outsize = named_pipe(conn,vuid,outbuf,
489 name+name_offset+strlen("\\PIPE\\"),setup,data,params,
490 suwcnt,tdscnt,tpscnt,msrcnt,mdrcnt,mprcnt);
491 } else {
492 DEBUG(3,("invalid pipe name\n"));
493 outsize = 0;
497 if (data)
498 free(data);
499 if (params)
500 free(params);
501 if (setup)
502 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(ERRSRV,ERRnosupport));
517 END_PROFILE(SMBtrans);
518 return(outsize);
520 #undef OLD_NTDOMAIN