/*
 * $Id: c8b67d226bd8d7148beca13ef4b626b2f2568f3b $
 *
 * This file is part of nsmtp.
 *
 * Copyright (c) 2007, 2008 Niklas Olmes <niklas@noxa.de>
 *                          http://www.nevm.de/nsmtp/
 *                          NEVM-RIPE
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License Version 2
 * as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 *
 */

#include <syslog.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>

#include "check.h"
#include "ldapauth.h"
#include "maildir.h"
#include "relay.h"
#include "log.h"
#include "misc.h"
#include "config.h"

#include "auth.h"
#include "authmod.h"

static const char rcsid[] = "$Id: c8b67d226bd8d7148beca13ef4b626b2f2568f3b $";

int
main(int argc, char *argv[])
{
	char tmp[512];
	const char *u, *p;
	const char *service, *type;
	char *maildir;
	char *data, *t;
	char *ip;
	uid_t uid;
	gid_t gid;
	unsigned int uidnumber;
	int e;

	openlog("nsmtp(authcourier3)", LOG_PID, LOG_MAIL);

	authmod_init(argc, argv, &service, &type, &data);

	if (strcmp(type, AUTHTYPE_LOGIN) != 0) {
		xwarn("warn: authtype is not login, can't do anything");
		authmod_fail_completely();
	}

	/*
	 * Extract Username and Password
	 */
	u = data;
	p = data; /* shut up compiler 'might be used uninitialized' warning */
	if (strlen(data) < 5 || (t = strchr(u, '\n')) == NULL) {
		xwarn("warn: authdata is too short, must be garbage");
		authmod_fail_completely();
	} else {
		/*
		 * Need explicit else here because compiler doesn't know
		 * authmod_fail_completely() does not return
		 */
		*t = '\0';
		t++;
		p = t;
	}

	if ((t = strchr(p, '\n')) == NULL) {
		xwarn("warn: authdata is garbage");
		authmod_fail_completely();
	} else {
		/* see above */
		*t = '\0';
	}

	if (*u == '\0' || *p == '\0') {
		xinfo("info: FAILED user=<%s> and/or password is empty", u);
		authmod_fail_completely();
	}

	/*
	 * Authenticate against LDAP
	 */
	read_ldap_cfg();

	if ((e = ldapauth(u, p)) > 0) {
		xinfo("info: FAILED for user=<%s>", u);
		free_ldap_cfg();
		authmod_fail_completely();
	} else if (e < 0) {
		xinfo("info: TEMPFAIL for user=<%s>", u);
		free_ldap_cfg();
		authmod_fail_completely();
	}

	/*
	 * Get Settings from LDAP
	 */
	if ((e = get_maildir_and_uid(u, &maildir, &uidnumber)) > 0) {
		xwarn("warn: FAILED for user=<%s>, auth success but could not get maildir and/or uid", u);
		free_ldap_cfg();
		authmod_fail_completely();
	} else if (e < 0) {
		xwarn("warn: TEMPFAIL for user=<%s>, auth success but temporary failure getting maildir and uid", u);
		free_ldap_cfg();
		authmod_fail_completely();
	}

	free_ldap_cfg();

	uid = uidnumber;
	gid = uidnumber;
	(void)snprintf(tmp, sizeof(tmp), "%s/%s", nsmc_mail_root, maildir);

	xinfo("info: SUCCESS for user=<%s>, mailhome=<%s> expanded=<%s> uid=(%d) gid=(%d)", u, maildir, tmp, uid, gid);

	/*
	 * Temporarily allow relaying for the user's IP address
	 */
	if ((ip = getenv("TCPREMOTEIP")) != NULL)
		temp_allow_relay(ip);
	else
		xwarn("warn: could not get remote ip address from environment, can't allow relaying");

	/*
	 * Drop privileges, setup environment
	 */
	authsuccess(tmp, '\0', &uid, &gid, u, '\0');

	if (setenv("HOME", tmp, 1) != 0) {
		xfatal("fatal: setenv(HOME) failed: \"%s\"", strerror(errno));
		authmod_fail_completely();
	}

	(void)snprintf(tmp, sizeof(tmp), "%s/%s/Maildir", nsmc_mail_root, maildir);
	if (setenv("MAILDIR", tmp, 1) != 0) {
		xfatal("fatal: setenv(MAILDIR) failed: \"%s\"", strerror(errno));
		authmod_fail_completely();
	}

	authmod_success(argc, argv, u);

	/* NOTREACHED */
	return 0;
}
