#endif
#include <sys/types.h>
+#ifdef HAVE_SYS_CAPABILITY_H
+#include <sys/capability.h>
+#endif
+#include <sys/prctl.h>
#include <sys/stat.h>
#include <ctype.h>
* containing an appropriate pathname, or NULL if an error
* occurs. Caller must free the returned result with free(3).
*/
-__attribute_malloc__
+__attribute__((__malloc__))
static char *
nsm_make_record_pathname(const char *directory, const char *hostname)
{
* containing an appropriate pathname, or NULL if an error
* occurs. Caller must free the returned result with free(3).
*/
-__attribute_malloc__
+__attribute__((__malloc__))
static char *
nsm_make_pathname(const char *directory)
{
* containing an appropriate pathname, or NULL if an error
* occurs. Caller must free the returned result with free(3).
*/
-__attribute_malloc__
+__attribute__((__malloc__))
static char *
nsm_make_temp_pathname(const char *pathname)
{
return strcmp(nsm_base_dirname, NSM_DEFAULT_STATEDIR) == 0;
}
+/*
+ * Clear all capabilities but CAP_NET_BIND_SERVICE. This permits
+ * callers to acquire privileged source ports, but all other root
+ * capabilities are disallowed.
+ *
+ * Returns true if successful, or false if some error occurred.
+ */
+static _Bool
+nsm_clear_capabilities(void)
+{
+#ifdef HAVE_SYS_CAPABILITY_H
+ cap_t caps;
+
+ caps = cap_from_text("cap_net_bind_service=ep");
+ 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);
+#endif
+ return true;
+}
+
/**
* nsm_drop_privileges - drop root privileges
* @pidfd: file descriptor of a pid file
return false;
}
- if (st.st_uid == 0) {
- xlog_warn("Running as root. "
- "chown %s to choose different user", nsm_base_dirname);
- return true;
- }
-
if (chdir(nsm_base_dirname) == -1) {
xlog(L_ERROR, "Failed to change working directory to %s: %m",
nsm_base_dirname);
return false;
}
+ if (st.st_uid == 0) {
+ xlog_warn("Running as root. "
+ "chown %s to choose different user", nsm_base_dirname);
+ return true;
+ }
+
/*
* If the pidfile happens to reside on NFS, dropping privileges
* will probably cause us to lose access, even though we are
if (fchown(pidfd, st.st_uid, st.st_gid) == -1)
xlog_warn("Failed to change owner of pidfile: %m");
+ /*
+ * Don't clear capabilities when dropping root.
+ */
+ if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) == -1) {
+ xlog(L_ERROR, "prctl(PR_SET_KEEPCAPS) failed: %m");
+ return false;
+ }
+
if (setgroups(0, NULL) == -1) {
xlog(L_ERROR, "Failed to drop supplementary groups: %m");
return false;
}
xlog(D_CALL, "Effective UID, GID: %u, %u", st.st_uid, st.st_gid);
- return true;
+
+ return nsm_clear_capabilities();
}
/**
while ((de = readdir(dir)) != NULL) {
char *src, *dst;
+ struct stat stb;
- if (de->d_type != (unsigned char)DT_REG)
- continue;
if (de->d_name[0] == '.')
continue;
continue;
}
+ /* NB: not all file systems fill in d_type correctly */
+ if (lstat(src, &stb) == -1) {
+ xlog_warn("Bad monitor file %s, skipping: %m",
+ de->d_name);
+ free(src);
+ continue;
+ }
+ if (!S_ISREG(stb.st_mode)) {
+ xlog(D_GENERAL, "Skipping non-regular file %s",
+ de->d_name);
+ free(src);
+ continue;
+ }
+
dst = nsm_make_record_pathname(NSM_NOTIFY_DIR, de->d_name);
if (dst == NULL) {
free(src);
/*
* Returns the length in bytes of the created record.
*/
-__attribute_noinline__
+__attribute__((__noinline__))
static size_t
nsm_create_monitor_record(char *buf, const size_t buflen,
const struct sockaddr *sap, const struct mon *m)
return result;
}
-__attribute_noinline__
+__attribute__((__noinline__))
static _Bool
nsm_parse_line(char *line, struct sockaddr_in *sin, struct mon *m)
{
}
/*
- * Given a filename, reads data from a file under NSM_MONITOR_DIR
+ * Given a filename, reads data from a file under "directory"
* and invokes @func so caller can populate their in-core
* database with this data.
*/
if (path == NULL)
goto out_err;
- if (stat(path, &stb) == -1) {
+ if (lstat(path, &stb) == -1) {
xlog(L_ERROR, "Failed to stat %s: %m", path);
goto out_freepath;
}
+ if (!S_ISREG(stb.st_mode)) {
+ xlog(D_GENERAL, "Skipping non-regular file %s",
+ path);
+ goto out_freepath;
+ }
f = fopen(path, "r");
if (f == NULL) {
}
while ((de = readdir(dir)) != NULL) {
- if (de->d_type != (unsigned char)DT_REG)
- continue;
if (de->d_name[0] == '.')
continue;