Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : RAP handlers
4 :
5 : Copyright (C) Volker Lendecke 2004
6 :
7 : This program is free software; you can redistribute it and/or modify
8 : it under the terms of the GNU General Public License as published by
9 : the Free Software Foundation; either version 3 of the License, or
10 : (at your option) any later version.
11 :
12 : This program is distributed in the hope that it will be useful,
13 : but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 : GNU General Public License for more details.
16 :
17 : You should have received a copy of the GNU General Public License
18 : along with this program. If not, see <http://www.gnu.org/licenses/>.
19 : */
20 :
21 : #include "includes.h"
22 : #include "libcli/raw/interfaces.h"
23 : #include "../librpc/gen_ndr/rap.h"
24 : #include "events/events.h"
25 : #include "ntvfs/ipc/proto.h"
26 : #include "librpc/ndr/libndr.h"
27 : #include "param/param.h"
28 :
29 : #define NDR_RETURN(call) do { \
30 : enum ndr_err_code _ndr_err; \
31 : _ndr_err = call; \
32 : if (!NDR_ERR_CODE_IS_SUCCESS(_ndr_err)) { \
33 : return ndr_map_error2ntstatus(_ndr_err); \
34 : } \
35 : } while (0)
36 :
37 : #define RAP_GOTO(call) do { \
38 : result = call; \
39 : if (NT_STATUS_EQUAL(result, NT_STATUS_BUFFER_TOO_SMALL)) {\
40 : goto buffer_overflow; \
41 : } \
42 : if (!NT_STATUS_IS_OK(result)) { \
43 : goto done; \
44 : } \
45 : } while (0)
46 :
47 : #define NDR_GOTO(call) do { \
48 : enum ndr_err_code _ndr_err; \
49 : _ndr_err = call; \
50 : if (!NDR_ERR_CODE_IS_SUCCESS(_ndr_err)) { \
51 : RAP_GOTO(ndr_map_error2ntstatus(_ndr_err)); \
52 : } \
53 : } while (0)
54 :
55 :
56 : #define NERR_notsupported 50
57 :
58 : struct rap_string_heap {
59 : TALLOC_CTX *mem_ctx;
60 : int offset;
61 : int num_strings;
62 : const char **strings;
63 : };
64 :
65 : struct rap_heap_save {
66 : int offset, num_strings;
67 : };
68 :
69 0 : static void rap_heap_save(struct rap_string_heap *heap,
70 : struct rap_heap_save *save)
71 : {
72 0 : save->offset = heap->offset;
73 0 : save->num_strings = heap->num_strings;
74 0 : }
75 :
76 0 : static void rap_heap_restore(struct rap_string_heap *heap,
77 : struct rap_heap_save *save)
78 : {
79 0 : heap->offset = save->offset;
80 0 : heap->num_strings = save->num_strings;
81 0 : }
82 :
83 : struct rap_call {
84 : struct loadparm_context *lp_ctx;
85 :
86 : TALLOC_CTX *mem_ctx;
87 : uint16_t callno;
88 : const char *paramdesc;
89 : const char *datadesc;
90 :
91 : uint16_t status;
92 : uint16_t convert;
93 :
94 : uint16_t rcv_paramlen, rcv_datalen;
95 :
96 : struct ndr_push *ndr_push_param;
97 : struct ndr_push *ndr_push_data;
98 : struct rap_string_heap *heap;
99 :
100 : struct ndr_pull *ndr_pull_param;
101 : struct ndr_pull *ndr_pull_data;
102 :
103 : struct tevent_context *event_ctx;
104 : };
105 :
106 : #define RAPNDR_FLAGS (LIBNDR_FLAG_NOALIGN|LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM);
107 :
108 0 : static struct rap_call *new_rap_srv_call(TALLOC_CTX *mem_ctx,
109 : struct tevent_context *ev_ctx,
110 : struct loadparm_context *lp_ctx,
111 : struct smb_trans2 *trans)
112 : {
113 0 : struct rap_call *call;
114 :
115 0 : call = talloc(mem_ctx, struct rap_call);
116 :
117 0 : if (call == NULL)
118 0 : return NULL;
119 :
120 0 : ZERO_STRUCTP(call);
121 :
122 0 : call->lp_ctx = talloc_reference(call, lp_ctx);
123 0 : call->event_ctx = ev_ctx;
124 :
125 0 : call->mem_ctx = mem_ctx;
126 :
127 0 : call->ndr_pull_param = ndr_pull_init_blob(&trans->in.params, mem_ctx);
128 0 : call->ndr_pull_param->flags = RAPNDR_FLAGS;
129 :
130 0 : call->ndr_pull_data = ndr_pull_init_blob(&trans->in.data, mem_ctx);
131 0 : call->ndr_pull_data->flags = RAPNDR_FLAGS;
132 :
133 0 : call->heap = talloc(mem_ctx, struct rap_string_heap);
134 :
135 0 : if (call->heap == NULL)
136 0 : return NULL;
137 :
138 0 : ZERO_STRUCTP(call->heap);
139 :
140 0 : call->heap->mem_ctx = mem_ctx;
141 :
142 0 : return call;
143 : }
144 :
145 0 : static NTSTATUS rap_srv_pull_word(struct rap_call *call, uint16_t *result)
146 : {
147 0 : enum ndr_err_code ndr_err;
148 :
149 0 : if (*call->paramdesc++ != 'W')
150 0 : return NT_STATUS_INVALID_PARAMETER;
151 :
152 0 : ndr_err = ndr_pull_uint16(call->ndr_pull_param, NDR_SCALARS, result);
153 0 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
154 0 : return ndr_map_error2ntstatus(ndr_err);
155 : }
156 :
157 0 : return NT_STATUS_OK;
158 : }
159 :
160 0 : static NTSTATUS rap_srv_pull_dword(struct rap_call *call, uint32_t *result)
161 : {
162 0 : enum ndr_err_code ndr_err;
163 :
164 0 : if (*call->paramdesc++ != 'D')
165 0 : return NT_STATUS_INVALID_PARAMETER;
166 :
167 0 : ndr_err = ndr_pull_uint32(call->ndr_pull_param, NDR_SCALARS, result);
168 0 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
169 0 : return ndr_map_error2ntstatus(ndr_err);
170 : }
171 :
172 0 : return NT_STATUS_OK;
173 : }
174 :
175 0 : static NTSTATUS rap_srv_pull_string(struct rap_call *call, const char **result)
176 : {
177 0 : enum ndr_err_code ndr_err;
178 0 : char paramdesc = *call->paramdesc++;
179 :
180 0 : if (paramdesc == 'O') {
181 0 : *result = NULL;
182 0 : return NT_STATUS_OK;
183 : }
184 :
185 0 : if (paramdesc != 'z')
186 0 : return NT_STATUS_INVALID_PARAMETER;
187 :
188 0 : ndr_err = ndr_pull_string(call->ndr_pull_param, NDR_SCALARS, result);
189 0 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
190 0 : return ndr_map_error2ntstatus(ndr_err);
191 : }
192 :
193 0 : return NT_STATUS_OK;
194 : }
195 :
196 0 : static NTSTATUS rap_srv_pull_bufsize(struct rap_call *call, uint16_t *bufsize)
197 : {
198 0 : enum ndr_err_code ndr_err;
199 :
200 0 : if ( (*call->paramdesc++ != 'r') || (*call->paramdesc++ != 'L') )
201 0 : return NT_STATUS_INVALID_PARAMETER;
202 :
203 0 : ndr_err = ndr_pull_uint16(call->ndr_pull_param, NDR_SCALARS, bufsize);
204 0 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
205 0 : return ndr_map_error2ntstatus(ndr_err);
206 : }
207 :
208 0 : call->heap->offset = *bufsize;
209 :
210 0 : return NT_STATUS_OK;
211 : }
212 :
213 0 : static NTSTATUS rap_srv_pull_expect_multiple(struct rap_call *call)
214 : {
215 0 : if ( (*call->paramdesc++ != 'e') || (*call->paramdesc++ != 'h') )
216 0 : return NT_STATUS_INVALID_PARAMETER;
217 :
218 0 : return NT_STATUS_OK;
219 : }
220 :
221 0 : static NTSTATUS rap_push_string(struct ndr_push *data_push,
222 : struct rap_string_heap *heap,
223 : const char *str)
224 : {
225 0 : size_t space;
226 :
227 0 : if (str == NULL)
228 0 : str = "";
229 :
230 0 : space = strlen(str)+1;
231 :
232 0 : if (heap->offset < space)
233 0 : return NT_STATUS_BUFFER_TOO_SMALL;
234 :
235 0 : heap->offset -= space;
236 :
237 0 : NDR_RETURN(ndr_push_uint16(data_push, NDR_SCALARS, heap->offset));
238 0 : NDR_RETURN(ndr_push_uint16(data_push, NDR_SCALARS, 0));
239 :
240 0 : heap->strings = talloc_realloc(heap->mem_ctx,
241 : heap->strings,
242 : const char *,
243 : heap->num_strings + 1);
244 :
245 0 : if (heap->strings == NULL)
246 0 : return NT_STATUS_NO_MEMORY;
247 :
248 0 : heap->strings[heap->num_strings] = str;
249 0 : heap->num_strings += 1;
250 :
251 0 : return NT_STATUS_OK;
252 : }
253 :
254 0 : static NTSTATUS _rap_netshareenum(struct rap_call *call)
255 : {
256 0 : struct rap_NetShareEnum r;
257 0 : NTSTATUS result;
258 0 : uint32_t offset_save = 0;
259 0 : struct rap_heap_save heap_save = {0};
260 :
261 0 : RAP_GOTO(rap_srv_pull_word(call, &r.in.level));
262 0 : RAP_GOTO(rap_srv_pull_bufsize(call, &r.in.bufsize));
263 0 : RAP_GOTO(rap_srv_pull_expect_multiple(call));
264 :
265 0 : switch(r.in.level) {
266 0 : case 0:
267 0 : if (strcmp(call->datadesc, "B13") != 0)
268 0 : return NT_STATUS_INVALID_PARAMETER;
269 0 : break;
270 0 : case 1:
271 0 : if (strcmp(call->datadesc, "B13BWz") != 0)
272 0 : return NT_STATUS_INVALID_PARAMETER;
273 0 : break;
274 0 : default:
275 0 : return NT_STATUS_INVALID_PARAMETER;
276 : break;
277 : }
278 :
279 0 : result = rap_netshareenum(call, call->event_ctx, call->lp_ctx, &r);
280 :
281 0 : if (!NT_STATUS_IS_OK(result))
282 0 : return result;
283 :
284 0 : for (r.out.count = 0; r.out.count < r.out.available; r.out.count++) {
285 :
286 0 : int i = r.out.count;
287 :
288 0 : offset_save = call->ndr_push_data->offset;
289 0 : rap_heap_save(call->heap, &heap_save);
290 :
291 0 : switch(r.in.level) {
292 0 : case 0:
293 0 : NDR_GOTO(ndr_push_bytes(call->ndr_push_data,
294 : (const uint8_t *)r.out.info[i].info0.share_name,
295 : sizeof(r.out.info[i].info0.share_name)));
296 0 : break;
297 0 : case 1:
298 0 : NDR_GOTO(ndr_push_bytes(call->ndr_push_data,
299 : (const uint8_t *)r.out.info[i].info1.share_name,
300 : sizeof(r.out.info[i].info1.share_name)));
301 0 : NDR_GOTO(ndr_push_uint8(call->ndr_push_data,
302 : NDR_SCALARS, r.out.info[i].info1.reserved1));
303 0 : NDR_GOTO(ndr_push_uint16(call->ndr_push_data,
304 : NDR_SCALARS, r.out.info[i].info1.share_type));
305 :
306 0 : RAP_GOTO(rap_push_string(call->ndr_push_data,
307 : call->heap,
308 : r.out.info[i].info1.comment));
309 :
310 0 : break;
311 : }
312 :
313 0 : if (call->ndr_push_data->offset > call->heap->offset) {
314 :
315 0 : buffer_overflow:
316 :
317 0 : call->ndr_push_data->offset = offset_save;
318 0 : rap_heap_restore(call->heap, &heap_save);
319 0 : break;
320 : }
321 : }
322 :
323 0 : call->status = r.out.status;
324 :
325 0 : NDR_RETURN(ndr_push_uint16(call->ndr_push_param, NDR_SCALARS, r.out.count));
326 0 : NDR_RETURN(ndr_push_uint16(call->ndr_push_param, NDR_SCALARS, r.out.available));
327 :
328 0 : result = NT_STATUS_OK;
329 :
330 0 : done:
331 0 : return result;
332 : }
333 :
334 0 : static NTSTATUS _rap_netserverenum2(struct rap_call *call)
335 : {
336 0 : struct rap_NetServerEnum2 r;
337 0 : NTSTATUS result;
338 0 : uint32_t offset_save = 0;
339 0 : struct rap_heap_save heap_save = {0};
340 :
341 0 : RAP_GOTO(rap_srv_pull_word(call, &r.in.level));
342 0 : RAP_GOTO(rap_srv_pull_bufsize(call, &r.in.bufsize));
343 0 : RAP_GOTO(rap_srv_pull_expect_multiple(call));
344 0 : RAP_GOTO(rap_srv_pull_dword(call, &r.in.servertype));
345 0 : RAP_GOTO(rap_srv_pull_string(call, &r.in.domain));
346 :
347 0 : switch(r.in.level) {
348 0 : case 0:
349 0 : if (strcmp(call->datadesc, "B16") != 0)
350 0 : return NT_STATUS_INVALID_PARAMETER;
351 0 : break;
352 0 : case 1:
353 0 : if (strcmp(call->datadesc, "B16BBDz") != 0)
354 0 : return NT_STATUS_INVALID_PARAMETER;
355 0 : break;
356 0 : default:
357 0 : return NT_STATUS_INVALID_PARAMETER;
358 : break;
359 : }
360 :
361 0 : result = rap_netserverenum2(call, call->lp_ctx, &r);
362 :
363 0 : if (!NT_STATUS_IS_OK(result))
364 0 : return result;
365 :
366 0 : for (r.out.count = 0; r.out.count < r.out.available; r.out.count++) {
367 :
368 0 : int i = r.out.count;
369 :
370 0 : offset_save = call->ndr_push_data->offset;
371 0 : rap_heap_save(call->heap, &heap_save);
372 :
373 0 : switch(r.in.level) {
374 0 : case 0:
375 0 : NDR_GOTO(ndr_push_bytes(call->ndr_push_data,
376 : (const uint8_t *)r.out.info[i].info0.name,
377 : sizeof(r.out.info[i].info0.name)));
378 0 : break;
379 0 : case 1:
380 0 : NDR_GOTO(ndr_push_bytes(call->ndr_push_data,
381 : (const uint8_t *)r.out.info[i].info1.name,
382 : sizeof(r.out.info[i].info1.name)));
383 0 : NDR_GOTO(ndr_push_uint8(call->ndr_push_data,
384 : NDR_SCALARS, r.out.info[i].info1.version_major));
385 0 : NDR_GOTO(ndr_push_uint8(call->ndr_push_data,
386 : NDR_SCALARS, r.out.info[i].info1.version_minor));
387 0 : NDR_GOTO(ndr_push_uint32(call->ndr_push_data,
388 : NDR_SCALARS, r.out.info[i].info1.servertype));
389 :
390 0 : RAP_GOTO(rap_push_string(call->ndr_push_data,
391 : call->heap,
392 : r.out.info[i].info1.comment));
393 :
394 0 : break;
395 : }
396 :
397 0 : if (call->ndr_push_data->offset > call->heap->offset) {
398 :
399 0 : buffer_overflow:
400 :
401 0 : call->ndr_push_data->offset = offset_save;
402 0 : rap_heap_restore(call->heap, &heap_save);
403 0 : break;
404 : }
405 : }
406 :
407 0 : call->status = r.out.status;
408 :
409 0 : NDR_RETURN(ndr_push_uint16(call->ndr_push_param, NDR_SCALARS, r.out.count));
410 0 : NDR_RETURN(ndr_push_uint16(call->ndr_push_param, NDR_SCALARS, r.out.available));
411 :
412 0 : result = NT_STATUS_OK;
413 :
414 0 : done:
415 0 : return result;
416 : }
417 :
418 0 : static NTSTATUS api_Unsupported(struct rap_call *call)
419 : {
420 0 : call->status = NERR_notsupported;
421 0 : call->convert = 0;
422 0 : return NT_STATUS_OK;
423 : }
424 :
425 : static const struct
426 : {
427 : const char *name;
428 : int id;
429 : NTSTATUS (*fn)(struct rap_call *call);
430 : } api_commands[] = {
431 : {"NetShareEnum", RAP_WshareEnum, _rap_netshareenum },
432 : {"NetServerEnum2", RAP_NetServerEnum2, _rap_netserverenum2 },
433 : {NULL, -1, api_Unsupported}
434 : };
435 :
436 0 : NTSTATUS ipc_rap_call(TALLOC_CTX *mem_ctx, struct tevent_context *event_ctx, struct loadparm_context *lp_ctx,
437 : struct smb_trans2 *trans)
438 : {
439 0 : int i;
440 0 : NTSTATUS result;
441 0 : struct rap_call *call;
442 0 : DATA_BLOB result_param, result_data;
443 0 : struct ndr_push *final_param;
444 0 : struct ndr_push *final_data;
445 :
446 0 : call = new_rap_srv_call(mem_ctx, event_ctx, lp_ctx, trans);
447 :
448 0 : if (call == NULL)
449 0 : return NT_STATUS_NO_MEMORY;
450 :
451 0 : NDR_RETURN(ndr_pull_uint16(call->ndr_pull_param, NDR_SCALARS, &call->callno));
452 0 : NDR_RETURN(ndr_pull_string(call->ndr_pull_param, NDR_SCALARS,
453 : &call->paramdesc));
454 0 : NDR_RETURN(ndr_pull_string(call->ndr_pull_param, NDR_SCALARS,
455 : &call->datadesc));
456 :
457 0 : call->ndr_push_param = ndr_push_init_ctx(call);
458 0 : call->ndr_push_data = ndr_push_init_ctx(call);
459 :
460 0 : if ((call->ndr_push_param == NULL) || (call->ndr_push_data == NULL))
461 0 : return NT_STATUS_NO_MEMORY;
462 :
463 0 : call->ndr_push_param->flags = RAPNDR_FLAGS;
464 0 : call->ndr_push_data->flags = RAPNDR_FLAGS;
465 :
466 0 : result = NT_STATUS_INVALID_SYSTEM_SERVICE;
467 :
468 0 : for (i=0; api_commands[i].name != NULL; i++) {
469 0 : if (api_commands[i].id == call->callno) {
470 0 : DEBUG(5, ("Running RAP call %s\n",
471 : api_commands[i].name));
472 0 : result = api_commands[i].fn(call);
473 0 : break;
474 : }
475 : }
476 :
477 0 : if (!NT_STATUS_IS_OK(result))
478 0 : return result;
479 :
480 0 : result_param = ndr_push_blob(call->ndr_push_param);
481 0 : result_data = ndr_push_blob(call->ndr_push_data);
482 :
483 0 : final_param = ndr_push_init_ctx(call);
484 0 : final_data = ndr_push_init_ctx(call);
485 :
486 0 : if ((final_param == NULL) || (final_data == NULL))
487 0 : return NT_STATUS_NO_MEMORY;
488 :
489 0 : final_param->flags = RAPNDR_FLAGS;
490 0 : final_data->flags = RAPNDR_FLAGS;
491 :
492 0 : NDR_RETURN(ndr_push_uint16(final_param, NDR_SCALARS, call->status));
493 0 : NDR_RETURN(ndr_push_uint16(final_param,
494 : NDR_SCALARS, call->heap->offset - result_data.length));
495 0 : NDR_RETURN(ndr_push_bytes(final_param, result_param.data,
496 : result_param.length));
497 :
498 0 : NDR_RETURN(ndr_push_bytes(final_data, result_data.data,
499 : result_data.length));
500 :
501 0 : for (i=call->heap->num_strings-1; i>=0; i--)
502 0 : NDR_RETURN(ndr_push_string(final_data, NDR_SCALARS,
503 : call->heap->strings[i]));
504 :
505 0 : trans->out.setup_count = 0;
506 0 : trans->out.setup = NULL;
507 0 : trans->out.params = ndr_push_blob(final_param);
508 0 : trans->out.data = ndr_push_blob(final_data);
509 :
510 0 : return result;
511 : }
|