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;
- }
-