ldap/servers/slapd/dynalib.c | 47 ++++-------------------------------
ldap/servers/slapd/fedse.c | 50 ++++++++++++++++++++++++++++++++++++++
ldap/servers/slapd/slapi-plugin.h | 10 +++++++
ldap/servers/slapd/util.c | 39 +++++++++++++++++++++++++++++
4 files changed, 105 insertions(+), 41 deletions(-)
New commits:
commit a4b81c0ae59a4246d2d44790efea093a62fc972c
Author: Noriko Hosoi <nhosoi(a)redhat.com>
Date: Thu Jun 27 15:48:30 2013 -0700
Ticket #47384 - Plugin library path validation
Bug description: ldapmodify could replace the plugin path with
an invalid path.
Fix description: This patch adds the validation code to dse
callback. If modify operation is requested for a plugin entry,
the registered callback check_plugin_path is called and check
the given plugin path.
This patch also has made get_plugin_name public as slapi_get_
plugin_name. Now, the following plugin paths are allowed:
/path/to/lib<plugin>.so, /path/to/lib<plugin>,
lib<plugin>.so, lib<plugin>
https://fedorahosted.org/389/ticket/47384
Reviewed by Rich (Thanks!!)
diff --git a/ldap/servers/slapd/dynalib.c b/ldap/servers/slapd/dynalib.c
index 58481a8..0448537 100644
--- a/ldap/servers/slapd/dynalib.c
+++ b/ldap/servers/slapd/dynalib.c
@@ -58,13 +58,6 @@ static struct dynalib {
static void symload_report_error( const char *libpath, char *symbol, char *plugin,
int libopen );
-/* construct a full path and name of a plugin
- very similar to PR_GetLibraryName except that function inserts
- the string "lib" at the beginning of name, making that function
- unsuitable for constructing plugin names
-*/
-static char *get_plugin_name(const char *dir, const char *name);
-
static void free_plugin_name(char *name)
{
PR_smprintf_free(name);
@@ -114,7 +107,11 @@ sym_load_with_flags( char *libpath, char *symbol, char *plugin, int
report_error
}
if (PR_SUCCESS != PR_Access(libpath, PR_ACCESS_READ_OK)) {
- libSpec.value.pathname = get_plugin_name(PLUGINDIR, libpath);
+ if (strncmp(libpath, PLUGINDIR, strlen(PLUGINDIR))) {
+ libSpec.value.pathname = slapi_get_plugin_name(PLUGINDIR, libpath);
+ } else {
+ libSpec.value.pathname = slapi_get_plugin_name(NULL, libpath);
+ }
/* then just handle that failure case with symload_report_error below */
}
@@ -123,7 +120,7 @@ sym_load_with_flags( char *libpath, char *symbol, char *plugin, int
report_error
symload_report_error( libSpec.value.pathname, symbol, plugin, 0 /* lib not open */ );
}
if (libSpec.value.pathname != libpath) {
- free_plugin_name((char *)libSpec.value.pathname); /* cast ok - allocated by
get_plugin_name */
+ free_plugin_name((char *)libSpec.value.pathname); /* cast ok - allocated by
slapi_get_plugin_name */
}
return( NULL );
}
@@ -171,35 +168,3 @@ symload_report_error( const char *libpath, char *symbol, char
*plugin, int libop
libpath, plugin, 0 );
}
}
-
-/* PR_GetLibraryName does almost everything we need, and unfortunately
- a little bit more - it adds "lib" to be beginning of the library
- name if the library name does not end with the current platform
- DLL suffix - so
- foo.so -> /path/foo.so
- libfoo.so -> /path/libfoo.so
- BUT
- foo -> /path/libfoo.so
- libfoo -> /path/liblibfoo.so
-*/
-static char *
-get_plugin_name(const char *path, const char *lib)
-{
- const char *libstr = "/lib";
- size_t libstrlen = 4;
- char *fullname = PR_GetLibraryName(path, lib);
- char *ptr = PL_strrstr(fullname, lib);
-
- /* see if /lib was added */
- if (ptr && ((ptr - fullname) >= libstrlen)) {
- /* ptr is at the libname in fullname, and there is something before it */
- ptr -= libstrlen; /* ptr now points at the "/" in "/lib" if
it is there */
- if (0 == PL_strncmp(ptr, libstr, libstrlen)) {
- /* just copy the remainder of the string on top of here */
- ptr++; /* ptr now points at the "l" in "/lib" - keep the
"/" */
- memmove(ptr, ptr+3, strlen(ptr+3)+1);
- }
- }
-
- return fullname;
-}
diff --git a/ldap/servers/slapd/fedse.c b/ldap/servers/slapd/fedse.c
index 5434c75..ab6ee62 100644
--- a/ldap/servers/slapd/fedse.c
+++ b/ldap/servers/slapd/fedse.c
@@ -1551,6 +1551,8 @@ static const char *easter_egg_photos[NUM_EASTER_EGG_PHOTOS + 1];
static struct dse *pfedse= NULL;
+static int check_plugin_path(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e,
int *returncode, char *returntext, void *arg);
+
static void
internal_add_helper(Slapi_Entry *e, int dont_write_file)
{
@@ -1786,6 +1788,7 @@ setup_internal_backends(char *configdir)
Slapi_Backend *be;
Slapi_DN encryption;
Slapi_DN saslmapping;
+ Slapi_DN plugins;
slapi_sdn_init_ndn_byref(&monitor,"cn=monitor");
slapi_sdn_init_ndn_byref(&counters,"cn=counters,cn=monitor");
@@ -1794,6 +1797,7 @@ setup_internal_backends(char *configdir)
slapi_sdn_init_ndn_byref(&encryption,"cn=encryption,cn=config");
slapi_sdn_init_ndn_byref(&saslmapping,"cn=mapping,cn=sasl,cn=config");
+ slapi_sdn_init_ndn_byref(&plugins,"cn=plugins,cn=config");
/* Search */
dse_register_callback(pfedse,SLAPI_OPERATION_SEARCH,DSE_FLAG_PREOP,&config,LDAP_SCOPE_BASE,"(objectclass=*)",read_config_dse,NULL);
@@ -1809,6 +1813,7 @@ setup_internal_backends(char *configdir)
dse_register_callback(pfedse,SLAPI_OPERATION_MODIFY,DSE_FLAG_POSTOP,&config,LDAP_SCOPE_BASE,"(objectclass=*)",postop_modify_config_dse,NULL);
dse_register_callback(pfedse,SLAPI_OPERATION_MODIFY,DSE_FLAG_PREOP,&root,LDAP_SCOPE_BASE,"(objectclass=*)",modify_root_dse,NULL);
dse_register_callback(pfedse,SLAPI_OPERATION_MODIFY,DSE_FLAG_PREOP,&saslmapping,LDAP_SCOPE_SUBTREE,"(objectclass=nsSaslMapping)",sasl_map_config_modify,NULL);
+ dse_register_callback(pfedse,SLAPI_OPERATION_MODIFY,DSE_FLAG_PREOP,&plugins,LDAP_SCOPE_SUBTREE,"(objectclass=nsSlapdPlugin)",check_plugin_path,NULL);
/* Delete */
dse_register_callback(pfedse,SLAPI_OPERATION_DELETE,DSE_FLAG_PREOP,&config,LDAP_SCOPE_BASE,"(objectclass=*)",dont_allow_that,NULL);
@@ -1839,6 +1844,7 @@ setup_internal_backends(char *configdir)
slapi_sdn_done(&snmp);
slapi_sdn_done(&root);
slapi_sdn_done(&saslmapping);
+ slapi_sdn_done(&plugins);
} else {
slapi_log_error( SLAPI_LOG_FATAL, "dse",
"Please edit the file to correct the reported problems"
@@ -1903,3 +1909,47 @@ int fedse_create_startOK(char *filename, char *startokfilename,
const char *con
return rc;
}
+
+static int
+check_plugin_path(Slapi_PBlock *pb,
+ Slapi_Entry* entryBefore,
+ Slapi_Entry* e,
+ int *returncode,
+ char *returntext,
+ void *arg)
+{
+ /* check for invalid nsslapd-pluginPath */
+ char **vals = slapi_entry_attr_get_charray (e, ATTR_PLUGIN_PATH);
+ int plugindir_len = sizeof(PLUGINDIR)-1;
+ int j = 0;
+ int rc = SLAPI_DSE_CALLBACK_OK;
+ for (j = 0; vals && vals[j]; j++) {
+ char *full_path = NULL;
+ char *resolved_path = NULL;
+ char *res = NULL;
+
+ if ( *vals[j] == '/' ) { /* absolute path */
+ full_path = slapi_get_plugin_name(NULL, vals[j]);
+ } else { /* relative path */
+ full_path = slapi_get_plugin_name(PLUGINDIR, vals[j]);
+ }
+ resolved_path = slapi_ch_malloc(strlen(full_path) + 1);
+ res = realpath( full_path, resolved_path );
+ if (res) {
+ if (strncmp(PLUGINDIR, resolved_path, plugindir_len) != 0) {
+ *returncode = LDAP_UNWILLING_TO_PERFORM;
+ returntext = "Invalid plugin path";
+ rc = SLAPI_DSE_CALLBACK_ERROR;
+ }
+ } else {
+ *returncode = LDAP_UNWILLING_TO_PERFORM;
+ returntext = "Invalid plugin path";
+ rc = SLAPI_DSE_CALLBACK_ERROR;
+ }
+ slapi_ch_free_string(&full_path);
+ slapi_ch_free_string(&resolved_path);
+ }
+ slapi_ch_array_free(vals);
+
+ return rc;
+}
diff --git a/ldap/servers/slapd/slapi-plugin.h b/ldap/servers/slapd/slapi-plugin.h
index d1e90de..9a66f2a 100644
--- a/ldap/servers/slapd/slapi-plugin.h
+++ b/ldap/servers/slapd/slapi-plugin.h
@@ -7495,6 +7495,16 @@ int slapi_eq_cancel(Slapi_Eq_Context ctx);
*/
void *slapi_eq_get_arg (Slapi_Eq_Context ctx);
+/**
+ * Construct a full path and name of a plugin.
+ *
+ * \param dir The Directory where the plugin is located.
+ * \param name The name of the plugin.
+ *
+ * \return absolute path of the plugin. Caller is responsible to free it.
+ */
+char *slapi_get_plugin_name(const char *dir, const char *name);
+
#ifdef __cplusplus
}
#endif
diff --git a/ldap/servers/slapd/util.c b/ldap/servers/slapd/util.c
index 653914b..fb92867 100644
--- a/ldap/servers/slapd/util.c
+++ b/ldap/servers/slapd/util.c
@@ -1395,3 +1395,42 @@ slapi_str_to_u64(const char *s)
(v6 << 36) | (v7 << 32) | (v8 << 28) | (v9 << 24) | (v10
<< 20) | (v11 << 16) |
(v12 << 12) | (v13 << 8) | (v14 << 4) | v15;
}
+
+/* PR_GetLibraryName does almost everything we need, and unfortunately
+ a little bit more - it adds "lib" to be beginning of the library
+ name if the library name does not end with the current platform
+ DLL suffix - so
+ foo.so -> /path/foo.so
+ libfoo.so -> /path/libfoo.so
+ BUT
+ foo -> /path/libfoo.so
+ libfoo -> /path/liblibfoo.so
+ /path/libfoo -> lib/path/libfoo.so
+*/
+char *
+slapi_get_plugin_name(const char *path, const char *lib)
+{
+ const char *libstr = "/lib";
+ size_t libstrlen = 4;
+ char *fullname = PR_GetLibraryName(path, lib);
+ char *ptr = PL_strrstr(fullname, lib);
+
+ /* see if /lib was added */
+ if (ptr && ((ptr - fullname) >= libstrlen)) {
+ /* ptr is at the libname in fullname, and there is something before it */
+ ptr -= libstrlen; /* ptr now points at the "/" in "/lib" if
it is there */
+ if (0 == PL_strncmp(ptr, libstr, libstrlen)) {
+ /* just copy the remainder of the string on top of here */
+ ptr++; /* ptr now points at the "l" in "/lib" - keep the
"/" */
+ memmove(ptr, ptr+3, strlen(ptr+3)+1);
+ }
+ } else if ((NULL == path) && (0 == strncmp(fullname, "lib", 3))) {
+ /*
+ * case: /path/libfoo -> lib/path/libfoo.so
+ * remove "lib".
+ */
+ memmove(fullname, fullname+3, strlen(fullname)-2);
+ }
+
+ return fullname;
+}