summaryrefslogtreecommitdiff
path: root/source4/libcli
diff options
context:
space:
mode:
authorAndrew Tridgell <tridge@samba.org>2003-11-04 09:10:31 +0000
committerAndrew Tridgell <tridge@samba.org>2003-11-04 09:10:31 +0000
commit46046aa69be01d4868395b9b52b8bcd22c3859e5 (patch)
tree3af71169e89f42282e6a4363bc27863ed41ce31d /source4/libcli
parentd8cbe76b868eb6f2b3876fa540e0847bd2d4f9d7 (diff)
downloadsamba-46046aa69be01d4868395b9b52b8bcd22c3859e5.tar.gz
samba-46046aa69be01d4868395b9b52b8bcd22c3859e5.tar.bz2
samba-46046aa69be01d4868395b9b52b8bcd22c3859e5.zip
yipee! we can now do lsaOpenPolicy() via the new interfaces, without
using any of the old lsa code (This used to be commit f5bd301ff7befa223a1d761a37ae8f7ce7f1fcd1)
Diffstat (limited to 'source4/libcli')
-rw-r--r--source4/libcli/ndr/libndr.h6
-rw-r--r--source4/libcli/ndr/ndr_basic.c96
-rw-r--r--source4/libcli/ndr/ndr_echo.c6
-rw-r--r--source4/libcli/ndr/ndr_lsa.c85
-rw-r--r--source4/libcli/ndr/ndr_lsa.h47
-rw-r--r--source4/libcli/ndr/ndr_misc.c45
-rw-r--r--source4/libcli/ndr/ndr_misc.h26
-rw-r--r--source4/libcli/raw/rawdcerpc.c62
-rw-r--r--source4/libcli/rpc/dcerpc.c10
-rw-r--r--source4/libcli/rpc/rpc_lsa.c64
10 files changed, 422 insertions, 25 deletions
diff --git a/source4/libcli/ndr/libndr.h b/source4/libcli/ndr/libndr.h
index 0205a64552..931fc1c341 100644
--- a/source4/libcli/ndr/libndr.h
+++ b/source4/libcli/ndr/libndr.h
@@ -54,6 +54,10 @@ struct ndr_push {
TALLOC_CTX *mem_ctx;
};
+struct ndr_push_save {
+ uint32 offset;
+};
+
#define NDR_BASE_MARSHALL_SIZE 1024
@@ -90,4 +94,6 @@ typedef NTSTATUS (*ndr_pull_fn_t)(struct ndr_pull *, void *);
/* now pull in the individual parsers */
#include "libcli/ndr/ndr_sec.h"
+#include "libcli/ndr/ndr_misc.h"
#include "libcli/ndr/ndr_echo.h"
+#include "libcli/ndr/ndr_lsa.h"
diff --git a/source4/libcli/ndr/ndr_basic.c b/source4/libcli/ndr/ndr_basic.c
index d06eac3ca9..8cbf375403 100644
--- a/source4/libcli/ndr/ndr_basic.c
+++ b/source4/libcli/ndr/ndr_basic.c
@@ -36,21 +36,6 @@
} while(0)
/*
- parse a GUID
-*/
-NTSTATUS ndr_pull_guid(struct ndr_pull *ndr, GUID *guid)
-{
- int i;
- NDR_PULL_NEED_BYTES(ndr, GUID_SIZE);
- for (i=0;i<GUID_SIZE;i++) {
- guid->info[i] = CVAL(ndr->data, ndr->offset + i);
- }
- ndr->offset += i;
- return NT_STATUS_OK;
-}
-
-
-/*
parse a u8
*/
NTSTATUS ndr_pull_u8(struct ndr_pull *ndr, uint8 *v)
@@ -96,17 +81,40 @@ NTSTATUS ndr_pull_u32(struct ndr_pull *ndr, uint32 *v)
}
/*
+ pull a NTSTATUS
+*/
+NTSTATUS ndr_pull_status(struct ndr_pull *ndr, NTSTATUS *status)
+{
+ uint32 v;
+ NDR_CHECK(ndr_pull_u32(ndr, &v));
+ *status = NT_STATUS(v);
+ return NT_STATUS_OK;
+}
+
+/*
parse a set of bytes
*/
-NTSTATUS ndr_pull_bytes(struct ndr_pull *ndr, char **data, uint32 n)
+NTSTATUS ndr_pull_bytes(struct ndr_pull *ndr, char *data, uint32 n)
{
NDR_PULL_NEED_BYTES(ndr, n);
- NDR_ALLOC_N(ndr, *data, n);
- memcpy(*data, ndr->data + ndr->offset, n);
+ memcpy(data, ndr->data + ndr->offset, n);
ndr->offset += n;
return NT_STATUS_OK;
}
+/*
+ parse a GUID
+*/
+NTSTATUS ndr_pull_guid(struct ndr_pull *ndr, GUID *guid)
+{
+ int i;
+ NDR_PULL_NEED_BYTES(ndr, GUID_SIZE);
+ for (i=0;i<GUID_SIZE;i++) {
+ guid->info[i] = CVAL(ndr->data, ndr->offset + i);
+ }
+ ndr->offset += i;
+ return NT_STATUS_OK;
+}
#define NDR_PUSH_NEED_BYTES(ndr, n) NDR_CHECK(ndr_push_expand(ndr, ndr->offset+(n)))
@@ -161,3 +169,55 @@ NTSTATUS ndr_push_bytes(struct ndr_push *ndr, const char *data, uint32 n)
ndr->offset += n;
return NT_STATUS_OK;
}
+
+
+/*
+ this is used when a packet has a 4 byte length field. We remember the start position
+ and come back to it later to fill in the size
+*/
+NTSTATUS ndr_push_length4_start(struct ndr_push *ndr, struct ndr_push_save *save)
+{
+ save->offset = ndr->offset;
+ return ndr_push_u32(ndr, 0);
+}
+
+NTSTATUS ndr_push_length4_end(struct ndr_push *ndr, struct ndr_push_save *save)
+{
+ uint32 offset = ndr->offset;
+ ndr->offset = save->offset;
+ NDR_CHECK(ndr_push_u32(ndr, offset - save->offset));
+ ndr->offset = offset;
+ return NT_STATUS_OK;
+}
+
+/*
+ push a 1 if a pointer is non-NULL, otherwise 0
+*/
+NTSTATUS ndr_push_ptr(struct ndr_push *ndr, const void *p)
+{
+ return ndr_push_u32(ndr, p?1:0);
+}
+
+/*
+ push a comformant, variable ucs2 string onto the wire from a C string
+*/
+NTSTATUS ndr_push_unistr(struct ndr_push *ndr, const char *s)
+{
+ smb_ucs2_t *ws;
+ ssize_t len;
+ int i;
+ len = push_ucs2_talloc(ndr->mem_ctx, &ws, s);
+ if (len == -1) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ NDR_CHECK(ndr_push_u32(ndr, len));
+ NDR_CHECK(ndr_push_u32(ndr, 0));
+ NDR_CHECK(ndr_push_u32(ndr, len-2));
+ NDR_PUSH_NEED_BYTES(ndr, len);
+ for (i=0;i<len;i+=2) {
+ SSVAL(ndr->data, ndr->offset + i, ws[i]);
+ }
+ ndr->offset += i;
+ return NT_STATUS_OK;
+}
+
diff --git a/source4/libcli/ndr/ndr_echo.c b/source4/libcli/ndr/ndr_echo.c
index a085a6534d..c60569676c 100644
--- a/source4/libcli/ndr/ndr_echo.c
+++ b/source4/libcli/ndr/ndr_echo.c
@@ -53,7 +53,8 @@ NTSTATUS ndr_pull_rpcecho_echodata(struct ndr_pull *ndr,
struct rpcecho_echodata *r)
{
NDR_CHECK(ndr_pull_u32(ndr, &r->out.len));
- NDR_CHECK(ndr_pull_bytes(ndr, &r->out.data, r->out.len));
+ NDR_ALLOC_N(ndr, r->out.data, r->out.len);
+ NDR_CHECK(ndr_pull_bytes(ndr, r->out.data, r->out.len));
return NT_STATUS_OK;
}
@@ -97,7 +98,8 @@ NTSTATUS ndr_pull_rpcecho_sourcedata(struct ndr_pull *ndr,
struct rpcecho_sourcedata *r)
{
NDR_CHECK(ndr_pull_u32(ndr, &r->out.len));
- NDR_CHECK(ndr_pull_bytes(ndr, &r->out.data, r->out.len));
+ NDR_ALLOC_N(ndr, r->out.data, r->out.len);
+ NDR_CHECK(ndr_pull_bytes(ndr, r->out.data, r->out.len));
return NT_STATUS_OK;
}
diff --git a/source4/libcli/ndr/ndr_lsa.c b/source4/libcli/ndr/ndr_lsa.c
new file mode 100644
index 0000000000..6649bd04c2
--- /dev/null
+++ b/source4/libcli/ndr/ndr_lsa.c
@@ -0,0 +1,85 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ routines for marshalling/unmarshalling lsa pipe
+
+ Copyright (C) Andrew Tridgell 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+
+#include "includes.h"
+
+NTSTATUS ndr_push_lsa_QosInfo(struct ndr_push *ndr,
+ struct lsa_QosInfo *r)
+{
+ struct ndr_push_save length;
+
+ NDR_CHECK(ndr_push_length4_start(ndr, &length));
+ NDR_CHECK(ndr_push_u16(ndr, r->impersonation_level));
+ NDR_CHECK(ndr_push_u8(ndr, r->context_mode));
+ NDR_CHECK(ndr_push_u8(ndr, r->effective_only));
+ NDR_CHECK(ndr_push_length4_end(ndr, &length));
+
+ return NT_STATUS_OK;
+}
+
+NTSTATUS ndr_push_lsa_ObjectAttribute(struct ndr_push *ndr,
+ struct lsa_ObjectAttribute *r)
+{
+ struct ndr_push_save length;
+
+ NDR_CHECK(ndr_push_length4_start(ndr, &length));
+ NDR_CHECK(ndr_push_ptr(ndr, r->root_dir));
+ NDR_CHECK(ndr_push_ptr(ndr, r->object_name));
+ NDR_CHECK(ndr_push_u32(ndr, r->attributes));
+ NDR_CHECK(ndr_push_ptr(ndr, r->sec_desc));
+ NDR_CHECK(ndr_push_ptr(ndr, r->sec_qos));
+
+ if (r->root_dir) NDR_CHECK(ndr_push_u8(ndr, r->root_dir[0]));
+ if (r->object_name) NDR_CHECK(ndr_push_unistr(ndr, r->object_name));
+ if (r->sec_desc) NDR_CHECK(ndr_push_security_descriptor(ndr, r->sec_desc));
+ if (r->sec_qos) NDR_CHECK(ndr_push_lsa_QosInfo(ndr, r->sec_qos));
+
+ NDR_CHECK(ndr_push_length4_end(ndr, &length));
+
+ return NT_STATUS_OK;
+}
+
+/*
+ push a openpolicy
+*/
+NTSTATUS ndr_push_lsa_OpenPolicy(struct ndr_push *ndr,
+ struct lsa_OpenPolicy *r)
+{
+ NDR_CHECK(ndr_push_ptr(ndr, r->in.system_name));
+ NDR_CHECK(ndr_push_u16(ndr, r->in.system_name[0]));
+ NDR_CHECK(ndr_push_lsa_ObjectAttribute(ndr, r->in.attr));
+ NDR_CHECK(ndr_push_u32(ndr, r->in.desired_access));
+ return NT_STATUS_OK;
+}
+
+
+/*
+ parse a openpolicy
+*/
+NTSTATUS ndr_pull_lsa_OpenPolicy(struct ndr_pull *ndr,
+ struct lsa_OpenPolicy *r)
+{
+ NDR_CHECK(ndr_pull_policy_handle(ndr, &r->out.handle));
+ NDR_CHECK(ndr_pull_status(ndr, &r->out.status));
+ return NT_STATUS_OK;
+}
diff --git a/source4/libcli/ndr/ndr_lsa.h b/source4/libcli/ndr/ndr_lsa.h
new file mode 100644
index 0000000000..4a0aff8323
--- /dev/null
+++ b/source4/libcli/ndr/ndr_lsa.h
@@ -0,0 +1,47 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ definitions for marshalling/unmarshalling the lsa pipe
+
+ Copyright (C) Andrew Tridgell 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+struct lsa_QosInfo {
+ uint16 impersonation_level;
+ uint8 context_mode;
+ uint8 effective_only;
+};
+
+struct lsa_ObjectAttribute {
+ const char *root_dir;
+ const char *object_name;
+ uint32 attributes;
+ struct security_descriptor *sec_desc;
+ struct lsa_QosInfo *sec_qos;
+};
+
+struct lsa_OpenPolicy {
+ struct {
+ const char *system_name;
+ struct lsa_ObjectAttribute *attr;
+ uint32 desired_access;
+ } in;
+ struct {
+ struct policy_handle handle;
+ NTSTATUS status;
+ } out;
+};
diff --git a/source4/libcli/ndr/ndr_misc.c b/source4/libcli/ndr/ndr_misc.c
new file mode 100644
index 0000000000..cdd6652068
--- /dev/null
+++ b/source4/libcli/ndr/ndr_misc.c
@@ -0,0 +1,45 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ routines for marshalling/unmarshalling miscellaneous rpc structures
+
+ Copyright (C) Andrew Tridgell 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+
+#include "includes.h"
+
+
+/*
+ parse a policy handle
+*/
+NTSTATUS ndr_pull_policy_handle(struct ndr_pull *ndr,
+ struct policy_handle *r)
+{
+ NDR_CHECK(ndr_pull_bytes(ndr, r->data, 20));
+ return NT_STATUS_OK;
+}
+
+/*
+ push a policy handle
+*/
+NTSTATUS ndr_push_policy_handle(struct ndr_push *ndr,
+ struct policy_handle *r)
+{
+ NDR_CHECK(ndr_push_bytes(ndr, r->data, 20));
+ return NT_STATUS_OK;
+}
diff --git a/source4/libcli/ndr/ndr_misc.h b/source4/libcli/ndr/ndr_misc.h
new file mode 100644
index 0000000000..cc3576b3e8
--- /dev/null
+++ b/source4/libcli/ndr/ndr_misc.h
@@ -0,0 +1,26 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ definitions for marshalling/unmarshalling miscellaneous structures
+
+ Copyright (C) Andrew Tridgell 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/* policy handles are used all over the place */
+struct policy_handle {
+ char data[20];
+};
diff --git a/source4/libcli/raw/rawdcerpc.c b/source4/libcli/raw/rawdcerpc.c
index a6cd75eeaa..6a3275c7a4 100644
--- a/source4/libcli/raw/rawdcerpc.c
+++ b/source4/libcli/raw/rawdcerpc.c
@@ -22,6 +22,68 @@
#include "includes.h"
+
+/*
+ open a rpc connection to a named pipe
+*/
+NTSTATUS dcerpc_pipe_open_smb(struct dcerpc_pipe *p, const char *pipe_name)
+{
+ NTSTATUS status;
+ char *name = NULL;
+ union smb_open io;
+ TALLOC_CTX *mem_ctx;
+
+ asprintf(&name, "\\%s", pipe_name);
+ if (!name) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ io.ntcreatex.level = RAW_OPEN_NTCREATEX;
+ io.ntcreatex.in.flags = 0;
+ io.ntcreatex.in.root_fid = 0;
+ io.ntcreatex.in.access_mask =
+ STD_RIGHT_READ_CONTROL_ACCESS |
+ SA_RIGHT_FILE_WRITE_ATTRIBUTES |
+ SA_RIGHT_FILE_WRITE_EA |
+ GENERIC_RIGHTS_FILE_READ |
+ GENERIC_RIGHTS_FILE_WRITE;
+ io.ntcreatex.in.file_attr = 0;
+ io.ntcreatex.in.alloc_size = 0;
+ io.ntcreatex.in.share_access =
+ NTCREATEX_SHARE_ACCESS_READ |
+ NTCREATEX_SHARE_ACCESS_WRITE;
+ io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN;
+ io.ntcreatex.in.create_options = 0;
+ io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_IMPERSONATION;
+ io.ntcreatex.in.security_flags = 0;
+ io.ntcreatex.in.fname = name;
+
+ mem_ctx = talloc_init("torture_rpc_connection");
+ status = smb_raw_open(p->tree, mem_ctx, &io);
+ free(name);
+ talloc_destroy(mem_ctx);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ p->fnum = io.ntcreatex.out.fnum;
+
+ /* bind to the pipe, using the pipe_name as the key */
+ status = dcerpc_bind_byname(p, pipe_name);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ union smb_close c;
+ c.close.level = RAW_CLOSE_CLOSE;
+ c.close.in.fnum = p->fnum;
+ c.close.in.write_time = 0;
+ smb_raw_close(p->tree, &c);
+ }
+
+ return status;
+}
+
+
struct cli_request *dcerpc_raw_send(struct dcerpc_pipe *p, DATA_BLOB *blob)
{
struct smb_trans2 trans;
diff --git a/source4/libcli/rpc/dcerpc.c b/source4/libcli/rpc/dcerpc.c
index 7d6888dde7..89f2c6d5b1 100644
--- a/source4/libcli/rpc/dcerpc.c
+++ b/source4/libcli/rpc/dcerpc.c
@@ -28,7 +28,7 @@ struct dcerpc_pipe *dcerpc_pipe_init(struct cli_tree *tree)
{
struct dcerpc_pipe *p;
- TALLOC_CTX *mem_ctx = talloc_init("cli_dcerpc_tree");
+ TALLOC_CTX *mem_ctx = talloc_init("dcerpc_tree");
if (mem_ctx == NULL)
return NULL;
@@ -513,7 +513,7 @@ NTSTATUS dcerpc_bind(struct dcerpc_pipe *p,
DATA_BLOB blob;
DATA_BLOB blob_out;
- mem_ctx = talloc_init("cli_dcerpc_bind");
+ mem_ctx = talloc_init("dcerpc_bind");
if (!mem_ctx) {
return NT_STATUS_NO_MEMORY;
}
@@ -590,7 +590,7 @@ static const struct {
/* Perform a bind using the given well-known pipe name */
-NTSTATUS cli_dcerpc_bind_byname(struct dcerpc_pipe *p, const char *pipe_name)
+NTSTATUS dcerpc_bind_byname(struct dcerpc_pipe *p, const char *pipe_name)
{
int i;
@@ -609,7 +609,7 @@ NTSTATUS cli_dcerpc_bind_byname(struct dcerpc_pipe *p, const char *pipe_name)
/*
perform a full request/response pair on a dcerpc pipe
*/
-NTSTATUS cli_dcerpc_request(struct dcerpc_pipe *p,
+NTSTATUS dcerpc_request(struct dcerpc_pipe *p,
uint16 opnum,
TALLOC_CTX *mem_ctx,
DATA_BLOB *stub_data_in,
@@ -777,7 +777,7 @@ NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
request = ndr_push_blob(push);
/* make the actual dcerpc request */
- status = cli_dcerpc_request(p, opnum, mem_ctx, &request, &response);
+ status = dcerpc_request(p, opnum, mem_ctx, &request, &response);
if (!NT_STATUS_IS_OK(status)) {
goto failed;
}
diff --git a/source4/libcli/rpc/rpc_lsa.c b/source4/libcli/rpc/rpc_lsa.c
new file mode 100644
index 0000000000..b747762984
--- /dev/null
+++ b/source4/libcli/rpc/rpc_lsa.c
@@ -0,0 +1,64 @@
+/*
+ Unix SMB/CIFS implementation.
+
+ rpc lsa pipe calls
+
+ Copyright (C) Andrew Tridgell 2003
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/*
+ OpenPolicy interface
+*/
+NTSTATUS dcerpc_lsa_OpenPolicy(struct dcerpc_pipe *p,
+ const char *server,
+ struct lsa_ObjectAttribute *attr,
+ uint32 access_mask,
+ struct policy_handle *handle)
+{
+ struct lsa_OpenPolicy r;
+ NTSTATUS status;
+ TALLOC_CTX *mem_ctx;
+
+ mem_ctx = talloc_init("dcerpc_rpcecho_addone");
+ if (!mem_ctx) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ /* fill the .in side of the call */
+ r.in.system_name = server;
+ r.in.attr = attr;
+ r.in.desired_access = access_mask;
+
+ /* make the call */
+ status = dcerpc_ndr_request(p, LSA_OPENPOLICY, mem_ctx,
+ (ndr_push_fn_t) ndr_push_lsa_OpenPolicy,
+ (ndr_pull_fn_t) ndr_pull_lsa_OpenPolicy,
+ &r);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto done;
+ }
+
+ /* and extract the .out parameters */
+ *handle = r.out.handle;
+ status = r.out.status;
+
+done:
+ talloc_destroy(mem_ctx);
+ return status;
+}