adding error checking in parsing code
[jra/samba/.git] / source3 / rpc_server / srv_pipe_hnd.c
1
2 /* 
3  *  Unix SMB/Netbios implementation.
4  *  Version 1.9.
5  *  RPC Pipe client / server routines
6  *  Copyright (C) Andrew Tridgell              1992-1998,
7  *  Copyright (C) Luke Kenneth Casson Leighton 1996-1998,
8  *  
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.
13  *  
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.
18  *  
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.
22  */
23
24
25 #include "includes.h"
26
27
28 #define PIPE            "\\PIPE\\"
29 #define PIPELEN         strlen(PIPE)
30
31 extern int DEBUGLEVEL;
32 static pipes_struct *chain_p;
33 static int pipes_open;
34
35 #ifndef MAX_OPEN_PIPES
36 #define MAX_OPEN_PIPES 64
37 #endif
38
39 static pipes_struct *Pipes;
40 static struct bitmap *bmap;
41
42 /* this must be larger than the sum of the open files and directories */
43 static int pipe_handle_offset;
44
45 /****************************************************************************
46  Set the pipe_handle_offset. Called from smbd/files.c
47 ****************************************************************************/
48
49 void set_pipe_handle_offset(int max_open_files)
50 {
51   if(max_open_files < 0x7000)
52     pipe_handle_offset = 0x7000;
53   else
54     pipe_handle_offset = max_open_files + 10; /* For safety. :-) */
55 }
56
57 /****************************************************************************
58   reset pipe chain handle number
59 ****************************************************************************/
60 void reset_chain_p(void)
61 {
62         chain_p = NULL;
63 }
64
65 /****************************************************************************
66   initialise pipe handle states...
67 ****************************************************************************/
68 void init_rpc_pipe_hnd(void)
69 {
70         bmap = bitmap_allocate(MAX_OPEN_PIPES);
71         if (!bmap) {
72                 exit_server("out of memory in init_rpc_pipe_hnd\n");
73         }
74 }
75
76
77 /****************************************************************************
78   find first available file slot
79 ****************************************************************************/
80 pipes_struct *open_rpc_pipe_p(char *pipe_name, 
81                               connection_struct *conn, uint16 vuid)
82 {
83         int i;
84         pipes_struct *p;
85         static int next_pipe;
86
87         DEBUG(4,("Open pipe requested %s (pipes_open=%d)\n",
88                  pipe_name, pipes_open));
89         
90         /* not repeating pipe numbers makes it easier to track things in 
91            log files and prevents client bugs where pipe numbers are reused
92            over connection restarts */
93         if (next_pipe == 0) {
94                 next_pipe = (getpid() ^ time(NULL)) % MAX_OPEN_PIPES;
95         }
96
97         i = bitmap_find(bmap, next_pipe);
98
99         if (i == -1) {
100                 DEBUG(0,("ERROR! Out of pipe structures\n"));
101                 return NULL;
102         }
103
104         next_pipe = (i+1) % MAX_OPEN_PIPES;
105
106         for (p = Pipes; p; p = p->next)
107         {
108                 DEBUG(5,("open pipes: name %s pnum=%x\n", p->name, p->pnum));  
109         }
110
111         p = (pipes_struct *)malloc(sizeof(*p));
112         if (!p) return NULL;
113
114         ZERO_STRUCTP(p);
115         DLIST_ADD(Pipes, p);
116
117         bitmap_set(bmap, i);
118         i += pipe_handle_offset;
119
120         pipes_open++;
121
122         p->pnum = i;
123
124         p->open = True;
125         p->device_state = 0;
126         p->priority = 0;
127         p->conn = conn;
128         p->vuid  = vuid;
129         
130         p->rhdr.data  = NULL;
131         p->rdata.data = NULL;
132         p->rhdr.offset  = 0;
133         p->rdata.offset = 0;
134         
135         p->file_offset     = 0;
136         p->prev_pdu_file_offset = 0;
137         p->hdr_offsets     = 0;
138         
139         p->ntlmssp_validated = False;
140         p->ntlmssp_auth      = False;
141         
142         fstrcpy(p->name, pipe_name);
143
144         DEBUG(4,("Opened pipe %s with handle %x (pipes_open=%d)\n",
145                  pipe_name, i, pipes_open));
146         
147         chain_p = p;
148         
149         /* OVERWRITE p as a temp variable, to display all open pipes */ 
150         for (p = Pipes; p; p = p->next)
151         {
152                 DEBUG(5,("open pipes: name %s pnum=%x\n", p->name, p->pnum));  
153         }
154
155         return chain_p;
156 }
157
158
159 /****************************************************************************
160  writes data to a pipe.
161
162  SERIOUSLY ALPHA CODE!
163  ****************************************************************************/
164 ssize_t write_pipe(pipes_struct *p, char *data, size_t n)
165 {
166         prs_struct pd;
167         struct mem_buf data_buf;
168
169         DEBUG(6,("write_pipe: %x", p->pnum));
170
171         DEBUG(6,("name: %s open: %s len: %d",
172                  p->name, BOOLSTR(p->open), n));
173
174         dump_data(50, data, n);
175
176         /* fake up a data buffer from the write_pipe data parameters */
177         mem_create(&data_buf, data, 0, n, 0, False);
178         data_buf.offset.start = 0;
179         data_buf.offset.end   = n;
180
181         /* fake up a parsing structure */
182         pd.data = &data_buf;
183         pd.align = 4;
184         pd.io = True;
185         pd.error = False;
186         pd.offset = 0;
187
188         return rpc_command(p, &pd) ? ((ssize_t)n) : -1;
189 }
190
191
192 /****************************************************************************
193  reads data from a pipe.
194
195  headers are interspersed with the data at regular intervals.  by the time
196  this function is called, the start of the data could possibly have been
197  read by an SMBtrans (file_offset != 0).
198
199  calling create_rpc_reply() here is a fudge.  the data should already
200  have been prepared into arrays of headers + data stream sections.
201
202  ****************************************************************************/
203 int read_pipe(pipes_struct *p, char *data, uint32 pos, int n)
204 {
205         int num = 0;
206         int pdu_len = 0;
207         uint32 hdr_num = 0;
208         int pdu_data_sent; /* amount of current pdu already sent */
209         int data_pos; /* entire rpc data sent - no headers, no auth verifiers */
210         int this_pdu_data_pos;
211
212         DEBUG(6,("read_pipe: %x name: %s open: %s pos: %d len: %d",
213                  p->pnum, p->name, BOOLSTR(p->open),
214                  pos, n));
215
216         if (!p || !p->open)
217         {
218                 DEBUG(6,("pipe not open\n"));
219                 return -1;              
220         }
221
222
223         if (p->rhdr.data == NULL || p->rhdr.data->data == NULL ||
224             p->rhdr.data->data_used == 0)
225         {
226                 return 0;
227         }
228
229         DEBUG(6,("read_pipe: p: %p file_offset: %d file_pos: %d\n",
230                  p, p->file_offset, n));
231
232         /* the read request starts from where the SMBtrans2 left off. */
233         data_pos = p->file_offset - p->hdr_offsets;
234         pdu_data_sent = p->file_offset - p->prev_pdu_file_offset;
235         this_pdu_data_pos = (pdu_data_sent == 0) ? 0 : (pdu_data_sent - 0x18);
236
237         if (!IS_BITS_SET_ALL(p->hdr.flags, RPC_FLG_LAST))
238         {
239                 /* intermediate fragment - possibility of another header */
240                 
241                 DEBUG(5,("read_pipe: frag_len: %d data_pos: %d pdu_data_sent: %d\n",
242                          p->hdr.frag_len, data_pos, pdu_data_sent));
243                 
244                 if (pdu_data_sent == 0)
245                 {
246                         DEBUG(6,("read_pipe: next fragment header\n"));
247
248                         /* this is subtracted from the total data bytes, later */
249                         hdr_num = 0x18;
250                         p->hdr_offsets += 0x18;
251                         data_pos -= 0x18;
252
253                         /* create and copy in a new header. */
254                         create_rpc_reply(p, data_pos, p->rdata.offset);
255                 }                       
256         }
257         
258         pdu_len = mem_buf_len(p->rhdr.data);
259         num = pdu_len - this_pdu_data_pos;
260         
261         DEBUG(6,("read_pipe: pdu_len: %d num: %d n: %d\n", pdu_len, num, n));
262         
263         if (num > n) num = n;
264         if (num <= 0)
265         {
266                 DEBUG(5,("read_pipe: 0 or -ve data length\n"));
267                 return 0;
268         }
269
270         if (num < hdr_num)
271         {
272                 DEBUG(5,("read_pipe: warning - data read only part of a header\n"));
273         }
274
275         mem_buf_copy(data, p->rhdr.data, pdu_data_sent, num);
276         
277         p->file_offset  += num;
278         pdu_data_sent  += num;
279         
280         if (hdr_num == 0x18 && num == 0x18)
281         {
282                 DEBUG(6,("read_pipe: just header read\n"));
283         }
284
285         if (pdu_data_sent == p->hdr.frag_len)
286         {
287                 DEBUG(6,("read_pipe: next fragment expected\n"));
288                 p->prev_pdu_file_offset = p->file_offset;
289         }
290
291         return num;
292 }
293
294
295 /****************************************************************************
296   wait device state on a pipe.  exactly what this is for is unknown...
297 ****************************************************************************/
298 BOOL wait_rpc_pipe_hnd_state(pipes_struct *p, uint16 priority)
299 {
300         if (p == NULL) return False;
301
302         if (p->open)
303         {
304                 DEBUG(3,("%s Setting pipe wait state priority=%x on pipe (name=%s)\n",
305                          timestring(), priority, p->name));
306
307                 p->priority = priority;
308                 
309                 return True;
310         } 
311
312         DEBUG(3,("%s Error setting pipe wait state priority=%x (name=%s)\n",
313                  timestring(), priority, p->name));
314         return False;
315 }
316
317
318 /****************************************************************************
319   set device state on a pipe.  exactly what this is for is unknown...
320 ****************************************************************************/
321 BOOL set_rpc_pipe_hnd_state(pipes_struct *p, uint16 device_state)
322 {
323         if (p == NULL) return False;
324
325         if (p->open) {
326                 DEBUG(3,("%s Setting pipe device state=%x on pipe (name=%s)\n",
327                          timestring(), device_state, p->name));
328
329                 p->device_state = device_state;
330                 
331                 return True;
332         } 
333
334         DEBUG(3,("%s Error setting pipe device state=%x (name=%s)\n",
335                  timestring(), device_state, p->name));
336         return False;
337 }
338
339
340 /****************************************************************************
341   close an rpc pipe
342 ****************************************************************************/
343 BOOL close_rpc_pipe_hnd(pipes_struct *p, connection_struct *conn)
344 {
345         if (!p) {
346                 DEBUG(0,("Invalid pipe in close_rpc_pipe_hnd\n"));
347                 return False;
348         }
349
350         mem_buf_free(&(p->rdata.data));
351         mem_buf_free(&(p->rhdr .data));
352
353         bitmap_clear(bmap, p->pnum - pipe_handle_offset);
354
355         pipes_open--;
356
357         DEBUG(4,("closed pipe name %s pnum=%x (pipes_open=%d)\n", 
358                  p->name, p->pnum, pipes_open));  
359
360         DLIST_REMOVE(Pipes, p);
361
362         ZERO_STRUCTP(p);
363
364         free(p);
365         
366         return True;
367 }
368
369 /****************************************************************************
370   close an rpc pipe
371 ****************************************************************************/
372 pipes_struct *get_rpc_pipe_p(char *buf, int where)
373 {
374         int pnum = SVAL(buf,where);
375
376         if (chain_p) return chain_p;
377
378         return get_rpc_pipe(pnum);
379 }
380
381 /****************************************************************************
382   close an rpc pipe
383 ****************************************************************************/
384 pipes_struct *get_rpc_pipe(int pnum)
385 {
386         pipes_struct *p;
387
388         DEBUG(4,("search for pipe pnum=%x\n", pnum));
389
390         for (p=Pipes;p;p=p->next)
391         {
392                 DEBUG(5,("pipe name %s pnum=%x (pipes_open=%d)\n", 
393                           p->name, p->pnum, pipes_open));  
394         }
395
396         for (p=Pipes;p;p=p->next)
397         {
398                 if (p->pnum == pnum)
399                 {
400                         chain_p = p;
401                         return p;
402                 }
403         }
404
405         return NULL;
406 }
407