Download | Plain Text | No Line Numbers
    - /*
-  * Copyright (c) 2016, Manuel Mausz <manuel at mausz dot at>,
-  * All rights reserved.
-  *
-  * Some maildir specified code is copied from dovecot (dovecot.org),
-  * Copyright by Timo Sirainen <tss at iki dot fi> (and others).
-  *
-  * This library is free software; you can redistribute it and/or
-  * modify it under the terms of the GNU Lesser General Public
-  * License as published by the Free Software Foundation; either
-  * version 2.1 of the License, or (at your option) any later version.
-  *
-  * This library 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
-  * Lesser General Public License for more details.
-  *
-  * You should have received a copy of the GNU Lesser General Public
-  * License along with this library; if not, write to the Free Software
-  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
-  * MA 02110-1301 USA
-  */
-  
- #include <stdio.h>
- #include <stdlib.h>
- #include <stdbool.h>
- #include <stdarg.h>
- #include <string.h>
- #include <unistd.h>
- #include <errno.h>
- #include <sys/socket.h>
- #include <sys/un.h>
- #include <netdb.h>
-  
- #define LOGPREFIX "QUOTA: "
-  
- typedef struct
- {
-   const char *action, *msg;
- } policy_reply;
-  
- int check_parent(void)
- {
-   /* check parent */
-   pid_t parent = getppid();
-   char buf[256];
-   if (num < 0 || num > sizeof(buf))
-   {
-     return 0;
-   }
-  
-   char buf2[256];
-   num = readlink(buf, buf2, sizeof(buf2));
-   if (num < 0)
-   {
-     return 0;
-   }
-   buf2[num] = '\0';
-  
-   const char *smtpbin = "/var/qmail/bin/qmail-smtpd";
-   {
-     return 0;
-   }
-  
-   return 1;
- }
-  
- static int net_connect_inet(const char *host, const char *port)
- {
-   struct addrinfo hints = {
-     .ai_family = AF_UNSPEC,
-     .ai_socktype = SOCK_STREAM
-   };
-   struct addrinfo *result;
-  
-   int s = getaddrinfo(host, port, &hints, &result);
-   if (s != 0)
-   {
-     return -1;
-   }
-  
-   //FIXME: connect might hang
-   int sockfd = -1;
-   struct addrinfo *r;
-   for (r = result; r != NULL; r=r->ai_next)
-   {
-     sockfd = socket(r->ai_family, r->ai_socktype | SOCK_CLOEXEC,
-       r->ai_protocol);
-     if (sockfd == -1)
-       continue;
-     if (connect(sockfd, r->ai_addr, r->ai_addrlen) != -1)
-       break; /* success */
-     (void)close(sockfd);
-     sockfd = -1;
-     break; /* we only try the first record */
-   }
-  
-   (void)freeaddrinfo(result);
-   return sockfd;
- }
-  
- static int net_connect_unix(const char *path)
- {
-   int sockfd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
-   if (sockfd < 0)
-     return -1;
-  
-   struct sockaddr_un saddr;
-   saddr.sun_family = AF_UNIX;
-   int conn = connect(sockfd, (struct sockaddr *)&saddr, sizeof(saddr));
-   if (conn != -1)
-     return sockfd;
-   (void)close(sockfd);
-   return -1;
- }
-  
- static int net_connect(const char *uri, bool readenv)
- {
-   int sockfd = -1;
-   {
-  
-     if (portptr == NULL)
-     {
-       return -1;
-     }
-     *portptr = '\0';
-  
-     char *host = path;
-     if (host[0] == '[' && *(portptr - 1) == ']')
-     {
-       host++;
-       *(portptr - 1) = '\0';
-     }
-  
-     sockfd = net_connect_inet(host, portptr + 1);
-   }
-   {
-       return net_connect(uri, false);
-     return -1;
-   }
-   else
-   {
-     return -1;
-   }
-  
-   if (sockfd < 0)
-   return sockfd;
- }
-  
- static const policy_reply policy_check(const char *uri, const char *format, ...)
- {
-   policy_reply reply = { .action = NULL, .msg = NULL };
-  
-   /* connect to policy server */
-   int sockfd = net_connect(uri, true);
-   if (sockfd < 0)
-     goto end;
-  
-   /* send data */
-   va_list ap;
-   (void)vdprintf(sockfd, format, ap);
-   (void)dprintf(sockfd, "\n");
-   if (errno)
-   {
-     goto end;
-   }
-  
-   /* wait for reply */
-   static char buf[2048];
-   ssize_t read = recv(sockfd, &buf, sizeof(buf) - 1, 0);
-   if (read <= 0)
-   {
-     goto end;
-   }
-  
-   /* parse reply */
-       || buf[read - 2] != '\n')
-   {
-     goto end;
-   }
-   buf[read - 2] = '\0';
-  
-   if (msgptr)
-   {
-     *msgptr = '\0';
-     reply.msg = ++msgptr;
-   }
-  
- end:
-   (void)close(sockfd);
-   return reply;
- }
-  
- int main(int argc, char *argv[])
- {
-   if (argc != 2)
-     return 0;
-  
-   if (!username)
-     return 0;
-  
-   /* check parent */
-   if (!check_parent())
-     return 0;
-  
-   // size not exported by qmail (at least for now)
-   // assume a minimum size of 500 bytes
-   size_t size = 500;
-  
-   const policy_reply reply = policy_check(argv[1],
-       "recipient=%s\nsize=%zu\n", username, size);
-   if (reply.action == NULL)
-     return 0;
-  
-   if (*reply.action == '5' || *reply.action == '4'
-   {
-     const char *code = (*reply.action == '5' || *reply.action == '4')
-       ? reply.action : "552";
-     const char *msg = (reply.msg) ? reply.msg : "User over quota. (#5.2.2)";
-   }
-     { ; } /* nothing here */
-   else
-   {
-         " reply=%s msg=%s\n", reply.action, (reply.msg) ? reply.msg : "NULL");
-   }
-  
-   return 0;
- }
-