diff options
Diffstat (limited to 'sqmail-4.3.07/src/qmail-qmaint.c')
-rw-r--r-- | sqmail-4.3.07/src/qmail-qmaint.c | 594 |
1 files changed, 0 insertions, 594 deletions
diff --git a/sqmail-4.3.07/src/qmail-qmaint.c b/sqmail-4.3.07/src/qmail-qmaint.c deleted file mode 100644 index e83ab6f..0000000 --- a/sqmail-4.3.07/src/qmail-qmaint.c +++ /dev/null @@ -1,594 +0,0 @@ -/* - Based on an implementation of queue-fix 1.2 by Eric Huss -*/ -#include <unistd.h> -#include <sys/stat.h> -#include <pwd.h> -#include <grp.h> -#include "stralloc.h" -#include "direntry.h" -#include "fmt.h" -#include "fmtqfn.h" -#include "error.h" -#include "buffer.h" -#include "getln.h" -#include "str.h" -#include "open.h" -#include "fifo.h" -#include "scan.h" -#include "readsubdir.h" -#include "logmsg.h" -#include "exit.h" -#include "auto_qmail.h" -#include "auto_split.h" -#include "auto_uids.h" - -#define WHO "qmail-qmaint" - -stralloc queue_dir = {0}; /*the root queue dir with trailing slash*/ -stralloc check_dir = {0}; /*the current directory being checked*/ -stralloc temp_dirname = {0}; /*temporary used for checking directories */ -stralloc temp_filename = {0}; /*temporary used for checking individuals*/ -stralloc old_name = {0}; /*used in rename*/ -stralloc new_name = {0}; /*used in rename*/ -stralloc mess_dir = {0}; /*used for renaming in mess dir*/ -stralloc query = {0}; /*used in interactive query function*/ - -char strnum[FMT_ULONG]; -int flag_interactive = 0; -int flag_dircreate = 0; -int flag_filecreate = 0; -int flag_permfix = 0; -int flag_namefix = 0; -int flag_delete = 0; - -int qmailq_uid; -int qmails_uid; -int qmailr_uid; -int qmail_gid; -int split_num; - -void die_make(char *name) -{ - logmsg(WHO,111,ERROR,B("Failed to make: ",name)); -} - -void die_user(char *user) -{ - logmsg(WHO,111,ERROR,B("Failed to determine uid of: ",user)); -} - -void die_group(char *group) -{ - logmsg(WHO,111,ERROR,B("Failed to determine gid of: ",group)); -} - -void die_check() -{ - logmsg(WHO,111,ERROR,"Failed while checking directory structure. \nEnsure the given queue exists and you have permission to access it."); -} - -void die_recon() -{ - logmsg(WHO,110,ERROR,"Failed to reconstruct queue. \nEnsure the queue exists and you have permission to modify it."); -} - -void die_nomem() -{ - logmsg(WHO,110,ERROR,"Out of memory."); -} - -/*returns 1==yes, 0==no*/ - -int confirm() -{ - int match; - - if (getln(buffer_0,&query,&match,'\n')) return 0; - if (!match) return 0; - if (query.s[0] == 'y' || query.s[0] == 'Y' || query.s[0] == '\n') return 1; - return 0; -} - -/*gid may be -1 on files for "unknown*/ - -#define DIRS logmsg(WHO,0,WARN,"It looks like some directories don't exist, should I create them? (Y/n)") -#define FILES logmsg(WHO,0,WARN,"It looks like some files don't exist, should I create them? (Y/n)") - -#define PERMS logmsg(WHO,0,WARN,B("It looks like permissions are wrong for ",name," should I fix them? (Y/n)")) -#define CPERMS logmsg(WHO,0,WARN,B("Changing permissions: ",name," => ",pnum)) - -#define OWNER logmsg(WHO,0,WARN,B("It looks like ownerships are wrong for ",name," should I fix them? (Y/n)")) -#define COWNER logmsg(WHO,0,WARN,B("Changing ownership: ",name," => ",unum,"/",gnum)) - -int check_item(char *name,int uid,int gid,int perm,char type,int size) -{ - struct stat st; - int fd; - char num[12]; - char unum[12]; - char gnum[12]; - char pnum[12]; - - /*check for existence and proper credentials*/ - - strnum[fmt_ulong(unum,uid)] = 0; - strnum[fmt_ulong(gnum,gid)] = 0; - strnum[fmt_ulong(pnum,perm)] = 0; - - switch (type) { - case 'd': /*directory*/ - if (stat(name,&st)) { - if (errno != ENOENT) return -1; - if (!flag_dircreate && flag_interactive) { - DIRS; if (!confirm()) return -1; - flag_dircreate = 1; - } - /*create it*/ - logmsg(WHO,0,INFO,B("Creating directory: ",name)); - if (mkdir(name,perm)) die_make(name); - CPERMS; if (chmod(name,perm)) die_make(name); - COWNER; if (chown(name,uid,gid)) die_make(name); - return 0; - } - /*check the values*/ - if (st.st_uid != uid || st.st_gid != gid) { - if (!flag_permfix && flag_interactive) { OWNER; if (!confirm()) return -1; flag_permfix = 1; } - COWNER; if (chown(name,uid,gid)) die_make(name); - } - if ((st.st_mode & 07777) != perm) { - if (!flag_permfix && flag_interactive) { PERMS; if (!confirm()) return -1; flag_permfix = 1; } - CPERMS; if (chmod(name,perm)) die_make(name); - } - return 0; - case 'f': /*regular file*/ - if (stat(name,&st)) return -1; - /*check the values*/ - if (st.st_uid != uid || (st.st_gid != gid && gid != -1)) { - if (!flag_permfix && flag_interactive) { OWNER; if (!confirm()) return -1; flag_permfix = 1; } - COWNER; if (chown(name,uid,gid)) die_make(name); - } - if ((st.st_mode & 07777) != perm) { - if (!flag_permfix && flag_interactive) { PERMS; if (!confirm()) return -1; flag_permfix = 1; } - CPERMS; if (chmod(name,perm)) die_make(name); - } - return 0; - case 'z': /*regular file with a size*/ - if (stat(name,&st)) { - if (errno != ENOENT) return -1; - if (!flag_filecreate && flag_interactive) { - FILES; if (!confirm()) return -1; - flag_filecreate = 1; - } - /*create it*/ - - strnum[fmt_ulong(num,size)] = 0; - logmsg(WHO,0,INFO,B("Creating: ",name," with size ",num)); - fd = open_trunc(name); - if (fd == -1) die_make(name); - while (size--) { if (write(fd,"",1)!=1) die_make(name); } - close(fd); - CPERMS; if (chmod(name,perm)) die_make(name); - COWNER; if (chown(name,uid,gid)) die_make(name); - return 0; - } - /*check the values*/ - if (st.st_uid != uid || (st.st_gid != gid && gid != -1)) { - if (!flag_permfix && flag_interactive) { OWNER; if (!confirm()) return -1; flag_permfix = 1; } - COWNER; if (chown(name,uid,gid)) die_make(name); - } - if ((st.st_mode & 07777) != perm) { - if (!flag_permfix && flag_interactive) { PERMS; if (!confirm()) return -1; flag_permfix = 1; } - CPERMS; if (chmod(name,perm)) die_make(name); - } - if (st.st_size != size) { - logmsg(WHO,0,WARN,B("File ",name," has not the right size. I will not fix it, please investigate.")); - } - return 0; - case 'p': /*a named pipe*/ - if (stat(name,&st)) { - if (errno != ENOENT) return -1; - if (!flag_filecreate && flag_interactive) { - FILES; if (!confirm()) return -1; - flag_filecreate = 1; - } - /*create it*/ - logmsg(WHO,INFO,0,B("Creating fifo: ",name)); - if (fifo_make(name,perm)) die_make(name); - CPERMS; if (chmod(name,perm)) die_make(name); - COWNER; if (chown(name,uid,gid)) die_make(name); - return 0; - } - /*check the values*/ - if (st.st_uid != uid || (st.st_gid != gid && gid != -1)) { - if (!flag_permfix && flag_interactive) { OWNER; if (!confirm()) return -1; flag_permfix = 1; } - COWNER; if (chown(name,uid,gid)) die_make(name); - } - if ((st.st_mode & 07777) != perm) { - if (!flag_permfix && flag_interactive) { PERMS; if (!confirm()) return -1; flag_permfix = 1; } - CPERMS; if (chmod(name,perm)) die_make(name); - } - return 0; - } - - return 0; -} - -int check_files(char * directory,int uid,int gid,int perm) -{ - DIR *dir; - direntry *d; - - dir = opendir(directory); - - if (!dir) return -1; - while ((d = readdir(dir))) { - if (d->d_name[0] == '.') continue; - if (!stralloc_copys(&temp_filename,directory)) die_nomem(); - if (!stralloc_append(&temp_filename,"/")) die_nomem(); - if (!stralloc_cats(&temp_filename,d->d_name)) die_nomem(); - if (!stralloc_0(&temp_filename)) die_nomem(); - if (check_item(temp_filename.s,uid,gid,perm,'f',0)) { closedir(dir); return -1; } - } - closedir(dir); - return 0; -} - -void warn_files(char * directory) -{ - DIR *dir; - direntry *d; - int found = 0; - - dir = opendir(directory); - if (!dir) return; - - while ((d = readdir(dir))) { - if (d->d_name[0] == '.') continue; - found = 1; - break; - } - - closedir(dir); - - if (found) - logmsg(WHO,0,WARN,B("Found files in ",directory," that shouldn't be there. I will not remove them. You should consider checking it out.")); -} - -int check_splits(char * directory,int dir_uid,int dir_gid,int dir_perm,int file_gid,int file_perm) -{ - DIR *dir; - direntry *d; - int i; - - for (i = 0; i < split_num ; i++) { - strnum[fmt_ulong(strnum,i)] = 0; - if (!stralloc_copys(&temp_dirname,directory)) die_nomem(); - if (!stralloc_append(&temp_dirname,"/")) die_nomem(); - if (!stralloc_cats(&temp_dirname,strnum)) die_nomem(); - if (!stralloc_0(&temp_dirname)) die_nomem(); - - /*check the split dir*/ - if (check_item(temp_dirname.s,dir_uid,dir_gid,dir_perm,'d',0)) return -1; - - /*check its contents*/ - dir = opendir(temp_dirname.s); - if (!dir) return -1; - while ((d = readdir(dir))) { - if (d->d_name[0] == '.') continue; - if (!stralloc_copys(&temp_filename,temp_dirname.s)) die_nomem(); - if (!stralloc_append(&temp_filename,"/")) die_nomem(); - if (!stralloc_cats(&temp_filename,d->d_name)) die_nomem(); - if (!stralloc_0(&temp_filename)) die_nomem(); - if (check_item(temp_filename.s,dir_uid,file_gid,file_perm,'f',0)) { closedir(dir); return -1; } - } - closedir(dir); - } - - return 0; -} - -int rename_mess(char *dir, char *part, char *new_part, char *old_filename, char *new_filename) -{ - - if (flag_interactive && !flag_namefix) { - logmsg(WHO,0,INFO,"It looks like some files need to be renamed, should I rename them? (Y/n)\n"); - if (!confirm()) return -1; - flag_namefix = 1; - } - - /*prepare the old filename*/ - if (!stralloc_copy(&old_name,&queue_dir)) die_nomem(); - if (!stralloc_cats(&old_name,dir)) die_nomem(); - if (!stralloc_cats(&old_name,part)) die_nomem(); - if (!stralloc_append(&old_name,"/")) die_nomem(); - if (!stralloc_cats(&old_name,old_filename)) die_nomem(); - if (!stralloc_0(&old_name)) die_nomem(); - - /*prepare the new filename*/ - if (!stralloc_copy(&new_name,&queue_dir)) die_nomem(); - if (!stralloc_cats(&new_name,dir)) die_nomem(); - if (!stralloc_cats(&new_name,new_part)) die_nomem(); - if (!stralloc_append(&new_name,"/")) die_nomem(); - if (!stralloc_cats(&new_name,new_filename)) die_nomem(); - if (!stralloc_0(&new_name)) die_nomem(); - - logmsg(WHO,0,INFO,B("Renaming ",old_name.s," to ",new_name.s)); - if (rename(old_name.s,new_name.s)) { - if (errno != ENOENT) return -1; - } - - return 0; -} - -int fix_part(char *part) -{ - DIR *dir; - direntry *d; - struct stat st; - char inode[FMT_ULONG]; - char new_part[FMT_ULONG]; - int old_inode; - int part_num; - int correct_part_num; - - scan_uint(part,&part_num); - - if (!stralloc_copy(&mess_dir,&queue_dir)) die_nomem(); - if (!stralloc_cats(&mess_dir,"mess/")) die_nomem(); - if (!stralloc_cats(&mess_dir,part)) die_nomem(); - if (!stralloc_0(&mess_dir)) die_nomem(); - - dir = opendir(mess_dir.s); - if (!dir) return -1; - - while ((d = readdir(dir))) { - if (d->d_name[0] == '.') continue; - /*check from mess*/ - if (!stralloc_copys(&temp_filename,mess_dir.s)) die_nomem(); - if (!stralloc_append(&temp_filename,"/")) die_nomem(); - if (!stralloc_cats(&temp_filename,d->d_name)) die_nomem(); - if (!stralloc_0(&temp_filename)) die_nomem(); - if (stat(temp_filename.s,&st)) { closedir(dir); return -1; } - - /*check that filename == inode number*/ - /*check that inode%auto_split == part_num*/ - scan_uint(d->d_name,&old_inode); - correct_part_num = st.st_ino % split_num; - if (st.st_ino != old_inode || part_num != correct_part_num) { - /*rename*/ - inode[fmt_ulong(inode,st.st_ino)] = 0; - new_part[fmt_ulong(new_part,correct_part_num)] = 0; - if (rename_mess("mess/",part,new_part,d->d_name,inode)) { closedir(dir); return -1; } - if (rename_mess("info/",part,new_part,d->d_name,inode)) { closedir(dir); return -1; } - if (rename_mess("local/",part,new_part,d->d_name,inode)) { closedir(dir); return -1; } - if (rename_mess("remote/",part,new_part,d->d_name,inode)) { closedir(dir); return -1; } - if (rename_mess("todo/",part,new_part,d->d_name,inode)) { closedir(dir); return -1; } - if (rename_mess("intd/",part,new_part,d->d_name,inode)) { closedir(dir); return -1; } - - if (rename_mess("bounce","","",d->d_name,inode)) { closedir(dir); return -1; } - } - } - - closedir(dir); - return 0; -} - -int fix_names() -{ - int i; - - if (!stralloc_copy(&check_dir,&queue_dir)) die_nomem(); - if (!stralloc_cats(&check_dir,"mess")) die_nomem(); - if (!stralloc_0(&check_dir)) die_nomem(); - - for (i = 0; i < split_num; i++) { - strnum[fmt_ulong(strnum,i)] = 0; - if (fix_part(strnum)) return -1; - } - - return 0; -} - -int check_dirs() -{ - /*check root existence*/ - if (!stralloc_copy(&check_dir,&queue_dir)) die_nomem(); - if (!stralloc_0(&check_dir)) die_nomem(); - if (check_item(check_dir.s,qmailq_uid,qmail_gid,0750,'d',0)) return -1; - - /*check the bigtodo queue */ - if (!stralloc_copy(&check_dir,&queue_dir)) die_nomem(); - if (!stralloc_cats(&check_dir,"info")) die_nomem(); - if (!stralloc_0(&check_dir)) die_nomem(); - if (check_item(check_dir.s,qmails_uid,qmail_gid,0700,'d',0)) return -1; - if (check_splits(check_dir.s,qmails_uid,qmail_gid,0700,qmail_gid,0600)) return -1; - - if (!stralloc_copy(&check_dir,&queue_dir)) die_nomem(); - if (!stralloc_cats(&check_dir,"mess")) die_nomem(); - if (!stralloc_0(&check_dir)) die_nomem(); - if (check_item(check_dir.s,qmailq_uid,qmail_gid,0750,'d',0)) return -1; - if (check_splits(check_dir.s,qmailq_uid,qmail_gid,0750,-1,0644)) return -1; - - if (!stralloc_copy(&check_dir,&queue_dir)) die_nomem(); - if (!stralloc_cats(&check_dir,"remote")) die_nomem(); - if (!stralloc_0(&check_dir)) die_nomem(); - if (check_item(check_dir.s,qmails_uid,qmail_gid,0700,'d',0)) return -1; - if (check_splits(check_dir.s,qmails_uid,qmail_gid,0700,qmail_gid,0600)) return -1; - - if (!stralloc_copy(&check_dir,&queue_dir)) die_nomem(); - if (!stralloc_cats(&check_dir,"local")) die_nomem(); - if (!stralloc_0(&check_dir)) die_nomem(); - if (check_item(check_dir.s,qmails_uid,qmail_gid,0700,'d',0)) return -1; - if (check_splits(check_dir.s,qmails_uid,qmail_gid,0700,qmail_gid,0600)) return -1; - - if (!stralloc_copy(&check_dir,&queue_dir)) die_nomem(); - if (!stralloc_cats(&check_dir,"intd")) die_nomem(); - if (!stralloc_0(&check_dir)) die_nomem(); - if (check_item(check_dir.s,qmailq_uid,qmail_gid,0700,'d',0)) return -1; - if (check_splits(check_dir.s,qmailq_uid,qmail_gid,0700,qmail_gid,0600)) return -1; - - if (!stralloc_copy(&check_dir,&queue_dir)) die_nomem(); - if (!stralloc_cats(&check_dir,"todo")) die_nomem(); - if (!stralloc_0(&check_dir)) die_nomem(); - if (check_item(check_dir.s,qmailq_uid,qmail_gid,0750,'d',0)) return -1; - if (check_splits(check_dir.s,qmailq_uid,qmail_gid,0750,-1,0644)) return -1; - - if (!stralloc_copy(&check_dir,&queue_dir)) die_nomem(); - if (!stralloc_cats(&check_dir,"dkim")) die_nomem(); - if (!stralloc_0(&check_dir)) die_nomem(); - if (check_item(check_dir.s,qmailq_uid,qmail_gid,0750,'d',0)) return -1; - if (check_splits(check_dir.s,qmailq_uid,qmail_gid,0750,qmail_gid,0644)) return -1; - - /*check the others*/ - if (!stralloc_copy(&check_dir,&queue_dir)) die_nomem(); - if (!stralloc_cats(&check_dir,"bounce")) die_nomem(); - if (!stralloc_0(&check_dir)) die_nomem(); - if (check_item(check_dir.s,qmails_uid,qmail_gid,0700,'d',0)) return -1; - if (check_files(check_dir.s,qmails_uid,qmail_gid,0600)) return -1; - - if (!stralloc_copy(&check_dir,&queue_dir)) die_nomem(); - if (!stralloc_cats(&check_dir,"pid")) die_nomem(); - if (!stralloc_0(&check_dir)) die_nomem(); - if (check_item(check_dir.s,qmailq_uid,qmail_gid,0700,'d',0)) return -1; - - warn_files(check_dir.s); - - /*lock has special files that must exist*/ - if (!stralloc_copy(&check_dir,&queue_dir)) die_nomem(); - if (!stralloc_cats(&check_dir,"lock")) die_nomem(); - if (!stralloc_0(&check_dir)) die_nomem(); - if (check_item(check_dir.s,qmailq_uid,qmail_gid,0750,'d',0)) return -1; - - if (!stralloc_copy(&check_dir,&queue_dir)) die_nomem(); - if (!stralloc_cats(&check_dir,"lock/sendmutex")) die_nomem(); - if (!stralloc_0(&check_dir)) die_nomem(); - if (check_item(check_dir.s,qmails_uid,qmail_gid,0600,'z',0)) return -1; - - if (!stralloc_copy(&check_dir,&queue_dir)) die_nomem(); - if (!stralloc_cats(&check_dir,"lock/tcpto")) die_nomem(); - if (!stralloc_0(&check_dir)) die_nomem(); - if (check_item(check_dir.s,qmailr_uid,qmail_gid,0644,'z',1024)) return -1; - - if (!stralloc_copy(&check_dir,&queue_dir)) die_nomem(); - if (!stralloc_cats(&check_dir,"lock/trigger")) die_nomem(); - if (!stralloc_0(&check_dir)) die_nomem(); - if (check_item(check_dir.s,qmails_uid,qmail_gid,0622,'p',0)) return -1; - - return 0; -} - -/* stolen from qmail-send */ - -stralloc fn = {0}; - -void fnmake_init() { while (!stralloc_ready(&fn,FMTQFN)) die_nomem(); } -void fnmake_local(unsigned long id) { fn.len = fmtqfn(fn.s,"local/",id,1); } -void fnmake_remote(unsigned long id) { fn.len = fmtqfn(fn.s,"remote/",id,1); } -void fnmake_mess(unsigned long id) { fn.len = fmtqfn(fn.s,"mess/",id,1); } -void fnmake_dkim(unsigned long id) { fn.len = fmtqfn(fn.s,"dkim/",id,1); } -void fnmake_info(unsigned long id) { fn.len = fmtqfn(fn.s,"info/",id,1); } -void fnmake_bounce(unsigned long id) { fn.len = fmtqfn(fn.s,"bounce/",id,0); } - -void warn_unlink(unsigned long id) -{ - char foo[FMT_ULONG]; - foo[fmt_ulong(foo,id)] = 0; - logmsg(WHO,99,WARN,B("no such file to unlink #",foo)); -} - -void err_unlink(unsigned long id) -{ - char foo[FMT_ULONG]; - foo[fmt_ulong(foo,id)] = 0; - logmsg(WHO,100,ERROR,B("trouble with unlinking #",foo)); -} - -void err_chdir() -{ - logmsg(WHO,110,FATAL,"unable to chdir"); -} - -int delete_msg(unsigned long id) -{ - struct stat st; - int bounce = 1; - - if (chdir(auto_qmail) == -1) err_chdir(); - if (chdir("queue") == -1) err_chdir(); - fnmake_init(); - - fnmake_mess(id); // regular message pre-processed - if (stat(fn.s,&st) == -1) err_unlink(id); - else bounce = 0; - if (!bounce && unlink(fn.s) == -1) - if (errno != ENOENT) err_unlink(id); - - fnmake_info(id); // not delivered yet - if (!stat(fn.s,&st)) - if (unlink(fn.s) == -1) - if (errno != ENOENT) err_unlink(id); - - if (bounce) { - fnmake_bounce(id); - if (!stat(fn.s,&st)) { warn_unlink(id); return 1; } - if (unlink(fn.s) == -1) - if (errno != ENOENT) err_unlink(id); - } - - fnmake_remote(id); - if (!stat(fn.s,&st)) - if (unlink(fn.s) == -1) - if (errno != ENOENT) err_unlink(id); - - fnmake_local(id); - if (!stat(fn.s,&st)) - if (unlink(fn.s) == -1) - if (errno != ENOENT) err_unlink(id); - - return 0; -} - -int main(int argc, char **argv) -{ - char *mess = 0; - unsigned long id = 0; - - if (argc > 1) { - if (!str_diff(argv[1],"-i")) { - flag_interactive = 1; - } else if (!str_diff(argv[1],"-d")) { - if (!argv[2]) logmsg(WHO,111,USAGE,"qmail-qmaint [-i] || [-d messid]"); - mess = argv[2]; - flag_delete = 1; - scan_ulong(mess,&id); - } - } - - if (!stralloc_copys(&queue_dir,auto_qmail)) die_nomem(); - if (!stralloc_cats(&queue_dir,"/queue/")) die_nomem(); - - logmsg(WHO,0,INFO,B("Checking s/qmail queue at: ",auto_qmail,"/queue/")); - - /* get constants */ - - qmailq_uid = auto_uidq; - qmails_uid = auto_uids; - qmailr_uid = auto_uidr; - qmail_gid = auto_gidq; - split_num = auto_split; - - /*check that all the proper directories exist with proper credentials*/ - - if (check_dirs()) die_check(); - - if (flag_delete) { - if (!delete_msg(id)) - logmsg(WHO,0,INFO,B("file ",mess," from queue deleted.")); - } else - if (fix_names()) die_check(); - - logmsg(WHO,0,INFO,"done."); - - _exit (0); -} |