aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2007-11-19 13:41:07 +0000
committerSergey Poznyakoff <gray@gnu.org.ua>2007-11-19 13:41:07 +0000
commit719964de49d9a50b63b006bcf64e632c2503327a (patch)
treed1210d7baaec5a7fcc05067108b6dd7d24cd9e31
parentb1a3e134c1e3127cf3f31cdfa24d784858c9873d (diff)
downloadmailfromd-719964de49d9a50b63b006bcf64e632c2503327a.tar.gz
mailfromd-719964de49d9a50b63b006bcf64e632c2503327a.tar.bz2
* smap: New directory.
* smap/smap.c: New file. A general-purpose socket map for MeTA1 (for future use). git-svn-id: file:///svnroot/mailfromd/trunk@1528 7a8a7f39-df28-0410-adc6-e0d955640f24
-rw-r--r--ChangeLog4
-rw-r--r--smap/smap.c907
2 files changed, 911 insertions, 0 deletions
diff --git a/ChangeLog b/ChangeLog
index e57b7c75..71380907 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,9 @@
2007-11-19 Sergey Poznyakoff <gray@gnu.org.ua>
+ * smap: New directory.
+ * smap/smap.c: New file. A general-purpose socket map for MeTA1
+ (for future use).
+
* src/mu_dbm.c [WITH_GDBM]: do not bail out if the database does
not exist.
* src/mailfromd.h: Add argp.h
diff --git a/smap/smap.c b/smap/smap.c
new file mode 100644
index 00000000..f22cf27b
--- /dev/null
+++ b/smap/smap.c
@@ -0,0 +1,907 @@
+/* This file is part of smap.
+ Copyright (C) 2006, 2007 Sergey Poznyakoff
+
+ This program 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.
+
+ This program 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 this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <signal.h>
+#include <syslog.h>
+#include <grp.h>
+#include <pwd.h>
+#include <ctype.h>
+#include <sysexits.h> /* FIXME */
+#include <mailutils/mailutils.h>
+#define obstack_chunk_alloc malloc
+#define obstack_chunk_free free
+#include <obstack.h>
+
+/* FIXME */
+#include <inttypes.h>
+const char *mu_umaxtostr (unsigned slot, uintmax_t val);
+
+#define DEFAULT_URL "tcp://127.0.0.1:"
+int reuse_smap_address = 1;
+char *smap_url_string;
+char *run_as_user;
+char *syslog_tag;
+char *negative_reply = "Nie znam takiego";
+char *positive_reply = "Swoj chlop";
+
+struct daemon_param daemon_param = {
+ MODE_DAEMON, /* Start in daemon mode */
+ 20, /* Default maximum number of children */
+ 0, /* No standard port */
+ 600, /* Idle timeout */
+ 0, /* No transcript by default */
+ NULL /* No PID file by default */
+};
+
+typedef union
+{
+ struct sockaddr sa;
+ struct sockaddr_in s_in;
+ struct sockaddr_un s_un;
+} all_addr_t;
+
+enum macro_id {
+ MACRO_KEY,
+ MACRO_AUTH_NAME,
+ MACRO_AUTH_PASSWD,
+ MACRO_AUTH_UID,
+ MACRO_AUTH_GID,
+ MACRO_AUTH_GECOS,
+ MACRO_AUTH_DIR,
+ MACRO_AUTH_SHELL,
+ MACRO_AUTH_MAILBOX,
+ MACRO_AUTH_QUOTA
+};
+
+struct macro_tab
+{
+ char *name;
+ size_t len;
+ enum macro_id id;
+};
+
+static struct macro_tab macro_tab[] = {
+#define S(s,m) { s, sizeof (s) - 1, m }
+ { "key", 3, MACRO_KEY },
+ S(MU_AUTH_NAME, MACRO_AUTH_NAME),
+ S(MU_AUTH_PASSWD, MACRO_AUTH_PASSWD),
+ S(MU_AUTH_UID, MACRO_AUTH_UID),
+ S(MU_AUTH_GID, MACRO_AUTH_GID),
+ S(MU_AUTH_GECOS, MACRO_AUTH_GECOS),
+ S(MU_AUTH_DIR, MACRO_AUTH_DIR),
+ S(MU_AUTH_SHELL, MACRO_AUTH_SHELL),
+ S(MU_AUTH_MAILBOX, MACRO_AUTH_MAILBOX),
+ S(MU_AUTH_QUOTA, MACRO_AUTH_QUOTA),
+ { NULL }
+#undef S
+#undef concat
+};
+
+static struct obstack expand_stk;
+
+static const char *
+expand_macro (const char *str, const char *key, struct mu_auth_data *auth,
+ int delim, const char **endp)
+{
+ const char *p;
+ size_t len;
+ struct macro_tab *macro;
+ const char *ret = NULL;
+
+ for (p = str; *p != delim && isascii (*p) && isalpha (*p); p++)
+ ;
+ len = p - str;
+ for (macro = macro_tab; macro->name; macro++)
+ {
+ if (len == macro->len && memcmp (macro->name, str, len) == 0)
+ {
+ switch (macro->id)
+ {
+ case MACRO_KEY:
+ ret = key;
+ break;
+
+ case MACRO_AUTH_NAME:
+ ret = auth ? auth->name : "";
+ break;
+
+ case MACRO_AUTH_PASSWD:
+ ret = auth ? auth->passwd : "";
+ break;
+
+ case MACRO_AUTH_UID:
+ ret = auth ? mu_umaxtostr (1, auth->uid) : "-1";
+ break;
+
+ case MACRO_AUTH_GID:
+ ret = auth ? mu_umaxtostr (1, auth->gid) : "-1";
+ break;
+
+ case MACRO_AUTH_GECOS:
+ ret = auth ? auth->gecos : "";
+ break;
+
+ case MACRO_AUTH_DIR:
+ ret = auth ? auth->dir : "";
+ break;
+
+ case MACRO_AUTH_SHELL:
+ ret = auth ? auth->shell : "";
+ break;
+
+ case MACRO_AUTH_MAILBOX:
+ ret = auth ? auth->mailbox : "";
+ break;
+
+ case MACRO_AUTH_QUOTA:
+ ret = auth ? mu_umaxtostr (1, auth->quota) : "NONE";
+ break;
+ }
+ break;
+ }
+ }
+ if (ret)
+ *endp = *p ? p + 1 : p;
+ return ret;
+}
+
+static const char *
+expand_reply_text (const char *arg, const char *key, struct mu_auth_data *auth)
+{
+ const char *p;
+ const char *str;
+
+ obstack_init (&expand_stk);
+ for (p = arg; *p; )
+ {
+ if (*p == '$')
+ {
+ if (p[1] == '$')
+ {
+ obstack_1grow (&expand_stk, '$');
+ p += 2;
+ }
+ else if (p[1] == '{')
+ {
+ str = expand_macro (p + 2, key, auth, '}', &p);
+ if (str)
+ obstack_grow (&expand_stk, str, strlen (str));
+ else
+ {
+ obstack_grow (&expand_stk, p, 2);
+ p += 2;
+ }
+ }
+ else
+ {
+ str = expand_macro (p + 1, key, auth, 0, &p);
+ if (str)
+ obstack_grow (&expand_stk, str, strlen (str));
+ else
+ {
+ obstack_grow (&expand_stk, p, 1);
+ p++;
+ }
+ }
+ }
+ else
+ {
+ obstack_1grow (&expand_stk, *p);
+ p++;
+ }
+ }
+ obstack_1grow (&expand_stk, 0);
+ return obstack_finish (&expand_stk);
+}
+
+static int
+smap_open_internal (int *pfd, mu_url_t url, const char *urlstr)
+{
+ int fd;
+ int rc;
+ int t = 1;
+ char buffer[64];
+ all_addr_t addr;
+ int addrsize;
+ mode_t saved_umask;
+
+ rc = mu_url_get_scheme (url, buffer, sizeof buffer, NULL);
+ if (rc)
+ {
+ mu_error (_("%s: cannot get scheme from URL: %s"),
+ urlstr, mu_strerror(rc));
+ return EX_CONFIG;
+ }
+
+ memset (&addr, 0, sizeof addr);
+ if (strcmp (buffer, "file") == 0 || strcmp (buffer, "socket") == 0)
+ {
+ size_t size;
+
+ rc = mu_url_get_path (url, NULL, 0, &size);
+ if (rc)
+ {
+ mu_error (_("%s: cannot get path: %s"), urlstr, mu_strerror(rc));
+ return EX_CONFIG;
+ }
+
+ if (size > sizeof addr.s_un.sun_path - 1)
+ {
+ mu_error (_("%s: file name too long"), urlstr);
+ return EX_TEMPFAIL;
+ }
+ mu_url_get_path (url, addr.s_un.sun_path, sizeof addr.s_un.sun_path,
+ NULL);
+
+ fd = socket (PF_UNIX, SOCK_STREAM, 0);
+ if (fd < 0)
+ {
+ mu_error ("socket: %s", mu_strerror (errno));
+ return EX_TEMPFAIL;
+ }
+
+ addr.s_un.sun_family = AF_UNIX;
+ addrsize = sizeof addr.s_un;
+
+ if (reuse_smap_address)
+ {
+ struct stat st;
+ if (stat (addr.s_un.sun_path, &st))
+ {
+ if (errno != ENOENT)
+ {
+ mu_error (_("file %s exists but cannot be stat'd"),
+ addr.s_un.sun_path);
+ return EX_TEMPFAIL;
+ }
+ }
+ else if (!S_ISSOCK (st.st_mode))
+ {
+ mu_error (_("file %s is not a socket"),
+ addr.s_un.sun_path);
+ return EX_TEMPFAIL;
+ }
+ else
+ unlink (addr.s_un.sun_path);
+ }
+
+ }
+ else if (strcmp (buffer, "tcp") == 0)
+ {
+ size_t size;
+ long n;
+ struct hostent *hp;
+ char *path = NULL;
+ short port = 0;
+
+ rc = mu_url_get_port (url, &n);
+ if (rc)
+ {
+ mu_error (_("%s: cannot get port: %s"), urlstr, mu_strerror(rc));
+ return EX_CONFIG;
+ }
+
+ if (n == 0 || (port = n) != n)
+ {
+ mu_error (_("Port out of range: %ld"), n);
+ return EX_CONFIG;
+ }
+
+ rc = mu_url_get_host (url, NULL, 0, &size);
+ if (rc)
+ {
+ mu_error (_("%s: cannot get host: %s"), urlstr, mu_strerror(rc));
+ return EX_CONFIG;
+ }
+ path = malloc (size + 1);
+ if (!path)
+ {
+ mu_error (_("Not enough memory"));
+ return EX_TEMPFAIL;
+ }
+ mu_url_get_host (url, path, size + 1, NULL);
+
+ fd = socket (PF_INET, SOCK_STREAM, 0);
+ if (fd < 0)
+ {
+ mu_error ("socket: %s", mu_strerror (errno));
+ return EX_TEMPFAIL;
+ }
+
+ addr.s_in.sin_family = AF_INET;
+ if (hp = gethostbyname (path))
+ {
+ char **ap;
+ int count = 0;
+
+ addr.s_in.sin_addr.s_addr = *(unsigned long*) hp->h_addr_list[0];
+
+ for (ap = hp->h_addr_list; *ap; ap++)
+ count++;
+ if (count > 1)
+ mu_error (_("warning: %s has several IP addresses, using %s"),
+ path, inet_ntoa (addr.s_in.sin_addr));
+ }
+ else if (inet_aton (path, &addr.s_in.sin_addr) == 0)
+ {
+ mu_error ("invalid IP address: %s", path);
+ return EX_TEMPFAIL;
+ }
+ addr.s_in.sin_port = htons (port);
+ addrsize = sizeof addr.s_in;
+
+ if (reuse_smap_address)
+ setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, &t, sizeof(t));
+ }
+ else
+ {
+ mu_error (_("%s: invalid scheme"), urlstr);
+ return EX_CONFIG;
+ }
+
+ saved_umask = umask (0117);
+ if (bind (fd, &addr.sa, addrsize) == -1)
+ {
+ mu_error ("bind: %s", strerror (errno));
+ close (fd);
+ return EXIT_FAILURE;
+ }
+ umask (saved_umask);
+ *pfd = fd;
+ return 0;
+}
+
+int
+smap_open (int *pfd, char *urlstr)
+{
+ mu_url_t url = NULL;
+ int rc;
+
+ rc = mu_url_create (&url, urlstr);
+ if (rc)
+ {
+ mu_error (_("%s: cannot create URL: %s"),
+ urlstr, mu_strerror (rc));
+ return EX_CONFIG;
+ }
+ rc = mu_url_parse (url);
+ if (rc)
+ {
+ mu_error (_("%s: error parsing URL: %s"),
+ urlstr, mu_strerror(rc));
+ return EX_CONFIG;
+ }
+
+ rc = smap_open_internal (pfd, url, urlstr);
+ mu_url_destroy (&url);
+ return rc;
+}
+
+size_t children;
+static int need_cleanup = 0;
+
+void
+process_cleanup ()
+{
+ pid_t pid;
+ int status;
+
+ if (need_cleanup)
+ {
+ need_cleanup = 0;
+ while ( (pid = waitpid (-1, &status, WNOHANG)) > 0)
+ --children;
+ }
+}
+
+RETSIGTYPE
+smap_sigchld (int signo)
+{
+ need_cleanup = 1;
+#ifndef HAVE_SIGACTION
+ signal (signo, smap_sigchld);
+#endif
+}
+
+void
+log_connection (all_addr_t *addr, socklen_t addrlen)
+{
+ switch (addr->sa.sa_family)
+ {
+ case PF_UNIX:
+ syslog (LOG_INFO, _("connect from socket"));
+ break;
+
+ case PF_INET:
+ syslog (LOG_INFO, _("connect from %s"), inet_ntoa (addr->s_in.sin_addr));
+ }
+}
+
+int
+smap_daemon (char *urlstr)
+{
+ int rc;
+ int listenfd, connfd;
+ all_addr_t addr;
+ socklen_t addrlen;
+ pid_t pid;
+
+ if (daemon_param.mode == MODE_DAEMON)
+ {
+ if (daemon (0, 0) < 0)
+ {
+ mu_error (_("Failed to become a daemon"));
+ return EX_UNAVAILABLE;
+ }
+ }
+
+ rc = smap_open (&listenfd, urlstr);
+ if (rc)
+ return rc;
+
+ if (listen (listenfd, 128) == -1)
+ {
+ mu_error ("listen: %s", strerror (errno));
+ close (listenfd);
+ return EX_UNAVAILABLE;
+ }
+
+#ifdef HAVE_SIGACTION
+ {
+ struct sigaction act;
+ act.sa_handler = lmtp_sigchld;
+ sigemptyset (&act.sa_mask);
+ act.sa_flags = 0;
+ sigaction (SIGCHLD, &act, NULL);
+ }
+#else
+ signal (SIGCHLD, smap_sigchld);
+#endif
+
+ for (;;)
+ {
+ process_cleanup ();
+ if (children > daemon_param.maxchildren)
+ {
+ mu_error (_("too many children (%lu)"),
+ (unsigned long) children);
+ pause ();
+ continue;
+ }
+ addrlen = sizeof addr;
+ connfd = accept (listenfd, (struct sockaddr *)&addr, &addrlen);
+ if (connfd == -1)
+ {
+ if (errno == EINTR)
+ continue;
+ mu_error ("accept: %s", strerror (errno));
+ continue;
+ /*exit (EXIT_FAILURE);*/
+ }
+
+ log_connection (&addr, addrlen);
+
+ pid = fork ();
+ if (pid == -1)
+ syslog (LOG_ERR, "fork: %s", strerror (errno));
+ else if (pid == 0) /* Child. */
+ {
+ int status;
+
+ close (listenfd);
+ status = smap_loop (fdopen (connfd, "r"), fdopen (connfd, "w"));
+ exit (status);
+ }
+ else
+ {
+ ++children;
+ }
+ close (connfd);
+ }
+}
+
+
+const char *program_version = "smap (" PACKAGE_STRING ")";
+static char doc[] = "Simple remote map for MeTA1";
+static char args_doc[] = "";
+
+#define OPTION_GECOS 256
+#define OPTION_POSITIVE_REPLY 257
+#define OPTION_NEGATIVE_REPLY 258
+#define OPTION_NEGATIVE_OK 259
+
+static struct argp_option options[] =
+{
+ { "url", 'u', "URL", 0,
+ N_("Set URL to listen on"), 0 },
+ { "user", 'U', "NAME", 0,
+ N_("Run as user NAME"), 0 },
+ { "gecos", OPTION_GECOS, NULL, 0,
+ N_("Return gecos"), 0 },
+ { "log-tag", 'L', N_("STRING"), 0,
+ N_("Set syslog tag"), 0 },
+ { "positive-reply", OPTION_POSITIVE_REPLY, N_("STRING"), 0,
+ N_("Set positive reply text"), 0 },
+ { "negative-reply", OPTION_NEGATIVE_REPLY, N_("STRING"), 0,
+ N_("Set negative reply text"), 0 },
+ { NULL }
+};
+
+static error_t parse_opt (int key, char *arg, struct argp_state *state);
+
+static struct argp argp = {
+ options,
+ parse_opt,
+ args_doc,
+ doc,
+ NULL,
+ NULL, NULL
+};
+
+static const char *argp_capa[] = {
+ "daemon",
+ "auth",
+ "common",
+ "license",
+ "logging",
+ NULL
+};
+
+static error_t
+parse_opt (int key, char *arg, struct argp_state *state)
+{
+ switch (key)
+ {
+ case ARGP_KEY_INIT:
+ state->child_inputs[0] = state->input;
+ break;
+
+ case OPTION_NEGATIVE_REPLY:
+ negative_reply = arg;
+ break;
+
+ case OPTION_POSITIVE_REPLY:
+ positive_reply = arg;
+ break;
+
+ case 'L':
+ syslog_tag = arg;
+ break;
+
+ case 'U':
+ run_as_user = arg;
+ break;
+
+ case 'u':
+ smap_url_string = arg;
+ break;
+
+ case OPTION_GECOS:
+ positive_reply = "${gecos}";
+ break;
+
+ default:
+ return ARGP_ERR_UNKNOWN;
+
+ case ARGP_KEY_ERROR:
+ exit (EX_USAGE);
+ }
+ return 0;
+}
+
+int
+read_delim (FILE *fp, int delim, char *buf, size_t bufsize)
+{
+ int c;
+ int len = 0;
+
+ bufsize--;
+ while (len < bufsize && ((c = fgetc (fp))) != delim)
+ {
+ if (c == EOF)
+ {
+ if (len)
+ {
+ if (daemon_param.transcript && len)
+ syslog (LOG_INFO, "recv: %.*s:", len, buf);
+ mu_error ("unexpected end of file in input");
+ exit (1);
+ }
+ return 0;
+ }
+ buf[len++] = c;
+ }
+ buf[len] = 0;
+ if (daemon_param.transcript)
+ syslog (LOG_INFO, "recv: %s:", buf);
+ return len;
+}
+
+void
+smap_reply (FILE *fp, const char *code, const char *result)
+{
+ size_t len = strlen (code);
+ if (result)
+ len += 1 + strlen (result);
+ if (result)
+ {
+ if (daemon_param.transcript)
+ syslog (LOG_INFO, "send: %lu:%s %s,",
+ (unsigned long) len, code, result);
+ fprintf (fp, "%lu:%s %s,", (unsigned long) len, code, result);
+ }
+ else
+ {
+ if (daemon_param.transcript)
+ syslog (LOG_INFO, "send: %lu:%s,",
+ (unsigned long) len, code);
+ fprintf (fp, "%s:%s,", (unsigned long) len, code);
+ }
+}
+
+int
+smap_loop (FILE *in, FILE *out)
+{
+ char buf[80];
+ size_t len;
+ char *key, *p;
+ struct mu_auth_data *auth;
+
+ setvbuf (in, NULL, _IONBF, 0);
+ setvbuf (out, NULL, _IONBF, 0);
+
+ /* Read input: */
+ while (read_delim (in, ':', buf, sizeof buf))
+ {
+ len = strtoul (buf, &p, 10);
+ if (*p != 0)
+ {
+ mu_error ("protocol error: expected packet length, but found %s", buf);
+ exit (1);
+ }
+
+ if (len > sizeof buf - 1)
+ {
+ mu_error ("protocol error: packet length too big");
+ exit (1);
+ }
+
+ if (fread (buf, 1, len, in) != len)
+ {
+ mu_error ("protocol error: short read");
+ exit (1);
+ }
+
+ buf[len] = 0;
+
+ if (daemon_param.transcript)
+ syslog (LOG_INFO, "recv: %s,", buf);
+
+ if (getc (in) != ',')
+ {
+ mu_error ("protocol error: missing terminating comma");
+ exit (1);
+ }
+ buf[len] = 0;
+
+ key = strchr (buf, ' ');
+ if (!key)
+ {
+ mu_error ("protocol error: missing map name");
+ exit (1);
+ }
+ key++;
+
+ len = strlen (key);
+ if (key[len-1] == '*')
+ key[len-1] = 0;
+
+ auth = mu_get_auth_by_name (key);
+
+ /* Reply: */
+ if (!auth)
+ {
+ smap_reply (out, "NOTFOUND",
+ expand_reply_text (negative_reply, key, NULL));
+ }
+ else
+ {
+ smap_reply (out, "OK", expand_reply_text (positive_reply, key, auth));
+ mu_auth_data_free (auth);
+ }
+ }
+ /* Cleanup and exit */
+ fclose (in);
+ fclose (out);
+ return 0;
+}
+
+int
+switch_to_privs (uid_t uid, gid_t gid)
+{
+ int rc = 0;
+ gid_t emptygidset;
+
+ if (uid == 0)
+ return 1;
+
+ /* Reset group permissions */
+ if (geteuid() == 0 && setgroups(1, &gid))
+ {
+ mu_error (_("setgroups(1, %lu) failed: %s"),
+ (unsigned long) gid,
+ mu_strerror (errno));
+ rc = 1;
+ }
+
+ /* Switch to the user's gid. On some OSes the effective gid must
+ be reset first */
+
+#if defined(HAVE_SETEGID)
+ if ((rc = setegid (gid)) < 0)
+ mu_error (_("setegid(%lu) failed: %s"),
+ (unsigned long) gid, mu_strerror (errno));
+#elif defined(HAVE_SETREGID)
+ if ((rc = setregid (gid, gid)) < 0)
+ mu_error(_("setregid(%lu,%lu) failed: %s"),
+ (unsigned long) gid, (unsigned long) gid,
+ mu_strerror (errno));
+#elif defined(HAVE_SETRESGID)
+ if ((rc = setresgid (gid, gid, gid)) < 0)
+ mu_error (_("setresgid(%lu,%lu,%lu) failed: %s"),
+ (unsigned long) gid,
+ (unsigned long) gid,
+ (unsigned long) gid,
+ mu_strerror (errno));
+#endif
+
+ if (rc == 0 && gid != 0)
+ {
+ if ((rc = setgid (gid)) < 0 && getegid () != gid)
+ mu_error (_("setgid(%lu) failed: %s"),
+ (unsigned long) gid, mu_strerror (errno));
+ if (rc == 0 && getegid() != gid)
+ {
+ mu_error (_("Cannot set effective gid to %lu"),
+ (unsigned long) gid);
+ rc = 1;
+ }
+ }
+
+ /* Now reset uid */
+ if (rc == 0 && uid != 0)
+ {
+ uid_t euid;
+
+ if (setuid (uid)
+ || geteuid () != uid
+ || (getuid () != uid
+ && (geteuid () == 0 || getuid () == 0)))
+ {
+#if defined(HAVE_SETREUID)
+ if (geteuid () != uid)
+ {
+ if (setreuid (uid, -1) < 0)
+ {
+ mu_error (_("setreuid(%lu,-1) failed"),
+ (unsigned long) uid,
+ mu_strerror (errno));
+ rc = 1;
+ }
+ if (setuid (uid) < 0)
+ {
+ mu_error (_("second setuid(%lu) failed"),
+ (unsigned long) uid,
+ mu_strerror (errno));
+ rc = 1;
+ }
+ }
+ else
+#endif
+ {
+ mu_error (_("setuid(%lu) failed"),
+ (unsigned long) uid,
+ mu_strerror (errno));
+ rc = 1;
+ }
+ }
+
+ euid = geteuid ();
+ if (uid != 0 && setuid (0) == 0)
+ {
+ mu_error (_("seteuid(0) succeeded when it should not"));
+ rc = 1;
+ }
+ else if (uid != euid && setuid (euid) == 0)
+ {
+ mu_error (_("Cannot drop non-root setuid privileges"));
+ rc = 1;
+ }
+ }
+ return rc;
+}
+
+void
+priv_setup ()
+{
+ if (getuid () == 0 && run_as_user)
+ {
+ struct passwd *pw = getpwnam (run_as_user);
+ if (!pw)
+ {
+ mu_error (_("No such user: %s"), run_as_user);
+ exit (EX_SOFTWARE);
+ }
+ if (pw && switch_to_privs (pw->pw_uid, pw->pw_gid))
+ exit (EX_SOFTWARE);
+ }
+}
+
+int
+main (int argc, char **argv)
+{
+ int arg_index;
+ struct group *gr;
+
+ MU_AUTH_REGISTER_ALL_MODULES ();
+ mu_argp_init (program_version, "<" PACKAGE_BUGREPORT ">");
+ syslog_tag = strrchr (argv[0], '/');
+ if (syslog_tag)
+ syslog_tag++;
+ else
+ syslog_tag = argv[0];
+ /* Parse command line */
+ mu_argp_parse (&argp, &argc, &argv, 0, argp_capa, &arg_index, &daemon_param);
+ if (!smap_url_string && !daemon_param.port && daemon_param.mode != MODE_INTERACTIVE)
+ {
+ mu_error ("either --url or --port must be given");
+ exit (EX_CONFIG);
+ }
+
+ openlog (syslog_tag, LOG_PID, log_facility);
+ mu_error_set_print (mu_syslog_error_printer);
+
+ priv_setup ();
+
+ if (smap_url_string)
+ return smap_daemon (smap_url_string);
+ else if (daemon_param.mode == MODE_INTERACTIVE)
+ return smap_loop (stdin, stdout);
+ else
+ {
+ const char *pstr = mu_umaxtostr (0, daemon_param.port);
+ char *urls = malloc (sizeof (DEFAULT_URL) + strlen (pstr));
+ if (!urls)
+ {
+ mu_error (_("Not enough memory"));
+ return EX_TEMPFAIL;
+ }
+ strcpy (urls, DEFAULT_URL);
+ strcat (urls, pstr);
+ return smap_daemon (urls);
+ }
+}

Return to:

Send suggestions and report system problems to the System administrator.