summaryrefslogtreecommitdiff
path: root/libexec/popa3d/virtual.c
diff options
context:
space:
mode:
authorCamiel Dobbelaar <camield@cvs.openbsd.org>2001-08-13 19:59:03 +0000
committerCamiel Dobbelaar <camield@cvs.openbsd.org>2001-08-13 19:59:03 +0000
commitc29fb47c597abce79a48b9179039dca232bb9b85 (patch)
treef24b9f4ec5272eeb475f2d8e159619e662b95ad2 /libexec/popa3d/virtual.c
parente912815d30df3264d2e6df15b9cf9cc8cd144487 (diff)
Solar Designer's popa3d POP3 daemon, version 0.4.9.1
Changes so far: - removed auth_pam.c - removed auth_shadow.c - add BSD makefile - remove md5, in favour of libc md5 - params.h: AUTH_PASSWD and MAIL_SPOOL_PATH
Diffstat (limited to 'libexec/popa3d/virtual.c')
-rw-r--r--libexec/popa3d/virtual.c183
1 files changed, 183 insertions, 0 deletions
diff --git a/libexec/popa3d/virtual.c b/libexec/popa3d/virtual.c
new file mode 100644
index 00000000000..9b87ebb9660
--- /dev/null
+++ b/libexec/popa3d/virtual.c
@@ -0,0 +1,183 @@
+/*
+ * Virtual domain support.
+ */
+
+#include "params.h"
+
+#if POP_VIRTUAL
+
+#define _XOPEN_SOURCE
+#define _XOPEN_SOURCE_EXTENDED
+#define _XOPEN_VERSION 4
+#define _XPG4_2
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <errno.h>
+#include <pwd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+extern int log_error(char *s);
+
+char *virtual_domain;
+char *virtual_spool;
+
+int virtual_startup(void)
+{
+ return 0;
+}
+
+static char *lookup(void)
+{
+ struct sockaddr_in sin;
+ int length;
+
+ length = sizeof(sin);
+ if (getsockname(0, (struct sockaddr *)&sin, &length)) {
+ if (errno == ENOTSOCK) return "";
+ log_error("getsockname");
+ return NULL;
+ }
+ if (length != sizeof(sin) || sin.sin_family != AF_INET) return NULL;
+
+ return inet_ntoa(sin.sin_addr);
+}
+
+static int isvaliduser(char *user)
+{
+ unsigned char *p;
+
+/* This is pretty liberal, but we're going to use direct syscalls only,
+ * and they have to accept all the printable characters */
+ for (p = (unsigned char *)user; *p; p++)
+ if (*p < ' ' || *p > 0x7E || *p == '.' || *p == '/') return 0;
+
+ if (p - (unsigned char *)user > NAME_MAX) return 0;
+
+ return 1;
+}
+
+struct passwd *virtual_userpass(char *user, char *pass, char **mailbox)
+{
+ struct passwd *pw, *result;
+ struct stat stat;
+ char auth[VIRTUAL_AUTH_SIZE];
+ char *address, *pathname;
+ char *template, *passwd;
+ int fail;
+ int fd, size;
+
+/* Make sure we don't try to authenticate globally if something fails
+ * before we find out whether the virtual domain is known to us */
+ virtual_domain = "UNKNOWN";
+ virtual_spool = NULL;
+
+ if (!(address = lookup())) return NULL;
+
+/* Authenticate globally (if supported) if run on a non-socket */
+ if (!*address) {
+ virtual_domain = NULL;
+ return NULL;
+ }
+
+ fail = 0;
+ if (!isvaliduser(user)) {
+ user = "INVALID";
+ fail = 1;
+ }
+
+/* This "can't happen", but is just too critical to not check explicitly */
+ if (strchr(address, '/') || strchr(user, '/'))
+ return NULL;
+
+ pathname = malloc(strlen(VIRTUAL_HOME_PATH) + strlen(address) +
+ strlen(VIRTUAL_AUTH_PATH) + strlen(user) + 4);
+ if (!pathname) return NULL;
+ sprintf(pathname, "%s/%s", VIRTUAL_HOME_PATH, address);
+
+ if (lstat(pathname, &stat)) {
+ if (errno == ENOENT)
+ virtual_domain = NULL;
+ else
+ log_error("lstat");
+ free(pathname);
+ return NULL;
+ }
+
+ if (!(address = strdup(address))) return NULL;
+ virtual_domain = address;
+
+ sprintf(pathname, "%s/%s/%s/%s", VIRTUAL_HOME_PATH, address,
+ VIRTUAL_AUTH_PATH, user);
+
+ if ((fd = open(pathname, O_RDONLY)) < 0 && errno != ENOENT) {
+ log_error("open");
+ fail = 1;
+ }
+
+ free(pathname);
+
+ virtual_spool = malloc(strlen(VIRTUAL_HOME_PATH) +
+ strlen(virtual_domain) +
+ strlen(VIRTUAL_SPOOL_PATH) + 3);
+ if (!virtual_spool) {
+ close(fd);
+ return NULL;
+ }
+ sprintf(virtual_spool, "%s/%s/%s", VIRTUAL_HOME_PATH, virtual_domain,
+ VIRTUAL_SPOOL_PATH);
+
+ size = 0;
+ if (fd >= 0) {
+ if (!fail) *mailbox = user;
+
+ if ((size = read(fd, auth, sizeof(auth))) < 0) {
+ log_error("read");
+ size = 0;
+ fail = 1;
+ }
+
+ close(fd);
+ }
+
+ if (size >= sizeof(auth)) {
+ size = 0;
+ fail = 1;
+ }
+
+ auth[size] = 0;
+
+ if (!(template = strtok(auth, ":")) || !*template) {
+ template = "INVALID";
+ fail = 1;
+ }
+ if (!(passwd = strtok(NULL, ":")) || !*passwd ||
+ *passwd == '*' || *passwd == '!') {
+ passwd = AUTH_DUMMY_SALT;
+ fail = 1;
+ }
+ if (!strtok(NULL, ":")) fail = 1;
+
+ if ((pw = getpwnam(template))) {
+ memset(pw->pw_passwd, 0, strlen(pw->pw_passwd));
+ pw->pw_passwd = "*";
+ }
+ endpwent();
+
+ result = NULL;
+ if (!strcmp(crypt(pass, passwd), passwd) && !fail)
+ result = pw;
+
+ memset(auth, 0, sizeof(auth));
+
+ return result;
+}
+
+#endif