nttrans.c:
[samba.git] / source / 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-1997,
7  *  Copyright (C) Luke Kenneth Casson Leighton 1996-1997,
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 /* this must be larger than the sum of the open files and directories */
32 #define PIPE_HANDLE_OFFSET 0x7000
33
34 extern int DEBUGLEVEL;
35 static pipes_struct *chain_p;
36 static int pipes_open;
37
38 #ifndef MAX_OPEN_PIPES
39 #define MAX_OPEN_PIPES 64
40 #endif
41
42 static pipes_struct *Pipes;
43 static struct bitmap *bmap;
44
45 /****************************************************************************
46   reset pipe chain handle number
47 ****************************************************************************/
48 void reset_chain_p(void)
49 {
50         chain_p = NULL;
51 }
52
53 /****************************************************************************
54   initialise pipe handle states...
55 ****************************************************************************/
56 void init_rpc_pipe_hnd(void)
57 {
58         bmap = bitmap_allocate(MAX_OPEN_PIPES);
59         if (!bmap) {
60                 exit_server("out of memory in init_rpc_pipe_hnd\n");
61         }
62 }
63
64
65 /****************************************************************************
66   find first available file slot
67 ****************************************************************************/
68 pipes_struct *open_rpc_pipe_p(char *pipe_name, 
69                               connection_struct *conn, uint16 vuid)
70 {
71         int i;
72         pipes_struct *p;
73         static int next_pipe;
74
75         DEBUG(4,("Open pipe requested %s (pipes_open=%d)\n",
76                  pipe_name, pipes_open));
77         
78         /* not repeating pipe numbers makes it easier to track things in 
79            log files and prevents client bugs where pipe numbers are reused
80            over connection restarts */
81         if (next_pipe == 0) {
82                 next_pipe = (getpid() ^ time(NULL)) % MAX_OPEN_PIPES;
83         }
84
85         i = bitmap_find(bmap, next_pipe);
86
87         if (i == -1) {
88                 DEBUG(0,("ERROR! Out of pipe structures\n"));
89                 return NULL;
90         }
91
92         next_pipe = (i+1) % MAX_OPEN_PIPES;
93
94         for (p = Pipes; p; p = p->next)
95         {
96                 DEBUG(5,("open pipes: name %s pnum=%x\n", p->name, p->pnum));  
97         }
98
99         p = (pipes_struct *)malloc(sizeof(*p));
100         if (!p) return NULL;
101
102         ZERO_STRUCTP(p);
103         DLIST_ADD(Pipes, p);
104
105         bitmap_set(bmap, i);
106         i += PIPE_HANDLE_OFFSET;
107
108         pipes_open++;
109
110         p->pnum = i;
111
112         p->open = True;
113         p->device_state = 0;
114         p->conn = conn;
115         p->uid  = vuid;
116         
117         p->rhdr.data  = NULL;
118         p->rdata.data = NULL;
119         p->rhdr.offset  = 0;
120         p->rdata.offset = 0;
121         
122         p->file_offset     = 0;
123         p->hdr_offsets     = 0;
124         p->frag_len_left   = 0;
125         p->next_frag_start = 0;
126         
127         fstrcpy(p->name, pipe_name);
128         
129         DEBUG(4,("Opened pipe %s with handle %x (pipes_open=%d)\n",
130                  pipe_name, i, pipes_open));
131         
132         chain_p = p;
133         
134         /* OVERWRITE p as a temp variable, to display all open pipes */ 
135         for (p = Pipes; p; p = p->next)
136         {
137                 DEBUG(5,("open pipes: name %s pnum=%x\n", p->name, p->pnum));  
138         }
139
140         return chain_p;
141 }
142
143
144 /****************************************************************************
145  reads data from a pipe.
146
147  headers are interspersed with the data at regular intervals.  by the time
148  this function is called, the start of the data could possibly have been
149  read by an SMBtrans (file_offset != 0).
150
151  calling create_rpc_request() here is a fudge.  the data should already
152  have been prepared into arrays of headers + data stream sections.
153
154  ****************************************************************************/
155 int read_pipe(pipes_struct *p, char *data, uint32 pos, int n)
156 {
157         int num = 0;
158         int len = 0;
159         uint32 hdr_num = 0;
160         int data_hdr_pos;
161         int data_pos;
162
163         DEBUG(6,("read_pipe: %x", p->pnum));
164
165         DEBUG(6,("name: %s open: %s pos: %d len: %d",
166                  p->name,
167                  BOOLSTR(p->open),
168                  pos, n));
169
170         if (!p || !p->open) {
171                 DEBUG(6,("pipe not open\n"));
172                 return -1;              
173         }
174
175
176         if (p->rhdr.data == NULL || p->rhdr.data->data == NULL ||
177             p->rhdr.data->data_used == 0) {
178                 return 0;
179         }
180
181         DEBUG(6,("read_pipe: p: %p file_offset: %d file_pos: %d\n",
182                  p, p->file_offset, n));
183         DEBUG(6,("read_pipe: frag_len_left: %d next_frag_start: %d\n",
184                  p->frag_len_left, p->next_frag_start));
185
186         /* the read request starts from where the SMBtrans2 left off. */
187         data_pos     = p->file_offset - p->hdr_offsets;
188         data_hdr_pos = p->file_offset;
189
190         len = mem_buf_len(p->rhdr.data);
191         num = len - (int)data_pos;
192         
193         DEBUG(6,("read_pipe: len: %d num: %d n: %d\n", len, num, n));
194         
195         if (num > n) num = n;
196         if (num <= 0) {
197                 DEBUG(5,("read_pipe: 0 or -ve data length\n"));
198                 return 0;
199         }
200
201         if (!IS_BITS_SET_ALL(p->hdr.flags, RPC_FLG_LAST)) {
202                 /* intermediate fragment - possibility of another header */
203                 
204                 DEBUG(5,("read_pipe: frag_len: %d data_pos: %d data_hdr_pos: %d\n",
205                          p->hdr.frag_len, data_pos, data_hdr_pos));
206                 
207                 if (data_hdr_pos == p->next_frag_start) {
208                         DEBUG(6,("read_pipe: next fragment header\n"));
209
210                         /* this is subtracted from the total data bytes, later */
211                         hdr_num = 0x18;
212
213                         /* create and copy in a new header. */
214                         create_rpc_reply(p, data_pos, p->rdata.offset);
215                         mem_buf_copy(data, p->rhdr.data, 0, 0x18);
216                         
217                         data += 0x18;
218                         p->frag_len_left = p->hdr.frag_len;
219                         p->next_frag_start += p->hdr.frag_len;
220                         p->hdr_offsets += 0x18;
221                 }                       
222                 
223         }
224         
225         if (num < hdr_num) {
226                 DEBUG(5,("read_pipe: warning - data read only part of a header\n"));
227         }
228
229         DEBUG(6,("read_pipe: adjusted data_pos: %d num-hdr_num: %d\n",
230                  data_pos, num - hdr_num));
231         mem_buf_copy(data, p->rhdr.data, data_pos, num - hdr_num);
232         
233         data_pos += num;
234         data_hdr_pos += num;
235         
236         if (hdr_num == 0x18 && num == 0x18) {
237                 DEBUG(6,("read_pipe: just header read\n"));
238
239                 /* advance to the next fragment */
240                 p->frag_len_left -= 0x18; 
241         } else if (data_hdr_pos == p->next_frag_start) {
242                 DEBUG(6,("read_pipe: next fragment expected\n"));
243         }
244
245         p->file_offset  += num;
246         
247         return num;
248 }
249
250
251 /****************************************************************************
252   set device state on a pipe.  exactly what this is for is unknown...
253 ****************************************************************************/
254 BOOL set_rpc_pipe_hnd_state(pipes_struct *p, uint16 device_state)
255 {
256         if (p == NULL) return False;
257
258         if (p->open) {
259                 DEBUG(3,("%s Setting pipe device state=%x on pipe (name=%s)\n",
260                          timestring(), device_state, p->name));
261
262                 p->device_state = device_state;
263                 
264                 return True;
265         } 
266
267         DEBUG(3,("%s Error setting pipe device state=%x (name=%s)\n",
268                  timestring(), device_state, p->name));
269         return False;
270 }
271
272
273 /****************************************************************************
274   close an rpc pipe
275 ****************************************************************************/
276 BOOL close_rpc_pipe_hnd(pipes_struct *p, connection_struct *conn)
277 {
278         if (!p) {
279                 DEBUG(0,("Invalid pipe in close_rpc_pipe_hnd\n"));
280                 return False;
281         }
282
283         mem_buf_free(&(p->rdata.data));
284         mem_buf_free(&(p->rhdr .data));
285
286         bitmap_clear(bmap, p->pnum - PIPE_HANDLE_OFFSET);
287
288         pipes_open--;
289
290         DEBUG(4,("closed pipe name %s pnum=%x (pipes_open=%d)\n", 
291                  p->name, p->pnum, pipes_open));  
292
293         DLIST_REMOVE(Pipes, p);
294
295         ZERO_STRUCTP(p);
296
297         free(p);
298         
299         return True;
300 }
301
302 /****************************************************************************
303   close an rpc pipe
304 ****************************************************************************/
305 pipes_struct *get_rpc_pipe_p(char *buf, int where)
306 {
307         int pnum = SVAL(buf,where);
308
309         if (chain_p) return chain_p;
310
311         return get_rpc_pipe(pnum);
312 }
313
314 /****************************************************************************
315   close an rpc pipe
316 ****************************************************************************/
317 pipes_struct *get_rpc_pipe(int pnum)
318 {
319         pipes_struct *p;
320
321         DEBUG(4,("search for pipe pnum=%x\n", pnum));
322
323         for (p=Pipes;p;p=p->next)
324         {
325                 DEBUG(5,("pipe name %s pnum=%x (pipes_open=%d)\n", 
326                           p->name, p->pnum, pipes_open));  
327         }
328
329         for (p=Pipes;p;p=p->next)
330         {
331                 if (p->pnum == pnum)
332                 {
333                         chain_p = p;
334                         return p;
335                 }
336         }
337
338         return NULL;
339 }
340