Fairly large change to printing code.
[Samba.git] / source / smbd / ipc.c
blob91b221968f27bbfc33ae29c0279827af606438d5
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_NT(STATUS_BUFFER_OVERFLOW);
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 = 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(-1);
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 DEBUG(1,("api_fd_reply: INVALID PIPE HANDLE: %x\n", pnum));
285 return api_no_reply(outbuf, mdrcnt);
288 DEBUG(3,("Got API command 0x%x on pipe \"%s\" (pnum %x)", subcommand, p->name, pnum));
290 /* record maximum data length that can be transmitted in an SMBtrans */
291 p->max_trans_reply = mdrcnt;
293 DEBUG(10,("api_fd_reply: p:%p max_trans_reply: %d\n", p, p->max_trans_reply));
295 switch (subcommand) {
296 case 0x26:
297 /* dce/rpc command */
298 reply = write_to_pipe(p, data, tdscnt);
299 if (reply)
300 reply = api_rpc_trans_reply(outbuf, p);
301 break;
302 case 0x53:
303 /* Wait Named Pipe Handle state */
304 reply = api_WNPHS(outbuf, p, params, tpscnt);
305 break;
306 case 0x01:
307 /* Set Named Pipe Handle state */
308 reply = api_SNPHS(outbuf, p, params, tpscnt);
309 break;
312 if (!reply)
313 return api_no_reply(outbuf, mdrcnt);
315 return -1;
318 /****************************************************************************
319 handle named pipe commands
320 ****************************************************************************/
321 static int named_pipe(connection_struct *conn,uint16 vuid, char *outbuf,char *name,
322 uint16 *setup,char *data,char *params,
323 int suwcnt,int tdscnt,int tpscnt,
324 int msrcnt,int mdrcnt,int mprcnt)
326 DEBUG(3,("named pipe command on <%s> name\n", name));
328 if (strequal(name,"LANMAN"))
329 return api_reply(conn,vuid,outbuf,data,params,tdscnt,tpscnt,mdrcnt,mprcnt);
331 if (strequal(name,"WKSSVC") ||
332 strequal(name,"SRVSVC") ||
333 strequal(name,"WINREG") ||
334 strequal(name,"SAMR") ||
335 strequal(name,"LSARPC"))
337 DEBUG(4,("named pipe command from Win95 (wow!)\n"));
338 return api_fd_reply(conn,vuid,outbuf,setup,data,params,suwcnt,tdscnt,tpscnt,mdrcnt,mprcnt);
341 if (strlen(name) < 1)
342 return api_fd_reply(conn,vuid,outbuf,setup,data,params,suwcnt,tdscnt,tpscnt,mdrcnt,mprcnt);
344 if (setup)
345 DEBUG(3,("unknown named pipe: setup 0x%X setup1=%d\n", (int)setup[0],(int)setup[1]));
347 return 0;
351 /****************************************************************************
352 Reply to a SMBtrans.
353 ****************************************************************************/
355 int reply_trans(connection_struct *conn, char *inbuf,char *outbuf, int size, int bufsize)
357 fstring name;
358 int name_offset = 0;
359 char *data=NULL,*params=NULL;
360 uint16 *setup=NULL;
361 int outsize = 0;
362 uint16 vuid = SVAL(inbuf,smb_uid);
363 int tpscnt = SVAL(inbuf,smb_vwv0);
364 int tdscnt = SVAL(inbuf,smb_vwv1);
365 int mprcnt = SVAL(inbuf,smb_vwv2);
366 int mdrcnt = SVAL(inbuf,smb_vwv3);
367 int msrcnt = CVAL(inbuf,smb_vwv4);
368 BOOL close_on_completion = BITSETW(inbuf+smb_vwv5,0);
369 BOOL one_way = BITSETW(inbuf+smb_vwv5,1);
370 int pscnt = SVAL(inbuf,smb_vwv9);
371 int psoff = SVAL(inbuf,smb_vwv10);
372 int dscnt = SVAL(inbuf,smb_vwv11);
373 int dsoff = SVAL(inbuf,smb_vwv12);
374 int suwcnt = CVAL(inbuf,smb_vwv13);
375 START_PROFILE(SMBtrans);
377 memset(name, '\0',sizeof(name));
378 srvstr_pull_buf(inbuf, name, smb_buf(inbuf), sizeof(name), STR_TERMINATE);
380 if (dscnt > tdscnt || pscnt > tpscnt) {
381 exit_server("invalid trans parameters");
384 if (tdscnt) {
385 if((data = (char *)malloc(tdscnt)) == NULL) {
386 DEBUG(0,("reply_trans: data malloc fail for %d bytes !\n", tdscnt));
387 END_PROFILE(SMBtrans);
388 return(ERROR_DOS(ERRDOS,ERRnomem));
390 memcpy(data,smb_base(inbuf)+dsoff,dscnt);
393 if (tpscnt) {
394 if((params = (char *)malloc(tpscnt)) == NULL) {
395 DEBUG(0,("reply_trans: param malloc fail for %d bytes !\n", tpscnt));
396 END_PROFILE(SMBtrans);
397 return(ERROR_DOS(ERRDOS,ERRnomem));
399 memcpy(params,smb_base(inbuf)+psoff,pscnt);
402 if (suwcnt) {
403 int i;
404 if((setup = (uint16 *)malloc(suwcnt*sizeof(uint16))) == NULL) {
405 DEBUG(0,("reply_trans: setup malloc fail for %d bytes !\n", (int)(suwcnt * sizeof(uint16))));
406 END_PROFILE(SMBtrans);
407 return(ERROR_DOS(ERRDOS,ERRnomem));
409 for (i=0;i<suwcnt;i++)
410 setup[i] = SVAL(inbuf,smb_vwv14+i*SIZEOFWORD);
414 if (pscnt < tpscnt || dscnt < tdscnt) {
415 /* We need to send an interim response then receive the rest
416 of the parameter/data bytes */
417 outsize = set_message(outbuf,0,0,True);
418 show_msg(outbuf);
419 if (!send_smb(smbd_server_fd(),outbuf))
420 exit_server("reply_trans: send_smb failed.");
423 /* receive the rest of the trans packet */
424 while (pscnt < tpscnt || dscnt < tdscnt) {
425 BOOL ret;
426 int pcnt,poff,dcnt,doff,pdisp,ddisp;
428 ret = receive_next_smb(inbuf,bufsize,SMB_SECONDARY_WAIT);
430 if ((ret && (CVAL(inbuf, smb_com) != SMBtranss)) || !ret) {
431 if(ret) {
432 DEBUG(0,("reply_trans: Invalid secondary trans packet\n"));
433 } else {
434 DEBUG(0,("reply_trans: %s in getting secondary trans response.\n",
435 (smb_read_error == READ_ERROR) ? "error" : "timeout" ));
437 SAFE_FREE(params);
438 SAFE_FREE(data);
439 SAFE_FREE(setup);
440 END_PROFILE(SMBtrans);
441 return(ERROR_DOS(ERRSRV,ERRerror));
444 show_msg(inbuf);
446 tpscnt = SVAL(inbuf,smb_vwv0);
447 tdscnt = SVAL(inbuf,smb_vwv1);
449 pcnt = SVAL(inbuf,smb_vwv2);
450 poff = SVAL(inbuf,smb_vwv3);
451 pdisp = SVAL(inbuf,smb_vwv4);
453 dcnt = SVAL(inbuf,smb_vwv5);
454 doff = SVAL(inbuf,smb_vwv6);
455 ddisp = SVAL(inbuf,smb_vwv7);
457 pscnt += pcnt;
458 dscnt += dcnt;
460 if (dscnt > tdscnt || pscnt > tpscnt) {
461 exit_server("invalid trans parameters");
464 if (pcnt)
465 memcpy(params+pdisp,smb_base(inbuf)+poff,pcnt);
466 if (dcnt)
467 memcpy(data+ddisp,smb_base(inbuf)+doff,dcnt);
471 DEBUG(3,("trans <%s> data=%d params=%d setup=%d\n",
472 name,tdscnt,tpscnt,suwcnt));
475 * WinCE wierdness....
478 if (name[0] == '\\' && (StrnCaseCmp(&name[1],local_machine, strlen(local_machine)) == 0) &&
479 (name[strlen(local_machine)+1] == '\\'))
480 name_offset = strlen(local_machine)+1;
482 if (strnequal(&name[name_offset], "\\PIPE", strlen("\\PIPE"))) {
483 name_offset += strlen("\\PIPE");
485 /* Win9x weirdness. When talking to a unicode server Win9x
486 only sends \PIPE instead of \PIPE\ */
488 if (name[name_offset] == '\\')
489 name_offset++;
491 DEBUG(5,("calling named_pipe\n"));
492 outsize = named_pipe(conn,vuid,outbuf,
493 name+name_offset,setup,data,params,
494 suwcnt,tdscnt,tpscnt,msrcnt,mdrcnt,mprcnt);
495 } else {
496 DEBUG(3,("invalid pipe name\n"));
497 outsize = 0;
501 SAFE_FREE(data);
502 SAFE_FREE(params);
503 SAFE_FREE(setup);
505 if (close_on_completion)
506 close_cnum(conn,vuid);
508 if (one_way) {
509 END_PROFILE(SMBtrans);
510 return(-1);
513 if (outsize == 0) {
514 END_PROFILE(SMBtrans);
515 return(ERROR_DOS(ERRSRV,ERRnosupport));
518 END_PROFILE(SMBtrans);
519 return(outsize);