| 1 | /* |
| 2 | ** Copyright 1998 - 2001 Double Precision, Inc. See COPYING for |
| 3 | ** distribution information. |
| 4 | */ |
| 5 | |
| 6 | #if HAVE_CONFIG_H |
| 7 | #include "courier_auth_config.h" |
| 8 | #endif |
| 9 | #include <stdio.h> |
| 10 | #include <stdlib.h> |
| 11 | #include <string.h> |
| 12 | #include <errno.h> |
| 13 | #include <pwd.h> |
| 14 | #if HAVE_UNISTD_H |
| 15 | #include <unistd.h> |
| 16 | #endif |
| 17 | #include "auth.h" |
| 18 | #include "courierauthdebug.h" |
| 19 | #include <vpopmail.h> |
| 20 | #include <vauth.h> |
| 21 | #include "vpopmail_config.h" |
| 22 | |
| 23 | /* make use of pw_flags only if available */ |
| 24 | #ifndef VQPASSWD_HAS_PW_FLAGS |
| 25 | #define pw_flags pw_gid |
| 26 | #endif |
| 27 | |
| 28 | extern FILE *authvchkpw_file(const char *, const char *); |
| 29 | |
| 30 | static const char rcsid[]="$Id: preauthvchkpw.c,v 1.26 2007/04/22 18:53:30 mrsam Exp $"; |
| 31 | |
| 32 | /* This function is called by the auth_vchkpw() function |
| 33 | * |
| 34 | * This function does the following : |
| 35 | * - extract the username and domain from the supplied userid |
| 36 | * - lookup the passwd entry for that user from the auth backend |
| 37 | * - populate *and return) a courier authinfo structure with the values |
| 38 | * from the vpopmail passwd entry |
| 39 | * |
| 40 | * Return -1 on perm failure |
| 41 | * Return 0 on success |
| 42 | * Return 1 on temp failure |
| 43 | * |
| 44 | */ |
| 45 | |
| 46 | int auth_vchkpw_pre( |
| 47 | const char *userid, |
| 48 | const char *service, |
| 49 | int (*callback)(struct authinfo *, void *), |
| 50 | void *arg) |
| 51 | { |
| 52 | struct vqpasswd *vpw; |
| 53 | static uid_t uid; |
| 54 | gid_t gid; |
| 55 | struct authinfo auth; |
| 56 | static char User[256]; |
| 57 | static char Domain[256]; |
| 58 | static char options[80]; |
| 59 | |
| 60 | /* Make sure the auth struct is empty */ |
| 61 | memset(&auth, 0, sizeof(auth)); |
| 62 | |
| 63 | /* Take the supplied userid, and split it out into the user and domain |
| 64 | * parts. (If a domain was not supplied, then set the domain to be |
| 65 | * the default domain) |
| 66 | */ |
| 67 | if ( parse_email(userid, User, Domain, 256) != 0) { |
| 68 | /* Failed to successfully extract user and domain. |
| 69 | * So now exit with a permanent failure code |
| 70 | */ |
| 71 | DPRINTF("vchkpw: unable to split into user and domain"); |
| 72 | return(-1); |
| 73 | } |
| 74 | |
| 75 | /* Check to see if the domain exists. |
| 76 | * If so, on return vget_assign will : |
| 77 | * Rewrite Domain to be the real domain if it was sent as an alias domain |
| 78 | * Retrieve the domain's uid and gid |
| 79 | */ |
| 80 | if ( vget_assign(Domain,NULL,0,&uid, &gid) == NULL ) { |
| 81 | /* Domain does not exist |
| 82 | * So now exit with a permanent failure code */ |
| 83 | DPRINTF("vchkpw: domain does not exist"); |
| 84 | return (-1); |
| 85 | } |
| 86 | |
| 87 | /* Try and retrieve the user's passwd entry from the auth backend */ |
| 88 | if ( (vpw=vauth_getpw(User, Domain)) == NULL) { |
| 89 | /* User does not exist |
| 90 | * So now exit with a permanent failure code |
| 91 | */ |
| 92 | DPRINTF("vchkpw: user does not exist"); |
| 93 | return (-1); |
| 94 | } |
| 95 | |
| 96 | /* Check to see if the user has been allocated a dir yet. |
| 97 | * Some of the vpopmail backends (eg mysql) allow users to |
| 98 | * be manually inserted into the auth backend but without |
| 99 | * allocating a dir. A dir will be created when the user |
| 100 | * first trys to auth (or when they 1st receive mail) |
| 101 | */ |
| 102 | if (vpw->pw_dir == NULL || strlen(vpw->pw_dir) == 0 ) { |
| 103 | /* user does not have a dir allocated yet */ |
| 104 | if ( make_user_dir(User, Domain, uid, gid) == NULL) { |
| 105 | /* Could not allocate a user dir at this time |
| 106 | * so exit with a temp error code |
| 107 | */ |
| 108 | DPRINTF("vchkpw: make_user_dir failed"); |
| 109 | return(1); |
| 110 | } |
| 111 | /* We have allocated the user a dir now. |
| 112 | * Go and grab the updated passwd entry |
| 113 | */ |
| 114 | if ( (vpw=vauth_getpw(User, Domain)) == NULL ) { |
| 115 | /* Could not get the passwd entry |
| 116 | * So exit with a permanent failure code |
| 117 | */ |
| 118 | DPRINTF("vchkpw: could not get the password entry"); |
| 119 | return(-1); |
| 120 | } |
| 121 | } |
| 122 | |
| 123 | snprintf(options, sizeof(options), |
| 124 | "disablewebmail=%d,disablepop3=%d,disableimap=%d", |
| 125 | vpw->pw_flags & NO_WEBMAIL ? 1 : 0, |
| 126 | vpw->pw_flags & NO_POP ? 1 : 0, |
| 127 | vpw->pw_flags & NO_IMAP ? 1 : 0); |
| 128 | |
| 129 | #ifdef HAVE_VSET_LASTAUTH |
| 130 | /* if we are keeping track of their last auth time, |
| 131 | * then store this value now. Note that this isnt |
| 132 | * consistent with the authentication via vchkpw |
| 133 | * because it only stores the lastauth attempt |
| 134 | * after the password has been verified. Here we are |
| 135 | * logging it after the user has been found to exist, |
| 136 | * but before the password has been verified. We could |
| 137 | * do the logging inside authvchkpw.c, but that would |
| 138 | * be a lot harder because we would have to go and |
| 139 | * parse_email() again there before calling vset_lastauth() |
| 140 | */ |
| 141 | vset_lastauth(User, Domain, service); |
| 142 | #endif |
| 143 | |
| 144 | /* save the user's passwd fields into the appropriate |
| 145 | * courier structure |
| 146 | */ |
| 147 | /*auth.sysusername = userid;*/ |
| 148 | auth.sysuserid = &uid; |
| 149 | auth.sysgroupid = gid; |
| 150 | auth.homedir = vpw->pw_dir; |
| 151 | auth.address = userid; |
| 152 | auth.fullname = vpw->pw_gecos; |
| 153 | auth.passwd = vpw->pw_passwd; |
| 154 | auth.clearpasswd = vpw->pw_clear_passwd; |
| 155 | auth.options = options; |
| 156 | courier_authdebug_authinfo("DEBUG: authvchkpw: ", &auth, 0, vpw->pw_passwd); |
| 157 | |
| 158 | return ((*callback)(&auth, arg)); |
| 159 | } |