Update of /cvsroot/vpopmail/vpopmail In directory fdv4jf1.ch3.sourceforge.com:/tmp/cvs-serv4030 Modified Files: ChangeLog Makefile.am configure configure.in vpopmail.c vpopmail.h Added Files: README.authvchkpw authvchkpw.c backfill.c Log Message: Added authvchkpw module for Courier-IMAP [2507177] Added backfill patch [2507177] Index: configure =================================================================== RCS file: /cvsroot/vpopmail/vpopmail/configure,v retrieving revision 1.52 retrieving revision 1.53 diff -u -d -r1.52 -r1.53 --- configure 4 Nov 2007 01:10:00 -0000 1.52 +++ configure 15 Jan 2009 15:31:23 -0000 1.53 @@ -7396,7 +7396,7 @@ { (exit 1); exit 1; }; } fi - auth_libs="-L$libdir $extralibflags -lmysqlclient -lz -lm" + auth_libs="-Xlinker -R -Xlinker $libdir -L$libdir $extralibflags -lmysqlclient -lz -lm" ;; @@ -9462,21 +9462,22 @@ fi rm -f "$tmp/out12" # Compute $ac_file's index in $config_headers. +_am_arg=$ac_file _am_stamp_count=1 for _am_header in $config_headers :; do case $_am_header in - $ac_file | $ac_file:* ) + $_am_arg | $_am_arg:* ) break ;; * ) _am_stamp_count=`expr $_am_stamp_count + 1` ;; esac done -echo "timestamp for $ac_file" >`$as_dirname -- $ac_file || -$as_expr X$ac_file : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X$ac_file : 'X\(//\)[^/]' \| \ - X$ac_file : 'X\(//\)$' \| \ - X$ac_file : 'X\(/\)' \| . 2>/dev/null || -echo X$ac_file | +echo "timestamp for $_am_arg" >`$as_dirname -- "$_am_arg" || +$as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$_am_arg" : 'X\(//\)[^/]' \| \ + X"$_am_arg" : 'X\(//\)$' \| \ + X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null || +echo X"$_am_arg" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q @@ -9513,7 +9514,7 @@ # each Makefile.in and add a new line on top of each file to say so. # Grep'ing the whole file is not good either: AIX grep has a line # limit of 2048, but all sed's we know have understand at least 4000. - if sed 10q "$mf" | grep '^#.*generated by automake' > /dev/null 2>&1; then + if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then dirpart=`$as_dirname -- "$mf" || $as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$mf" : 'X\(//\)[^/]' \| \ Index: configure.in =================================================================== RCS file: /cvsroot/vpopmail/vpopmail/configure.in,v retrieving revision 1.48 retrieving revision 1.49 diff -u -d -r1.48 -r1.49 --- configure.in 4 Nov 2007 01:10:00 -0000 1.48 +++ configure.in 15 Jan 2009 15:31:23 -0000 1.49 @@ -1094,7 +1094,7 @@ AC_MSG_ERROR([Unable to find your MySQL lib dir, specify --enable-libdir.]) fi - auth_libs="-L$libdir $extralibflags -lmysqlclient -lz -lm" + auth_libs="-Xlinker -R -Xlinker $libdir -L$libdir $extralibflags -lmysqlclient -lz -lm" AC_SUBST(auth_libs) ;; --- NEW FILE: README.authvchkpw --- I have tweaked a bit authvchkpw module for vpopmail. It includes most of the function needed to authenticate. To install it you need to apply patch to vpopmail-5.4.26d. It modifies Makefile.am, configure.in, vpopmail.c, vpopmail.h and creates a new file authvchkpw.c. I have tested it on my laptop and found it to work. But I give no warranty. AUTHMODULES in courier-imap needs to have authvchkpw as one of the authentication modules The module does the following reads 5 lines from imaplogin or pop3login. Authenticates the user and if successful executes the imapd or pop3d executable. If the authentication is not successful, the data is passed to the next authmodule in chain. On successful authentication the module adds entry to lastauth and a entry in relay table. Instructions are in INSTALL section below. If you need more help let me know. If more modifications are needed let me know. /* * Courier-IMAP authmodules Protocol * imap\n * login\n * pos...@te...\n * pass\n * newpass\n * argv[0]=/var/indimail/libexec/authlib/authvchkpw * argv[1]=/var/indimail/libexec/authlib/authpam * argv[2]=/var/indimail/bin/imapd * argv[3]=Maildir */ INSTALLATION 1. Extract vpopmail Development tar.gz file vpopmail-5.4.26d.tar.gz wget http://downloads.sourceforge.net/vpopmail/vpopmail-5.4.26d.tar.gz cd /home/local/src gunzip -c vpopmail-5.4.26d.tar.gz |tar xf - 2. patch -p0 authvchkpw-vpopmail-5.4.26d.patch 3. cd vpopmail-5.4.26 su ./configure # with the usual options make make install-strip Index: ChangeLog =================================================================== RCS file: /cvsroot/vpopmail/vpopmail/ChangeLog,v retrieving revision 1.189 retrieving revision 1.190 diff -u -d -r1.189 -r1.190 --- ChangeLog 6 Dec 2007 01:45:29 -0000 1.189 +++ ChangeLog 15 Jan 2009 15:31:23 -0000 1.190 @@ -12,6 +12,9 @@ - Fix mixed up usage of MYSQL_UPDATE_* and MYSQL_READ_* in vmysql.c:load_connection_info() This may need a tracker number attached. I can't find it. + Manvendra Bhangui + - Added authvchkpw module for Courier-IMAP + - Added backfill patch [2507177] 5.4.26 - Released 3-Nov-2007 Bill Shupp Index: vpopmail.h =================================================================== RCS file: /cvsroot/vpopmail/vpopmail/vpopmail.h,v retrieving revision 1.34 retrieving revision 1.35 diff -u -d -r1.34 -r1.35 --- vpopmail.h 31 Oct 2007 07:55:39 -0000 1.34 +++ vpopmail.h 15 Jan 2009 15:31:23 -0000 1.35 @@ -303,7 +303,6 @@ char *make_user_dir(char *username, char *domain, uid_t uid, gid_t gid); int r_mkdir(char *, uid_t uid, gid_t gid); struct vqpasswd *vgetent(FILE *); -int pw_comp(char *, char *, char *, int); char *default_domain(); void vset_default_domain( char *); void vupdate_rules(int); @@ -361,3 +360,7 @@ extern int allow_onchange; int call_onchange(); #endif + +#ifdef USERS_BIG_DIR +char *backfill(char *, char *, char *, int); +#endif Index: Makefile.am =================================================================== RCS file: /cvsroot/vpopmail/vpopmail/Makefile.am,v retrieving revision 1.26 retrieving revision 1.27 diff -u -d -r1.26 -r1.27 --- Makefile.am 31 Oct 2007 07:55:39 -0000 1.26 +++ Makefile.am 15 Jan 2009 15:31:23 -0000 1.27 @@ -9,7 +9,7 @@ noinst_HEADERS=md5.h vpopmail.h file_lock.h vauth.h vlimits.h maildirquota.h vcdb.h vldap.h vmysql.h voracle.h vpgsql.h vsybase.h vlog.h global.h hmac_md5.h seek.h vutil.h -COMMONSOURCES=vpopmail.c md5.c bigdir.c vauth.c file_lock.c vpalias.c seek.c vlimits.c maildirquota.c vutil.c vlistlib.c +COMMONSOURCES=vpopmail.c md5.c bigdir.c vauth.c file_lock.c vpalias.c seek.c vlimits.c maildirquota.c vutil.c vlistlib.c backfill.c CONFIG_CLEAN_FILES=vauth.c cdb/conf-cc cdb/conf-ld cdb/compile cdb/load @@ -30,7 +30,7 @@ vdeldomain vpasswd vadduser vdeluser vaddaliasdomain vsetuserquota \ vpopbull vdeloldusers vmoduser valias vuserinfo vmkpasswd vipmap \ vdominfo vconvert vkill vmoddomlimits vchangepw dotqmail2valias \ - vpopmaild vlist + vpopmaild vlist authvchkpw vuserinfo_SOURCES = vuserinfo.c maildirquota.c vuserinfo_LDADD = libvpopmail.a @auth_libs@ @@ -38,6 +38,9 @@ vlist_SOURCES = vlist.c vlistlib.c vutil.c vlist_LDADD = libvpopmail.a @auth_libs@ +authvchkpw_SOURCES = authvchkpw.c hmac_md5.c +authvchkpw_LDADD = libvpopmail.a @auth_libs@ + vpopmaild_SOURCES = vpopmaild.c vpopmaild_LDADD = libvpopmail.a @auth_libs@ Index: vpopmail.c =================================================================== RCS file: /cvsroot/vpopmail/vpopmail/vpopmail.c,v retrieving revision 1.58 retrieving revision 1.59 diff -u -d -r1.58 -r1.59 --- vpopmail.c 31 Oct 2007 07:55:39 -0000 1.58 +++ vpopmail.c 15 Jan 2009 15:31:23 -0000 1.59 @@ -1434,6 +1434,7 @@ pid=vfork(); if ( pid==0){ + umask(022); execl(QMAILNEWU,"qmail-newu", NULL); exit(127); } else { @@ -1764,6 +1765,8 @@ return (-1); } + /* write the information to backfill */ + backfill(user, domain, mypw->pw_dir, 2); dec_dir_control(domain, uid, gid); /* remove the user's directory from the file system @@ -2364,9 +2367,13 @@ user_hash=""; #ifdef USERS_BIG_DIR /* go into a user hash dir if required */ - open_big_dir(domain, uid, gid); - user_hash = next_big_dir(uid, gid); - close_big_dir(domain, uid, gid); + if (!(user_hash = backfill(username, domain, 0, 1))) + { + open_big_dir(domain, uid, gid); + user_hash = next_big_dir(uid, gid); + close_big_dir(domain, uid, gid); + } else + r_mkdir(user_hash, uid, gid); chdir(user_hash); #endif /* check the length of the dir path to make sure it is not too --- NEW FILE: authvchkpw.c --- /* * $Log: authvchkpw.c,v $ * Revision 1.1 2009/01/15 15:31:23 volz0r * Added authvchkpw module for Courier-IMAP [2507177] * Added backfill patch [2507177] * * Revision 2.2 2008-08-24 17:43:44+05:30 Cprogrammer * added code to return error for password changes * * Revision 2.1 2008-08-24 14:44:56+05:30 Cprogrammer * courier-imap authmodule for IndiMail * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License. * * 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, see <http://www.gnu.org/licenses/>. * * The GNU General Public License does not permit incorporating your program * into proprietary programs. If your program is a subroutine library, you * may consider it more useful to permit linking proprietary applications with * the library. If this is what you want to do, use the GNU Lesser General * Public License instead of this License. But first, please read * <http://www.gnu.org/philosophy/why-not-lgpl.html>. * */ #include "config.h" #include "vpopmail.h" #include <stdio.h> #include <fcntl.h> #include <stdlib.h> #include <signal.h> #include <pwd.h> #include <string.h> #include "md5.h" #include "hmac_md5.h" #include <unistd.h> #include <errno.h> #include <sys/types.h> #include <sys/stat.h> #include "vauth.h" #ifndef lint static char sccsid[] = "$Id: authvchkpw.c,v 1.1 2009/01/15 15:31:23 volz0r Exp $"; #endif #ifdef AUTH_SIZE #undef AUTH_SIZE #define AUTH_SIZE 512 #else #define AUTH_SIZE 512 #endif int authlen = AUTH_SIZE; static int exec_local(char **, char *, char *, struct vqpasswd *, char *); static char hextab[] = "0123456789abcdef"; void close_connection() { #ifdef PASSWD_CACHE if (!getenv("PASSWD_CACHE")) vclose(); #else /*- Not PASSWD_CACHE */ vclose(); #endif } int pw_comp(char *testlogin, char *password, char *challenge, char *response) { unsigned char digest[16]; unsigned char digascii[33]; char *crypt_pass; unsigned char h; int j; if(!response || (response && !*response)) { if (!(crypt_pass = crypt((char *) challenge, (char *) password))) { printf("454-%s (#4.3.0)\r\n", strerror(errno)); fflush(stdout); _exit (111); } return(strncmp((const char *) crypt_pass, (const char *) password, (size_t) 14)); } hmac_md5((unsigned char *) challenge, (int) strlen((const char *) challenge), (unsigned char *) password, (int) strlen((const char *) password), digest); digascii[32] = 0; for (j = 0; j < 16; j++) { h = digest[j] >> 4; digascii[2 * j] = hextab[h]; h = digest[j] & 0x0f; digascii[(2 * j) + 1] = hextab[h]; } return (strcmp((const char *) digascii, (const char *) response) && strcmp((const char *) password, (const char *) challenge)); } /* * getEnvConfigStr */ void getEnvConfigStr(char **source, char *envname, char *defaultValue) { if (!(*source = getenv(envname))) *source = defaultValue; return; } int Login_Tasks(pw, user, ServiceType) struct passwd *pw; const char *user; char *ServiceType; { char *domain, *ptr; char fqemail[MAX_BUFF]; #ifdef ENABLE_AUTH_LOGGING #ifdef MIN_LOGIN_INTERVAL time_t min_login_interval, last_time; #endif #ifdef USE_MAILDIRQUOTA mdir_t size_limit, count_limit; #endif #endif if (!pw) return(1); lowerit((char *) user); lowerit(pw->pw_name); if (!(ptr = strchr(user, '@'))) { getEnvConfigStr(&domain, "DEFAULT_DOMAIN", DEFAULT_DOMAIN); lowerit(domain); snprintf(fqemail, MAX_BUFF, "%s@%s", user, domain); } else { domain = ptr + 1; strncpy(fqemail, user, MAX_BUFF); *ptr = 0; } if (access(pw->pw_dir, F_OK)) vmake_maildir(domain, pw->pw_dir); #ifdef POP_AUTH_OPEN_RELAY /*- open the relay to pop3/imap users */ if (!getenv("NORELAY") && (pw->pw_gid & NO_RELAY) == 0) open_smtp_relay(pw->pw_name, domain); #endif #ifdef ENABLE_AUTH_LOGGING #ifdef MIN_LOGIN_INTERVAL last_time = vget_lastauth(pw, domain); #endif if (!(ptr = getenv("TCPERMOTEIP"))) ptr = "0.0.0.0"; vset_lastauth(pw->pw_name, domain, ptr); #ifdef MIN_LOGIN_INTERVAL if(( vget_lastauth(vpw,TheDomain ) - last_time ) < MIN_LOGIN_INTERVAL ) { vchkpw_exit(1); } #endif #endif /*- ENABLE_AUTH_LOGGING */ return(0); } int pipe_exec(char **argv, char *tmpbuf, int len) { int pipe_fd[2]; void (*pstat) (); if ((pstat = signal(SIGPIPE, SIG_IGN)) == SIG_ERR) { fprintf(stderr, "pipe_exec: signal: %s\n", strerror(errno)); return (-1); } if(pipe(pipe_fd) == -1) { fprintf(stderr, "pipe_exec: pipe: %s\n", strerror(errno)); signal(SIGPIPE, pstat); return(-1); } if(dup2(pipe_fd[0], 3) == -1 || dup2(pipe_fd[1], 4) == -1) { fprintf(stderr, "pipe_exec: dup2: %s\n", strerror(errno)); signal(SIGPIPE, pstat); return(-1); } if(pipe_fd[0] != 3 && pipe_fd[0] != 4) close(pipe_fd[0]); if(pipe_fd[1] != 3 && pipe_fd[1] != 4) close(pipe_fd[1]); if(write(4, tmpbuf, len) != len) { fprintf(stderr, "pipe_exec: %s: %s\n", argv[1], strerror(errno)); signal(SIGPIPE, pstat); return(-1); } close(4); signal(SIGPIPE, pstat); execvp(argv[1], argv + 1); fprintf(stderr, "pipe_exec: %s: %s\n", argv[1], strerror(errno)); return(-1); } int main(int argc, char **argv) { char *buf, *tmpbuf, *login, *challenge, *crypt_pass, *prog_name, *service, *service_type; char user[AUTH_SIZE], domain[AUTH_SIZE], Email[MAX_BUFF]; int count, offset; uid_t uid; gid_t gid; struct vqpasswd *pw; char *(indiargs[]) = { VPOPMAILDIR"/sbin/imaplogin", VPOPMAILDIR"/libexec/authlib/authvchkpw", VPOPMAILDIR"/bin/imapd", "Maildir", 0 }; if ((prog_name = strrchr(argv[0], '/'))) prog_name++; else prog_name = argv[0]; if (argc < 3) { fprintf(stderr, "%s: no more modules will be tried\n", prog_name); return(1); } if (!(tmpbuf = calloc(1, (authlen + 1) * sizeof(char)))) { fprintf(stderr, "%s: malloc-%d: %s\n", prog_name, authlen + 1, strerror(errno)); return(1); } /* * Courier-IMAP authmodules Protocol * imap\n * login\n * pos...@te...\n * pass\n * newpass\n * argv[0]=/var/indimail/libexec/authlib/try * argv[1]=/var/indimail/libexec/authlib/authpam * argv[2]=/var/indimail/bin/imapd * argv[3]=Maildir */ for (offset = 0;;) { do { count = read(3, tmpbuf + offset, authlen + 1 - offset); #ifdef ERESTART } while (count == -1 && (errno == EINTR || errno == ERESTART)); #else } while (count == -1 && errno == EINTR); #endif if (count == -1) { fprintf(stderr, "read: %s\n", strerror(errno)); return(1); } else if (!count) break; offset += count; if (offset >= (authlen + 1)) { fprintf(stderr, "%s: auth data too long\n", prog_name); return(2); } } if (!(buf = calloc(1, (offset + 1) * sizeof(char)))) { fprintf(stderr, "%s: malloc-%d: %s\n", prog_name, authlen + 1, strerror(errno)); return(1); } memcpy(buf, tmpbuf, offset); count = 0; service = tmpbuf + count; /*- service */ for (;tmpbuf[count] != '\n' && count < offset;count++); if (count == offset || (count + 1) == offset) { fprintf(stderr, "%s: auth data too short\n", prog_name); return(2); } tmpbuf[count++] = 0; service_type = tmpbuf + count; /* type (login or pass) */ for (;tmpbuf[count] != '\n' && count < offset;count++); if (count == offset || (count + 1) == offset) { fprintf(stderr, "%s: auth data too short\n", prog_name); return(2); } tmpbuf[count++] = 0; login = tmpbuf + count; /*- username */ for (;tmpbuf[count] != '\n' && count < offset;count++); if (count == offset || (count + 1) == offset) { fprintf(stderr, "%s: auth data too short\n", prog_name); return(2); } tmpbuf[count++] = 0; challenge = tmpbuf + count; /*- challenge (plain text) */ for (;tmpbuf[count] != '\n' && count < offset;count++); tmpbuf[count++] = 0; if (!strncmp(service_type, "pass", 5)) { fprintf(stderr, "%s: Password Change not supported\n", prog_name); pipe_exec(argv, buf, offset); return(1); } if (parse_email(login, user, domain, MAX_BUFF)) { fprintf(stderr, "%s: could not parse email [%s]\n", prog_name, login); pipe_exec(argv, buf, offset); return (1); } if (!vget_assign(domain, 0, 0, &uid, &gid)) { fprintf(stderr, "%s: domain %s does not exist\n", prog_name, domain); pipe_exec(argv, buf, offset); return (1); } snprintf(Email, MAX_BUFF, "%s@%s", user, domain); if (vauth_open(0)) { fprintf(stderr, "%s: inquery: %s\n", prog_name, strerror(errno)); pipe_exec(argv, buf, offset); return (1); } pw = vauth_getpw(user, domain); if (!pw) { fprintf(stderr, "%s: inquery: %s\n", prog_name, strerror(errno)); pipe_exec(argv, buf, offset); close_connection(); return (1); } /* * Look at what type of connection we are trying to auth. * And then see if the user is permitted to make this type * of connection */ if (strcmp("webmail", service) == 0) { if (pw->pw_gid & NO_WEBMAIL) { fprintf(stderr, "%s: webmail disabled for this account", prog_name); write(2, "AUTHFAILURE\n", 12); close_connection(); execv(*indiargs, argv); fprintf(stderr, "execv %s: %s", *indiargs, strerror(errno)); return (1); } } else if (strcmp("pop3", service) == 0) { if (pw->pw_gid & NO_POP) { fprintf(stderr, "%s: pop3 disabled for this account", prog_name); write(2, "AUTHFAILURE\n", 12); close_connection(); execv(*indiargs, argv); fprintf(stderr, "execv %s: %s", *indiargs, strerror(errno)); return (1); } } else if (strcmp("imap", service) == 0) { if (pw->pw_gid & NO_IMAP) { fprintf(stderr, "%s: imap disabled for this account", prog_name); write(2, "AUTHFAILURE\n", 12); close_connection(); execv(*indiargs, argv); fprintf(stderr, "execv %s: %s", *indiargs, strerror(errno)); return (1); } } crypt_pass = pw->pw_passwd; if (getenv("DEBUG_LOGIN")) { fprintf(stderr, "%s: service[%s] type [%s] login [%s] challenge [%s] pw_passwd [%s]\n", prog_name, service, service_type, login, challenge, crypt_pass); } if (pw_comp(login, crypt_pass, challenge, 0)) { if (argc == 3) { fprintf(stderr, "%s: no more modules will be tried\n", prog_name); write(2, "AUTHFAILURE\n", 12); close_connection(); execv(*indiargs, indiargs); fprintf(stderr, "execv %s: %s", *indiargs, strerror(errno)); return (1); } close_connection(); pipe_exec(argv, buf, offset); return (1); } exec_local(argv + argc - 2, login, domain, pw, service); return(0); } static int exec_local(char **argv, char *userid, char *TheDomain, struct vqpasswd *pw, char *service) { char Maildir[MAX_BUFF], authenv1[MAX_BUFF], authenv2[MAX_BUFF], authenv3[MAX_BUFF], authenv4[MAX_BUFF], authenv5[MAX_BUFF], TheUser[MAX_BUFF], TmpBuf[MAX_BUFF]; char *ptr, *cptr; int status; #ifdef USE_MAILDIRQUOTA mdir_t size_limit, count_limit; #endif for (cptr = TheUser, ptr = userid;*ptr && *ptr != '@';*cptr++ = *ptr++); *cptr = 0; strncpy(TmpBuf, service, MAX_BUFF); if ((ptr = strrchr(TmpBuf, ':'))) *ptr = 0; status = Login_Tasks(pw, userid, TmpBuf); if (status == 2 && !strncasecmp(service, "imap", 4)) { close_connection(); return(1); } close_connection(); snprintf(Maildir, MAX_BUFF, "%s/Maildir", status == 2 ? "/mail/tmp" : pw->pw_dir); if (access(pw->pw_dir, F_OK) || access(Maildir, F_OK) || chdir(pw->pw_dir)) { fprintf(stderr, "chdir: %s: %s\n", pw->pw_dir, strerror(errno)); return(1); } snprintf(authenv1, MAX_BUFF, "AUTHENTICATED=%s", userid); snprintf(authenv2, MAX_BUFF, "AUTHADDR=%s@%s", TheUser, TheDomain); snprintf(authenv3, MAX_BUFF, "AUTHFULLNAME=%s", pw->pw_gecos); #ifdef USE_MAILDIRQUOTA size_limit = parse_quota(pw->pw_shell, &count_limit); snprintf(authenv4, MAX_BUFF, "MAILDIRQUOTA=%"PRIu64"S,%"PRIu64"C", size_limit, count_limit); #else snprintf(authenv4, MAX_BUFF, "MAILDIRQUOTA=%sS", pw->pw_shell); #endif snprintf(authenv5, MAX_BUFF, "MAILDIR=%s", Maildir); putenv(authenv1); putenv(authenv2); putenv(authenv3); putenv(authenv4); putenv(authenv5); close_connection(); execv(argv[0], argv); return(1); } void getversion_authvchkpw_c() { printf("%s\n", sccsid); } --- NEW FILE: backfill.c --- /* * $Log: backfill.c,v $ * Revision 1.1 2009/01/15 15:31:23 volz0r * Added authvchkpw module for Courier-IMAP [2507177] * Added backfill patch [2507177] * * Revision 2.1 2009-01-12 10:38:56+05:30 Cprogrammer * function to backfill empty slots in dir_control * */ #include <string.h> #include <ctype.h> #include <errno.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include "vpopmail.h" #include "vauth.h" /* * Generic remove a line from a file utility * input: template to search for * file to search inside * * output: less than zero on failure * 0 if successful * 1 if match found */ int remove_line(char *template, char *filename, mode_t mode, int once_only) { int found; char bak_file[MAX_BUFF], tmpbuf[MAX_BUFF]; struct stat statbuf; char *ptr; FILE *fs1, *fs2; int fd; #ifdef FILE_LOCKING int lockfd; #endif if (stat(filename, &statbuf)) { fprintf(stderr, "%s: %s\n", filename, strerror(errno)); return (-1); } #ifdef FILE_LOCKING snprintf(lockfile, sizeof(lockfile), "%s.lock", filename); if ((lockfd = open(lockfile, O_WRONLY | O_CREAT, S_IRUSR|S_IWUSR)) < 0) { fprintf(stderr, "could not open lock file %s: %s\n", lockfile, strerror(errno)); return(-1); } if (get_write_lock(lockfd) < 0 ) return(-1); #endif /*- format a new string */ snprintf(bak_file, MAX_BUFF, "%s.bak", filename); if (rename(filename, bak_file)) { fprintf(stderr, "rename %s->%s: %s\n", filename, bak_file, strerror(errno)); #ifdef FILE_LOCKING unlock_lock(lockfd, 0, SEEK_SET, 0); close(lockfd); #endif return(-1); } /*- open the file and check for error */ if (!(fs1 = fopen(filename, "w+"))) { rename(bak_file, filename); #ifdef FILE_LOCKING unlock_lock(lockfd, 0, SEEK_SET, 0); close(lockfd); #endif fprintf(stderr, "fopen(%s, w+: %s\n", filename, strerror(errno)); return (-1); } fd = fileno(fs1); if (fchmod(fd, mode) || fchown(fd, statbuf.st_uid, statbuf.st_gid)) { rename(bak_file, filename); #ifdef FILE_LOCKING unlock_lock(lockfd, 0, SEEK_SET, 0); close(lockfd); #endif fprintf(stderr, "chmod(%s, %d, %d, %o): %s\n", filename, statbuf.st_uid, statbuf.st_gid, mode, strerror(errno)); return (-1); } /*- open in read mode and check for error */ if (!(fs2 = fopen(bak_file, "r+"))) { rename(bak_file, filename); #ifdef FILE_LOCKING unlock_lock(lockfd, 0, SEEK_SET, 0); close(lockfd); #endif fprintf(stderr, "fopen(%s, r+): %s\n", filename, strerror(errno)); fclose(fs1); return (-1); } /*- pound away on the files run the search algorythm */ for (found = 0;;) { if (!fgets(tmpbuf, MAX_BUFF, fs2)) break; if ((ptr = strchr(tmpbuf, '\n')) != NULL) *ptr = 0; if (once_only & found) { fprintf(fs1, "%s\n", tmpbuf); continue; } if (strncmp(template, tmpbuf, strlen(template))) fprintf(fs1, "%s\n", tmpbuf); else found++; } fclose(fs1); fclose(fs2); unlink(bak_file); #ifdef FILE_LOCKING unlock_lock(lockfd, 0, SEEK_SET, 0); close(lockfd); #endif /* * return 0 = everything went okay, but we didn't find it * 1 = everything went okay and we found a match */ return (found); } char * backfill(char *username, char *domain, char *path, int operation) { vdir_type vdir; char *ptr = (char *) 0; char filename[MAX_BUFF]; static char tmpbuf[MAX_BUFF]; int count, len; #ifdef FILE_LOCKING char lockfile[MAX_BUFF]; int lockfd; #endif uid_t uid; gid_t gid; FILE *fp; if (!domain || !*domain) return ((char *) 0); if (!(ptr = vget_assign(domain, NULL, 0, &uid, &gid))) { fprintf(stderr, "%s: No such domain\n", domain); return((char *) 0); } snprintf(filename, MAX_BUFF, "%s/.dir_control_free", ptr); if (operation == 1) /*- Delete */ { if (!(fp = fopen(filename, "r"))) return ((char *) 0); for (count = 1;;count++) { if (!fgets(tmpbuf, MAX_BUFF - 2, fp)) { fclose(fp); return ((char *) 0); } if (tmpbuf[(len = strlen(tmpbuf)) - 1] != '\n') { fprintf(stderr, "Line No %d in %s Exceeds %d chars\n", count, filename, MAX_BUFF - 2); fclose(fp); return ((char *) 0); } if ((ptr = strchr(tmpbuf, '#'))) *ptr = '\0'; for (ptr = tmpbuf; *ptr && isspace((int) *ptr); ptr++); if (!*ptr) continue; tmpbuf[len - 1] = 0; break; } fclose(fp); if (remove_line(ptr, filename, VPOPMAIL_QMAIL_MODE, 1) == 1) { vread_dir_control(&vdir, domain, uid, gid); if (vdir.cur_users) ++vdir.cur_users; vwrite_dir_control(&vdir, domain, uid, gid); return (ptr); } } else if (operation == 2) /*- add */ { (void) strncpy(tmpbuf, path, MAX_BUFF); if ((ptr = strstr(tmpbuf, username))) { if (ptr != tmpbuf) ptr--; if (*ptr == '/') *ptr = 0; } if ((ptr = strstr(tmpbuf, domain))) { ptr += strlen(domain); if (*ptr == '/') ptr++; if (ptr && *ptr) { #ifdef FILE_LOCKING snprintf(lockfile, sizeof(lockfile), "%s.lock", filename); if ((lockfd = open(lockfile, O_WRONLY | O_CREAT, S_IRUSR|S_IWUSR)) < 0) { fprintf(stderr, "could not open lock file %s: %s\n", lockfile, strerror(errno)); return((char *) 0); } if (get_write_lock(lockfd) < 0 ) return((char *) 0); #endif if (!(fp = fopen(filename, "a"))) { #ifdef FILE_LOCKING unlock_lock(lockfd, 0, SEEK_SET, 0); close(lockfd); #endif return((char *) 0); } fprintf(fp, "%s\n", ptr); fclose(fp); #ifdef FILE_LOCKING unlock_lock(lockfd, 0, SEEK_SET, 0); close(lockfd); #endif return(ptr); } } } return((char *) 0); } |