Commit e75e9123 e75e9123344ff44bacdbe28d071411e6799384ec by Sergey Poznyakoff

Implement session ID for TCP/UDP servers.

* imap4d/imap4d.c (set_strerr_flt,clr_strerr_flt): New functions.
(imap4d_connection): Setup session prefix in strerr if
mu_log_session_id is set.
* imap4d/io.c (io_setio): Bugfix: unref debug stream.
* pop3d/extra.c (pop3d_setio): Likewise.
* pop3d/pop3d.c (set_strerr_flt,clr_strerr_flt): New functions.
(pop3d_connection): Setup session prefix in strerr if
mu_log_session_id is set.

* include/mailutils/acl.h (mu_acl_setenv)
(mu_acl_getenv,mu_acl_set_session_id): New functions.
* include/mailutils/server.h (mu_session_id): New extern.
(mu_m_server_configured_count): Fix signature.
* include/mailutils/syslog.h (mu_log_session_id): New extern.
* libmailutils/diag/syslog.c (mu_log_session_id): New global.

* libmailutils/server/acl.c (_mu_acl) <envv,envc,envn>: New
members.
(run_closure) <env>: New member.
(mu_acl_destroy): Free environment.
(_acl_match): Handle "family" variable.
(expand_arg): Propagate ACL environment to wordsplit.
(mu_acl_check_sockaddr): Propagate ACL environment.
(mu_acl_setenv)
(mu_acl_getenv,mu_acl_set_session_id): New functions.

* libmailutils/server/ipsrv.c (mu_ip_tcp_accept): Store session ID
in the ACL.
(mu_ip_udp_accept): Likewise.
* libmailutils/server/msrv.c (mu_m_server_configured_count): Fix
signature.
(mu_m_server_check_acl): Store session ID in the ACL.
* libmailutils/server/server.c (mu_session_id): New global variable.
(connection_loop): Increment session ID
(mu_acl_set_session_id): New function.
* libmailutils/stream/fltstream.c (filter_ctl): Handle
MU_IOCTL_SUBSTREAM.
* libmailutils/stream/logstream.c (_log_ctl): Likewise.
* libmu_cfg/common.c (mu_logging_param) <session-id>: New statement.
1 parent da65d500
......@@ -409,6 +409,69 @@ get_client_address (int fd, struct sockaddr_in *pcs)
return 0;
}
static int
set_strerr_flt ()
{
mu_stream_t flt, trans[2];
int rc;
rc = mu_stream_ioctl (mu_strerr, MU_IOCTL_SUBSTREAM, MU_IOCTL_OP_GET, trans);
if (rc == 0)
{
char sessidstr[10];
char *argv[] = { "inline-comment", NULL, "-S", NULL };
snprintf (sessidstr, sizeof sessidstr, "%08lx:", mu_session_id);
argv[1] = sessidstr;
rc = mu_filter_create_args (&flt, trans[0], "inline-comment", 3,
(const char **)argv,
MU_FILTER_ENCODE, MU_STREAM_WRITE);
mu_stream_unref (trans[0]);
if (rc == 0)
{
mu_stream_set_buffer (flt, mu_buffer_line, 0);
trans[0] = flt;
trans[1] = NULL;
rc = mu_stream_ioctl (mu_strerr, MU_IOCTL_SUBSTREAM,
MU_IOCTL_OP_SET, trans);
mu_stream_unref (trans[0]);
if (rc)
mu_error (_("%s failed: %s"), "MU_IOCTL_SET_STREAM",
mu_stream_strerror (mu_strerr, rc));
}
else
mu_error (_("cannot create log filter stream: %s"), mu_strerror (rc));
}
else
{
mu_error (_("%s failed: %s"), "MU_IOCTL_GET_STREAM",
mu_stream_strerror (mu_strerr, rc));
}
return rc;
}
static void
clr_strerr_flt ()
{
mu_stream_t flt, trans[2];
int rc;
rc = mu_stream_ioctl (mu_strerr, MU_IOCTL_SUBSTREAM, MU_IOCTL_OP_GET, trans);
if (rc == 0)
{
flt = trans[0];
rc = mu_stream_ioctl (flt, MU_IOCTL_SUBSTREAM, MU_IOCTL_OP_GET, trans);
if (rc == 0)
{
mu_stream_unref (trans[0]);
rc = mu_stream_ioctl (mu_strerr, MU_IOCTL_SUBSTREAM,
MU_IOCTL_OP_SET, trans);
if (rc == 0)
mu_stream_unref (flt);
}
}
}
void
imap4d_child_signal_setup (RETSIGTYPE (*handler) (int signo))
......@@ -507,10 +570,21 @@ imap4d_connection (int fd, struct sockaddr *sa, int salen,
struct mu_srv_config *pconf, void *data)
{
struct imap4d_srv_config *cfg = (struct imap4d_srv_config *) pconf;
int rc;
idle_timeout = pconf->timeout;
imap4d_transcript = pconf->transcript;
if (mu_log_session_id)
rc = set_strerr_flt ();
else
rc = 1;
imap4d_mainloop (fd, fd, cfg->tls);
if (rc == 0)
clr_strerr_flt ();
return 0;
}
......
......@@ -76,6 +76,7 @@ io_setio (int ifd, int ofd, int tls)
else
{
rc = mu_xscript_stream_create (&xstr, iostream, dstr, NULL);
mu_stream_unref (dstr);
if (rc)
mu_error (_("cannot create transcript stream: %s"),
mu_strerror (rc));
......
......@@ -63,4 +63,8 @@ int mu_acl_check_fd (mu_acl_t acl, int fd, mu_acl_result_t *pres);
int mu_acl_action_to_string (mu_acl_action_t act, const char **pstr);
int mu_acl_string_to_action (const char *str, mu_acl_action_t *pres);
int mu_acl_setenv (mu_acl_t acl, const char *name, const char *val);
const char *mu_acl_getenv (mu_acl_t acl, const char *name);
int mu_acl_set_session_id (mu_acl_t acl);
#endif
......
......@@ -21,6 +21,8 @@
#include <mailutils/types.h>
#include <signal.h>
extern unsigned long mu_session_id;
typedef int (*mu_conn_loop_fp) (int fd, void *conn_data, void *server_data);
typedef void (*mu_conn_free_fp) (void *conn_data, void *server_data);
typedef int (*mu_server_idle_fp) (void *server_data);
......@@ -124,7 +126,7 @@ const char * mu_m_server_pidfile (mu_m_server_t srv);
void mu_m_server_get_sigset (mu_m_server_t srv, sigset_t *sigset);
int mu_m_server_get_srvlist (mu_m_server_t srv, mu_list_t *plist);
void mu_m_server_configured_count (mu_m_server_t msrv, size_t count);
void mu_m_server_configured_count (mu_m_server_t msrv, size_t *count);
void mu_m_server_begin (mu_m_server_t msrv);
int mu_m_server_run (mu_m_server_t msrv);
......
......@@ -29,6 +29,7 @@ extern int mu_log_facility;
extern char *mu_log_tag;
extern int mu_log_print_severity;
extern unsigned mu_log_severity_threshold;
extern int mu_log_session_id;
#define MU_LOG_TAG() (mu_log_tag ? mu_log_tag : mu_program_name)
......
......@@ -133,3 +133,4 @@ int mu_log_facility = LOG_FACILITY;
char *mu_log_tag = NULL;
int mu_log_print_severity = 0;
unsigned mu_log_severity_threshold = MU_LOG_DEBUG;
int mu_log_session_id;
......
......@@ -58,6 +58,21 @@ struct _mu_acl_entry
struct _mu_acl
{
mu_list_t aclist;
char **envv;
size_t envc;
size_t envn;
};
struct run_closure
{
unsigned idx;
struct mu_cidr addr;
char **env;
char ipstr[40];
char *addrstr;
char *numbuf;
mu_acl_result_t *result;
};
......@@ -117,11 +132,16 @@ mu_acl_count (mu_acl_t acl, size_t *pcount)
int
mu_acl_destroy (mu_acl_t *pacl)
{
size_t i;
mu_acl_t acl;
if (!pacl || !*pacl)
return EINVAL;
acl = *pacl;
mu_list_destroy (&acl->aclist);
for (i = 0; i < acl->envc && acl->envv[i]; i++)
free (acl->envv[i]);
free (acl->envv);
free (acl);
*pacl = acl;
return 0;
......@@ -249,17 +269,6 @@ mu_acl_string_to_action (const char *str, mu_acl_action_t *pres)
return rc;
}
struct run_closure
{
unsigned idx;
struct mu_cidr addr;
char ipstr[40];
char *addrstr;
char *numbuf;
mu_acl_result_t *result;
};
int
_acl_match (struct _mu_acl_entry *ent, struct run_closure *rp)
{
......@@ -297,6 +306,26 @@ acl_getvar (const char *name, size_t nlen, void *data)
{
struct run_closure *rp = data;
if (SEQ ("family", name, nlen))
{
switch (rp->addr.family)
{
case AF_INET:
return "AF_INET";
#ifdef MAILUTILS_IPV6
case AF_INET6:
return "AF_INET6";
#endif
case AF_UNIX:
return "AF_UNIX";
default:
return NULL;
}
}
if (SEQ ("aclno", name, nlen))
{
if (!rp->numbuf && mu_asprintf (&rp->numbuf, "%u", rp->idx))
......@@ -330,33 +359,19 @@ expand_arg (const char *cmdline, struct run_closure *rp, char **s)
{
int rc;
struct mu_wordsplit ws;
const char *env[3];
int envflag = 0;
mu_debug (MU_DEBCAT_ACL, MU_DEBUG_TRACE, ("Expanding \"%s\"", cmdline));
env[0] = "family";
switch (rp->addr.family)
if (rp->env)
{
case AF_INET:
env[1] = "AF_INET";
break;
#ifdef MAILUTILS_IPV6
case AF_INET6:
env[1] = "AF_INET6";
break;
#endif
case AF_UNIX:
env[1] = "AF_UNIX";
break;
ws.ws_env = (const char **) rp->env;
envflag = MU_WRDSF_ENV;
}
env[2] = NULL;
ws.ws_env = env;
ws.ws_getvar = acl_getvar;
ws.ws_closure = rp;
rc = mu_wordsplit (cmdline, &ws,
MU_WRDSF_NOSPLIT | MU_WRDSF_NOCMD |
MU_WRDSF_ENV | MU_WRDSF_ENV_KV |
envflag | MU_WRDSF_ENV_KV |
MU_WRDSF_GETVAR | MU_WRDSF_CLOSURE);
if (rc == 0)
......@@ -553,6 +568,7 @@ mu_acl_check_sockaddr (mu_acl_t acl, const struct sockaddr *sa, int salen,
r.idx = 0;
r.result = pres;
r.env = acl->envv;
*r.result = mu_acl_result_undefined;
r.numbuf = NULL;
mu_list_foreach (acl->aclist, _run_entry, &r);
......@@ -607,3 +623,94 @@ mu_acl_check_fd (mu_acl_t acl, int fd, mu_acl_result_t *pres)
return mu_acl_check_sockaddr (acl, &addr.sa, len, pres);
}
static int
_acl_getenv (mu_acl_t acl, const char *name, size_t *pres)
{
size_t i;
if (!acl->envv)
return MU_ERR_NOENT;
for (i = 0; i < acl->envc; i++)
if (strcmp (acl->envv[i], name) == 0)
{
*pres = i;
return 0;
}
return MU_ERR_NOENT;
}
const char *
mu_acl_getenv (mu_acl_t acl, const char *name)
{
size_t i;
if (_acl_getenv (acl, name, &i) == 0)
{
return acl->envv[i + 1];
}
return NULL;
}
static int
_acl_env_store (mu_acl_t acl, int i, const char *val)
{
char *copy = strdup (val);
if (!copy)
return ENOMEM;
free (acl->envv[i]);
acl->envv[i] = copy;
return 0;
}
int
mu_acl_setenv (mu_acl_t acl, const char *name, const char *val)
{
size_t i;
if (_acl_getenv (acl, name, &i) == 0)
{
if (!val)
{
free (acl->envv[i]);
free (acl->envv[i + 1]);
memmove (acl->envv + i, acl->envv + i + 3,
(acl->envn + 1 - (i + 3)) * sizeof (acl->envv[0]));
acl->envn -= 2;
return 0;
}
return _acl_env_store (acl, i + 1, val);
}
if (!acl->envv || acl->envn + 1 == acl->envc)
{
char **p;
if (!val)
return 0;
if (acl->envv == NULL)
p = calloc (3, sizeof (acl->envv[0]));
else
{
p = realloc (acl->envv, (acl->envc + 3) * sizeof (acl->envv[0]));
if (!p)
return ENOMEM;
p[acl->envc] = NULL;
}
acl->envv = p;
acl->envc += 3;
}
if (_acl_env_store (acl, acl->envn, name))
return ENOMEM;
if (_acl_env_store (acl, acl->envn + 1, val))
{
free (acl->envv[acl->envn]);
acl->envv[acl->envn] = NULL;
return ENOMEM;
}
acl->envn += 2;
return 0;
}
......
......@@ -372,7 +372,10 @@ mu_ip_tcp_accept (mu_ip_server_t srv, void *call_data)
if (srv->acl)
{
mu_acl_result_t res;
int rc = mu_acl_check_sockaddr (srv->acl, &client.sa, size, &res);
int rc;
mu_acl_set_session_id (srv->acl);
rc = mu_acl_check_sockaddr (srv->acl, &client.sa, size, &res);
if (rc)
mu_debug (MU_DEBCAT_SERVER, MU_DEBUG_ERROR,
("%s: mu_acl_check_sockaddr: %s",
......@@ -453,7 +456,10 @@ mu_ip_udp_accept (mu_ip_server_t srv, void *call_data)
if (srv->acl)
{
mu_acl_result_t res;
int rc = mu_acl_check_sockaddr (srv->acl, &client.sa, size, &res);
int rc;
mu_acl_set_session_id (srv->acl);
rc = mu_acl_check_sockaddr (srv->acl, &client.sa, size, &res);
if (rc)
mu_debug (MU_DEBCAT_SERVER, MU_DEBUG_ERROR,
("%s: mu_acl_check_sockaddr: %s\n",
......
......@@ -343,9 +343,12 @@ mu_m_server_set_max_children (mu_m_server_t srv, size_t num)
int
mu_m_server_set_pidfile (mu_m_server_t srv, const char *pidfile)
{
char *p = strdup (pidfile);
if (!p)
return errno;
free (srv->pidfile);
srv->pidfile = strdup (pidfile);
return srv->pidfile ? 0 : errno;
srv->pidfile = p;
return 0;
}
int
......@@ -476,9 +479,9 @@ add_server (mu_m_server_t msrv, struct mu_sockaddr *s, int type)
}
void
mu_m_server_configured_count (mu_m_server_t msrv, size_t count)
mu_m_server_configured_count (mu_m_server_t msrv, size_t *count)
{
mu_list_count (msrv->srvlist, &count);
mu_list_count (msrv->srvlist, count);
}
void
......@@ -645,7 +648,10 @@ mu_m_server_check_acl (mu_m_server_t msrv, struct sockaddr *s, int salen)
if (msrv->acl)
{
mu_acl_result_t res;
int rc = mu_acl_check_sockaddr (msrv->acl, s, salen, &res);
int rc;
mu_acl_set_session_id (msrv->acl);
rc = mu_acl_check_sockaddr (msrv->acl, s, salen, &res);
if (rc)
{
char *p = mu_sockaddr_to_astr (s, salen);
......
......@@ -38,6 +38,8 @@ struct _mu_connection
#define MU_SERVER_TIMEOUT 0x1
unsigned long mu_session_id;
struct _mu_server
{
int nfd;
......@@ -104,7 +106,10 @@ connection_loop (mu_server_t srv, fd_set *fdset)
struct _mu_connection *next = conn->next;
if (FD_ISSET (conn->fd, fdset))
{
int rc = conn->f_loop (conn->fd, conn->data, srv->server_data);
int rc;
++mu_session_id;
rc = conn->f_loop (conn->fd, conn->data, srv->server_data);
switch (rc)
{
case 0:
......@@ -291,3 +296,12 @@ mu_server_add_connection (mu_server_t srv,
srv->tail = p;
return 0;
}
int
mu_acl_set_session_id (mu_acl_t acl)
{
char sessidstr[9];
snprintf (sessidstr, sizeof sessidstr, "%08lx", mu_session_id);
return mu_acl_setenv (acl, "sessid", sessidstr);
}
......
......@@ -422,6 +422,32 @@ filter_ctl (struct _mu_stream *stream, int code, int opcode, void *ptr)
}
break;
case MU_IOCTL_SUBSTREAM:
if (!ptr)
return EINVAL;
else
{
mu_stream_t *pstr = ptr;
switch (opcode)
{
case MU_IOCTL_OP_GET:
pstr[0] = fs->transport;
mu_stream_ref (pstr[0]);
pstr[1] = NULL;
break;
case MU_IOCTL_OP_SET:
mu_stream_unref (fs->transport);
fs->transport = pstr[0];
mu_stream_ref (fs->transport);
break;
default:
return EINVAL;
}
}
break;
case MU_IOCTL_TRANSPORT:
switch (opcode)
{
......
......@@ -309,6 +309,32 @@ _log_ctl (struct _mu_stream *str, int code, int opcode, void *arg)
}
break;
case MU_IOCTL_SUBSTREAM:
if (!arg)
return EINVAL;
else
{
mu_stream_t *pstr = arg;
switch (opcode)
{
case MU_IOCTL_OP_GET:
pstr[0] = sp->transport;
mu_stream_ref (pstr[0]);
pstr[1] = NULL;
break;
case MU_IOCTL_OP_SET:
mu_stream_unref (sp->transport);
sp->transport = pstr[0];
mu_stream_ref (sp->transport);
break;
default:
return EINVAL;
}
}
break;
case MU_IOCTL_LOGSTREAM:
switch (opcode)
{
......
......@@ -171,6 +171,8 @@ static struct mu_cfg_param mu_logging_param[] = {
N_("Set syslog facility. Arg is one of the following: user, daemon, "
"auth, authpriv, mail, cron, local0 through local7 (case-insensitive), "
"or a facility number.") },
{ "session-id", mu_cfg_bool, &mu_log_session_id, 0, NULL,
N_("Log session ID") },
{ "tag", mu_cfg_string, &mu_log_tag, 0, NULL,
N_("Tag syslog messages with this string.") },
{ NULL }
......
......@@ -185,6 +185,7 @@ pop3d_setio (int ifd, int ofd, int tls)
else
{
rc = mu_xscript_stream_create (&xstr, iostream, dstr, NULL);
mu_stream_unref (dstr);
if (rc)
mu_error (_("cannot create transcript stream: %s"),
mu_strerror (rc));
......
......@@ -366,17 +366,90 @@ pop3d_mainloop (int ifd, int ofd, int tls)
return status;
}
static int
set_strerr_flt ()
{
mu_stream_t flt, trans[2];
int rc;
rc = mu_stream_ioctl (mu_strerr, MU_IOCTL_SUBSTREAM, MU_IOCTL_OP_GET, trans);
if (rc == 0)
{
char sessidstr[10];
char *argv[] = { "inline-comment", NULL, "-S", NULL };
snprintf (sessidstr, sizeof sessidstr, "%08lx:", mu_session_id);
argv[1] = sessidstr;
rc = mu_filter_create_args (&flt, trans[0], "inline-comment", 3,
(const char **)argv,
MU_FILTER_ENCODE, MU_STREAM_WRITE);
mu_stream_unref (trans[0]);
if (rc == 0)
{
mu_stream_set_buffer (flt, mu_buffer_line, 0);
trans[0] = flt;
trans[1] = NULL;
rc = mu_stream_ioctl (mu_strerr, MU_IOCTL_SUBSTREAM,
MU_IOCTL_OP_SET, trans);
mu_stream_unref (trans[0]);
if (rc)
mu_error (_("%s failed: %s"), "MU_IOCTL_SET_STREAM",
mu_stream_strerror (mu_strerr, rc));
}
else
mu_error (_("cannot create log filter stream: %s"), mu_strerror (rc));
}
else
{
mu_error (_("%s failed: %s"), "MU_IOCTL_GET_STREAM",
mu_stream_strerror (mu_strerr, rc));
}
return rc;
}
static void
clr_strerr_flt ()
{
mu_stream_t flt, trans[2];
int rc;
rc = mu_stream_ioctl (mu_strerr, MU_IOCTL_SUBSTREAM, MU_IOCTL_OP_GET, trans);
if (rc == 0)
{
flt = trans[0];
rc = mu_stream_ioctl (flt, MU_IOCTL_SUBSTREAM, MU_IOCTL_OP_GET, trans);
if (rc == 0)
{
mu_stream_unref (trans[0]);
rc = mu_stream_ioctl (mu_strerr, MU_IOCTL_SUBSTREAM,
MU_IOCTL_OP_SET, trans);
if (rc == 0)
mu_stream_unref (flt);
}
}
}
int
pop3d_connection (int fd, struct sockaddr *sa, int salen,
struct mu_srv_config *pconf,
void *data)
{
struct pop3d_srv_config *cfg = (struct pop3d_srv_config *) pconf;
int rc;
idle_timeout = pconf->timeout;
pop3d_transcript = pconf->transcript;
if (mu_log_session_id)
rc = set_strerr_flt ();
else
rc = 1;
pop3d_mainloop (fd, fd, cfg->tls);
if (rc == 0)
clr_strerr_flt ();
return 0;
}
......