diff options
author | Eric Faurot <eric@cvs.openbsd.org> | 2013-07-21 09:38:53 +0000 |
---|---|---|
committer | Eric Faurot <eric@cvs.openbsd.org> | 2013-07-21 09:38:53 +0000 |
commit | 2b5e84a446c3d0e706617c5d5245d40eb96d9b7f (patch) | |
tree | 6dcf484d76c93b9d9dca0d65a70284d7ab4aae34 /usr.sbin/smtpd/table_passwd.c | |
parent | 78d33adf8409bf580a6c8307e0664efe20781e5d (diff) |
Add a "passwd" table backend. Useful for sharing vusers with other programs.
Diffstat (limited to 'usr.sbin/smtpd/table_passwd.c')
-rw-r--r-- | usr.sbin/smtpd/table_passwd.c | 258 |
1 files changed, 258 insertions, 0 deletions
diff --git a/usr.sbin/smtpd/table_passwd.c b/usr.sbin/smtpd/table_passwd.c new file mode 100644 index 00000000000..91a79f5659f --- /dev/null +++ b/usr.sbin/smtpd/table_passwd.c @@ -0,0 +1,258 @@ +/* $OpenBSD: table_passwd.c,v 1.1 2013/07/21 09:38:52 eric Exp $ */ + +/* + * Copyright (c) 2013 Gilles Chehade <gilles@poolp.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/types.h> + +#include <err.h> +#include <getopt.h> +#include <pwd.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "smtpd-defines.h" +#include "smtpd-api.h" +#include "log.h" + +static int table_passwd_update(void); +static int table_passwd_check(int, const char *); +static int table_passwd_lookup(int, const char *, char *, size_t); +static int table_passwd_fetch(int, char *, size_t); +static int parse_passwd_entry(struct passwd *, const char *); + +static char *config; +static struct dict *passwd; + +int +main(int argc, char **argv) +{ + int ch; + + log_init(1); + + while ((ch = getopt(argc, argv, "")) != -1) { + switch (ch) { + default: + log_warnx("warn: table-passwd: bad option"); + return (1); + /* NOTREACHED */ + } + } + argc -= optind; + argv += optind; + + if (argc != 1) { + log_warnx("warn: table-passwd: bogus argument(s)"); + return (1); + } + + config = argv[0]; + + if (table_passwd_update() == 0) { + log_warnx("warn: table-passwd: error parsing config file"); + return (1); + } + + table_api_on_update(table_passwd_update); + table_api_on_check(table_passwd_check); + table_api_on_lookup(table_passwd_lookup); + table_api_on_fetch(table_passwd_fetch); + table_api_dispatch(); + + return (0); +} + +static int +table_passwd_update(void) +{ + FILE *fp; + char *buf, *lbuf; + size_t len; + char *line; + struct passwd pw; + struct dict *npasswd; + + + /* Parse configuration */ + fp = fopen(config, "r"); + if (fp == NULL) + return (0); + + npasswd = calloc(1, sizeof *passwd); + if (npasswd == NULL) + goto err; + + dict_init(npasswd); + + lbuf = NULL; + while ((buf = fgetln(fp, &len))) { + if (buf[len - 1] == '\n') + buf[len - 1] = '\0'; + else { + /* EOF without EOL, copy and add the NUL */ + if ((lbuf = malloc(len + 1)) == NULL) + err(1, NULL); + memcpy(lbuf, buf, len); + lbuf[len] = '\0'; + buf = lbuf; + } + if (! parse_passwd_entry(&pw, buf)) { + log_warnx("warn: table-passwd: invalid entry"); + goto err; + } + if ((line = strdup(buf)) == NULL) + err(1, NULL); + dict_set(npasswd, pw.pw_name, line); + } + free(lbuf); + + /* swap passwd table and release old one*/ + if (passwd) + while (dict_poproot(passwd, NULL, (void**)&buf)) + free(buf); + passwd = npasswd; + + return (1); + +err: + /* release passwd table */ + if (npasswd) + while (dict_poproot(npasswd, NULL, (void**)&buf)) + free(buf); + return (0); +} + +static int +table_passwd_check(int service, const char *key) +{ + return (-1); +} + +static int +table_passwd_lookup(int service, const char *key, char *dst, size_t sz) +{ + int r; + struct passwd pw; + char *line; + + line = dict_get(passwd, key); + if (line == NULL) + return 0; + + if (! parse_passwd_entry(&pw, line)) { + log_warnx("warn: table-passwd: invalid entry"); + return -1; + } + + r = 1; + switch (service) { + case K_CREDENTIALS: + if (snprintf(dst, sz, "%s:%s", + pw.pw_name, pw.pw_passwd) > (ssize_t)sz) { + log_warnx("warn: table-passwd: result too large"); + r = -1; + } + break; + case K_USERINFO: + if (snprintf(dst, sz, "%i:%i:%s", + pw.pw_uid, pw.pw_gid, pw.pw_dir) + > (ssize_t)sz) { + log_warnx("warn: table-passwd: result too large"); + r = -1; + } + break; + default: + log_warnx("warn: table-passwd: unknown service %i", + service); + r = -1; + } + + return (r); +} + +static int +table_passwd_fetch(int service, char *dst, size_t sz) +{ + return (-1); +} + +static int +parse_passwd_entry(struct passwd *pw, const char *line) +{ + const char *errstr; + char *p, *q; + char buf[LINE_MAX]; + + if (strlcpy(buf, line, sizeof buf) >= sizeof buf) + return 0; + p = buf; + + /* username */ + q = p; + if ((p = strchr(q, ':')) == NULL) + return 0; + *p++ = 0; + pw->pw_name = q; + + /* password */ + q = p; + if ((p = strchr(q, ':')) == NULL) + return 0; + *p++ = 0; + pw->pw_passwd = q; + + /* uid */ + q = p; + if ((p = strchr(q, ':')) == NULL) + return 0; + *p++ = 0; + pw->pw_uid = strtonum(q, 1, UID_MAX, &errstr); + if (errstr) + return 0; + + /* gid */ + q = p; + if ((p = strchr(q, ':')) == NULL) + return 0; + *p++ = 0; + pw->pw_gid = strtonum(q, 1, GID_MAX, &errstr); + if (errstr) + return 0; + + /* gecos */ + q = p; + if ((p = strchr(q, ':')) == NULL) + return 0; + *p++ = 0; + pw->pw_gecos = q; + + /* home */ + q = p; + if ((p = strchr(q, ':')) == NULL) + return 0; + *p++ = 0; + pw->pw_dir = q; + + /* shell */ + q = p; + if ((p = strchr(q, ':')) != NULL) + return 0; + pw->pw_shell = q; + + return 1; +} |