/* ** Copyright 1998 - 2007 Double Precision, Inc. See COPYING for ** distribution information. */ #if HAVE_CONFIG_H #include "courier_auth_config.h" #endif #include #include #include #include #include #if HAVE_UNISTD_H #include #endif #include "auth.h" #include "authstaticlist.h" #include "courierauthdebug.h" #include "vpopmail_config.h" #include #include 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 : useridpassword */ 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; }