s3-rpc_server: Don't segfault if there are not handles to free.
[kai/samba.git] / source3 / rpc_server / rpc_handles.c
1 /* 
2  *  Unix SMB/CIFS implementation.
3  *  RPC Pipe client / server routines
4  *  Copyright (C) Andrew Tridgell              1992-1997,
5  *  Copyright (C) Luke Kenneth Casson Leighton 1996-1997,
6  *  Copyright (C) Jeremy Allison                           2001.
7  *  
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 3 of the License, or
11  *  (at your option) any later version.
12  *  
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *  
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
20  */
21
22 #include "includes.h"
23 #include "../librpc/gen_ndr/ndr_lsa.h"
24 #include "../librpc/gen_ndr/ndr_samr.h"
25 #include "auth.h"
26 #include "ntdomain.h"
27 #include "rpc_server/rpc_ncacn_np.h"
28
29 #undef DBGC_CLASS
30 #define DBGC_CLASS DBGC_RPC_SRV
31
32 /*
33  * Handle database - stored per pipe.
34  */
35
36 struct dcesrv_handle {
37         struct dcesrv_handle *prev, *next;
38         struct policy_handle wire_handle;
39         uint32_t access_granted;
40         void *data;
41 };
42
43 struct handle_list {
44         struct dcesrv_handle *handles;  /* List of pipe handles. */
45         size_t count;                   /* Current number of handles. */
46         size_t pipe_ref_count;          /* Number of pipe handles referring
47                                          * to this tree. */
48 };
49
50 /* This is the max handles across all instances of a pipe name. */
51 #ifndef MAX_OPEN_POLS
52 #define MAX_OPEN_POLS 2048
53 #endif
54
55 /****************************************************************************
56  Hack as handles need to be persisant over lsa pipe closes so long as a samr
57  pipe is open. JRA.
58 ****************************************************************************/
59
60 static bool is_samr_lsa_pipe(const struct ndr_syntax_id *syntax)
61 {
62         return (ndr_syntax_id_equal(syntax, &ndr_table_samr.syntax_id)
63                 || ndr_syntax_id_equal(syntax, &ndr_table_lsarpc.syntax_id));
64 }
65
66 size_t num_pipe_handles(struct pipes_struct *p)
67 {
68         if (p->pipe_handles == NULL) {
69                 return 0;
70         }
71         return p->pipe_handles->count;
72 }
73
74 /****************************************************************************
75  Initialise a policy handle list on a pipe. Handle list is shared between all
76  pipes of the same name.
77 ****************************************************************************/
78
79 bool init_pipe_handles(struct pipes_struct *p, const struct ndr_syntax_id *syntax)
80 {
81         struct pipes_struct *plist;
82         struct handle_list *hl;
83
84         for (plist = get_first_internal_pipe();
85              plist;
86              plist = get_next_internal_pipe(plist)) {
87                 struct pipe_rpc_fns *p_ctx;
88                 bool stop = false;
89
90                 for (p_ctx = plist->contexts;
91                      p_ctx != NULL;
92                      p_ctx = p_ctx->next) {
93                         if (ndr_syntax_id_equal(syntax, &p_ctx->syntax)) {
94                                 stop = true;
95                                 break;
96                         }
97                         if (is_samr_lsa_pipe(&p_ctx->syntax)
98                             && is_samr_lsa_pipe(syntax)) {
99                                 /*
100                                  * samr and lsa share a handle space (same process
101                                  * under Windows?)
102                                  */
103                                 stop = true;
104                                 break;
105                         }
106                 }
107
108                 if (stop) {
109                         break;
110                 }
111         }
112
113         if (plist != NULL) {
114                 hl = plist->pipe_handles;
115                 if (hl == NULL) {
116                         return false;
117                 }
118         } else {
119                 /*
120                  * First open, we have to create the handle list
121                  */
122                 hl = talloc_zero(NULL, struct handle_list);
123                 if (hl == NULL) {
124                         return false;
125                 }
126
127                 DEBUG(10,("init_pipe_handle_list: created handle list for "
128                           "pipe %s\n",
129                           get_pipe_name_from_syntax(talloc_tos(), syntax)));
130         }
131
132         /*
133          * One more pipe is using this list.
134          */
135
136         hl->pipe_ref_count++;
137
138         /*
139          * Point this pipe at this list.
140          */
141
142         p->pipe_handles = hl;
143
144         DEBUG(10,("init_pipe_handle_list: pipe_handles ref count = %lu for "
145                   "pipe %s\n", (unsigned long)p->pipe_handles->pipe_ref_count,
146                   get_pipe_name_from_syntax(talloc_tos(), syntax)));
147
148         return True;
149 }
150
151 /****************************************************************************
152   find first available policy slot.  creates a policy handle for you.
153
154   If "data_ptr" is given, this must be a talloc'ed object, create_policy_hnd
155   talloc_moves this into the handle. If the policy_hnd is closed,
156   data_ptr is TALLOC_FREE()'ed
157 ****************************************************************************/
158
159 static struct dcesrv_handle *create_rpc_handle_internal(struct pipes_struct *p,
160                                 struct policy_handle *hnd, void *data_ptr)
161 {
162         struct dcesrv_handle *rpc_hnd;
163         static uint32 pol_hnd_low  = 0;
164         static uint32 pol_hnd_high = 0;
165         time_t t = time(NULL);
166
167         if (p->pipe_handles->count > MAX_OPEN_POLS) {
168                 DEBUG(0,("create_policy_hnd: ERROR: too many handles (%d) on this pipe.\n",
169                                 (int)p->pipe_handles->count));
170                 return NULL;
171         }
172
173         rpc_hnd = talloc_zero(p->pipe_handles, struct dcesrv_handle);
174         if (!rpc_hnd) {
175                 DEBUG(0,("create_policy_hnd: ERROR: out of memory!\n"));
176                 return NULL;
177         }
178
179         if (data_ptr != NULL) {
180                 rpc_hnd->data = talloc_move(rpc_hnd, &data_ptr);
181         }
182
183         pol_hnd_low++;
184         if (pol_hnd_low == 0) {
185                 pol_hnd_high++;
186         }
187
188         /* first bit must be null */
189         SIVAL(&rpc_hnd->wire_handle.handle_type, 0 , 0);
190
191         /* second bit is incrementing */
192         SIVAL(&rpc_hnd->wire_handle.uuid.time_low, 0 , pol_hnd_low);
193         SSVAL(&rpc_hnd->wire_handle.uuid.time_mid, 0 , pol_hnd_high);
194         SSVAL(&rpc_hnd->wire_handle.uuid.time_hi_and_version, 0, (pol_hnd_high >> 16));
195
196         /* split the current time into two 16 bit values */
197
198         /* something random */
199         SSVAL(rpc_hnd->wire_handle.uuid.clock_seq, 0, (t >> 16));
200         /* something random */
201         SSVAL(rpc_hnd->wire_handle.uuid.node, 0, t);
202         /* something more random */
203         SIVAL(rpc_hnd->wire_handle.uuid.node, 2, sys_getpid());
204
205         DLIST_ADD(p->pipe_handles->handles, rpc_hnd);
206         p->pipe_handles->count++;
207
208         *hnd = rpc_hnd->wire_handle;
209
210         DEBUG(4, ("Opened policy hnd[%d] ", (int)p->pipe_handles->count));
211         dump_data(4, (uint8_t *)hnd, sizeof(*hnd));
212
213         return rpc_hnd;
214 }
215
216 bool create_policy_hnd(struct pipes_struct *p, struct policy_handle *hnd,
217                        void *data_ptr)
218 {
219         struct dcesrv_handle *rpc_hnd;
220
221         rpc_hnd = create_rpc_handle_internal(p, hnd, data_ptr);
222         if (rpc_hnd == NULL) {
223                 return false;
224         }
225         return true;
226 }
227
228 /****************************************************************************
229   find policy by handle - internal version.
230 ****************************************************************************/
231
232 static struct dcesrv_handle *find_policy_by_hnd_internal(struct pipes_struct *p,
233                                 const struct policy_handle *hnd, void **data_p)
234 {
235         struct dcesrv_handle *h;
236         unsigned int count;
237
238         if (data_p) {
239                 *data_p = NULL;
240         }
241
242         count = 0;
243         for (h = p->pipe_handles->handles; h != NULL; h = h->next) {
244                 if (memcmp(&h->wire_handle, hnd, sizeof(*hnd)) == 0) {
245                         DEBUG(4,("Found policy hnd[%u] ", count));
246                         dump_data(4, (const uint8 *)hnd, sizeof(*hnd));
247                         if (data_p) {
248                                 *data_p = h->data;
249                         }
250                         return h;
251                 }
252                 count++;
253         }
254
255         DEBUG(4,("Policy not found: "));
256         dump_data(4, (const uint8_t *)hnd, sizeof(*hnd));
257
258         p->bad_handle_fault_state = true;
259
260         return NULL;
261 }
262
263 /****************************************************************************
264   find policy by handle
265 ****************************************************************************/
266
267 bool find_policy_by_hnd(struct pipes_struct *p, const struct policy_handle *hnd,
268                         void **data_p)
269 {
270         struct dcesrv_handle *rpc_hnd;
271
272         rpc_hnd = find_policy_by_hnd_internal(p, hnd, data_p);
273         if (rpc_hnd == NULL) {
274                 return false;
275         }
276         return true;
277 }
278
279 /****************************************************************************
280   Close a policy.
281 ****************************************************************************/
282
283 bool close_policy_hnd(struct pipes_struct *p, struct policy_handle *hnd)
284 {
285         struct dcesrv_handle *rpc_hnd;
286
287         rpc_hnd = find_policy_by_hnd_internal(p, hnd, NULL);
288
289         if (rpc_hnd == NULL) {
290                 DEBUG(3, ("Error closing policy (policy not found)\n"));
291                 return false;
292         }
293
294         DEBUG(3,("Closed policy\n"));
295
296         p->pipe_handles->count--;
297
298         DLIST_REMOVE(p->pipe_handles->handles, rpc_hnd);
299         TALLOC_FREE(rpc_hnd);
300
301         return true;
302 }
303
304 /****************************************************************************
305  Close a pipe - free the handle set if it was the last pipe reference.
306 ****************************************************************************/
307
308 void close_policy_by_pipe(struct pipes_struct *p)
309 {
310         if (p->pipe_handles == NULL) {
311                 return;
312         }
313
314         p->pipe_handles->pipe_ref_count--;
315
316         if (p->pipe_handles->pipe_ref_count == 0) {
317                 /*
318                  * Last pipe open on this list - free the list.
319                  */
320                 TALLOC_FREE(p->pipe_handles);
321
322                 DEBUG(10,("close_policy_by_pipe: deleted handle list for "
323                           "pipe %s\n",
324                           get_pipe_name_from_syntax(talloc_tos(), &p->syntax)));
325         }
326 }
327
328 /*******************************************************************
329 Shall we allow access to this rpc?  Currently this function
330 implements the 'restrict anonymous' setting by denying access to
331 anonymous users if the restrict anonymous level is > 0.  Further work
332 will be checking a security descriptor to determine whether a user
333 token has enough access to access the pipe.
334 ********************************************************************/
335
336 bool pipe_access_check(struct pipes_struct *p)
337 {
338         /* Don't let anonymous users access this RPC if restrict
339            anonymous > 0 */
340
341         if (lp_restrict_anonymous() > 0) {
342
343                 /* schannel, so we must be ok */
344                 if (p->pipe_bound &&
345                     (p->auth.auth_type == DCERPC_AUTH_TYPE_SCHANNEL)) {
346                         return True;
347                 }
348
349                 if (p->session_info->guest) {
350                         return False;
351                 }
352         }
353
354         return True;
355 }
356
357 void *_policy_handle_create(struct pipes_struct *p, struct policy_handle *hnd,
358                             uint32_t access_granted, size_t data_size,
359                             const char *type, NTSTATUS *pstatus)
360 {
361         struct dcesrv_handle *rpc_hnd;
362         void *data;
363
364         if (p->pipe_handles->count > MAX_OPEN_POLS) {
365                 DEBUG(0, ("policy_handle_create: ERROR: too many handles (%d) "
366                           "on pipe %s.\n", (int)p->pipe_handles->count,
367                           get_pipe_name_from_syntax(talloc_tos(), &p->syntax)));
368                 *pstatus = NT_STATUS_INSUFFICIENT_RESOURCES;
369                 return NULL;
370         }
371
372         data = talloc_size(talloc_tos(), data_size);
373         if (data == NULL) {
374                 *pstatus = NT_STATUS_NO_MEMORY;
375                 return NULL;
376         }
377         talloc_set_name_const(data, type);
378
379         rpc_hnd = create_rpc_handle_internal(p, hnd, data);
380         if (rpc_hnd == NULL) {
381                 TALLOC_FREE(data);
382                 *pstatus = NT_STATUS_NO_MEMORY;
383                 return NULL;
384         }
385         rpc_hnd->access_granted = access_granted;
386         *pstatus = NT_STATUS_OK;
387         return data;
388 }
389
390 void *_policy_handle_find(struct pipes_struct *p,
391                           const struct policy_handle *hnd,
392                           uint32_t access_required,
393                           uint32_t *paccess_granted,
394                           const char *name, const char *location,
395                           NTSTATUS *pstatus)
396 {
397         struct dcesrv_handle *rpc_hnd;
398         void *data;
399
400         rpc_hnd = find_policy_by_hnd_internal(p, hnd, &data);
401         if (rpc_hnd == NULL) {
402                 *pstatus = NT_STATUS_INVALID_HANDLE;
403                 return NULL;
404         }
405         if (strcmp(name, talloc_get_name(data)) != 0) {
406                 DEBUG(10, ("expected %s, got %s\n", name,
407                            talloc_get_name(data)));
408                 *pstatus = NT_STATUS_INVALID_HANDLE;
409                 return NULL;
410         }
411         if ((access_required & rpc_hnd->access_granted) != access_required) {
412                 if (geteuid() == sec_initial_uid()) {
413                         DEBUG(4, ("%s: ACCESS should be DENIED (granted: "
414                                   "%#010x; required: %#010x)\n", location,
415                                   rpc_hnd->access_granted, access_required));
416                         DEBUGADD(4,("but overwritten by euid == 0\n"));
417                         goto okay;
418                 }
419                 DEBUG(2,("%s: ACCESS DENIED (granted: %#010x; required: "
420                          "%#010x)\n", location, rpc_hnd->access_granted,
421                          access_required));
422                 *pstatus = NT_STATUS_ACCESS_DENIED;
423                 return NULL;
424         }
425
426  okay:
427         DEBUG(10, ("found handle of type %s\n", talloc_get_name(data)));
428         if (paccess_granted != NULL) {
429                 *paccess_granted = rpc_hnd->access_granted;
430         }
431         *pstatus = NT_STATUS_OK;
432         return data;
433 }