/*
* auth_flatfile.c:
* Authenticate users using an alternate passwd file
*
* designed for tpop3d by Angel Marin <anmar@gmx.net>
* Copyright (c) 2002 Angel Marin, Chris Lightfoot. All rights reserved.
*/
#ifdef HAVE_CONFIG_H
#include "configuration.h"
#endif /* HAVE_CONFIG_H */
#ifdef AUTH_FLATFILE
static const char rcsid[] = "$Id: auth_flatfile.c,v 1.2 2003/02/17 23:18:32 chris Exp $";
#include <sys/types.h>
#ifdef HAVE_CRYPT_H /* XXX */
#include <crypt.h>
#endif
#include <unistd.h>
#include <grp.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include "auth_flatfile.h"
#include "authswitch.h"
#include "password.h"
#include "config.h"
#include "util.h"
static gid_t virtual_gid;
static uid_t virtual_uid;
static char *user_passwd_file_template;
/* auth_flatfile_init:
* Initialise the driver. Reads the config directives. */
int auth_flatfile_init(void) {
char *s;
int ret = 0;
/* Obtain uid to use */
if ((s = config_get_string("auth-flatfile-mail-user"))) {
if (!parse_uid(s, &virtual_uid)) {
log_print(LOG_ERR, _("auth_flatfile_init: auth-flatfile-mail-user directive `%s' does not make sense"), s);
goto fail;
}
} else {
log_print(LOG_ERR, _("auth_flatfile_init: no auth-flatfile-mail-user directive in config"));
goto fail;
}
/* Obtain gid to use */
if ((s = config_get_string("auth-flatfile-mail-group"))) {
if (!parse_gid(s, &virtual_gid)) {
log_print(LOG_ERR, _("auth_flatfile_init: auth-flatfile-mail-group directive `%s' does not make sense"), s);
goto fail;
}
} else {
log_print(LOG_ERR, _("auth_flatfile_init: no auth-flatfile-mail-group directive in config"));
goto fail;
}
/* Obtain path template to passwd file */
if ((s = config_get_string("auth-flatfile-passwd-file"))) {
user_passwd_file_template = s;
} else {
log_print(LOG_ERR, _("auth_flatfile_init: no auth-flatfile-passwd-file directive in config"));
goto fail;
}
ret = 1;
fail:
return ret;
}
/* read_user_passwd LOCALPART DOMAIN
* Read the password hash from the proper flat file for the given LOCALPART and
* DOMAIN. Returns the password or NULL if not found. The files are structured
* with colon-separated fields, where the first field is the local-part and the
* second field to the password hash. Any subsequent fields are ignored. */
static char *read_user_passwd(const char *local_part, const char *domain) {
FILE *fp = NULL;
char *filename = NULL;
struct sverr err;
static char *buf, *pwhash;
static size_t buflen;
size_t i, linenum;
int c;
if (!(filename = substitute_variables(user_passwd_file_template, &err, 1, "domain", domain))) {
log_print(LOG_ERR, _("read_user_passwd: %s near `%.16s'"), err.msg, user_passwd_file_template + err.offset);
goto fail;
}
if (!(fp = fopen(filename, "rt"))) {
log_print(LOG_ERR, _("read_user_passwd: flat file %s: %m"), filename);
goto fail;
}
/* Read lines from the file. */
if (!buf)
buf = xmalloc(buflen = 1024);
linenum = 0;
while (1) {
char *user, *end;
i = 0;
while ((c = getc(fp)) != EOF) {
if (c == '\n')
break;
buf[i++] = (char)c;
if (i == buflen)
buf = xrealloc(buf, buflen *= 2);
}
buf[i] = 0;
if (c == EOF) {
if (ferror(fp)) {
/* Read error. */
log_print(LOG_ERR, _("read_user_passwd: flat file %s: %m"), filename);
goto fail;
} else if (i == 0)
/* Read nothing at end of file. */
break;
}
/* OK, have a line. */
user = buf;
pwhash = strchr(buf, ':');
if (!pwhash) {
log_print(LOG_WARNING, _("read_user_passwd: flat file %s: line %u: bad format (missing :)"), filename, (unsigned)linenum);
continue;
}
*pwhash++ = 0;
/* Check username. */
if (strcmp(user, local_part) != 0)
continue;
if ((end = strchr(pwhash, ':')))
*end = 0;
break;
}
fail:
if (fp)
fclose(fp);
if (filename)
xfree(filename);
return pwhash;
}
/* auth_flatfile_new_user_pass:
* Attempt to authenticate user and pass using an alternate passwd file,
* as configured at compile-time. This is a virtual-domains authenticator. */
authcontext auth_flatfile_new_user_pass(const char *user, const char *local_part, const char *domain, const char *pass, const char *clienthost /* unused */, const char *serverhost /* unused */) {
authcontext a = NULL;
char *pwhash, *who;
if (!local_part) return NULL;
who = username_string(user, local_part, domain);
pwhash = read_user_passwd(local_part, domain);
if (pwhash) {
if (check_password(who, pwhash, pass, "{crypt}"))
a = authcontext_new(virtual_uid, virtual_gid, NULL, NULL, NULL);
else
log_print(LOG_ERR, _("auth_flatfile_new_user_pass: failed login for %s"), who);
}
return a;
}
/* auth_flatfile_new_apop:
* Attempt to authenticate user via APOP using an alternate passwd file,
* as configured at compile-time. This is a virtual-domains authenticator. */
authcontext auth_flatfile_new_apop(const char *user, const char *local_part, const char *domain, const char *timestamp, const unsigned char *digest, const char *clienthost /* unused */, const char *serverhost /* unused */) {
authcontext a = NULL;
char *pwhash, *who;
if (!local_part) return NULL;
who = username_string(user, local_part, domain);
pwhash = read_user_passwd(local_part, domain);
if (pwhash) {
if (check_password_apop(who, pwhash, timestamp, digest))
a = authcontext_new(virtual_uid, virtual_gid, NULL, NULL, NULL);
else
log_print(LOG_ERR, _("auth_flatfile_new_apop: failed login for %s"), who);
}
return a;
}
#endif /* AUTH_FLATFILE */
syntax highlighted by Code2HTML, v. 0.9.1