/* $OpenBSD: table_passwd.c,v 1.2 2013/07/22 13:14:49 eric Exp $ */ /* * Copyright (c) 2013 Gilles Chehade * * 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 #include #include #include #include #include #include #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; }