Patchwork [11/12] libnsdb: Eliminate nsdb_create_basedir()

login
register
mail settings
Submitter Chuck Lever
Date Nov. 11, 2011, 8:27 p.m.
Message ID <20111111202736.10717.33589.stgit@degas.1015granger.net>
Download mbox | patch
Permalink /patch/125292/
State Accepted
Headers show

Comments

Chuck Lever - Nov. 11, 2011, 8:27 p.m.
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(-)

Patch

diff --git a/src/fedfsd/main.c b/src/fedfsd/main.c
index 31718e8..eb7ab48 100644
--- a/src/fedfsd/main.c
+++ b/src/fedfsd/main.c
@@ -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);
 
diff --git a/src/include/nsdb.h b/src/include/nsdb.h
index 9c8383b..2ba1b7a 100644
--- a/src/include/nsdb.h
+++ b/src/include/nsdb.h
@@ -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);
 
diff --git a/src/libnsdb/nsdb.c b/src/libnsdb/nsdb.c
index c81f228..dec2091 100644
--- a/src/libnsdb/nsdb.c
+++ b/src/libnsdb/nsdb.c
@@ -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)
diff --git a/src/nsdbparams/Makefile.am b/src/nsdbparams/Makefile.am
index ddc3cd9..6205e32 100644
--- a/src/nsdbparams/Makefile.am
+++ b/src/nsdbparams/Makefile.am
@@ -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 \
diff --git a/src/nsdbparams/delete.c b/src/nsdbparams/delete.c
index 37f30b1..6b86e3d 100644
--- a/src/nsdbparams/delete.c
+++ b/src/nsdbparams/delete.c
@@ -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;
 
diff --git a/src/nsdbparams/list.c b/src/nsdbparams/list.c
index e79b896..f877604 100644
--- a/src/nsdbparams/list.c
+++ b/src/nsdbparams/list.c
@@ -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;
 
diff --git a/src/nsdbparams/main.c b/src/nsdbparams/main.c
index 91b0372..6e96c1c 100644
--- a/src/nsdbparams/main.c
+++ b/src/nsdbparams/main.c
@@ -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;
 }
 
 /**
diff --git a/src/nsdbparams/show.c b/src/nsdbparams/show.c
index ba52521..d95f61c 100644
--- a/src/nsdbparams/show.c
+++ b/src/nsdbparams/show.c
@@ -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;
 
diff --git a/src/nsdbparams/update.c b/src/nsdbparams/update.c
index bde2151..d073552 100644
--- a/src/nsdbparams/update.c
+++ b/src/nsdbparams/update.c
@@ -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;