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 "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_Success 0
57 #define NERR_badpass 86
58 #define NERR_notsupported 50
60 struct rap_string_heap
{
67 struct rap_heap_save
{
68 int offset
, num_strings
;
71 static void rap_heap_save(struct rap_string_heap
*heap
,
72 struct rap_heap_save
*save
)
74 save
->offset
= heap
->offset
;
75 save
->num_strings
= heap
->num_strings
;
78 static void rap_heap_restore(struct rap_string_heap
*heap
,
79 struct rap_heap_save
*save
)
81 heap
->offset
= save
->offset
;
82 heap
->num_strings
= save
->num_strings
;
86 struct loadparm_context
*lp_ctx
;
90 const char *paramdesc
;
96 uint16_t rcv_paramlen
, rcv_datalen
;
98 struct ndr_push
*ndr_push_param
;
99 struct ndr_push
*ndr_push_data
;
100 struct rap_string_heap
*heap
;
102 struct ndr_pull
*ndr_pull_param
;
103 struct ndr_pull
*ndr_pull_data
;
105 struct event_context
*event_ctx
;
108 #define RAPNDR_FLAGS (LIBNDR_FLAG_NOALIGN|LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM);
110 static struct rap_call
*new_rap_srv_call(TALLOC_CTX
*mem_ctx
,
111 struct event_context
*ev_ctx
,
112 struct loadparm_context
*lp_ctx
,
113 struct smb_trans2
*trans
)
115 struct rap_call
*call
;
117 call
= talloc(mem_ctx
, struct rap_call
);
124 call
->lp_ctx
= talloc_reference(call
, lp_ctx
);
125 call
->event_ctx
= ev_ctx
;
127 call
->mem_ctx
= mem_ctx
;
129 call
->ndr_pull_param
= ndr_pull_init_blob(&trans
->in
.params
, mem_ctx
, lp_iconv_convenience(lp_ctx
));
130 call
->ndr_pull_param
->flags
= RAPNDR_FLAGS
;
132 call
->ndr_pull_data
= ndr_pull_init_blob(&trans
->in
.data
, mem_ctx
, lp_iconv_convenience(lp_ctx
));
133 call
->ndr_pull_data
->flags
= RAPNDR_FLAGS
;
135 call
->heap
= talloc(mem_ctx
, struct rap_string_heap
);
137 if (call
->heap
== NULL
)
140 ZERO_STRUCTP(call
->heap
);
142 call
->heap
->mem_ctx
= mem_ctx
;
147 static NTSTATUS
rap_srv_pull_word(struct rap_call
*call
, uint16_t *result
)
149 enum ndr_err_code ndr_err
;
151 if (*call
->paramdesc
++ != 'W')
152 return NT_STATUS_INVALID_PARAMETER
;
154 ndr_err
= ndr_pull_uint16(call
->ndr_pull_param
, NDR_SCALARS
, result
);
155 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
156 return ndr_map_error2ntstatus(ndr_err
);
162 static NTSTATUS
rap_srv_pull_dword(struct rap_call
*call
, uint32_t *result
)
164 enum ndr_err_code ndr_err
;
166 if (*call
->paramdesc
++ != 'D')
167 return NT_STATUS_INVALID_PARAMETER
;
169 ndr_err
= ndr_pull_uint32(call
->ndr_pull_param
, NDR_SCALARS
, result
);
170 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
171 return ndr_map_error2ntstatus(ndr_err
);
177 static NTSTATUS
rap_srv_pull_string(struct rap_call
*call
, const char **result
)
179 enum ndr_err_code ndr_err
;
180 char paramdesc
= *call
->paramdesc
++;
182 if (paramdesc
== 'O') {
187 if (paramdesc
!= 'z')
188 return NT_STATUS_INVALID_PARAMETER
;
190 ndr_err
= ndr_pull_string(call
->ndr_pull_param
, NDR_SCALARS
, result
);
191 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
192 return ndr_map_error2ntstatus(ndr_err
);
198 static NTSTATUS
rap_srv_pull_bufsize(struct rap_call
*call
, uint16_t *bufsize
)
200 enum ndr_err_code ndr_err
;
202 if ( (*call
->paramdesc
++ != 'r') || (*call
->paramdesc
++ != 'L') )
203 return NT_STATUS_INVALID_PARAMETER
;
205 ndr_err
= ndr_pull_uint16(call
->ndr_pull_param
, NDR_SCALARS
, bufsize
);
206 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
207 return ndr_map_error2ntstatus(ndr_err
);
210 call
->heap
->offset
= *bufsize
;
215 static NTSTATUS
rap_srv_pull_expect_multiple(struct rap_call
*call
)
217 if ( (*call
->paramdesc
++ != 'e') || (*call
->paramdesc
++ != 'h') )
218 return NT_STATUS_INVALID_PARAMETER
;
223 static NTSTATUS
rap_push_string(struct ndr_push
*data_push
,
224 struct rap_string_heap
*heap
,
232 space
= strlen(str
)+1;
234 if (heap
->offset
< space
)
235 return NT_STATUS_BUFFER_TOO_SMALL
;
237 heap
->offset
-= space
;
239 NDR_RETURN(ndr_push_uint16(data_push
, NDR_SCALARS
, heap
->offset
));
240 NDR_RETURN(ndr_push_uint16(data_push
, NDR_SCALARS
, 0));
242 heap
->strings
= talloc_realloc(heap
->mem_ctx
,
245 heap
->num_strings
+ 1);
247 if (heap
->strings
== NULL
)
248 return NT_STATUS_NO_MEMORY
;
250 heap
->strings
[heap
->num_strings
] = str
;
251 heap
->num_strings
+= 1;
256 static NTSTATUS
_rap_netshareenum(struct rap_call
*call
)
258 struct rap_NetShareEnum r
;
261 RAP_GOTO(rap_srv_pull_word(call
, &r
.in
.level
));
262 RAP_GOTO(rap_srv_pull_bufsize(call
, &r
.in
.bufsize
));
263 RAP_GOTO(rap_srv_pull_expect_multiple(call
));
267 if (strcmp(call
->datadesc
, "B13") != 0)
268 return NT_STATUS_INVALID_PARAMETER
;
271 if (strcmp(call
->datadesc
, "B13BWz") != 0)
272 return NT_STATUS_INVALID_PARAMETER
;
275 return NT_STATUS_INVALID_PARAMETER
;
279 result
= rap_netshareenum(call
, call
->event_ctx
, call
->lp_ctx
, &r
);
281 if (!NT_STATUS_IS_OK(result
))
284 for (r
.out
.count
= 0; r
.out
.count
< r
.out
.available
; r
.out
.count
++) {
287 uint32_t offset_save
;
288 struct rap_heap_save heap_save
;
290 offset_save
= call
->ndr_push_data
->offset
;
291 rap_heap_save(call
->heap
, &heap_save
);
295 NDR_GOTO(ndr_push_bytes(call
->ndr_push_data
,
296 (const uint8_t *)r
.out
.info
[i
].info0
.name
,
297 sizeof(r
.out
.info
[i
].info0
.name
)));
300 NDR_GOTO(ndr_push_bytes(call
->ndr_push_data
,
301 (const uint8_t *)r
.out
.info
[i
].info1
.name
,
302 sizeof(r
.out
.info
[i
].info1
.name
)));
303 NDR_GOTO(ndr_push_uint8(call
->ndr_push_data
,
304 NDR_SCALARS
, r
.out
.info
[i
].info1
.pad
));
305 NDR_GOTO(ndr_push_uint16(call
->ndr_push_data
,
306 NDR_SCALARS
, r
.out
.info
[i
].info1
.type
));
308 RAP_GOTO(rap_push_string(call
->ndr_push_data
,
310 r
.out
.info
[i
].info1
.comment
));
315 if (call
->ndr_push_data
->offset
> call
->heap
->offset
) {
319 call
->ndr_push_data
->offset
= offset_save
;
320 rap_heap_restore(call
->heap
, &heap_save
);
325 call
->status
= r
.out
.status
;
327 NDR_RETURN(ndr_push_uint16(call
->ndr_push_param
, NDR_SCALARS
, r
.out
.count
));
328 NDR_RETURN(ndr_push_uint16(call
->ndr_push_param
, NDR_SCALARS
, r
.out
.available
));
330 result
= NT_STATUS_OK
;
336 static NTSTATUS
_rap_netserverenum2(struct rap_call
*call
)
338 struct rap_NetServerEnum2 r
;
341 RAP_GOTO(rap_srv_pull_word(call
, &r
.in
.level
));
342 RAP_GOTO(rap_srv_pull_bufsize(call
, &r
.in
.bufsize
));
343 RAP_GOTO(rap_srv_pull_expect_multiple(call
));
344 RAP_GOTO(rap_srv_pull_dword(call
, &r
.in
.servertype
));
345 RAP_GOTO(rap_srv_pull_string(call
, &r
.in
.domain
));
349 if (strcmp(call
->datadesc
, "B16") != 0)
350 return NT_STATUS_INVALID_PARAMETER
;
353 if (strcmp(call
->datadesc
, "B16BBDz") != 0)
354 return NT_STATUS_INVALID_PARAMETER
;
357 return NT_STATUS_INVALID_PARAMETER
;
361 result
= rap_netserverenum2(call
, call
->lp_ctx
, &r
);
363 if (!NT_STATUS_IS_OK(result
))
366 for (r
.out
.count
= 0; r
.out
.count
< r
.out
.available
; r
.out
.count
++) {
369 uint32_t offset_save
;
370 struct rap_heap_save heap_save
;
372 offset_save
= call
->ndr_push_data
->offset
;
373 rap_heap_save(call
->heap
, &heap_save
);
377 NDR_GOTO(ndr_push_bytes(call
->ndr_push_data
,
378 (const uint8_t *)r
.out
.info
[i
].info0
.name
,
379 sizeof(r
.out
.info
[i
].info0
.name
)));
382 NDR_GOTO(ndr_push_bytes(call
->ndr_push_data
,
383 (const uint8_t *)r
.out
.info
[i
].info1
.name
,
384 sizeof(r
.out
.info
[i
].info1
.name
)));
385 NDR_GOTO(ndr_push_uint8(call
->ndr_push_data
,
386 NDR_SCALARS
, r
.out
.info
[i
].info1
.version_major
));
387 NDR_GOTO(ndr_push_uint8(call
->ndr_push_data
,
388 NDR_SCALARS
, r
.out
.info
[i
].info1
.version_minor
));
389 NDR_GOTO(ndr_push_uint32(call
->ndr_push_data
,
390 NDR_SCALARS
, r
.out
.info
[i
].info1
.servertype
));
392 RAP_GOTO(rap_push_string(call
->ndr_push_data
,
394 r
.out
.info
[i
].info1
.comment
));
399 if (call
->ndr_push_data
->offset
> call
->heap
->offset
) {
403 call
->ndr_push_data
->offset
= offset_save
;
404 rap_heap_restore(call
->heap
, &heap_save
);
409 call
->status
= r
.out
.status
;
411 NDR_RETURN(ndr_push_uint16(call
->ndr_push_param
, NDR_SCALARS
, r
.out
.count
));
412 NDR_RETURN(ndr_push_uint16(call
->ndr_push_param
, NDR_SCALARS
, r
.out
.available
));
414 result
= NT_STATUS_OK
;
420 static NTSTATUS
api_Unsupported(struct rap_call
*call
)
422 call
->status
= NERR_notsupported
;
431 NTSTATUS (*fn
)(struct rap_call
*call
);
433 {"NetShareEnum", RAP_WshareEnum
, _rap_netshareenum
},
434 {"NetServerEnum2", RAP_NetServerEnum2
, _rap_netserverenum2
},
435 {NULL
, -1, api_Unsupported
}
438 NTSTATUS
ipc_rap_call(TALLOC_CTX
*mem_ctx
, struct event_context
*event_ctx
, struct loadparm_context
*lp_ctx
,
439 struct smb_trans2
*trans
)
443 struct rap_call
*call
;
444 DATA_BLOB result_param
, result_data
;
445 struct ndr_push
*final_param
;
446 struct ndr_push
*final_data
;
448 call
= new_rap_srv_call(mem_ctx
, event_ctx
, lp_ctx
, trans
);
451 return NT_STATUS_NO_MEMORY
;
453 NDR_RETURN(ndr_pull_uint16(call
->ndr_pull_param
, NDR_SCALARS
, &call
->callno
));
454 NDR_RETURN(ndr_pull_string(call
->ndr_pull_param
, NDR_SCALARS
,
456 NDR_RETURN(ndr_pull_string(call
->ndr_pull_param
, NDR_SCALARS
,
459 call
->ndr_push_param
= ndr_push_init_ctx(call
, lp_iconv_convenience(lp_ctx
));
460 call
->ndr_push_data
= ndr_push_init_ctx(call
, lp_iconv_convenience(lp_ctx
));
462 if ((call
->ndr_push_param
== NULL
) || (call
->ndr_push_data
== NULL
))
463 return NT_STATUS_NO_MEMORY
;
465 call
->ndr_push_param
->flags
= RAPNDR_FLAGS
;
466 call
->ndr_push_data
->flags
= RAPNDR_FLAGS
;
468 result
= NT_STATUS_INVALID_SYSTEM_SERVICE
;
470 for (i
=0; api_commands
[i
].name
!= NULL
; i
++) {
471 if (api_commands
[i
].id
== call
->callno
) {
472 DEBUG(5, ("Running RAP call %s\n",
473 api_commands
[i
].name
));
474 result
= api_commands
[i
].fn(call
);
479 if (!NT_STATUS_IS_OK(result
))
482 result_param
= ndr_push_blob(call
->ndr_push_param
);
483 result_data
= ndr_push_blob(call
->ndr_push_data
);
485 final_param
= ndr_push_init_ctx(call
, lp_iconv_convenience(lp_ctx
));
486 final_data
= ndr_push_init_ctx(call
, lp_iconv_convenience(lp_ctx
));
488 if ((final_param
== NULL
) || (final_data
== NULL
))
489 return NT_STATUS_NO_MEMORY
;
491 final_param
->flags
= RAPNDR_FLAGS
;
492 final_data
->flags
= RAPNDR_FLAGS
;
494 NDR_RETURN(ndr_push_uint16(final_param
, NDR_SCALARS
, call
->status
));
495 NDR_RETURN(ndr_push_uint16(final_param
,
496 NDR_SCALARS
, call
->heap
->offset
- result_data
.length
));
497 NDR_RETURN(ndr_push_bytes(final_param
, result_param
.data
,
498 result_param
.length
));
500 NDR_RETURN(ndr_push_bytes(final_data
, result_data
.data
,
501 result_data
.length
));
503 for (i
=call
->heap
->num_strings
-1; i
>=0; i
--)
504 NDR_RETURN(ndr_push_string(final_data
, NDR_SCALARS
,
505 call
->heap
->strings
[i
]));
507 trans
->out
.setup_count
= 0;
508 trans
->out
.setup
= NULL
;
509 trans
->out
.params
= ndr_push_blob(final_param
);
510 trans
->out
.data
= ndr_push_blob(final_data
);