]> source.dussan.org Git - rspamd.git/commitdiff
Allow customizations for unix sockets.
authorVsevolod Stakhov <vsevolod@highsecure.ru>
Fri, 20 Feb 2015 16:48:51 +0000 (16:48 +0000)
committerVsevolod Stakhov <vsevolod@highsecure.ru>
Mon, 23 Feb 2015 10:35:53 +0000 (10:35 +0000)
Issue: #182
Reported by: @AlexeySa

src/libutil/addr.c
src/libutil/addr.h

index a276f0cfda85382df87a1868ed8f26fe62b26b43..de8f8da91ce5b0954203ad4aa63edca518baa8cf 100644 (file)
@@ -150,6 +150,78 @@ out:
 
 }
 
+static gboolean
+rspamd_parse_unix_path (rspamd_inet_addr_t *target, const char *src)
+{
+       gchar **tokens, **cur_tok, *p, *pwbuf;
+       gint pwlen;
+       struct passwd pw, *ppw;
+       struct group gr, *pgr;
+
+       tokens = g_strsplit_set (src, " ", -1);
+
+       target->af = AF_UNIX;
+       target->slen = sizeof (target->addr.su);
+       rspamd_strlcpy (target->addr.su.sun_path, tokens[0],
+                       sizeof (target->addr.su.sun_path));
+       #ifdef FREEBSD
+       target->addr.su.sun_len = SUN_LEN (&target->addr.su);
+       #endif
+
+       target->mode = 00644;
+       target->owner = 0;
+       target->group = 0;
+
+       cur_tok = &tokens[1];
+       pwlen = sysconf (_SC_GETPW_R_SIZE_MAX);
+       g_assert (pwlen > 0);
+       pwbuf = g_alloca (pwlen);
+
+       while (*cur_tok) {
+               if (g_ascii_strncasecmp (*cur_tok, "mode=", sizeof ("mode=") - 1) == 0) {
+                       p = strchr (*cur_tok, '=');
+                       /* XXX: add error check */
+                       target->mode = strtoul (p + 1, NULL, 0);
+
+                       if (target->mode == 0) {
+                               msg_err ("bad mode: %s", p + 1);
+                               errno = EINVAL;
+                               return FALSE;
+                       }
+               }
+               else if (g_ascii_strncasecmp (*cur_tok, "owner=",
+                               sizeof ("owner=") - 1) == 0) {
+                       p = strchr (*cur_tok, '=');
+
+                       if (getpwnam_r (p + 1, &pw, pwbuf, pwlen, &ppw) != 0 || ppw == NULL) {
+                               msg_err ("bad user: %s", p + 1);
+                               if (ppw == NULL) {
+                                       errno = ENOENT;
+                               }
+                               return FALSE;
+                       }
+                       target->owner = pw.pw_uid;
+                       target->group = pw.pw_gid;
+               }
+               else if (g_ascii_strncasecmp (*cur_tok, "group=",
+                               sizeof ("group=") - 1) == 0) {
+                       p = strchr (*cur_tok, '=');
+
+                       if (getgrnam_r (p + 1, &gr, pwbuf, pwlen, &pgr) != 0 || pgr == NULL) {
+                               msg_err ("bad group: %s", p + 1);
+                               if (pgr == NULL) {
+                                       errno = ENOENT;
+                               }
+                               return FALSE;
+                       }
+                       target->group = gr.gr_gid;
+               }
+               cur_tok ++;
+       }
+
+       return TRUE;
+}
+
 gboolean
 rspamd_parse_inet_address (rspamd_inet_addr_t *target, const char *src)
 {
@@ -158,13 +230,7 @@ rspamd_parse_inet_address (rspamd_inet_addr_t *target, const char *src)
        rspamd_ip_check_ipv6 ();
 
        if (src[0] == '/' || src[0] == '.') {
-               target->af = AF_UNIX;
-               target->slen = sizeof (target->addr.su);
-               rspamd_strlcpy (target->addr.su.sun_path, src,
-                               sizeof (target->addr.su.sun_path));
-#ifdef FREEBSD
-               target->addr.su.sun_len = SUN_LEN (&target->addr.su);
-#endif
+               return rspamd_parse_unix_path (target, src);
        }
        else if (ipv6_status == RSPAMD_IPV6_SUPPORTED &&
                        inet_pton (AF_INET6, src, &target->addr.s6.sin6_addr) == 1) {
@@ -276,6 +342,11 @@ rspamd_inet_address_listen (rspamd_inet_addr_t *addr, gint type,
                return -1;
        }
 
+       if (addr->af == AF_UNIX && access (addr->addr.su.sun_path, W_OK) != -1) {
+               /* Unlink old socket */
+               (void)unlink (addr->addr.su.sun_path);
+       }
+
        setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, (const void *)&on, sizeof (gint));
        r = bind (fd, &addr->addr.sa, addr->slen);
        if (r == -1) {
@@ -288,6 +359,19 @@ rspamd_inet_address_listen (rspamd_inet_addr_t *addr, gint type,
        }
 
        if (type != SOCK_DGRAM) {
+
+               if (addr->af == AF_UNIX) {
+                       /* Try to set mode and owner */
+                       if (chown (addr->addr.su.sun_path, addr->owner, addr->group) == -1) {
+                               msg_info ("cannot change owner for %s to %d:%d: %s",
+                                               addr->addr.su.sun_path, addr->owner, addr->group,
+                                               strerror (errno));
+                       }
+                       if (chmod (addr->addr.su.sun_path, addr->mode) == -1) {
+                               msg_info ("cannot change mode for %s to %od %s",
+                                               addr->addr.su.sun_path, addr->mode, strerror (errno));
+                       }
+               }
                r = listen (fd, -1);
 
                if (r == -1) {
@@ -439,10 +523,12 @@ rspamd_parse_host_port_priority_strv (gchar **tokens,
                }
 
                cur_addr = *addr;
-               cur_addr->af = AF_UNIX;
-               memcpy (cur_addr->addr.su.sun_path, tokens[0],
-                               MIN (sizeof (cur_addr->addr.su.sun_path) - 1, strlen (tokens[0])));
-               rspamd_ip_validate_af (cur_addr);
+               if (!rspamd_parse_inet_address (cur_addr, tokens[0])) {
+                       msg_err ("cannot parse unix socket definition %s: %s",
+                                       tokens[0],
+                                       strerror (errno));
+                       goto err;
+               }
                *max_addrs = 1;
        }
 
index c907d80c2f08e07ceeeda533166104632431b1f0..b5282e34c6835f66ecc187478be1069b9434cede 100644 (file)
@@ -40,7 +40,11 @@ union sa_union {
 typedef struct _rspamd_inet_addr_s {
        union sa_union addr;
        socklen_t slen;
-       int af;
+       gint af;
+       /* Unix socket specific */
+       gint mode;
+       uid_t owner;
+       gid_t group;
 } rspamd_inet_addr_t;
 
 /**