@@ -212,9 +212,6 @@ int main(int argc, char **argv)
}
}
- if (!nsdb_create_basedir())
- exit(EXIT_FAILURE);
-
if (!fedfsd_drop_privileges(uid, gid))
exit(EXIT_FAILURE);
@@ -115,7 +115,6 @@ struct fedfs_fsl {
* Locate the cert store
*/
_Bool nsdb_set_parentdir(const char *parentdir);
-_Bool nsdb_create_basedir(void);
_Bool nsdb_is_default_parentdir(void);
_Bool nsdb_init_database(void);
@@ -157,50 +157,6 @@ nsdb_set_parentdir(const char *parentdir)
}
/**
- * Create parent directory
- *
- * @return true if fedfsd directory exists
- *
- * Warning: this function must be called as root, and is usually
- * invoked before the process has set its umask.
- */
-_Bool
-nsdb_create_basedir(void)
-{
- struct passwd *pw;
- _Bool retval;
-
- retval = false;
- if (mkdir(fedfs_base_dirname, FEDFS_BASE_DIRMODE) == -1) {
- if (errno == EEXIST) {
- xlog(D_CALL, "FedFS base directory exists");
- retval = true;
- goto out;
- }
- xlog(L_ERROR, "Failed to create base dir: %m");
- goto out;
- }
-
- pw = getpwnam(FEDFS_USER);
- if (pw == NULL) {
- xlog(L_ERROR, "Failed to find %s", FEDFS_USER);
- rmdir(fedfs_base_dirname);
- goto out;
- }
-
- if (chown(fedfs_base_dirname, pw->pw_uid, pw->pw_gid) == -1) {
- xlog(L_ERROR, "Failed to chown base dir: %m");
- rmdir(fedfs_base_dirname);
- goto out;
- }
-
- retval = true;
-
-out:
- return retval;
-}
-
-/**
* Predicate: Does parent directory refer to default FedFS state directory?
*
* @return true if active fedfsd directory is same as default
@@ -241,6 +197,10 @@ nsdb_create_tables(sqlite3 *db)
* Ensure database file and tables exist
*
* @return true if successful
+ *
+ * This must be called with capabilities that allow the base
+ * directory and database to be created. This is typically
+ * "cap_dac_override=ep".
*/
_Bool
nsdb_init_database(void)
@@ -253,6 +213,16 @@ nsdb_init_database(void)
xlog(D_CALL, "%s: Initializing database", __func__);
retval = false;
+
+ if (mkdir(fedfs_base_dirname, FEDFS_BASE_DIRMODE) == -1) {
+ if (errno != EEXIST) {
+ xlog(L_ERROR, "Failed to create base dir: %m");
+ goto out;
+ }
+ xlog(D_GENERAL, "%s: Base dir %s exists",
+ __func__, fedfs_base_dirname);
+ }
+
db = fedfs_open_db(fedfs_db_filename,
SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE);
if (db == NULL)
@@ -27,7 +27,7 @@ noinst_HEADERS = nsdbparams.h
sbin_PROGRAMS = nsdbparams
nsdbparams_SOURCES = delete.c list.c main.c show.c update.c
LDADD = $(LIBLDAP) $(LIBLBER) \
- $(LIBSQLITE3) $(LIBIDN) $(LIBUUID) \
+ $(LIBSQLITE3) $(LIBIDN) $(LIBUUID) $(LIBCAP) \
$(top_builddir)/src/libnsdb/libnsdb.a \
$(top_builddir)/src/libjunction/libjunction.a \
$(top_builddir)/src/libpath/libpath.a \
@@ -199,9 +199,6 @@ nsdbparams_delete(const char *progname, int argc, char **argv)
}
nsdbname = argv[optind];
- if (!nsdb_create_basedir())
- return EXIT_FAILURE;
-
if (!nsdbparams_drop_privileges(uid, gid))
return EXIT_FAILURE;
@@ -177,9 +177,6 @@ nsdbparams_list(const char *progname, int argc, char **argv)
return EXIT_FAILURE;
}
- if (!nsdb_create_basedir())
- return EXIT_FAILURE;
-
if (!nsdbparams_drop_privileges(uid, gid))
return EXIT_FAILURE;
@@ -47,6 +47,11 @@
#include "nsdbparams.h"
/**
+ * Capabilies that nsdbparams should retain, in text format.
+ */
+#define NSDBPARAMS_CAPABILITIES "cap_dac_override=ep"
+
+/**
* Display program synopsis
*
* @param progname NUL-terminated C string containing name of program
@@ -69,6 +74,52 @@ nsdbparams_usage(const char *progname)
}
/**
+ * Clear all capabilities but a certain few.
+ *
+ * @return true if successful
+ *
+ * This permits callers to create directories anywhere, but all other
+ * capabilities are dropped.
+ */
+static _Bool
+nsdbparams_clear_capabilities(void)
+{
+ cap_t caps;
+ char *text;
+
+ caps = cap_from_text(NSDBPARAMS_CAPABILITIES);
+ if (caps == NULL) {
+ xlog(L_ERROR, "Failed to allocate capability: %m");
+ return false;
+ }
+
+ if (cap_set_proc(caps) == -1) {
+ xlog(L_ERROR, "Failed to set capability flags: %m");
+ (void)cap_free(caps);
+ return false;
+ }
+
+ (void)cap_free(caps);
+
+ caps = cap_get_proc();
+ if (caps == NULL)
+ goto out;
+
+ text = cap_to_text(caps, NULL);
+ if (text == NULL)
+ goto out_free;
+
+ xlog(D_CALL, "Process capabilities: %s", text);
+ (void)cap_free(text);
+
+out_free:
+ (void)cap_free(caps);
+
+out:
+ return true;
+}
+
+/**
* Drop root privileges
*
* @param uid run as this effective uid
@@ -80,6 +131,8 @@ nsdbparams_usage(const char *progname)
_Bool
nsdbparams_drop_privileges(const uid_t uid, const gid_t gid)
{
+ _Bool result;
+
(void)umask(S_IWGRP | S_IWOTH);
/*
@@ -109,10 +162,11 @@ nsdbparams_drop_privileges(const uid_t uid, const gid_t gid)
return false;
}
+ result = nsdbparams_clear_capabilities();
+
xlog(D_CALL, "%s: Effective UID, GID: %u, %u",
__func__, geteuid(), getegid());
-
- return true;
+ return result;
}
/**
@@ -189,9 +189,6 @@ nsdbparams_show(const char *progname, int argc, char **argv)
}
}
- if (!nsdb_create_basedir())
- return EXIT_FAILURE;
-
if (!nsdbparams_drop_privileges(uid, gid))
return EXIT_FAILURE;
@@ -333,9 +333,6 @@ nsdbparams_update(const char *progname, int argc, char **argv)
goto out;
}
- if (!nsdb_create_basedir())
- goto out;
-
if (!nsdbparams_drop_privileges(uid, gid))
goto out;
By having nsdbparams retain cap_dac_override=ep, we can create the state directory after dropping privileges, rather than before. This gives better error reporting when fedfsd or nsdbparams are not run as root, and it also automatically creates the directory with the correct owner and group (the extra passwd look-up and chown(2) is unnecessary). A nice side effect is that the state directory can now be created as needed right in nsdb_init_database() rather than having a separate public function to do it. Thus nsdb_create_basedir() is no longer needed and can be removed. Note that the new behavior is slightly different than the old: nsdb_create_basedir() used to use FEDFS_USER always. Now the directory will get whatever uid and gid might be specified on the fedfsd or nsdbparams command line. This makes the --uid and --gid options behave closer to user expectations. Signed-off-by: Chuck Lever <chuck.lever@oracle.com> --- src/fedfsd/main.c | 3 -- src/include/nsdb.h | 1 - src/libnsdb/nsdb.c | 58 +++++++++++--------------------------------- src/nsdbparams/Makefile.am | 2 +- src/nsdbparams/delete.c | 3 -- src/nsdbparams/list.c | 3 -- src/nsdbparams/main.c | 58 ++++++++++++++++++++++++++++++++++++++++++-- src/nsdbparams/show.c | 3 -- src/nsdbparams/update.c | 3 -- 9 files changed, 71 insertions(+), 63 deletions(-)