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 2 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, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 #define NERR_Success 0
26 #define NERR_badpass 86
27 #define NERR_notsupported 50
29 struct rap_string_heap
{
36 struct rap_heap_save
{
37 int offset
, num_strings
;
40 static void rap_heap_save(struct rap_string_heap
*heap
,
41 struct rap_heap_save
*save
)
43 save
->offset
= heap
->offset
;
44 save
->num_strings
= heap
->num_strings
;
47 static void rap_heap_restore(struct rap_string_heap
*heap
,
48 struct rap_heap_save
*save
)
50 heap
->offset
= save
->offset
;
51 heap
->num_strings
= save
->num_strings
;
57 const char *paramdesc
;
63 uint16 rcv_paramlen
, rcv_datalen
;
65 struct ndr_push
*ndr_push_param
;
66 struct ndr_push
*ndr_push_data
;
67 struct rap_string_heap
*heap
;
69 struct ndr_pull
*ndr_pull_param
;
70 struct ndr_pull
*ndr_pull_data
;
73 #define RAPNDR_FLAGS (LIBNDR_FLAG_NOALIGN|LIBNDR_FLAG_STR_ASCII|LIBNDR_FLAG_STR_NULLTERM);
75 static struct rap_call
*new_rap_srv_call(TALLOC_CTX
*mem_ctx
,
76 struct smb_trans2
*trans
)
78 struct rap_call
*call
;
80 call
= talloc(mem_ctx
, struct rap_call
);
87 call
->mem_ctx
= mem_ctx
;
89 call
->ndr_pull_param
= ndr_pull_init_blob(&trans
->in
.params
, mem_ctx
);
90 call
->ndr_pull_param
->flags
= RAPNDR_FLAGS
;
92 call
->ndr_pull_data
= ndr_pull_init_blob(&trans
->in
.data
, mem_ctx
);
93 call
->ndr_pull_data
->flags
= RAPNDR_FLAGS
;
95 call
->heap
= talloc(mem_ctx
, struct rap_string_heap
);
97 if (call
->heap
== NULL
)
100 ZERO_STRUCTP(call
->heap
);
102 call
->heap
->mem_ctx
= mem_ctx
;
107 static NTSTATUS
rap_srv_pull_word(struct rap_call
*call
, uint16
*result
)
109 if (*call
->paramdesc
++ != 'W')
110 return NT_STATUS_INVALID_PARAMETER
;
112 return ndr_pull_uint16(call
->ndr_pull_param
, NDR_SCALARS
, result
);
115 static NTSTATUS
rap_srv_pull_dword(struct rap_call
*call
, uint32
*result
)
117 if (*call
->paramdesc
++ != 'D')
118 return NT_STATUS_INVALID_PARAMETER
;
120 return ndr_pull_uint32(call
->ndr_pull_param
, NDR_SCALARS
, result
);
123 static NTSTATUS
rap_srv_pull_string(struct rap_call
*call
, const char **result
)
125 char paramdesc
= *call
->paramdesc
++;
127 if (paramdesc
== 'O') {
132 if (paramdesc
!= 'z')
133 return NT_STATUS_INVALID_PARAMETER
;
135 return ndr_pull_string(call
->ndr_pull_param
, NDR_SCALARS
, result
);
138 static NTSTATUS
rap_srv_pull_bufsize(struct rap_call
*call
, uint16
*bufsize
)
142 if ( (*call
->paramdesc
++ != 'r') || (*call
->paramdesc
++ != 'L') )
143 return NT_STATUS_INVALID_PARAMETER
;
145 result
= ndr_pull_uint16(call
->ndr_pull_param
, NDR_SCALARS
, bufsize
);
147 if (!NT_STATUS_IS_OK(result
))
150 call
->heap
->offset
= *bufsize
;
155 static NTSTATUS
rap_srv_pull_expect_multiple(struct rap_call
*call
)
157 if ( (*call
->paramdesc
++ != 'e') || (*call
->paramdesc
++ != 'h') )
158 return NT_STATUS_INVALID_PARAMETER
;
163 static NTSTATUS
rap_push_string(struct ndr_push
*data_push
,
164 struct rap_string_heap
*heap
,
172 space
= strlen(str
)+1;
174 if (heap
->offset
< space
)
175 return NT_STATUS_BUFFER_TOO_SMALL
;
177 heap
->offset
-= space
;
179 NDR_CHECK(ndr_push_uint16(data_push
, NDR_SCALARS
, heap
->offset
));
180 NDR_CHECK(ndr_push_uint16(data_push
, NDR_SCALARS
, 0));
182 heap
->strings
= talloc_realloc(heap
->mem_ctx
,
185 heap
->num_strings
+ 1);
187 if (heap
->strings
== NULL
)
188 return NT_STATUS_NO_MEMORY
;
190 heap
->strings
[heap
->num_strings
] = str
;
191 heap
->num_strings
+= 1;
196 #define NDR_OK(call) do { result = call; \
197 if (NT_STATUS_EQUAL(result, NT_STATUS_BUFFER_TOO_SMALL)) \
198 goto buffer_overflow; \
199 if (!NT_STATUS_IS_OK(result)) \
203 static NTSTATUS
_rap_netshareenum(struct smbsrv_request
*req
,
204 struct rap_call
*call
)
206 struct rap_NetShareEnum r
;
209 NDR_OK(rap_srv_pull_word(call
, &r
.in
.level
));
210 NDR_OK(rap_srv_pull_bufsize(call
, &r
.in
.bufsize
));
211 NDR_OK(rap_srv_pull_expect_multiple(call
));
215 if (strcmp(call
->datadesc
, "B13") != 0)
216 return NT_STATUS_INVALID_PARAMETER
;
219 if (strcmp(call
->datadesc
, "B13BWz") != 0)
220 return NT_STATUS_INVALID_PARAMETER
;
223 return NT_STATUS_INVALID_PARAMETER
;
227 result
= rap_netshareenum(req
, &r
);
229 if (!NT_STATUS_IS_OK(result
))
232 for (r
.out
.count
= 0; r
.out
.count
< r
.out
.available
; r
.out
.count
++) {
235 struct ndr_push_save data_save
;
236 struct rap_heap_save heap_save
;
238 ndr_push_save(call
->ndr_push_data
, &data_save
);
239 rap_heap_save(call
->heap
, &heap_save
);
243 NDR_OK(ndr_push_bytes(call
->ndr_push_data
,
244 (const uint8_t *)r
.out
.info
[i
].info0
.name
,
245 sizeof(r
.out
.info
[i
].info0
.name
)));
248 NDR_OK(ndr_push_bytes(call
->ndr_push_data
,
249 (const uint8_t *)r
.out
.info
[i
].info1
.name
,
250 sizeof(r
.out
.info
[i
].info1
.name
)));
251 NDR_OK(ndr_push_uint8(call
->ndr_push_data
,
252 NDR_SCALARS
, r
.out
.info
[i
].info1
.pad
));
253 NDR_OK(ndr_push_uint16(call
->ndr_push_data
,
254 NDR_SCALARS
, r
.out
.info
[i
].info1
.type
));
256 NDR_OK(rap_push_string(call
->ndr_push_data
,
258 r
.out
.info
[i
].info1
.comment
));
263 if (call
->ndr_push_data
->offset
> call
->heap
->offset
) {
267 ndr_push_restore(call
->ndr_push_data
, &data_save
);
268 rap_heap_restore(call
->heap
, &heap_save
);
273 call
->status
= r
.out
.status
;
275 NDR_CHECK(ndr_push_uint16(call
->ndr_push_param
, NDR_SCALARS
, r
.out
.count
));
276 NDR_CHECK(ndr_push_uint16(call
->ndr_push_param
, NDR_SCALARS
, r
.out
.available
));
278 result
= NT_STATUS_OK
;
284 static NTSTATUS
_rap_netserverenum2(struct smbsrv_request
*req
,
285 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(req
, &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 smbsrv_request
*req
,
370 struct rap_call
*call
)
372 call
->status
= NERR_notsupported
;
381 NTSTATUS (*fn
)(struct smbsrv_request
*req
, struct rap_call
*call
);
383 {"NetShareEnum", RAP_WshareEnum
, _rap_netshareenum
},
384 {"NetServerEnum2", RAP_NetServerEnum2
, _rap_netserverenum2
},
385 {NULL
, -1, api_Unsupported
}
388 NTSTATUS
ipc_rap_call(struct smbsrv_request
*req
, struct smb_trans2
*trans
)
392 struct rap_call
*call
;
393 DATA_BLOB result_param
, result_data
;
394 struct ndr_push
*final_param
;
395 struct ndr_push
*final_data
;
397 call
= new_rap_srv_call(req
, trans
);
400 return NT_STATUS_NO_MEMORY
;
402 NDR_CHECK(ndr_pull_uint16(call
->ndr_pull_param
, NDR_SCALARS
, &call
->callno
));
403 NDR_CHECK(ndr_pull_string(call
->ndr_pull_param
, NDR_SCALARS
,
405 NDR_CHECK(ndr_pull_string(call
->ndr_pull_param
, NDR_SCALARS
,
408 call
->ndr_push_param
= ndr_push_init_ctx(req
);
409 call
->ndr_push_data
= ndr_push_init_ctx(req
);
411 if ((call
->ndr_push_param
== NULL
) || (call
->ndr_push_data
== NULL
))
412 return NT_STATUS_NO_MEMORY
;
414 call
->ndr_push_param
->flags
= RAPNDR_FLAGS
;
415 call
->ndr_push_data
->flags
= RAPNDR_FLAGS
;
417 result
= NT_STATUS_INVALID_SYSTEM_SERVICE
;
419 for (i
=0; api_commands
[i
].name
!= NULL
; i
++) {
420 if (api_commands
[i
].id
== call
->callno
) {
421 DEBUG(5, ("Running RAP call %s\n",
422 api_commands
[i
].name
));
423 result
= api_commands
[i
].fn(req
, call
);
428 if (!NT_STATUS_IS_OK(result
))
431 result_param
= ndr_push_blob(call
->ndr_push_param
);
432 result_data
= ndr_push_blob(call
->ndr_push_data
);
434 final_param
= ndr_push_init_ctx(req
);
435 final_data
= ndr_push_init_ctx(req
);
437 if ((final_param
== NULL
) || (final_data
== NULL
))
438 return NT_STATUS_NO_MEMORY
;
440 final_param
->flags
= RAPNDR_FLAGS
;
441 final_data
->flags
= RAPNDR_FLAGS
;
443 NDR_CHECK(ndr_push_uint16(final_param
, NDR_SCALARS
, call
->status
));
444 NDR_CHECK(ndr_push_uint16(final_param
,
445 NDR_SCALARS
, call
->heap
->offset
- result_data
.length
));
446 NDR_CHECK(ndr_push_bytes(final_param
, result_param
.data
,
447 result_param
.length
));
449 NDR_CHECK(ndr_push_bytes(final_data
, result_data
.data
,
450 result_data
.length
));
452 for (i
=call
->heap
->num_strings
-1; i
>=0; i
--)
453 NDR_CHECK(ndr_push_string(final_data
, NDR_SCALARS
,
454 call
->heap
->strings
[i
]));
456 trans
->out
.setup_count
= 0;
457 trans
->out
.setup
= NULL
;
458 trans
->out
.params
= ndr_push_blob(final_param
);
459 trans
->out
.data
= ndr_push_blob(final_data
);