aboutsummaryrefslogtreecommitdiff
path: root/smap
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2008-02-10 14:08:36 +0000
committerSergey Poznyakoff <gray@gnu.org.ua>2008-02-10 14:08:36 +0000
commita1871918823166cac9f0c12164ba27cb3b1f0c2c (patch)
tree7260d118aa5af6a8f006f9b2dac6cabde782db8c /smap
parent455b645247bdc0f01239b2352a9d8f07f446024f (diff)
downloadmailfromd-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.am27
-rw-r--r--smap/smap.c1024
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 */

Return to:

Send suggestions and report system problems to the