2 Unix SMB/CIFS implementation.
5 Copyright (C) Volker Lendecke 2004
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.
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.
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/>.
22 #include "libcli/raw/interfaces.h"
23 #include "libcli/rap/rap.h"
24 #include "ntvfs/ipc/proto.h"
25 #include "librpc/ndr/libndr.h"
27 #define NERR_Success 0
28 #define NERR_badpass 86
29 #define NERR_notsupported 50
31 struct rap_string_heap {
38 struct rap_heap_save {
39 int offset, num_strings;
42 static void rap_heap_save(struct rap_string_heap *heap,
43 struct rap_heap_save *save)
45 save->offset = heap->offset;
46 save->num_strings = heap->num_strings;
49 static void rap_heap_restore(struct rap_string_heap *heap,
50 struct rap_heap_save *save)
52 heap->offset = save->offset;
53 heap->num_strings = save->num_strings;
59 const char *paramdesc;
65 uint16_t rcv_paramlen, rcv_datalen;
67 struct ndr_push *ndr_push_param;
68 struct ndr_push *ndr_push_data;
69 struct rap_string_heap *heap;
71 struct ndr_pull *ndr_pull_param;
72 struct ndr_pull *ndr_pull_data;
75 #define RAPNDR_FLAGS (LIBNDR_FLAG_NOALIGN|LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM);
77 static struct rap_call *new_rap_srv_call(TALLOC_CTX *mem_ctx,
78 struct smb_trans2 *trans)
80 struct rap_call *call;
82 call = talloc(mem_ctx, struct rap_call);
89 call->mem_ctx = mem_ctx;
91 call->ndr_pull_param = ndr_pull_init_blob(&trans->in.params, mem_ctx);
92 call->ndr_pull_param->flags = RAPNDR_FLAGS;
94 call->ndr_pull_data = ndr_pull_init_blob(&trans->in.data, mem_ctx);
95 call->ndr_pull_data->flags = RAPNDR_FLAGS;
97 call->heap = talloc(mem_ctx, struct rap_string_heap);
99 if (call->heap == NULL)
102 ZERO_STRUCTP(call->heap);
104 call->heap->mem_ctx = mem_ctx;
109 static NTSTATUS rap_srv_pull_word(struct rap_call *call, uint16_t *result)
111 if (*call->paramdesc++ != 'W')
112 return NT_STATUS_INVALID_PARAMETER;
114 return ndr_pull_uint16(call->ndr_pull_param, NDR_SCALARS, result);
117 static NTSTATUS rap_srv_pull_dword(struct rap_call *call, uint32_t *result)
119 if (*call->paramdesc++ != 'D')
120 return NT_STATUS_INVALID_PARAMETER;
122 return ndr_pull_uint32(call->ndr_pull_param, NDR_SCALARS, result);
125 static NTSTATUS rap_srv_pull_string(struct rap_call *call, const char **result)
127 char paramdesc = *call->paramdesc++;
129 if (paramdesc == 'O') {
134 if (paramdesc != 'z')
135 return NT_STATUS_INVALID_PARAMETER;
137 return ndr_pull_string(call->ndr_pull_param, NDR_SCALARS, result);
140 static NTSTATUS rap_srv_pull_bufsize(struct rap_call *call, uint16_t *bufsize)
144 if ( (*call->paramdesc++ != 'r') || (*call->paramdesc++ != 'L') )
145 return NT_STATUS_INVALID_PARAMETER;
147 result = ndr_pull_uint16(call->ndr_pull_param, NDR_SCALARS, bufsize);
149 if (!NT_STATUS_IS_OK(result))
152 call->heap->offset = *bufsize;
157 static NTSTATUS rap_srv_pull_expect_multiple(struct rap_call *call)
159 if ( (*call->paramdesc++ != 'e') || (*call->paramdesc++ != 'h') )
160 return NT_STATUS_INVALID_PARAMETER;
165 static NTSTATUS rap_push_string(struct ndr_push *data_push,
166 struct rap_string_heap *heap,
174 space = strlen(str)+1;
176 if (heap->offset < space)
177 return NT_STATUS_BUFFER_TOO_SMALL;
179 heap->offset -= space;
181 NDR_CHECK(ndr_push_uint16(data_push, NDR_SCALARS, heap->offset));
182 NDR_CHECK(ndr_push_uint16(data_push, NDR_SCALARS, 0));
184 heap->strings = talloc_realloc(heap->mem_ctx,
187 heap->num_strings + 1);
189 if (heap->strings == NULL)
190 return NT_STATUS_NO_MEMORY;
192 heap->strings[heap->num_strings] = str;
193 heap->num_strings += 1;
198 #define NDR_OK(call) do { result = call; \
199 if (NT_STATUS_EQUAL(result, NT_STATUS_BUFFER_TOO_SMALL)) \
200 goto buffer_overflow; \
201 if (!NT_STATUS_IS_OK(result)) \
205 static NTSTATUS _rap_netshareenum(struct rap_call *call)
207 struct rap_NetShareEnum r;
210 NDR_OK(rap_srv_pull_word(call, &r.in.level));
211 NDR_OK(rap_srv_pull_bufsize(call, &r.in.bufsize));
212 NDR_OK(rap_srv_pull_expect_multiple(call));
216 if (strcmp(call->datadesc, "B13") != 0)
217 return NT_STATUS_INVALID_PARAMETER;
220 if (strcmp(call->datadesc, "B13BWz") != 0)
221 return NT_STATUS_INVALID_PARAMETER;
224 return NT_STATUS_INVALID_PARAMETER;
228 result = rap_netshareenum(call, &r);
230 if (!NT_STATUS_IS_OK(result))
233 for (r.out.count = 0; r.out.count < r.out.available; r.out.count++) {
236 struct ndr_push_save data_save;
237 struct rap_heap_save heap_save;
239 ndr_push_save(call->ndr_push_data, &data_save);
240 rap_heap_save(call->heap, &heap_save);
244 NDR_OK(ndr_push_bytes(call->ndr_push_data,
245 (const uint8_t *)r.out.info[i].info0.name,
246 sizeof(r.out.info[i].info0.name)));
249 NDR_OK(ndr_push_bytes(call->ndr_push_data,
250 (const uint8_t *)r.out.info[i].info1.name,
251 sizeof(r.out.info[i].info1.name)));
252 NDR_OK(ndr_push_uint8(call->ndr_push_data,
253 NDR_SCALARS, r.out.info[i].info1.pad));
254 NDR_OK(ndr_push_uint16(call->ndr_push_data,
255 NDR_SCALARS, r.out.info[i].info1.type));
257 NDR_OK(rap_push_string(call->ndr_push_data,
259 r.out.info[i].info1.comment));
264 if (call->ndr_push_data->offset > call->heap->offset) {
268 ndr_push_restore(call->ndr_push_data, &data_save);
269 rap_heap_restore(call->heap, &heap_save);
274 call->status = r.out.status;
276 NDR_CHECK(ndr_push_uint16(call->ndr_push_param, NDR_SCALARS, r.out.count));
277 NDR_CHECK(ndr_push_uint16(call->ndr_push_param, NDR_SCALARS, r.out.available));
279 result = NT_STATUS_OK;
285 static NTSTATUS _rap_netserverenum2(struct rap_call *call)
287 struct rap_NetServerEnum2 r;
290 NDR_OK(rap_srv_pull_word(call, &r.in.level));
291 NDR_OK(rap_srv_pull_bufsize(call, &r.in.bufsize));
292 NDR_OK(rap_srv_pull_expect_multiple(call));
293 NDR_OK(rap_srv_pull_dword(call, &r.in.servertype));
294 NDR_OK(rap_srv_pull_string(call, &r.in.domain));
298 if (strcmp(call->datadesc, "B16") != 0)
299 return NT_STATUS_INVALID_PARAMETER;
302 if (strcmp(call->datadesc, "B16BBDz") != 0)
303 return NT_STATUS_INVALID_PARAMETER;
306 return NT_STATUS_INVALID_PARAMETER;
310 result = rap_netserverenum2(call, &r);
312 if (!NT_STATUS_IS_OK(result))
315 for (r.out.count = 0; r.out.count < r.out.available; r.out.count++) {
318 struct ndr_push_save data_save;
319 struct rap_heap_save heap_save;
321 ndr_push_save(call->ndr_push_data, &data_save);
322 rap_heap_save(call->heap, &heap_save);
326 NDR_OK(ndr_push_bytes(call->ndr_push_data,
327 (const uint8_t *)r.out.info[i].info0.name,
328 sizeof(r.out.info[i].info0.name)));
331 NDR_OK(ndr_push_bytes(call->ndr_push_data,
332 (const uint8_t *)r.out.info[i].info1.name,
333 sizeof(r.out.info[i].info1.name)));
334 NDR_OK(ndr_push_uint8(call->ndr_push_data,
335 NDR_SCALARS, r.out.info[i].info1.version_major));
336 NDR_OK(ndr_push_uint8(call->ndr_push_data,
337 NDR_SCALARS, r.out.info[i].info1.version_minor));
338 NDR_OK(ndr_push_uint32(call->ndr_push_data,
339 NDR_SCALARS, r.out.info[i].info1.servertype));
341 NDR_OK(rap_push_string(call->ndr_push_data,
343 r.out.info[i].info1.comment));
348 if (call->ndr_push_data->offset > call->heap->offset) {
352 ndr_push_restore(call->ndr_push_data, &data_save);
353 rap_heap_restore(call->heap, &heap_save);
358 call->status = r.out.status;
360 NDR_CHECK(ndr_push_uint16(call->ndr_push_param, NDR_SCALARS, r.out.count));
361 NDR_CHECK(ndr_push_uint16(call->ndr_push_param, NDR_SCALARS, r.out.available));
363 result = NT_STATUS_OK;
369 static NTSTATUS api_Unsupported(struct rap_call *call)
371 call->status = NERR_notsupported;
380 NTSTATUS (*fn)(struct rap_call *call);
382 {"NetShareEnum", RAP_WshareEnum, _rap_netshareenum },
383 {"NetServerEnum2", RAP_NetServerEnum2, _rap_netserverenum2 },
384 {NULL, -1, api_Unsupported}
387 NTSTATUS ipc_rap_call(TALLOC_CTX *mem_ctx, struct smb_trans2 *trans)
391 struct rap_call *call;
392 DATA_BLOB result_param, result_data;
393 struct ndr_push *final_param;
394 struct ndr_push *final_data;
396 call = new_rap_srv_call(mem_ctx, trans);
399 return NT_STATUS_NO_MEMORY;
401 NDR_CHECK(ndr_pull_uint16(call->ndr_pull_param, NDR_SCALARS, &call->callno));
402 NDR_CHECK(ndr_pull_string(call->ndr_pull_param, NDR_SCALARS,
404 NDR_CHECK(ndr_pull_string(call->ndr_pull_param, NDR_SCALARS,
407 call->ndr_push_param = ndr_push_init_ctx(call);
408 call->ndr_push_data = ndr_push_init_ctx(call);
410 if ((call->ndr_push_param == NULL) || (call->ndr_push_data == NULL))
411 return NT_STATUS_NO_MEMORY;
413 call->ndr_push_param->flags = RAPNDR_FLAGS;
414 call->ndr_push_data->flags = RAPNDR_FLAGS;
416 result = NT_STATUS_INVALID_SYSTEM_SERVICE;
418 for (i=0; api_commands[i].name != NULL; i++) {
419 if (api_commands[i].id == call->callno) {
420 DEBUG(5, ("Running RAP call %s\n",
421 api_commands[i].name));
422 result = api_commands[i].fn(call);
427 if (!NT_STATUS_IS_OK(result))
430 result_param = ndr_push_blob(call->ndr_push_param);
431 result_data = ndr_push_blob(call->ndr_push_data);
433 final_param = ndr_push_init_ctx(call);
434 final_data = ndr_push_init_ctx(call);
436 if ((final_param == NULL) || (final_data == NULL))
437 return NT_STATUS_NO_MEMORY;
439 final_param->flags = RAPNDR_FLAGS;
440 final_data->flags = RAPNDR_FLAGS;
442 NDR_CHECK(ndr_push_uint16(final_param, NDR_SCALARS, call->status));
443 NDR_CHECK(ndr_push_uint16(final_param,
444 NDR_SCALARS, call->heap->offset - result_data.length));
445 NDR_CHECK(ndr_push_bytes(final_param, result_param.data,
446 result_param.length));
448 NDR_CHECK(ndr_push_bytes(final_data, result_data.data,
449 result_data.length));
451 for (i=call->heap->num_strings-1; i>=0; i--)
452 NDR_CHECK(ndr_push_string(final_data, NDR_SCALARS,
453 call->heap->strings[i]));
455 trans->out.setup_count = 0;
456 trans->out.setup = NULL;
457 trans->out.params = ndr_push_blob(final_param);
458 trans->out.data = ndr_push_blob(final_data);