summaryrefslogtreecommitdiffstats
path: root/crypto/heimdal/appl/popper/pop_dropcopy.c
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/heimdal/appl/popper/pop_dropcopy.c')
-rw-r--r--crypto/heimdal/appl/popper/pop_dropcopy.c173
1 files changed, 173 insertions, 0 deletions
diff --git a/crypto/heimdal/appl/popper/pop_dropcopy.c b/crypto/heimdal/appl/popper/pop_dropcopy.c
new file mode 100644
index 0000000..f33cfb0
--- /dev/null
+++ b/crypto/heimdal/appl/popper/pop_dropcopy.c
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 1989 Regents of the University of California.
+ * All rights reserved. The Berkeley software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+
+#include <popper.h>
+RCSID("$Id: pop_dropcopy.c,v 1.25 1999/09/16 20:38:49 assar Exp $");
+
+/*
+ * Run as the user in `pwd'
+ */
+
+int
+changeuser(POP *p, struct passwd *pwd)
+{
+ if(setgid(pwd->pw_gid) < 0) {
+ pop_log (p, POP_PRIORITY,
+ "Unable to change to gid %u: %s",
+ (unsigned)pwd->pw_gid,
+ strerror(errno));
+ return pop_msg (p, POP_FAILURE,
+ "Unable to change gid");
+ }
+ if(setuid(pwd->pw_uid) < 0) {
+ pop_log (p, POP_PRIORITY,
+ "Unable to change to uid %u: %s",
+ (unsigned)pwd->pw_uid,
+ strerror(errno));
+ return pop_msg (p, POP_FAILURE,
+ "Unable to change uid");
+ }
+#ifdef DEBUG
+ if(p->debug)
+ pop_log(p, POP_DEBUG,"uid = %u, gid = %u",
+ (unsigned)getuid(),
+ (unsigned)getgid());
+#endif /* DEBUG */
+ return POP_SUCCESS;
+}
+
+/*
+ * dropcopy: Make a temporary copy of the user's mail drop and
+ * save a stream pointer for it.
+ */
+
+int
+pop_dropcopy(POP *p, struct passwd *pwp)
+{
+ int mfd; /* File descriptor for
+ the user's maildrop */
+ int dfd; /* File descriptor for
+ the SERVER maildrop */
+ FILE *tf; /* The temp file */
+ char template[POP_TMPSIZE]; /* Temp name holder */
+ char buffer[BUFSIZ]; /* Read buffer */
+ long offset; /* Old/New boundary */
+ int nchar; /* Bytes written/read */
+ int tf_fd; /* fd for temp file */
+ int ret;
+
+ /* Create a temporary maildrop into which to copy the updated maildrop */
+ snprintf(p->temp_drop, sizeof(p->temp_drop), POP_DROP,p->user);
+
+#ifdef DEBUG
+ if(p->debug)
+ pop_log(p,POP_DEBUG,"Creating temporary maildrop '%s'",
+ p->temp_drop);
+#endif /* DEBUG */
+
+ /* Here we work to make sure the user doesn't cause us to remove or
+ * write over existing files by limiting how much work we do while
+ * running as root.
+ */
+
+ strlcpy(template, POP_TMPDROP, sizeof(template));
+ if ((tf_fd = mkstemp(template)) < 0 ||
+ (tf = fdopen(tf_fd, "w+")) == NULL) {
+ pop_log(p,POP_PRIORITY,
+ "Unable to create temporary temporary maildrop '%s': %s",template,
+ strerror(errno));
+ return pop_msg(p,POP_FAILURE,
+ "System error, can't create temporary file.");
+ }
+
+ /* Now give this file to the user */
+ chown(template, pwp->pw_uid, pwp->pw_gid);
+ chmod(template, 0600);
+
+ /* Now link this file to the temporary maildrop. If this fails it
+ * is probably because the temporary maildrop already exists. If so,
+ * this is ok. We can just go on our way, because by the time we try
+ * to write into the file we will be running as the user.
+ */
+ link(template,p->temp_drop);
+ fclose(tf);
+ unlink(template);
+
+ ret = changeuser(p, pwp);
+ if (ret != POP_SUCCESS)
+ return ret;
+
+ /* Open for append, this solves the crash recovery problem */
+ if ((dfd = open(p->temp_drop,O_RDWR|O_APPEND|O_CREAT,0600)) == -1){
+ pop_log(p,POP_PRIORITY,
+ "Unable to open temporary maildrop '%s': %s",p->temp_drop,
+ strerror(errno));
+ return pop_msg(p,POP_FAILURE,
+ "System error, can't open temporary file, do you own it?");
+ }
+
+ /* Lock the temporary maildrop */
+ if ( flock (dfd, (LOCK_EX | LOCK_NB)) == -1 )
+ switch(errno) {
+ case EWOULDBLOCK:
+ return pop_msg(p,POP_FAILURE,
+ "Maildrop lock busy! Is another session active?");
+ /* NOTREACHED */
+ default:
+ return pop_msg(p,POP_FAILURE,"flock: '%s': %s", p->temp_drop,
+ strerror(errno));
+ /* NOTREACHED */
+ }
+
+ /* May have grown or shrunk between open and lock! */
+ offset = lseek(dfd,0, SEEK_END);
+
+ /* Open the user's maildrop, If this fails, no harm in assuming empty */
+ if ((mfd = open(p->drop_name,O_RDWR)) > 0) {
+
+ /* Lock the maildrop */
+ if (flock (mfd, LOCK_EX) == -1) {
+ close(mfd) ;
+ return pop_msg(p,POP_FAILURE, "flock: '%s': %s", p->temp_drop,
+ strerror(errno));
+ }
+
+ /* Copy the actual mail drop into the temporary mail drop */
+ while ( (nchar=read(mfd,buffer,BUFSIZ)) > 0 )
+ if ( nchar != write(dfd,buffer,nchar) ) {
+ nchar = -1 ;
+ break ;
+ }
+
+ if ( nchar != 0 ) {
+ /* Error adding new mail. Truncate to original size,
+ and leave the maildrop as is. The user will not
+ see the new mail until the error goes away.
+ Should let them process the current backlog, in case
+ the error is a quota problem requiring deletions! */
+ ftruncate(dfd,(int)offset) ;
+ } else {
+ /* Mail transferred! Zero the mail drop NOW, that we
+ do not have to do gymnastics to figure out what's new
+ and what is old later */
+ ftruncate(mfd,0) ;
+ }
+
+ /* Close the actual mail drop */
+ close (mfd);
+ }
+
+ /* Acquire a stream pointer for the temporary maildrop */
+ if ( (p->drop = fdopen(dfd,"a+")) == NULL ) {
+ close(dfd) ;
+ return pop_msg(p,POP_FAILURE,"Cannot assign stream for %s",
+ p->temp_drop);
+ }
+
+ rewind (p->drop);
+
+ return(POP_SUCCESS);
+}
OpenPOWER on IntegriCloud