diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2008-02-10 14:08:36 +0000 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2008-02-10 14:08:36 +0000 |
commit | a1871918823166cac9f0c12164ba27cb3b1f0c2c (patch) | |
tree | 7260d118aa5af6a8f006f9b2dac6cabde782db8c /smap | |
parent | 455b645247bdc0f01239b2352a9d8f07f446024f (diff) | |
download | mailfromd-a1871918823166cac9f0c12164ba27cb3b1f0c2c.tar.gz mailfromd-a1871918823166cac9f0c12164ba27cb3b1f0c2c.tar.bz2 |
Merged HEAD from branches/gmach
git-svn-id: file:///svnroot/mailfromd/trunk@1612 7a8a7f39-df28-0410-adc6-e0d955640f24
Diffstat (limited to 'smap')
-rw-r--r-- | smap/Makefile.am | 27 | ||||
-rw-r--r-- | smap/smap.c | 1024 |
2 files changed, 324 insertions, 727 deletions
diff --git a/smap/Makefile.am b/smap/Makefile.am new file mode 100644 index 00000000..c2d47cdf --- /dev/null +++ b/smap/Makefile.am @@ -0,0 +1,27 @@ +# This file is part of Mailfromd. +# Copyright (C) 2008 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/>. + +sbin_PROGRAMS = smap +smap_SOURCES = smap.c + +INCLUDES = \ + $(MAILUTILS_INCLUDES)\ + $(MU_COMMON_INCLUDES)\ + -I$(top_srcdir)/lib\ + -I$(top_srcdir)/gnu\ + -I../gnu + +LDADD = ../lib/libmf.a $(MAILUTILS_LIBS) ../gnu/libgnu.a diff --git a/smap/smap.c b/smap/smap.c index f22cf27b..4f85e745 100644 --- a/smap/smap.c +++ b/smap/smap.c @@ -1,5 +1,5 @@ -/* This file is part of smap. - Copyright (C) 2006, 2007 Sergey Poznyakoff +/* This file is part of Mailfromd. + Copyright (C) 2006, 2007, 2008 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 @@ -32,593 +32,66 @@ #include <ctype.h> #include <sysexits.h> /* FIXME */ #include <mailutils/mailutils.h> -#define obstack_chunk_alloc malloc -#define obstack_chunk_free free -#include <obstack.h> +#include <mailutils/daemon.h> +#include <mailutils/syslog.h> +#include <mailutils/server.h> +#include <mailutils/libargp.h> +#include <mailutils/libcfg.h> + +#include "libmf.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; +int smap_reload; +unsigned int smap_timeout; +int smap_transcript; 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; +char *negative_reply; +char *positive_reply; -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 * +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); + mu_vartab_t vtab; + char *reply = NULL; + + if (!arg) + return NULL; + mu_vartab_create (&vtab); + mu_vartab_define (vtab, "key", key, 0); + mu_vartab_define (vtab, MU_AUTH_NAME, auth ? auth->name : "", 0); + mu_vartab_define (vtab, MU_AUTH_PASSWD, auth ? auth->passwd : "", 0); + mu_vartab_define (vtab, MU_AUTH_UID, + auth ? mu_umaxtostr (1, auth->uid) : "-1", 0); + mu_vartab_define (vtab, MU_AUTH_GID, + auth ? mu_umaxtostr (1, auth->gid) : "-1", 0); + mu_vartab_define (vtab, MU_AUTH_GECOS, + auth ? auth->gecos : "", 0); + mu_vartab_define (vtab, MU_AUTH_DIR, auth ? auth->dir : "", 0); + mu_vartab_define (vtab, MU_AUTH_SHELL, auth ? auth->shell : "", 0); + mu_vartab_define (vtab, MU_AUTH_MAILBOX, auth ? auth->mailbox : "", 0); + mu_vartab_define (vtab, MU_AUTH_QUOTA, + auth ? mu_umaxtostr (1, auth->quota) : "NONE", 0); + rc = mu_vartab_expand (vtab, arg, &reply); 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; + mu_error (_("cannot expand string `%s': %s"), arg, mu_strerror (rc)); + mu_vartab_destroy (&vtab); + return reply; } - -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; - + + alarm (smap_timeout); bufsize--; while (len < bufsize && ((c = fgetc (fp))) != delim) { @@ -626,18 +99,19 @@ read_delim (FILE *fp, int delim, char *buf, size_t bufsize) { if (len) { - if (daemon_param.transcript && len) - syslog (LOG_INFO, "recv: %.*s:", len, buf); - mu_error ("unexpected end of file in input"); + if (smap_transcript && len) + mu_diag_output (MU_DIAG_INFO, "recv: %.*s:", len, buf); + mu_error (_("unexpected end of file in input")); exit (1); } return 0; } buf[len++] = c; } + alarm (0); buf[len] = 0; - if (daemon_param.transcript) - syslog (LOG_INFO, "recv: %s:", buf); + if (smap_transcript) + mu_diag_output (MU_DIAG_INFO, "recv: %s:", buf); return len; } @@ -649,17 +123,17 @@ smap_reply (FILE *fp, const char *code, const char *result) len += 1 + strlen (result); if (result) { - if (daemon_param.transcript) - syslog (LOG_INFO, "send: %lu:%s %s,", - (unsigned long) len, code, result); + if (smap_transcript) + mu_diag_output (MU_DIAG_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); + if (smap_transcript) + mu_diag_output (MU_DIAG_INFO, "send: %lu:%s,", + (unsigned long) len, code); + fprintf (fp, "%lu:%s,", (unsigned long) len, code); } } @@ -677,33 +151,36 @@ smap_loop (FILE *in, FILE *out) /* Read input: */ while (read_delim (in, ':', buf, sizeof buf)) { + char *reply_txt = NULL; + len = strtoul (buf, &p, 10); if (*p != 0) { - mu_error ("protocol error: expected packet length, but found %s", buf); + 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"); + mu_error (_("protocol error: packet length too big")); exit (1); } if (fread (buf, 1, len, in) != len) { - mu_error ("protocol error: short read"); + mu_error (_("protocol error: short read")); exit (1); } buf[len] = 0; - if (daemon_param.transcript) - syslog (LOG_INFO, "recv: %s,", buf); + if (smap_transcript) + mu_diag_output (MU_DIAG_INFO, "recv: %s,", buf); if (getc (in) != ',') { - mu_error ("protocol error: missing terminating comma"); + mu_error (_("protocol error: missing terminating comma")); exit (1); } buf[len] = 0; @@ -711,7 +188,7 @@ smap_loop (FILE *in, FILE *out) key = strchr (buf, ' '); if (!key) { - mu_error ("protocol error: missing map name"); + mu_error (_("protocol error: missing map name")); exit (1); } key++; @@ -725,14 +202,16 @@ smap_loop (FILE *in, FILE *out) /* Reply: */ if (!auth) { - smap_reply (out, "NOTFOUND", - expand_reply_text (negative_reply, key, NULL)); + reply_txt = expand_reply_text (negative_reply, key, NULL); + smap_reply (out, "NOTFOUND", reply_txt); } else { - smap_reply (out, "OK", expand_reply_text (positive_reply, key, auth)); + reply_txt = expand_reply_text (positive_reply, key, auth); + smap_reply (out, "OK", reply_txt); mu_auth_data_free (auth); } + free (reply_txt); } /* Cleanup and exit */ fclose (in); @@ -741,110 +220,16 @@ smap_loop (FILE *in, FILE *out) } int -switch_to_privs (uid_t uid, gid_t gid) +smap_connection (int fd, struct sockaddr *sa, int salen, void *data, + mu_ip_server_t srv, time_t timeout, int transcript) { - 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; + smap_timeout = timeout; + smap_transcript = transcript; + smap_loop (fdopen (fd, "r"), fdopen (fd, "w")); + return 0; } + void priv_setup () { @@ -856,52 +241,237 @@ priv_setup () mu_error (_("No such user: %s"), run_as_user); exit (EX_SOFTWARE); } - if (pw && switch_to_privs (pw->pw_uid, pw->pw_gid)) + if (pw && switch_to_privs (pw->pw_uid, pw->pw_gid, NULL)) exit (EX_SOFTWARE); } } + +/* Command line and configuration */ +const char *program_version = "smap (" PACKAGE_STRING ")"; +static char doc[] = N_("General-purpose 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 +#define OPTION_FOREGROUND 260 + +static struct argp_option options[] = +{ +#define GRP 0 + { "foreground", OPTION_FOREGROUND, 0, 0, N_("Remain in foreground."), GRP+1}, + { "inetd", 'i', 0, 0, N_("Run in inetd mode"), GRP+1}, + { "daemon", 'd', N_("NUMBER"), OPTION_ARG_OPTIONAL, + N_("Runs in daemon mode with a maximum of NUMBER children"), GRP+1 }, +#undef GRP + +#define GRP 10 + { "user", 'U', "NAME", 0, + N_("Run as user NAME"), GRP+1 }, + { "gecos", OPTION_GECOS, NULL, 0, + N_("Same as '--positive-reply=${gecos}'"), GRP+1 }, + /* FIXME-MU: */ + { "log-tag", 'L', N_("STRING"), 0, + N_("Set syslog tag"), GRP+1 }, + { "positive-reply", OPTION_POSITIVE_REPLY, N_("STRING"), 0, + N_("Set positive reply text"), GRP+1 }, + { "negative-reply", OPTION_NEGATIVE_REPLY, N_("STRING"), 0, + N_("Set negative reply text"), GRP+1 }, +#undef GRP + { 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[] = { + "auth", + "common", + "debug", + "license", + "logging", + NULL +}; + +static error_t +parse_opt (int key, char *arg, struct argp_state *state) +{ + static struct mu_argp_node_list lst; + + switch (key) + { + case 'd': + mu_argp_node_list_new (&lst, "mode", "daemon"); + if (arg) + mu_argp_node_list_new (&lst, "max-children", arg); + break; + + case 'i': + mu_argp_node_list_new (&lst, "mode", "inetd"); + break; + + case OPTION_FOREGROUND: + mu_argp_node_list_new (&lst, "foreground", "yes"); + 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 OPTION_GECOS: + positive_reply = "${gecos}"; + break; + + default: + return ARGP_ERR_UNKNOWN; + + case ARGP_KEY_INIT: + mu_argp_node_list_init (&lst); + break; + + case ARGP_KEY_FINI: + mu_argp_node_list_finish (&lst, NULL, NULL); + break; + + case ARGP_KEY_ERROR: + exit (EX_USAGE); + } + return 0; +} + +static struct mu_cfg_param cfg_param[] = { + { "user", mu_cfg_string, &run_as_user, 0, NULL, + N_("Run with this user privileges.") }, + { "positive-reply", mu_cfg_string, &positive_reply, 0, NULL, + N_("Set positive reply text.") }, + { "negative-reply", mu_cfg_string, &negative_reply, 0, NULL, + N_("Set negative reply text.") }, + { ".server", mu_cfg_section, NULL, 0, NULL, + N_("Server configuration.") }, + { NULL } +}; + + +void +logging_setup () +{ + mu_debug_t debug; + + if (syslog_tag) + mu_log_tag = syslog_tag; + openlog (MU_LOG_TAG (), LOG_PID, mu_log_facility); + mu_diag_get_debug (&debug); + mu_debug_set_print (debug, mu_diag_syslog_printer, NULL); + mu_debug_default_printer = mu_debug_syslog_printer; +} + + +static RETSIGTYPE +smap_hup (int sig) +{ + mu_m_server_stop (1); + smap_reload = 1; +} + +static void +version (FILE *stream, struct argp_state *state) +{ + mailfromd_version ("smap", stream); +} + int main (int argc, char **argv) { - int arg_index; - struct group *gr; - + int status; + mu_m_server_t server; + + mf_init_nls (); + 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); - } + mu_acl_cfg_init (); + mu_m_server_cfg_init (); - openlog (syslog_tag, LOG_PID, log_facility); - mu_error_set_print (mu_syslog_error_printer); - - priv_setup (); + mu_m_server_create (&server, program_version); + mu_m_server_set_conn (server, smap_connection); + mu_m_server_set_mode (server, MODE_INTERACTIVE); + mu_m_server_set_max_children (server, 20); + /* FIXME: mu_m_server_set_pidfile (); */ + /* FIXME: mu_m_server_set_default_port (server, ??); */ + mu_m_server_set_timeout (server, 600); + + mu_argp_init (program_version, "<" PACKAGE_BUGREPORT ">"); + argp_program_version_hook = version; + + if (mu_app_init (&argp, argp_capa, cfg_param, argc, argv, 0, NULL, server)) + exit (1); - if (smap_url_string) - return smap_daemon (smap_url_string); - else if (daemon_param.mode == MODE_INTERACTIVE) - return smap_loop (stdin, stdout); - else + logging_setup (); + priv_setup (); + + if (mu_m_server_mode (server) == MODE_DAEMON) { - const char *pstr = mu_umaxtostr (0, daemon_param.port); - char *urls = malloc (sizeof (DEFAULT_URL) + strlen (pstr)); - if (!urls) + if (argv[0][0] != '/') + mu_diag_output (MU_DIAG_NOTICE, + _("Program name is not absolute; reloading will not " + "be possible")); + else { - mu_error (_("Not enough memory")); - return EX_TEMPFAIL; + sigset_t set; + + mu_m_server_get_sigset (server, &set); + sigdelset (&set, SIGHUP); + mu_m_server_set_sigset (server, &set); + signal (SIGHUP, smap_hup); + } + + mu_m_server_begin (server); + status = mu_m_server_run (server); + mu_m_server_end (server); + mu_m_server_destroy (&server); + if (smap_reload) + { + mu_diag_output (MU_DIAG_NOTICE, _("Restarting")); + execvp (argv[0], argv); } - strcpy (urls, DEFAULT_URL); - strcat (urls, pstr); - return smap_daemon (urls); } + else + status = smap_loop (stdin, stdout); + + exit (status == 0 ? 0 : EX_SOFTWARE); } + +void +xalloc_die () +{ + mu_error ("not enough memory"); + abort (); +} + +/* + Local Variables: + c-file-style: "gnu" + End: +*/ +/* EOF */ |