diff options
author | Camiel Dobbelaar <camield@cvs.openbsd.org> | 2001-08-13 19:59:03 +0000 |
---|---|---|
committer | Camiel Dobbelaar <camield@cvs.openbsd.org> | 2001-08-13 19:59:03 +0000 |
commit | c29fb47c597abce79a48b9179039dca232bb9b85 (patch) | |
tree | f24b9f4ec5272eeb475f2d8e159619e662b95ad2 /libexec/popa3d/virtual.c | |
parent | e912815d30df3264d2e6df15b9cf9cc8cd144487 (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.c | 183 |
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 |