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 "../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"
29 #define NDR_RETURN(call) do { \
30 enum ndr_err_code _ndr_err; \
32 if (!NDR_ERR_CODE_IS_SUCCESS(_ndr_err)) { \
33 return ndr_map_error2ntstatus(_ndr_err); \
37 #define RAP_GOTO(call) do { \
39 if (NT_STATUS_EQUAL(result, NT_STATUS_BUFFER_TOO_SMALL)) {\
40 goto buffer_overflow; \
42 if (!NT_STATUS_IS_OK(result)) { \
47 #define NDR_GOTO(call) do { \
48 enum ndr_err_code _ndr_err; \
50 if (!NDR_ERR_CODE_IS_SUCCESS(_ndr_err)) { \
51 RAP_GOTO(ndr_map_error2ntstatus(_ndr_err)); \
56 #define NERR_notsupported 50
58 struct rap_string_heap
{
65 struct rap_heap_save
{
66 int offset
, num_strings
;
69 static void rap_heap_save(struct rap_string_heap
*heap
,
70 struct rap_heap_save
*save
)
72 save
->offset
= heap
->offset
;
73 save
->num_strings
= heap
->num_strings
;
76 static void rap_heap_restore(struct rap_string_heap
*heap
,
77 struct rap_heap_save
*save
)
79 heap
->offset
= save
->offset
;
80 heap
->num_strings
= save
->num_strings
;
84 struct loadparm_context
*lp_ctx
;
88 const char *paramdesc
;
94 uint16_t rcv_paramlen
, rcv_datalen
;
96 struct ndr_push
*ndr_push_param
;
97 struct ndr_push
*ndr_push_data
;
98 struct rap_string_heap
*heap
;
100 struct ndr_pull
*ndr_pull_param
;
101 struct ndr_pull
*ndr_pull_data
;
103 struct tevent_context
*event_ctx
;
106 #define RAPNDR_FLAGS (LIBNDR_FLAG_NOALIGN|LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM);
108 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
)
113 struct rap_call
*call
;
115 call
= talloc(mem_ctx
, struct rap_call
);
122 call
->lp_ctx
= talloc_reference(call
, lp_ctx
);
123 call
->event_ctx
= ev_ctx
;
125 call
->mem_ctx
= mem_ctx
;
127 call
->ndr_pull_param
= ndr_pull_init_blob(&trans
->in
.params
, mem_ctx
);
128 call
->ndr_pull_param
->flags
= RAPNDR_FLAGS
;
130 call
->ndr_pull_data
= ndr_pull_init_blob(&trans
->in
.data
, mem_ctx
);
131 call
->ndr_pull_data
->flags
= RAPNDR_FLAGS
;
133 call
->heap
= talloc(mem_ctx
, struct rap_string_heap
);
135 if (call
->heap
== NULL
)
138 ZERO_STRUCTP(call
->heap
);
140 call
->heap
->mem_ctx
= mem_ctx
;
145 static NTSTATUS
rap_srv_pull_word(struct rap_call
*call
, uint16_t *result
)
147 enum ndr_err_code ndr_err
;
149 if (*call
->paramdesc
++ != 'W')
150 return NT_STATUS_INVALID_PARAMETER
;
152 ndr_err
= ndr_pull_uint16(call
->ndr_pull_param
, NDR_SCALARS
, result
);
153 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
154 return ndr_map_error2ntstatus(ndr_err
);
160 static NTSTATUS
rap_srv_pull_dword(struct rap_call
*call
, uint32_t *result
)
162 enum ndr_err_code ndr_err
;
164 if (*call
->paramdesc
++ != 'D')
165 return NT_STATUS_INVALID_PARAMETER
;
167 ndr_err
= ndr_pull_uint32(call
->ndr_pull_param
, NDR_SCALARS
, result
);
168 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
169 return ndr_map_error2ntstatus(ndr_err
);
175 static NTSTATUS
rap_srv_pull_string(struct rap_call
*call
, const char **result
)
177 enum ndr_err_code ndr_err
;
178 char paramdesc
= *call
->paramdesc
++;
180 if (paramdesc
== 'O') {
185 if (paramdesc
!= 'z')
186 return NT_STATUS_INVALID_PARAMETER
;
188 ndr_err
= ndr_pull_string(call
->ndr_pull_param
, NDR_SCALARS
, result
);
189 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
190 return ndr_map_error2ntstatus(ndr_err
);
196 static NTSTATUS
rap_srv_pull_bufsize(struct rap_call
*call
, uint16_t *bufsize
)
198 enum ndr_err_code ndr_err
;
200 if ( (*call
->paramdesc
++ != 'r') || (*call
->paramdesc
++ != 'L') )
201 return NT_STATUS_INVALID_PARAMETER
;
203 ndr_err
= ndr_pull_uint16(call
->ndr_pull_param
, NDR_SCALARS
, bufsize
);
204 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
205 return ndr_map_error2ntstatus(ndr_err
);
208 call
->heap
->offset
= *bufsize
;
213 static NTSTATUS
rap_srv_pull_expect_multiple(struct rap_call
*call
)
215 if ( (*call
->paramdesc
++ != 'e') || (*call
->paramdesc
++ != 'h') )
216 return NT_STATUS_INVALID_PARAMETER
;
221 static NTSTATUS
rap_push_string(struct ndr_push
*data_push
,
222 struct rap_string_heap
*heap
,
230 space
= strlen(str
)+1;
232 if (heap
->offset
< space
)
233 return NT_STATUS_BUFFER_TOO_SMALL
;
235 heap
->offset
-= space
;
237 NDR_RETURN(ndr_push_uint16(data_push
, NDR_SCALARS
, heap
->offset
));
238 NDR_RETURN(ndr_push_uint16(data_push
, NDR_SCALARS
, 0));
240 heap
->strings
= talloc_realloc(heap
->mem_ctx
,
243 heap
->num_strings
+ 1);
245 if (heap
->strings
== NULL
)
246 return NT_STATUS_NO_MEMORY
;
248 heap
->strings
[heap
->num_strings
] = str
;
249 heap
->num_strings
+= 1;
254 static NTSTATUS
_rap_netshareenum(struct rap_call
*call
)
256 struct rap_NetShareEnum r
;
259 RAP_GOTO(rap_srv_pull_word(call
, &r
.in
.level
));
260 RAP_GOTO(rap_srv_pull_bufsize(call
, &r
.in
.bufsize
));
261 RAP_GOTO(rap_srv_pull_expect_multiple(call
));
265 if (strcmp(call
->datadesc
, "B13") != 0)
266 return NT_STATUS_INVALID_PARAMETER
;
269 if (strcmp(call
->datadesc
, "B13BWz") != 0)
270 return NT_STATUS_INVALID_PARAMETER
;
273 return NT_STATUS_INVALID_PARAMETER
;
277 result
= rap_netshareenum(call
, call
->event_ctx
, call
->lp_ctx
, &r
);
279 if (!NT_STATUS_IS_OK(result
))
282 for (r
.out
.count
= 0; r
.out
.count
< r
.out
.available
; r
.out
.count
++) {
285 uint32_t offset_save
;
286 struct rap_heap_save heap_save
;
288 offset_save
= call
->ndr_push_data
->offset
;
289 rap_heap_save(call
->heap
, &heap_save
);
293 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
)));
298 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 NDR_GOTO(ndr_push_uint8(call
->ndr_push_data
,
302 NDR_SCALARS
, r
.out
.info
[i
].info1
.reserved1
));
303 NDR_GOTO(ndr_push_uint16(call
->ndr_push_data
,
304 NDR_SCALARS
, r
.out
.info
[i
].info1
.share_type
));
306 RAP_GOTO(rap_push_string(call
->ndr_push_data
,
308 r
.out
.info
[i
].info1
.comment
));
313 if (call
->ndr_push_data
->offset
> call
->heap
->offset
) {
317 call
->ndr_push_data
->offset
= offset_save
;
318 rap_heap_restore(call
->heap
, &heap_save
);
323 call
->status
= r
.out
.status
;
325 NDR_RETURN(ndr_push_uint16(call
->ndr_push_param
, NDR_SCALARS
, r
.out
.count
));
326 NDR_RETURN(ndr_push_uint16(call
->ndr_push_param
, NDR_SCALARS
, r
.out
.available
));
328 result
= NT_STATUS_OK
;
334 static NTSTATUS
_rap_netserverenum2(struct rap_call
*call
)
336 struct rap_NetServerEnum2 r
;
339 RAP_GOTO(rap_srv_pull_word(call
, &r
.in
.level
));
340 RAP_GOTO(rap_srv_pull_bufsize(call
, &r
.in
.bufsize
));
341 RAP_GOTO(rap_srv_pull_expect_multiple(call
));
342 RAP_GOTO(rap_srv_pull_dword(call
, &r
.in
.servertype
));
343 RAP_GOTO(rap_srv_pull_string(call
, &r
.in
.domain
));
347 if (strcmp(call
->datadesc
, "B16") != 0)
348 return NT_STATUS_INVALID_PARAMETER
;
351 if (strcmp(call
->datadesc
, "B16BBDz") != 0)
352 return NT_STATUS_INVALID_PARAMETER
;
355 return NT_STATUS_INVALID_PARAMETER
;
359 result
= rap_netserverenum2(call
, call
->lp_ctx
, &r
);
361 if (!NT_STATUS_IS_OK(result
))
364 for (r
.out
.count
= 0; r
.out
.count
< r
.out
.available
; r
.out
.count
++) {
367 uint32_t offset_save
;
368 struct rap_heap_save heap_save
;
370 offset_save
= call
->ndr_push_data
->offset
;
371 rap_heap_save(call
->heap
, &heap_save
);
375 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
)));
380 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 NDR_GOTO(ndr_push_uint8(call
->ndr_push_data
,
384 NDR_SCALARS
, r
.out
.info
[i
].info1
.version_major
));
385 NDR_GOTO(ndr_push_uint8(call
->ndr_push_data
,
386 NDR_SCALARS
, r
.out
.info
[i
].info1
.version_minor
));
387 NDR_GOTO(ndr_push_uint32(call
->ndr_push_data
,
388 NDR_SCALARS
, r
.out
.info
[i
].info1
.servertype
));
390 RAP_GOTO(rap_push_string(call
->ndr_push_data
,
392 r
.out
.info
[i
].info1
.comment
));
397 if (call
->ndr_push_data
->offset
> call
->heap
->offset
) {
401 call
->ndr_push_data
->offset
= offset_save
;
402 rap_heap_restore(call
->heap
, &heap_save
);
407 call
->status
= r
.out
.status
;
409 NDR_RETURN(ndr_push_uint16(call
->ndr_push_param
, NDR_SCALARS
, r
.out
.count
));
410 NDR_RETURN(ndr_push_uint16(call
->ndr_push_param
, NDR_SCALARS
, r
.out
.available
));
412 result
= NT_STATUS_OK
;
418 static NTSTATUS
api_Unsupported(struct rap_call
*call
)
420 call
->status
= NERR_notsupported
;
429 NTSTATUS (*fn
)(struct rap_call
*call
);
431 {"NetShareEnum", RAP_WshareEnum
, _rap_netshareenum
},
432 {"NetServerEnum2", RAP_NetServerEnum2
, _rap_netserverenum2
},
433 {NULL
, -1, api_Unsupported
}
436 NTSTATUS
ipc_rap_call(TALLOC_CTX
*mem_ctx
, struct tevent_context
*event_ctx
, struct loadparm_context
*lp_ctx
,
437 struct smb_trans2
*trans
)
441 struct rap_call
*call
;
442 DATA_BLOB result_param
, result_data
;
443 struct ndr_push
*final_param
;
444 struct ndr_push
*final_data
;
446 call
= new_rap_srv_call(mem_ctx
, event_ctx
, lp_ctx
, trans
);
449 return NT_STATUS_NO_MEMORY
;
451 NDR_RETURN(ndr_pull_uint16(call
->ndr_pull_param
, NDR_SCALARS
, &call
->callno
));
452 NDR_RETURN(ndr_pull_string(call
->ndr_pull_param
, NDR_SCALARS
,
454 NDR_RETURN(ndr_pull_string(call
->ndr_pull_param
, NDR_SCALARS
,
457 call
->ndr_push_param
= ndr_push_init_ctx(call
);
458 call
->ndr_push_data
= ndr_push_init_ctx(call
);
460 if ((call
->ndr_push_param
== NULL
) || (call
->ndr_push_data
== NULL
))
461 return NT_STATUS_NO_MEMORY
;
463 call
->ndr_push_param
->flags
= RAPNDR_FLAGS
;
464 call
->ndr_push_data
->flags
= RAPNDR_FLAGS
;
466 result
= NT_STATUS_INVALID_SYSTEM_SERVICE
;
468 for (i
=0; api_commands
[i
].name
!= NULL
; i
++) {
469 if (api_commands
[i
].id
== call
->callno
) {
470 DEBUG(5, ("Running RAP call %s\n",
471 api_commands
[i
].name
));
472 result
= api_commands
[i
].fn(call
);
477 if (!NT_STATUS_IS_OK(result
))
480 result_param
= ndr_push_blob(call
->ndr_push_param
);
481 result_data
= ndr_push_blob(call
->ndr_push_data
);
483 final_param
= ndr_push_init_ctx(call
);
484 final_data
= ndr_push_init_ctx(call
);
486 if ((final_param
== NULL
) || (final_data
== NULL
))
487 return NT_STATUS_NO_MEMORY
;
489 final_param
->flags
= RAPNDR_FLAGS
;
490 final_data
->flags
= RAPNDR_FLAGS
;
492 NDR_RETURN(ndr_push_uint16(final_param
, NDR_SCALARS
, call
->status
));
493 NDR_RETURN(ndr_push_uint16(final_param
,
494 NDR_SCALARS
, call
->heap
->offset
- result_data
.length
));
495 NDR_RETURN(ndr_push_bytes(final_param
, result_param
.data
,
496 result_param
.length
));
498 NDR_RETURN(ndr_push_bytes(final_data
, result_data
.data
,
499 result_data
.length
));
501 for (i
=call
->heap
->num_strings
-1; i
>=0; i
--)
502 NDR_RETURN(ndr_push_string(final_data
, NDR_SCALARS
,
503 call
->heap
->strings
[i
]));
505 trans
->out
.setup_count
= 0;
506 trans
->out
.setup
= NULL
;
507 trans
->out
.params
= ndr_push_blob(final_param
);
508 trans
->out
.data
= ndr_push_blob(final_data
);