summaryrefslogtreecommitdiffabout
authorSergey Poznyakoff <gray@nxc.no>2017-08-15 06:58:21 (GMT)
committer Sergey Poznyakoff <gray@nxc.no>2017-08-15 06:58:21 (GMT)
commit4d1f42638d16cf6f26983cee38a4c36e4b64b68a (patch) (side-by-side diff)
tree0718ed6117fc8c021a2a68294f3a74fb7eb1e495
parent03a9d11a59cec2047ec1282e0dfa76ef1f248a18 (diff)
downloadnssync-4d1f42638d16cf6f26983cee38a4c36e4b64b68a.tar.gz
nssync-4d1f42638d16cf6f26983cee38a4c36e4b64b68a.tar.bz2
Switch to user's privileges, if required
* src/runas.c: New file. * src/Makefile.am: Add runas.c * src/config.c: Move mysql configuration to a separate block. New configuration statements: "user" and "group". * src/nssync.c (main): Optionally switch to user privileges before starting operation. * src/nssync.h (runas_user, runas_group): New externs. (DEFAULT_NSSYNC_ADDR): Change to a safer value. (runas): New proto. * src/server.c (nssync_resources): Change endpoint. (nssync_mhd_handler): Remove debugging print.
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--src/Makefile.am1
-rw-r--r--src/config.c21
-rw-r--r--src/nssync.c2
-rw-r--r--src/nssync.h6
-rw-r--r--src/runas.c179
-rw-r--r--src/server.c7
6 files changed, 207 insertions, 9 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index e2e3783..5706ab7 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -22,6 +22,7 @@ nssync_SOURCES = \
nssync.c\
nssync.h\
output.c\
+ runas.c\
sqlop.c
if COND_MICROHTTPD
diff --git a/src/config.c b/src/config.c
index 0481dfe..b8f062e 100644
--- a/src/config.c
+++ b/src/config.c
@@ -118,12 +118,12 @@ cb_sync(enum grecs_callback_command cmd,
}
return err;
}
-
-static struct grecs_keyword nssync_kw[] = {
- { "sql-config-file",
+
+static struct grecs_keyword mysql_kw[] = {
+ { "config-file",
"file", "Read MySQL configuration from <file>",
grecs_type_string, GRECS_DFLT, &sql_config_file },
- { "sql-config-group",
+ { "config-group",
"name", "Read the named group from the SQL configuration file",
grecs_type_string, GRECS_DFLT, &sql_config_group },
{ "host",
@@ -145,12 +145,22 @@ static struct grecs_keyword nssync_kw[] = {
{ "slave-status-file",
NULL, "Check slave status and save it in the given file",
grecs_type_string, GRECS_DFLT, &slave_status_file },
+ { NULL }
+};
+static struct grecs_keyword nssync_kw[] = {
{ "pidfile",
"file",
"At startup, check if <file> already exists and is "
"owned by an existing process. Exit if so.",
grecs_type_string, GRECS_DFLT, &pidfile },
+
+ { "user",
+ "name", "Run as this user",
+ grecs_type_string, GRECS_DFLT, &runas_user },
+ { "group",
+ "name", "Run as this group",
+ grecs_type_string, GRECS_DFLT, &runas_group },
{ "tempdir",
NULL, "Name for the temporary directory (must exist)",
@@ -184,6 +194,9 @@ static struct grecs_keyword nssync_kw[] = {
{ "server", NULL, "Configure HTTP server",
grecs_type_section, GRECS_DFLT, NULL, 0, NULL, NULL, server_kw },
+
+ { "mysql", NULL, "Configure MySQL access",
+ grecs_type_section, GRECS_DFLT, NULL, 0, NULL, NULL, mysql_kw },
{ NULL }
};
diff --git a/src/nssync.c b/src/nssync.c
index e18100c..41a03af 100644
--- a/src/nssync.c
+++ b/src/nssync.c
@@ -617,6 +617,8 @@ main(int argc, char **argv)
get_host_addresses();
check_pidfile();
+
+ runas();
if (server_mode)
nssync_server();
diff --git a/src/nssync.h b/src/nssync.h
index 063b33a..588f28e 100644
--- a/src/nssync.h
+++ b/src/nssync.h
@@ -38,13 +38,15 @@ extern char *pidfile;
extern char *tempdir;
extern char *reload_command;
extern int check_ns;
+extern char *runas_user;
+extern char *runas_group;
extern struct json_value *changed_zones;
extern struct json_value *error_list;
extern struct grecs_sockaddr *server_addr;
#ifndef DEFAULT_NSSYNC_ADDR
-# define DEFAULT_NSSYNC_ADDR "0.0.0.0:8080"
+# define DEFAULT_NSSYNC_ADDR "127.0.0.1:8080"
#endif
extern char *sql_config_file;
@@ -86,6 +88,8 @@ void verror(const char *fmt, va_list ap);
void error(const char *fmt, ...) __PRINTFLIKE(1,2);
void debug_printf(const char *fmt, ...) __PRINTFLIKE(1,2);
+void runas(void);
+
void dlz_error(char const *zone, char const *fmt, ...);
void dlz_success(char const *zone);
diff --git a/src/runas.c b/src/runas.c
new file mode 100644
index 0000000..8d86468
--- a/dev/null
+++ b/src/runas.c
@@ -0,0 +1,179 @@
+/* This file is part of NSsync
+ Copyright (C) 2017 Sergey Poznyakoff
+
+ NSsync is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ NSsync is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with NSsync. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "nssync.h"
+#include <pwd.h>
+#include <grp.h>
+
+char *runas_user;
+char *runas_group;
+
+#ifndef SIZE_T_MAX
+# define SIZE_T_MAX ((size_t)-1)
+#endif
+
+static void
+addgid(gid_t **pgv, size_t *pgc, size_t *pgi, gid_t gid)
+{
+ gid_t *gv = *pgv;
+ size_t gc = *pgc;
+ size_t gi = *pgi;
+
+ if (gi == gc) {
+ if (gc == 0) {
+ gc = 16;
+ gv = grecs_calloc(gc, sizeof(*gv));
+ } else if (gc <= SIZE_T_MAX / 2 / sizeof(*gv)) {
+ gc *= 2;
+ gv = grecs_realloc(gv, gc * sizeof(*gv));
+ }
+ }
+ gv[gi++] = gid;
+ *pgv = gv;
+ *pgc = gc;
+ *pgi = gi;
+}
+
+static int
+member(gid_t *gv, size_t gc, gid_t gid)
+{
+ size_t i;
+
+ for (i = 0; i < gc; i++)
+ if (gv[i] == gid)
+ return 1;
+ return 0;
+}
+
+static size_t
+get_user_groups(const char *user, gid_t **pgv, size_t *pgc)
+{
+ struct group *gr;
+ size_t gi = 0;
+
+ setgrent();
+ while ((gr = getgrent())) {
+ char **p;
+ for (p = gr->gr_mem; *p; p++)
+ if (strcmp(*p, user) == 0)
+ addgid(pgv, pgc, &gi, gr->gr_gid);
+ }
+ endgrent();
+ return gi;
+}
+
+void
+runas(void)
+{
+ struct passwd *pw;
+ struct group *gr;
+ uid_t uid;
+ gid_t gid;
+ char const *user_name;
+ gid_t *gv;
+ size_t gc, gn;
+
+ if (!(runas_user || runas_group))
+ return;
+ if (getuid() != 0) {
+ error("not root: can't switch to user privileges");
+ exit(EX_USAGE);
+ }
+
+ user_name = runas_user;
+ if (!user_name) {
+ pw = getpwuid(0);
+ user_name = "root";
+ } else if (user_name[0] == '+') {
+ char *end;
+ unsigned long n;
+
+ errno = 0;
+ n = strtoul(user_name + 1, &end, 10);
+ if (errno || *end) {
+ error("invalid user name %s", user_name);
+ exit(EX_USAGE);
+ }
+
+ pw = getpwuid(n);
+ } else
+ pw = getpwnam(user_name);
+
+ if (!pw) {
+ error("%s: no such user", runas_user);
+ exit(EX_USAGE);
+ }
+ user_name = pw->pw_name;
+
+ uid = pw->pw_uid;
+ gid = pw->pw_gid;
+
+ if (runas_group) {
+ if (runas_group[0] == '+') {
+ char *end;
+ unsigned long n;
+
+ errno = 0;
+ n = strtoul(runas_group + 1, &end, 10);
+ if (errno || *end) {
+ error("invalid group name %s", runas_group);
+ exit(EX_USAGE);
+ }
+
+ gr = getgrgid(n);
+ } else
+ gr = getgrnam(runas_group);
+
+ if (!gr) {
+ error("%s: no such group", runas_user);
+ exit(EX_USAGE);
+ }
+
+ gid = gr->gr_gid;
+ }
+
+ gv = NULL;
+ gc = 0;
+ gn = get_user_groups(user_name, &gv, &gc);
+ if (!member(gv, gn, gid))
+ addgid(&gv, &gc, &gn, gid);
+
+ /* Reset group permissions */
+ if (setgroups(gc, gv)) {
+ error("setgroups failed: %s", strerror(errno));
+ exit(EX_UNAVAILABLE);
+ }
+ free(gv);
+
+
+ if (gid) {
+ /* Switch to the user's gid. */
+ if (setgid(gid)) {
+ error("setgid(%lu) failed: %s",
+ (unsigned long) gid, strerror(errno));
+ exit(EX_UNAVAILABLE);
+ }
+ }
+
+ /* Now reset uid */
+ if (uid) {
+ if (setuid(uid)) {
+ error("setuid(%lu) failed: %s",
+ (unsigned long) uid, strerror(errno));
+ exit(EX_UNAVAILABLE);
+ }
+ }
+}
diff --git a/src/server.c b/src/server.c
index ae0d755..574c34e 100644
--- a/src/server.c
+++ b/src/server.c
@@ -180,7 +180,7 @@ struct nssync_resource {
static struct nssync_resource nssync_resources[] = {
#define S(s) #s, (sizeof(#s) - 1)
- { S(sync), do_sync },
+ { S(nssync), do_sync },
#undef S
{ NULL }
};
@@ -219,8 +219,7 @@ nssync_mhd_handler(void *cls,
void **con_cls)
{
MHD_AccessHandlerCallback cb;
- error("METHOD: %s",method);
- error("URL: %s",url);
+
cb = find_callback(&url);
return cb(cls, conn, url, method, version, upload_data,
upload_data_size, con_cls);
@@ -234,7 +233,7 @@ nssync_server(void)
if (!server_addr) {
if (grecs_str_to_sockaddr(&server_addr, DEFAULT_NSSYNC_ADDR,
- NULL, NULL))
+ grecs_sockaddr_hints, NULL))
exit(EX_UNAVAILABLE);
}

Return to:

Send suggestions and report system problems to the System administrator.