1: /* 2: * Copyright (c) 1989 Regents of the University of California. 3: * All rights reserved. The Berkeley software License Agreement 4: * specifies the terms and conditions for redistribution. 5: */ 6: 7: #if !defined(lint) && defined(DOSCCS) 8: static char copyright[] = "Copyright (c) 1990 Regents of the University of California.\nAll rights reserved.\n"; 9: static char SccsId[] = "@(#)@(#)pop_dropcopy.c 2.6.1 (2.11BSD) 1996/3/21"; 10: #endif not lint 11: 12: #include <errno.h> 13: #include <stdio.h> 14: #include <sys/types.h> 15: #include <strings.h> 16: #include <sys/stat.h> 17: #include <sys/file.h> 18: #include <pwd.h> 19: #include "popper.h" 20: 21: /* 22: * dropcopy: Make a temporary copy of the user's mail drop and 23: * save a stream pointer for it. 24: */ 25: 26: pop_dropcopy(p,pwp) 27: POP * p; 28: struct passwd * pwp; 29: { 30: int mfd; /* File descriptor for 31: the user's maildrop */ 32: int dfd; /* File descriptor for 33: the SERVER maildrop */ 34: FILE *tf; /* The temp file */ 35: char template[POP_TMPSIZE]; /* Temp name holder */ 36: char buffer[BUFSIZ]; /* Read buffer */ 37: long offset; /* Old/New boundary */ 38: int nchar; /* Bytes written/read */ 39: struct stat mybuf; /* For lstat() */ 40: 41: /* Create a temporary maildrop into which to copy the updated maildrop */ 42: (void)sprintf(p->temp_drop,POP_DROP,p->user); 43: 44: #ifdef DEBUG 45: if(p->debug) 46: pop_log(p,POP_DEBUG,"Creating temporary maildrop '%s'", 47: p->temp_drop); 48: #endif DEBUG 49: 50: /* Here we work to make sure the user doesn't cause us to remove or 51: * write over existing files by limiting how much work we do while 52: * running as root. 53: */ 54: 55: /* First create a unique file. Would prefer mkstemp, but Ultrix...*/ 56: strcpy(template,POP_TMPDROP); 57: (void) mktemp(template); 58: if ( (tf=fopen(template,"w+")) == NULL ) { /* failure, bail out */ 59: pop_log(p,POP_PRIORITY, 60: "Unable to create temporary temporary maildrop '%s': %s",template, 61: strerror(errno)); 62: return pop_msg(p,POP_FAILURE, 63: "System error, can't create temporary file."); 64: } 65: 66: /* Now give this file to the user */ 67: (void) chown(template,pwp->pw_uid, pwp->pw_gid); 68: (void) chmod(template,0600); 69: 70: /* Now link this file to the temporary maildrop. If this fails it 71: * is probably because the temporary maildrop already exists. If so, 72: * this is ok. We can just go on our way, because by the time we try 73: * to write into the file we will be running as the user. 74: */ 75: (void) link(template,p->temp_drop); 76: (void) fclose(tf); 77: (void) unlink(template); 78: 79: /* Now we run as the user. */ 80: (void) setuid(pwp->pw_uid); 81: (void) setgid(pwp->pw_gid); 82: 83: #ifdef DEBUG 84: if(p->debug)pop_log(p,POP_DEBUG,"uid = %u, gid = %u",getuid(),getgid()); 85: #endif DEBUG 86: 87: /* Open for append, this solves the crash recovery problem */ 88: if ((dfd = open(p->temp_drop,O_RDWR|O_APPEND|O_CREAT,0600)) == -1){ 89: pop_log(p,POP_PRIORITY, 90: "Unable to open temporary maildrop '%s': %s",p->temp_drop, 91: strerror(errno)); 92: return pop_msg(p,POP_FAILURE, 93: "System error, can't open temporary file, do you own it?"); 94: } 95: 96: /* Lock the temporary maildrop */ 97: if ( flock (dfd, LOCK_EX|LOCK_NB) == -1 ) 98: switch(errno) { 99: case EWOULDBLOCK: 100: return pop_msg(p,POP_FAILURE, 101: "Maildrop lock busy! Is another session active?"); 102: /* NOTREACHED */ 103: default: 104: return pop_msg(p,POP_FAILURE,"flock: '%s': %s", p->temp_drop, 105: strerror(errno)); 106: /* NOTREACHED */ 107: } 108: 109: /* May have grown or shrunk between open and lock! */ 110: offset = lseek(dfd,0L,L_XTND); 111: 112: /* Open the user's maildrop, If this fails, no harm in assuming empty */ 113: if ((mfd = open(p->drop_name,O_RDWR)) > 0) { 114: 115: /* Lock the maildrop */ 116: if (flock (mfd,LOCK_EX) == -1) { 117: (void)close(mfd) ; 118: return pop_msg(p,POP_FAILURE, "flock: '%s': %s", p->temp_drop, 119: strerror(errno)); 120: } 121: 122: /* Copy the actual mail drop into the temporary mail drop */ 123: while ( (nchar=read(mfd,buffer,BUFSIZ)) > 0 ) 124: if ( nchar != write(dfd,buffer,nchar) ) { 125: nchar = -1 ; 126: break ; 127: } 128: 129: if ( nchar != 0 ) { 130: /* Error adding new mail. Truncate to original size, 131: and leave the maildrop as is. The user will not 132: see the new mail until the error goes away. 133: Should let them process the current backlog, in case 134: the error is a quota problem requiring deletions! */ 135: (void)ftruncate(dfd,offset) ; 136: } else { 137: /* Mail transferred! Zero the mail drop NOW, that we 138: do not have to do gymnastics to figure out what's new 139: and what is old later */ 140: (void)ftruncate(mfd,0L) ; 141: } 142: 143: /* Close the actual mail drop */ 144: (void)close (mfd); 145: } 146: 147: /* Acquire a stream pointer for the temporary maildrop */ 148: if ( (p->drop = fdopen(dfd,"a+")) == NULL ) { 149: (void)close(dfd) ; 150: return pop_msg(p,POP_FAILURE,"Cannot assign stream for %s", 151: p->temp_drop); 152: } 153: 154: rewind (p->drop); 155: 156: return(POP_SUCCESS); 157: }