/*
** Copyright 1998 - 2007 Double Precision, Inc. See COPYING for
** distribution information.
*/
#if HAVE_CONFIG_H
#include "courier_auth_config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <pwd.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#include "auth.h"
#include "authstaticlist.h"
#include "courierauthdebug.h"
#include "vpopmail_config.h"
#include <vpopmail.h>
#include <vauth.h>
static const char rcsid[]="$Id: authvchkpw.c,v 1.29 2007/10/07 02:50:45 mrsam Exp $";
extern int auth_vchkpw_pre(const char *userid, const char *service,
int (*callback)(struct authinfo *, void *),
void *arg);
extern FILE *authvchkpw_file(const char *, const char *);
static int auth_vchkpw_login(const char *service, char *authdata,
int (*callback_func)(struct authinfo *, void *), void *callback_arg);
struct callback_info {
const char *pass;
int (*callback_func)(struct authinfo *, void *);
void *callback_arg;
};
static int callback_vchkpw(struct authinfo *a, void *p)
{
struct callback_info *i=(struct callback_info *)p;
/* exit with perm failure if the supplied password is empty,
* or if the supplied password doesnt match the retrieved password */
if (a->passwd == 0)
{
DPRINTF("no password supplied");
return (-1);
}
if (authcheckpassword(i->pass, a->passwd))
return (-1);
a->clearpasswd=i->pass;
return (*i->callback_func)(a, i->callback_arg);
}
#if HAVE_HMACLIB
#include "libhmac/hmac.h"
#include "cramlib.h"
static int auth_vchkpw_login(const char *service, char *authdata,
int (*callback_func)(struct authinfo *, void *), void *callback_arg);
static int auth_vchkpw_cram(const char *service,
const char *authtype, char *authdata,
int (*callback_func)(struct authinfo *, void *),
void *callback_arg)
{
struct cram_callback_info cci;
if (auth_get_cram(authtype, authdata, &cci))
return (-1);
cci.callback_func=callback_func;
cci.callback_arg=callback_arg;
return auth_vchkpw_pre(cci.user, service, &auth_cram_callback, &cci);
}
#endif
int auth_vchkpw(const char *service, const char *authtype, char *authdata,
int (*callback_func)(struct authinfo *, void *),
void *callback_arg)
{
if (strcmp(authtype, AUTHTYPE_LOGIN) == 0)
return (auth_vchkpw_login(service, authdata,
callback_func, callback_arg));
#if HAVE_HMACLIB
return (auth_vchkpw_cram(service, authtype, authdata,
callback_func, callback_arg));
#else
errno=EPERM;
return (-1);
#endif
}
static int auth_vchkpw_login(const char *service, char *authdata,
int (*callback_func)(struct authinfo *, void *), void *callback_arg)
{
char *user, *pass;
struct callback_info ci;
int rc;
/* Make sure that we have been supplied with the correct
* AUTHDATA format which is : userid<NEWLINE>password<NEWLINE>
*/
if ( (user=strtok(authdata, "\n")) == 0 || (pass=strtok(0, "\n")) == 0)
{
/* login syntax was invalid */
errno=EPERM;
return (-1);
}
ci.pass=pass;
ci.callback_func=callback_func;
ci.callback_arg=callback_arg;
/* auth_vchkpw_pre() does this :
* - lookup the passwd entry for this user from the auth backend
* - check to see if this user is permitted to use this service type
* If successful it will populate the ci struct with the
* user's passwd entry. Return value of function will be 0.
* If unsuccessful (eg user doesnt exist, or is not permitted to
* use this auth method), it will return :
* <0 on a permanent failure (eg user doesnt exist)
* >0 on a temp failure
*/
rc=auth_vchkpw_pre(user, service, &callback_vchkpw, &ci);
if (rc)
return rc;
/* user has been successfully auth'ed at this point */
#if 0
/*
** sam - new courier-authlib never receives TCPREMOTEIP, at this
** time.
*/
#ifdef HAVE_OPEN_SMTP_RELAY
if ( (strcmp("pop3", service)==0) || (strcmp("imap", service)==0) ) {
/* Michael Bowe 13th August 2003
*
* There is a problem here because open_smtp_relay needs
* to get the user's ip from getenv("TCPREMOTEIP").
* If we run --with-authvchkpw --without-authdaemon,
* then this var is available.
* But if we run --with-authvchkpw --with-authdaemon,
* then TCPREMOTEIP is null
*
* If TCPREMOTEIP isnt available, then open_smtp_relay()
* will just return() back immediately.
*/
open_smtp_relay();
}
#endif
#endif
return 0;
}
static void authvchkpwclose()
{
}
static int auth_vchkpw_changepass(const char *service,
const char *username,
const char *pass,
const char *npass)
{
struct vqpasswd *vpw;
char User[256];
char Domain[256];
/* Take the supplied userid, and split it out into the user and domain
* parts. (If a domain was not supplied, then set the domain to be
* the default domain)
*/
/* WARNING: parse_email lowercases the username in place - not const!! */
if ( parse_email(username, User, Domain, 256) != 0) {
/* Failed to successfully extract user and domain.
* So now exit with a permanent failure code
*/
return(-1);
}
/* check to see if domain exists.
* If you pass an alias domain to vget_assign, it will change it
* to be the real domain on return from the function
*/
if ( vget_assign(Domain,NULL,0,NULL,NULL) ==NULL ) {
/* domain doesnt exist */
return (-1);
}
if ( (vpw=vauth_getpw(User, Domain)) == NULL) {
/* That user doesnt exist in the auth backend */
errno=ENOENT;
return (-1);
}
/* Exit if any of the following :
* - user's password field in the passwd entry is empty
* - supplied current password doesnt match stored password
*/
if (vpw->pw_passwd == 0 || authcheckpassword(pass, vpw->pw_passwd)) {
errno=EPERM;
return (-1);
}
/* save the new password into the auth backend */
if ( vpasswd(User, Domain, (char *)npass, 0) != 0 ) {
/* password set failed */
return (-1);
};
return (0);
}
struct authstaticinfo authvchkpw_info={
"authvchkpw",
auth_vchkpw,
auth_vchkpw_pre,
authvchkpwclose,
auth_vchkpw_changepass,
authvchkpwclose,
NULL};
struct authstaticinfo *courier_authvchkpw_init()
{
return &authvchkpw_info;
}
syntax highlighted by Code2HTML, v. 0.9.1