Blame SOURCES/0007-Ticket-51175-resolve-plugin-name-leaking.patch

6d0b66
From 279bdb5148eb0b67ddab40c4dd9d08e9e1672f13 Mon Sep 17 00:00:00 2001
6d0b66
From: William Brown <william@blackhats.net.au>
6d0b66
Date: Fri, 26 Jun 2020 10:27:56 +1000
6d0b66
Subject: [PATCH 07/12] Ticket 51175 - resolve plugin name leaking
6d0b66
6d0b66
Bug Description: Previously pblock.c assumed that all plugin
6d0b66
names were static c strings. Rust can't create static C
6d0b66
strings, so these were intentionally leaked.
6d0b66
6d0b66
Fix Description: Rather than leak these, we do a dup/free
6d0b66
through the slapiplugin struct instead, meaning we can use
6d0b66
ephemeral, and properly managed strings in rust. This does not
6d0b66
affect any other existing code which will still handle the
6d0b66
static strings correctly.
6d0b66
6d0b66
https://pagure.io/389-ds-base/issue/51175
6d0b66
6d0b66
Author: William Brown <william@blackhats.net.au>
6d0b66
6d0b66
Review by: mreynolds, tbordaz (Thanks!)
6d0b66
---
6d0b66
 Makefile.am                             |  1 +
6d0b66
 configure.ac                            |  2 +-
6d0b66
 ldap/servers/slapd/pagedresults.c       |  6 +--
6d0b66
 ldap/servers/slapd/pblock.c             |  9 ++--
6d0b66
 ldap/servers/slapd/plugin.c             |  7 +++
6d0b66
 ldap/servers/slapd/pw_verify.c          |  1 +
6d0b66
 ldap/servers/slapd/tools/pwenc.c        |  2 +-
6d0b66
 src/slapi_r_plugin/README.md            |  6 +--
6d0b66
 src/slapi_r_plugin/src/charray.rs       | 32 ++++++++++++++
6d0b66
 src/slapi_r_plugin/src/lib.rs           |  8 ++--
6d0b66
 src/slapi_r_plugin/src/macros.rs        | 17 +++++---
6d0b66
 src/slapi_r_plugin/src/syntax_plugin.rs | 57 +++++++------------------
6d0b66
 12 files changed, 85 insertions(+), 63 deletions(-)
6d0b66
 create mode 100644 src/slapi_r_plugin/src/charray.rs
6d0b66
6d0b66
diff --git a/Makefile.am b/Makefile.am
6d0b66
index 627953850..36434cf17 100644
6d0b66
--- a/Makefile.am
6d0b66
+++ b/Makefile.am
6d0b66
@@ -1312,6 +1312,7 @@ rust-nsslapd-private.h: @abs_top_builddir@/rs/@rust_target_dir@/librnsslapd.a
6d0b66
 libslapi_r_plugin_SOURCES = \
6d0b66
 	src/slapi_r_plugin/src/backend.rs \
6d0b66
 	src/slapi_r_plugin/src/ber.rs \
6d0b66
+	src/slapi_r_plugin/src/charray.rs \
6d0b66
 	src/slapi_r_plugin/src/constants.rs \
6d0b66
 	src/slapi_r_plugin/src/dn.rs \
6d0b66
 	src/slapi_r_plugin/src/entry.rs \
6d0b66
diff --git a/configure.ac b/configure.ac
6d0b66
index b3cf77d08..61bf35e4a 100644
6d0b66
--- a/configure.ac
6d0b66
+++ b/configure.ac
6d0b66
@@ -122,7 +122,7 @@ if test "$enable_debug" = yes ; then
6d0b66
   debug_defs="-DDEBUG -DMCC_DEBUG"
6d0b66
   debug_cflags="-g3 -O0 -rdynamic"
6d0b66
   debug_cxxflags="-g3 -O0 -rdynamic"
6d0b66
-  debug_rust_defs="-C debuginfo=2"
6d0b66
+  debug_rust_defs="-C debuginfo=2 -Z macro-backtrace"
6d0b66
   cargo_defs=""
6d0b66
   rust_target_dir="debug"
6d0b66
 else
6d0b66
diff --git a/ldap/servers/slapd/pagedresults.c b/ldap/servers/slapd/pagedresults.c
6d0b66
index d8b8798b6..e3444e944 100644
6d0b66
--- a/ldap/servers/slapd/pagedresults.c
6d0b66
+++ b/ldap/servers/slapd/pagedresults.c
6d0b66
@@ -738,10 +738,10 @@ pagedresults_cleanup(Connection *conn, int needlock)
6d0b66
     int i;
6d0b66
     PagedResults *prp = NULL;
6d0b66
 
6d0b66
-    slapi_log_err(SLAPI_LOG_TRACE, "pagedresults_cleanup", "=>\n");
6d0b66
+    /* slapi_log_err(SLAPI_LOG_TRACE, "pagedresults_cleanup", "=>\n"); */
6d0b66
 
6d0b66
     if (NULL == conn) {
6d0b66
-        slapi_log_err(SLAPI_LOG_TRACE, "pagedresults_cleanup", "<= Connection is NULL\n");
6d0b66
+        /* slapi_log_err(SLAPI_LOG_TRACE, "pagedresults_cleanup", "<= Connection is NULL\n"); */
6d0b66
         return 0;
6d0b66
     }
6d0b66
 
6d0b66
@@ -767,7 +767,7 @@ pagedresults_cleanup(Connection *conn, int needlock)
6d0b66
     if (needlock) {
6d0b66
         pthread_mutex_unlock(&(conn->c_mutex));
6d0b66
     }
6d0b66
-    slapi_log_err(SLAPI_LOG_TRACE, "pagedresults_cleanup", "<= %d\n", rc);
6d0b66
+    /* slapi_log_err(SLAPI_LOG_TRACE, "pagedresults_cleanup", "<= %d\n", rc); */
6d0b66
     return rc;
6d0b66
 }
6d0b66
 
6d0b66
diff --git a/ldap/servers/slapd/pblock.c b/ldap/servers/slapd/pblock.c
6d0b66
index 1ad9d0399..f7d1f8885 100644
6d0b66
--- a/ldap/servers/slapd/pblock.c
6d0b66
+++ b/ldap/servers/slapd/pblock.c
6d0b66
@@ -3351,13 +3351,15 @@ slapi_pblock_set(Slapi_PBlock *pblock, int arg, void *value)
6d0b66
         if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_SYNTAX) {
6d0b66
             return (-1);
6d0b66
         }
6d0b66
-        pblock->pb_plugin->plg_syntax_names = (char **)value;
6d0b66
+        PR_ASSERT(pblock->pb_plugin->plg_syntax_names == NULL);
6d0b66
+        pblock->pb_plugin->plg_syntax_names = slapi_ch_array_dup((char **)value);
6d0b66
         break;
6d0b66
     case SLAPI_PLUGIN_SYNTAX_OID:
6d0b66
         if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_SYNTAX) {
6d0b66
             return (-1);
6d0b66
         }
6d0b66
-        pblock->pb_plugin->plg_syntax_oid = (char *)value;
6d0b66
+        PR_ASSERT(pblock->pb_plugin->plg_syntax_oid == NULL);
6d0b66
+        pblock->pb_plugin->plg_syntax_oid = slapi_ch_strdup((char *)value);
6d0b66
         break;
6d0b66
     case SLAPI_PLUGIN_SYNTAX_FLAGS:
6d0b66
         if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_SYNTAX) {
6d0b66
@@ -3806,7 +3808,8 @@ slapi_pblock_set(Slapi_PBlock *pblock, int arg, void *value)
6d0b66
         if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_MATCHINGRULE) {
6d0b66
             return (-1);
6d0b66
         }
6d0b66
-        pblock->pb_plugin->plg_mr_names = (char **)value;
6d0b66
+        PR_ASSERT(pblock->pb_plugin->plg_mr_names == NULL);
6d0b66
+        pblock->pb_plugin->plg_mr_names = slapi_ch_array_dup((char **)value);
6d0b66
         break;
6d0b66
     case SLAPI_PLUGIN_MR_COMPARE:
6d0b66
         if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_MATCHINGRULE) {
6d0b66
diff --git a/ldap/servers/slapd/plugin.c b/ldap/servers/slapd/plugin.c
6d0b66
index 282b98738..e6b48de60 100644
6d0b66
--- a/ldap/servers/slapd/plugin.c
6d0b66
+++ b/ldap/servers/slapd/plugin.c
6d0b66
@@ -2694,6 +2694,13 @@ plugin_free(struct slapdplugin *plugin)
6d0b66
     if (plugin->plg_type == SLAPI_PLUGIN_PWD_STORAGE_SCHEME || plugin->plg_type == SLAPI_PLUGIN_REVER_PWD_STORAGE_SCHEME) {
6d0b66
         slapi_ch_free_string(&plugin->plg_pwdstorageschemename);
6d0b66
     }
6d0b66
+    if (plugin->plg_type == SLAPI_PLUGIN_SYNTAX) {
6d0b66
+        slapi_ch_free_string(&plugin->plg_syntax_oid);
6d0b66
+        slapi_ch_array_free(plugin->plg_syntax_names);
6d0b66
+    }
6d0b66
+    if (plugin->plg_type == SLAPI_PLUGIN_MATCHINGRULE) {
6d0b66
+        slapi_ch_array_free(plugin->plg_mr_names);
6d0b66
+    }
6d0b66
     release_componentid(plugin->plg_identity);
6d0b66
     slapi_counter_destroy(&plugin->plg_op_counter);
6d0b66
     if (!plugin->plg_group) {
6d0b66
diff --git a/ldap/servers/slapd/pw_verify.c b/ldap/servers/slapd/pw_verify.c
6d0b66
index 4f0944b73..4ff1fa2fd 100644
6d0b66
--- a/ldap/servers/slapd/pw_verify.c
6d0b66
+++ b/ldap/servers/slapd/pw_verify.c
6d0b66
@@ -111,6 +111,7 @@ pw_verify_token_dn(Slapi_PBlock *pb) {
6d0b66
     if (fernet_verify_token(dn, cred->bv_val, key, tok_ttl) != 0) {
6d0b66
         rc = SLAPI_BIND_SUCCESS;
6d0b66
     }
6d0b66
+    slapi_ch_free_string(&key);
6d0b66
 #endif
6d0b66
     return rc;
6d0b66
 }
6d0b66
diff --git a/ldap/servers/slapd/tools/pwenc.c b/ldap/servers/slapd/tools/pwenc.c
6d0b66
index 1629c06cd..d89225e34 100644
6d0b66
--- a/ldap/servers/slapd/tools/pwenc.c
6d0b66
+++ b/ldap/servers/slapd/tools/pwenc.c
6d0b66
@@ -34,7 +34,7 @@
6d0b66
 
6d0b66
 int ldap_syslog;
6d0b66
 int ldap_syslog_level;
6d0b66
-int slapd_ldap_debug = LDAP_DEBUG_ANY;
6d0b66
+/* int slapd_ldap_debug = LDAP_DEBUG_ANY; */
6d0b66
 int detached;
6d0b66
 FILE *error_logfp;
6d0b66
 FILE *access_logfp;
6d0b66
diff --git a/src/slapi_r_plugin/README.md b/src/slapi_r_plugin/README.md
6d0b66
index af9743ec9..1c9bcbf17 100644
6d0b66
--- a/src/slapi_r_plugin/README.md
6d0b66
+++ b/src/slapi_r_plugin/README.md
6d0b66
@@ -15,7 +15,7 @@ the [Rust Nomicon](https://doc.rust-lang.org/nomicon/index.html)
6d0b66
 > warning about danger.
6d0b66
 
6d0b66
 This document will not detail the specifics of unsafe or the invariants you must adhere to for rust
6d0b66
-to work with C.
6d0b66
+to work with C. Failure to uphold these invariants will lead to less than optimal consequences.
6d0b66
 
6d0b66
 If you still want to see more about the plugin bindings, go on ...
6d0b66
 
6d0b66
@@ -135,7 +135,7 @@ associated functions.
6d0b66
 Now, you may notice that not all members of the trait are implemented. This is due to a feature
6d0b66
 of rust known as default trait impls. This allows the trait origin (src/plugin.rs) to provide
6d0b66
 template versions of these functions. If you "overwrite" them, your implementation is used. Unlike
6d0b66
-OO, you may not inherit or call the default function. 
6d0b66
+OO, you may not inherit or call the default function.
6d0b66
 
6d0b66
 If a default is not provided you *must* implement that function to be considered valid. Today (20200422)
6d0b66
 this only applies to `start` and `close`.
6d0b66
@@ -183,7 +183,7 @@ It's important to understand how Rust manages memory both on the stack and the h
6d0b66
 As a result, this means that we must express in code, assertions about the proper ownership of memory
6d0b66
 and who is responsible for it (unlike C, where it can be hard to determine who or what is responsible
6d0b66
 for freeing some value.) Failure to handle this correctly, can and will lead to crashes, leaks or
6d0b66
-*hand waving* magical failures that are eXtReMeLy FuN to debug.
6d0b66
+*hand waving* magical failures that are `eXtReMeLy FuN` to debug.
6d0b66
 
6d0b66
 ### Reference Types
6d0b66
 
6d0b66
diff --git a/src/slapi_r_plugin/src/charray.rs b/src/slapi_r_plugin/src/charray.rs
6d0b66
new file mode 100644
6d0b66
index 000000000..d2e44693c
6d0b66
--- /dev/null
6d0b66
+++ b/src/slapi_r_plugin/src/charray.rs
6d0b66
@@ -0,0 +1,32 @@
6d0b66
+use std::ffi::CString;
6d0b66
+use std::iter::once;
6d0b66
+use std::os::raw::c_char;
6d0b66
+use std::ptr;
6d0b66
+
6d0b66
+pub struct Charray {
6d0b66
+    pin: Vec<CString>,
6d0b66
+    charray: Vec<*const c_char>,
6d0b66
+}
6d0b66
+
6d0b66
+impl Charray {
6d0b66
+    pub fn new(input: &[&str]) -> Result<Self, ()> {
6d0b66
+        let pin: Result<Vec<_>, ()> = input
6d0b66
+            .iter()
6d0b66
+            .map(|s| CString::new(*s).map_err(|_e| ()))
6d0b66
+            .collect();
6d0b66
+
6d0b66
+        let pin = pin?;
6d0b66
+
6d0b66
+        let charray: Vec<_> = pin
6d0b66
+            .iter()
6d0b66
+            .map(|s| s.as_ptr())
6d0b66
+            .chain(once(ptr::null()))
6d0b66
+            .collect();
6d0b66
+
6d0b66
+        Ok(Charray { pin, charray })
6d0b66
+    }
6d0b66
+
6d0b66
+    pub fn as_ptr(&self) -> *const *const c_char {
6d0b66
+        self.charray.as_ptr()
6d0b66
+    }
6d0b66
+}
6d0b66
diff --git a/src/slapi_r_plugin/src/lib.rs b/src/slapi_r_plugin/src/lib.rs
6d0b66
index 076907bae..be28cac95 100644
6d0b66
--- a/src/slapi_r_plugin/src/lib.rs
6d0b66
+++ b/src/slapi_r_plugin/src/lib.rs
6d0b66
@@ -1,9 +1,11 @@
6d0b66
-// extern crate lazy_static;
6d0b66
+#[macro_use]
6d0b66
+extern crate lazy_static;
6d0b66
 
6d0b66
 #[macro_use]
6d0b66
 pub mod macros;
6d0b66
 pub mod backend;
6d0b66
 pub mod ber;
6d0b66
+pub mod charray;
6d0b66
 mod constants;
6d0b66
 pub mod dn;
6d0b66
 pub mod entry;
6d0b66
@@ -20,6 +22,7 @@ pub mod value;
6d0b66
 pub mod prelude {
6d0b66
     pub use crate::backend::{BackendRef, BackendRefTxn};
6d0b66
     pub use crate::ber::BerValRef;
6d0b66
+    pub use crate::charray::Charray;
6d0b66
     pub use crate::constants::{FilterType, PluginFnType, PluginType, PluginVersion, LDAP_SUCCESS};
6d0b66
     pub use crate::dn::{Sdn, SdnRef};
6d0b66
     pub use crate::entry::EntryRef;
6d0b66
@@ -30,8 +33,7 @@ pub mod prelude {
6d0b66
     pub use crate::plugin::{register_plugin_ext, PluginIdRef, SlapiPlugin3};
6d0b66
     pub use crate::search::{Search, SearchScope};
6d0b66
     pub use crate::syntax_plugin::{
6d0b66
-        matchingrule_register, name_to_leaking_char, names_to_leaking_char_array, SlapiOrdMr,
6d0b66
-        SlapiSubMr, SlapiSyntaxPlugin1,
6d0b66
+        matchingrule_register, SlapiOrdMr, SlapiSubMr, SlapiSyntaxPlugin1,
6d0b66
     };
6d0b66
     pub use crate::task::{task_register_handler_fn, task_unregister_handler_fn, Task, TaskRef};
6d0b66
     pub use crate::value::{Value, ValueArray, ValueArrayRef, ValueRef};
6d0b66
diff --git a/src/slapi_r_plugin/src/macros.rs b/src/slapi_r_plugin/src/macros.rs
6d0b66
index bc8dfa60f..97fc5d7ef 100644
6d0b66
--- a/src/slapi_r_plugin/src/macros.rs
6d0b66
+++ b/src/slapi_r_plugin/src/macros.rs
6d0b66
@@ -249,6 +249,7 @@ macro_rules! slapi_r_syntax_plugin_hooks {
6d0b66
         paste::item! {
6d0b66
             use libc;
6d0b66
             use std::convert::TryFrom;
6d0b66
+            use std::ffi::CString;
6d0b66
 
6d0b66
             #[no_mangle]
6d0b66
             pub extern "C" fn [<$mod_ident _plugin_init>](raw_pb: *const libc::c_void) -> i32 {
6d0b66
@@ -261,15 +262,15 @@ macro_rules! slapi_r_syntax_plugin_hooks {
6d0b66
                 };
6d0b66
 
6d0b66
                 // Setup the names/oids that this plugin provides syntaxes for.
6d0b66
-
6d0b66
-                let name_ptr = unsafe { names_to_leaking_char_array(&$hooks_ident::attr_supported_names()) };
6d0b66
-                match pb.register_syntax_names(name_ptr) {
6d0b66
+                // DS will clone these, so they can be ephemeral to this function.
6d0b66
+                let name_vec = Charray::new($hooks_ident::attr_supported_names().as_slice()).expect("invalid supported names");
6d0b66
+                match pb.register_syntax_names(name_vec.as_ptr()) {
6d0b66
                     0 => {},
6d0b66
                     e => return e,
6d0b66
                 };
6d0b66
 
6d0b66
-                let name_ptr = unsafe { name_to_leaking_char($hooks_ident::attr_oid()) };
6d0b66
-                match pb.register_syntax_oid(name_ptr) {
6d0b66
+                let attr_oid = CString::new($hooks_ident::attr_oid()).expect("invalid attr oid");
6d0b66
+                match pb.register_syntax_oid(attr_oid.as_ptr()) {
6d0b66
                     0 => {},
6d0b66
                     e => return e,
6d0b66
                 };
6d0b66
@@ -430,7 +431,8 @@ macro_rules! slapi_r_syntax_plugin_hooks {
6d0b66
                     e => return e,
6d0b66
                 };
6d0b66
 
6d0b66
-                let name_ptr = unsafe { names_to_leaking_char_array(&$hooks_ident::eq_mr_supported_names()) };
6d0b66
+                let name_vec = Charray::new($hooks_ident::eq_mr_supported_names().as_slice()).expect("invalid mr supported names");
6d0b66
+                let name_ptr = name_vec.as_ptr();
6d0b66
                 // SLAPI_PLUGIN_MR_NAMES
6d0b66
                 match pb.register_mr_names(name_ptr) {
6d0b66
                     0 => {},
6d0b66
@@ -672,7 +674,8 @@ macro_rules! slapi_r_syntax_plugin_hooks {
6d0b66
                     e => return e,
6d0b66
                 };
6d0b66
 
6d0b66
-                let name_ptr = unsafe { names_to_leaking_char_array(&$hooks_ident::ord_mr_supported_names()) };
6d0b66
+                let name_vec = Charray::new($hooks_ident::ord_mr_supported_names().as_slice()).expect("invalid ord supported names");
6d0b66
+                let name_ptr = name_vec.as_ptr();
6d0b66
                 // SLAPI_PLUGIN_MR_NAMES
6d0b66
                 match pb.register_mr_names(name_ptr) {
6d0b66
                     0 => {},
6d0b66
diff --git a/src/slapi_r_plugin/src/syntax_plugin.rs b/src/slapi_r_plugin/src/syntax_plugin.rs
6d0b66
index e7d5c01bd..86f84bdd8 100644
6d0b66
--- a/src/slapi_r_plugin/src/syntax_plugin.rs
6d0b66
+++ b/src/slapi_r_plugin/src/syntax_plugin.rs
6d0b66
@@ -1,11 +1,11 @@
6d0b66
 use crate::ber::BerValRef;
6d0b66
 // use crate::constants::FilterType;
6d0b66
+use crate::charray::Charray;
6d0b66
 use crate::error::PluginError;
6d0b66
 use crate::pblock::PblockRef;
6d0b66
 use crate::value::{ValueArray, ValueArrayRef};
6d0b66
 use std::cmp::Ordering;
6d0b66
 use std::ffi::CString;
6d0b66
-use std::iter::once;
6d0b66
 use std::os::raw::c_char;
6d0b66
 use std::ptr;
6d0b66
 
6d0b66
@@ -26,37 +26,6 @@ struct slapi_matchingRuleEntry {
6d0b66
     mr_compat_syntax: *const *const c_char,
6d0b66
 }
6d0b66
 
6d0b66
-pub unsafe fn name_to_leaking_char(name: &str) -> *const c_char {
6d0b66
-    let n = CString::new(name)
6d0b66
-        .expect("An invalid string has been hardcoded!")
6d0b66
-        .into_boxed_c_str();
6d0b66
-    let n_ptr = n.as_ptr();
6d0b66
-    // Now we intentionally leak the name here, and the pointer will remain valid.
6d0b66
-    Box::leak(n);
6d0b66
-    n_ptr
6d0b66
-}
6d0b66
-
6d0b66
-pub unsafe fn names_to_leaking_char_array(names: &[&str]) -> *const *const c_char {
6d0b66
-    let n_arr: Vec<CString> = names
6d0b66
-        .iter()
6d0b66
-        .map(|s| CString::new(*s).expect("An invalid string has been hardcoded!"))
6d0b66
-        .collect();
6d0b66
-    let n_arr = n_arr.into_boxed_slice();
6d0b66
-    let n_ptr_arr: Vec<*const c_char> = n_arr
6d0b66
-        .iter()
6d0b66
-        .map(|v| v.as_ptr())
6d0b66
-        .chain(once(ptr::null()))
6d0b66
-        .collect();
6d0b66
-    let n_ptr_arr = n_ptr_arr.into_boxed_slice();
6d0b66
-
6d0b66
-    // Now we intentionally leak these names here,
6d0b66
-    let _r_n_arr = Box::leak(n_arr);
6d0b66
-    let r_n_ptr_arr = Box::leak(n_ptr_arr);
6d0b66
-
6d0b66
-    let name_ptr = r_n_ptr_arr as *const _ as *const *const c_char;
6d0b66
-    name_ptr
6d0b66
-}
6d0b66
-
6d0b66
 // oid - the oid of the matching rule
6d0b66
 // name - the name of the mr
6d0b66
 // desc - description
6d0b66
@@ -69,20 +38,24 @@ pub unsafe fn matchingrule_register(
6d0b66
     syntax: &str,
6d0b66
     compat_syntax: &[&str],
6d0b66
 ) -> i32 {
6d0b66
-    let oid_ptr = name_to_leaking_char(oid);
6d0b66
-    let name_ptr = name_to_leaking_char(name);
6d0b66
-    let desc_ptr = name_to_leaking_char(desc);
6d0b66
-    let syntax_ptr = name_to_leaking_char(syntax);
6d0b66
-    let compat_syntax_ptr = names_to_leaking_char_array(compat_syntax);
6d0b66
+    // Make everything CStrings that live long enough.
6d0b66
+
6d0b66
+    let oid_cs = CString::new(oid).expect("invalid oid");
6d0b66
+    let name_cs = CString::new(name).expect("invalid name");
6d0b66
+    let desc_cs = CString::new(desc).expect("invalid desc");
6d0b66
+    let syntax_cs = CString::new(syntax).expect("invalid syntax");
6d0b66
+
6d0b66
+    // We have to do this so the cstrings live long enough.
6d0b66
+    let compat_syntax_ca = Charray::new(compat_syntax).expect("invalid compat_syntax");
6d0b66
 
6d0b66
     let new_mr = slapi_matchingRuleEntry {
6d0b66
-        mr_oid: oid_ptr,
6d0b66
+        mr_oid: oid_cs.as_ptr(),
6d0b66
         _mr_oidalias: ptr::null(),
6d0b66
-        mr_name: name_ptr,
6d0b66
-        mr_desc: desc_ptr,
6d0b66
-        mr_syntax: syntax_ptr,
6d0b66
+        mr_name: name_cs.as_ptr(),
6d0b66
+        mr_desc: desc_cs.as_ptr(),
6d0b66
+        mr_syntax: syntax_cs.as_ptr(),
6d0b66
         _mr_obsolete: 0,
6d0b66
-        mr_compat_syntax: compat_syntax_ptr,
6d0b66
+        mr_compat_syntax: compat_syntax_ca.as_ptr(),
6d0b66
     };
6d0b66
 
6d0b66
     let new_mr_ptr = &new_mr as *const _;
6d0b66
-- 
6d0b66
2.26.3
6d0b66