⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 vpopmail.c

📁 相当优秀的 UNIX 进程管理工具
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * $Id: vpopmail.c,v 1.28.2.4 2004/06/26 02:20:56 tomcollins Exp $ * Copyright (C) 2000-2002 Inter7 Internet Technologies, Inc. * * 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 2 of the License, or * (at your option) any later version. * * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */#include <stdio.h>#include <stdlib.h>#include <stdarg.h>#include <unistd.h>#include <string.h>#include <pwd.h>#include <sys/stat.h>#include <sys/types.h>#include <sys/wait.h>#ifdef HAVE_SYS_VARARGS_H#include <sys/varargs.h>#endif#include <signal.h>#include <ctype.h>#include <fcntl.h>#include <time.h>#include <dirent.h>#include <pwd.h>#include "config.h"#include "md5.h"#include "vpopmail.h"#include "file_lock.h"#include "vauth.h"#include "vlimits.h"#include "maildirquota.h"#define MAX_BUFF 256#ifdef POP_AUTH_OPEN_RELAY/* keep a output pipe to tcp.smtp file */int tcprules_fdm;static char relay_tempfile[MAX_BUFF];#endifint verrori = 0;extern int cdb_seek();/* Global Flags */int NoMakeIndex = 0;int OptimizeAddDomain = 0;#define PS_TOKENS " \t"#define CDB_TOKENS ":\n\r"#ifdef IP_ALIAS_DOMAINSint host_in_locals(char *domain);#endifstatic char gen_chars[] = "abcdefghijklmnopqrstuvwxyz" \                          "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \                          "0123456789.@!#%*";static char ok_env_chars[] = "abcdefghijklmnopqrstuvwxyz" \                            "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \                            "1234567890_-.@";/************************************************************************//*  * Add a domain to the email system * * input: domain name *        dir to put the files *        uid and gid to assign to the files */int vadddomain( char *domain, char *dir, uid_t uid, gid_t gid ){ FILE *fs; int i; char *domain_hash; char DomainSubDir[MAX_BUFF]; char dir_control_for_uid[MAX_BUFF]; char tmpbuf[MAX_BUFF]; char Dir[MAX_BUFF]; char calling_dir[MAX_BUFF];  /* we only do lower case */  lowerit(domain);  /* reject domain names that are too short to be valid */  if ( strlen( domain) <3) return (VA_INVALID_DOMAIN_NAME);  /* reject domain names that exceed our max permitted/storable size */  if ( strlen( domain ) >= MAX_PW_DOMAIN ) return(VA_DOMAIN_NAME_TOO_LONG);  /* check invalid email domain characters */  for(i=0;domain[i]!=0;++i) {    if (i == 0 && domain[i] == '-' ) return(VA_INVALID_DOMAIN_NAME);    if (isalnum((int)domain[i])==0 && domain[i]!='-' && domain[i]!='.') {      return(VA_INVALID_DOMAIN_NAME);    }  }  if ( domain[i-1] == '-' ) return(VA_INVALID_DOMAIN_NAME);  /* after the name is okay, check if it already exists */  if ( vget_assign(domain, NULL, 0, NULL, NULL ) != NULL ) {    return(VA_DOMAIN_ALREADY_EXISTS);  }   /* set our file creation mask for machines where the   * sysadmin has tightened default permissions   */  umask(VPOPMAIL_UMASK);  /* store the calling directory */  getcwd(calling_dir, sizeof(calling_dir));  /* go to the directory where our Domains dir is to be stored    * check for error and return error on error   */  if ( chdir(dir) != 0 ) return(VA_BAD_V_DIR);  /* go into the Domains subdir */  if ( chdir(DOMAINS_DIR) != 0 ) {    /* if it's not there, no problem, just try to create it */    if ( mkdir(DOMAINS_DIR, VPOPMAIL_DIR_MODE) != 0 ) {      chdir(calling_dir);      return(VA_CAN_NOT_MAKE_DOMAINS_DIR);    }    /*  set the permisions on our new Domains dir */    chown(DOMAINS_DIR,uid,gid);    /* now try moving into the Domains subdir again */    if ( chdir(DOMAINS_DIR) != 0 ) {      chdir(calling_dir);      return(VA_BAD_D_DIR);    }  }  /* since domains can be added under any /etc/passwd   * user, we have to create dir_control information   * for each user/domain combination   */  snprintf(dir_control_for_uid, sizeof(dir_control_for_uid),   "dom_%lu", (long unsigned)uid);  /* work out a subdir name for the domain    * Depending on how many domains we have, it may need to be hashed   */  open_big_dir(dir_control_for_uid, uid, gid);         domain_hash = next_big_dir(uid, gid);  close_big_dir(dir_control_for_uid, uid, gid);        if ( strlen(domain_hash) > 0 ) {    snprintf(DomainSubDir, sizeof(DomainSubDir), "%s/%s", domain_hash, domain);  } else {    snprintf(DomainSubDir,sizeof(DomainSubDir), "%s", domain);  }  /* Check to make sure length of the dir isnt going to exceed   * the maximum storable size   * We dont want to start creating dirs and putting entries in   * the assign file etc if the path is going to be too long   */  if (strlen(dir)+strlen(DOMAINS_DIR)+strlen(DomainSubDir) >= MAX_PW_DIR) {    /* back out of changes made so far */    dec_dir_control(dir_control_for_uid, uid, gid);    chdir(calling_dir);    return(VA_DIR_TOO_LONG);  }  /* Make the subdir for the domain */  if ( r_mkdir(DomainSubDir, uid, gid ) != 0 ) {    /* back out of changes made so far */    dec_dir_control(dir_control_for_uid, uid, gid);    chdir(calling_dir);    return(VA_COULD_NOT_MAKE_DOMAIN_DIR);  }    if ( chdir(DomainSubDir) != 0 ) {    /* back out of changes made so far */    vdelfiles(DomainSubDir);    dec_dir_control(dir_control_for_uid, uid, gid);    chdir(calling_dir);    return(VA_BAD_D_DIR);  }  /* create the .qmail-default file */  snprintf(tmpbuf, sizeof(tmpbuf), "%s/%s/%s/.qmail-default", dir, DOMAINS_DIR,     DomainSubDir);  if ( (fs = fopen(tmpbuf, "w+"))==NULL) {    /* back out of changes made so far */    chdir(dir); chdir(DOMAINS_DIR);    if (vdelfiles(DomainSubDir) != 0) {      fprintf(stderr, "Failed to delete directory tree :%s\n", DomainSubDir);    }    dec_dir_control(dir_control_for_uid, uid, gid);    chdir(calling_dir);    return(VA_COULD_NOT_OPEN_QMAIL_DEFAULT);  } else {    fprintf(fs, "| %s/bin/vdelivermail '' bounce-no-mailbox\n", VPOPMAILDIR);    fclose(fs);  }  /* create an entry in the assign file for our new domain */  snprintf(tmpbuf, sizeof(tmpbuf), "%s/%s/%s", dir, DOMAINS_DIR, DomainSubDir);  if (add_domain_assign( domain, domain, tmpbuf, uid, gid ) != 0) {    /* back out of changes made so far */    chdir(dir); chdir(DOMAINS_DIR);    if (vdelfiles(DomainSubDir) != 0) {      fprintf(stderr, "Failed to delete directory tree: %s\n", DomainSubDir);    }    dec_dir_control(dir_control_for_uid, uid, gid);    chdir(calling_dir);    fprintf (stderr, "Error. Failed to add domain to assign file\n");    return (VA_COULD_NOT_UPDATE_FILE);  }  /* recursively change ownership to new file system entries */  snprintf(tmpbuf, sizeof(tmpbuf), "%s/%s/%s", dir, DOMAINS_DIR, DomainSubDir);  r_chown(tmpbuf, uid, gid);  /* ask the authentication module to add the domain entry */  /* until now we checked if domain already exists in cdb and   * setup all dirs, but vauth_adddomain may __fail__ so we need to check   */  if (vauth_adddomain( domain ) != VA_SUCCESS ) {    /* ok we have run into problems here. adding domain to auth backend failed     * so now we need to reverse the steps we have already performed above      */    fprintf(stderr, "Error. Failed while attempting to add domain to auth backend\n");    chdir(dir); chdir(DOMAINS_DIR);        if (vdelfiles(DomainSubDir) != 0) {      fprintf(stderr, "Failed to delete directory tree: %s\n", DomainSubDir);    }    dec_dir_control(dir_control_for_uid, uid, gid);    vget_assign(domain, Dir, sizeof(Dir), &uid, &gid );    if ( del_domain_assign(domain, domain, Dir, uid, gid) != 0) {      fprintf(stderr, "Failed while attempting to remove domain from assign file\n");    }    if (del_control(domain) !=0) {      fprintf(stderr, "Failed while attempting to delete domain from the qmail control files\n");    }    if (vdel_dir_control(domain) != 0) {      fprintf (stderr, "Failed while attempting to delete domain from dir_control\n");    }    /* send a HUP signal to qmail-send process to reread control files */    signal_process("qmail-send", SIGHUP);    return (VA_NO_AUTH_CONNECTION);  }	   /* ask qmail to re-read it's new control files */  if ( OptimizeAddDomain == 0 ) {    signal_process("qmail-send", SIGHUP);  }  /* return back to the callers directory and return success */  chdir(calling_dir);  return(VA_SUCCESS);}/************************************************************************//* Delete a domain from the entire mail system * * If we have problems at any of the following steps, it has been  * decided that the best course of action is to continue rather than * abort. The idea behind this is to allow the removal of a partially * installed domain. We will emit warnings should any of the expected * cleanup steps fail. */int vdeldomain( char *domain ){ struct stat statbuf; char Dir[MAX_BUFF]; char domain_to_del[MAX_BUFF]; char dircontrol[MAX_BUFF]; uid_t uid; gid_t gid;  /* we always convert domains to lower case */  lowerit(domain);  /* Check the length of the domain to del   * If it exceeds the max storable size,    * then the user has made some sort of error in    * asking to del that domain, because such a domain   * wouldnt be able to exist in the 1st place   */  if (strlen(domain) >= MAX_PW_DOMAIN) return (VA_DOMAIN_NAME_TOO_LONG);  /* now we want to check a couple for things :   * a) if the domain to del exists in the system   * b) if the domain to del is an aliased domain or not   */  /* Take a backup of the domain we want to del,   * because when we call vget_assign, if the domain   * is an alias, then the domain parameter will be   * rewritten on return as the name of the real domain   */  snprintf(domain_to_del, sizeof(domain_to_del), "%s", domain);  /* check if the domain exists. If so extract the dir, uid, gid */  if (vget_assign(domain, Dir, sizeof(Dir), &uid, &gid ) == NULL) {    return(VA_DOMAIN_DOES_NOT_EXIST);  }  /* if this is an NOT aliased domain....   * (aliased domains dont have any filestructure of their own)   */  if ( strcmp(domain_to_del, domain) == 0 ) {    /* check if the domain's dir exists */    if ( stat(Dir, &statbuf) != 0 ) {      fprintf(stderr, "Warning: Could not access (%s)\n",Dir);    }    /*     * Michael Bowe 23rd August 2003     *     * at this point, we need to write some code to check if any alias domains     * point to this (real) domain. If we find such aliases, then I guess we     * have a couple of options :     * 1. Abort with an error, saying cant delete domain until all     *    aliases are removed 1st (list them)     * 2. Zap all the aliases in additon to this domain     *     */    /* call the auth module to delete the domain from the storage */    /* Note !! We must del domain from auth module __before__ we delete it from     * fs, because deletion from auth module may fail !!!!     */    /* del a domain from the auth backend which includes :     * - drop the domain's table, or del all users from users table     * - delete domain's entries from lastauth table     * - delete domain's limit's entries     */    if (vauth_deldomain(domain) != VA_SUCCESS ) {      fprintf (stderr, "Warning: Failed while attempting to delete domain from auth backend\n");    }    /* vdel_limits does the following :     * If we have mysql_limits enabled,     *  it will delete the domain's entries from the limits table     * Or if we arent using mysql_limits,     *  it will delete the .qmail-admin file from the domain's dir     *     * Note there are inconsistencies in the auth backends.  Some     * will run vdel_limits() in vauth_deldomain(), others don't.     * For now, we always run it to be safe.  Ultimately, the auth     * backends should to be updated to do this.     */      vdel_limits(domain);    /* delete the dir control info for this domain */    if (vdel_dir_control(domain) != 0) {      fprintf (stderr, "Warning: Failed to delete dir_control for %s\n", domain);    }    /* Now remove domain from filesystem */    /* if it's a symbolic link just remove the link */    if ( S_ISLNK(statbuf.st_mode) ) {      if ( unlink(Dir) !=0) {        fprintf (stderr, "Warning: Failed to remove symlink for %s\n", domain);      }    } else {      char cwdbuff[MAX_BUFF];      char *cwd;      /* Not a symlink.. so we have to del some files structure now */      /* zap the domain's directory tree */      cwd = getcwd (cwdbuff, sizeof(cwdbuff));  /* save calling directory */      if ( vdelfiles(Dir) != 0 ) {        fprintf(stderr, "Warning: Failed to delete directory tree: %s\n", domain);      }      if (cwd != NULL) chdir (cwd);    }    /* decrement the master domain control info */    snprintf(dircontrol, sizeof(dircontrol), "dom_%lu", (long unsigned)uid);    dec_dir_control(dircontrol, uid, gid);  }  /* The following things need to happen for real and aliased domains */  /* delete the email domain from the qmail control files :   * rcpthosts, morercpthosts, virtualdomains   */  if (del_control(domain_to_del) != 0) {    fprintf (stderr, "Warning: Failed to delete domain from qmail's control files\n");  }  /* delete the assign file line */  if (del_domain_assign(domain_to_del, domain, Dir, uid, gid) != 0) {    fprintf (stderr, "Warning: Failed to delete domain from the assign file\n");  }  /* send a HUP signal to qmail-send process to reread control files */  signal_process("qmail-send", SIGHUP);  return(VA_SUCCESS);}/************************************************************************//* * Add a virtual domain user */int vadduser( char *username, char *domain, char *password, char *gecos,               int apop ){ char Dir[MAX_BUFF]; char *user_hash; char calling_dir [MAX_BUFF]; uid_t uid = VPOPMAILUID; gid_t gid = VPOPMAILGID; struct vlimits limits; char quota[50];  /* check gecos for : characters - bad */  if ( strchr(gecos,':')!=0) return(VA_BAD_CHAR);  if ( strlen(username) >= MAX_PW_NAME ) return(VA_USER_NAME_TOO_LONG);#ifdef USERS_BIG_DIR  if ( strlen(username) == 1 ) return(VA_ILLEGAL_USERNAME);#endif  if ( strlen(domain) >= MAX_PW_DOMAIN ) return(VA_DOMAIN_NAME_TOO_LONG);  if ( strlen(domain) < 3) return(VA_INVALID_DOMAIN_NAME);  if ( strlen(password) >= MAX_PW_CLEAR_PASSWD ) return(VA_PASSWD_TOO_LONG);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -