No empty .Rs/.Re
[netbsd-mini2440.git] / crypto / dist / heimdal / appl / popper / pop_dropcopy.c
blob15aaa0f383f4b9d05ba9bb56c0215a2f2f6ca634
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 */
7 #include <popper.h>
8 __RCSID("$Heimdal: pop_dropcopy.c 11050 2002-07-04 14:10:11Z joda $"
9 "$NetBSD$");
12 * Run as the user in `pwd'
15 int
16 changeuser(POP *p, struct passwd *pwd)
18 if(setgid(pwd->pw_gid) < 0) {
19 pop_log (p, POP_PRIORITY,
20 "Unable to change to gid %u: %s",
21 (unsigned)pwd->pw_gid,
22 strerror(errno));
23 return pop_msg (p, POP_FAILURE,
24 "Unable to change gid");
26 if(setuid(pwd->pw_uid) < 0) {
27 pop_log (p, POP_PRIORITY,
28 "Unable to change to uid %u: %s",
29 (unsigned)pwd->pw_uid,
30 strerror(errno));
31 return pop_msg (p, POP_FAILURE,
32 "Unable to change uid");
34 #ifdef DEBUG
35 if(p->debug)
36 pop_log(p, POP_DEBUG,"uid = %u, gid = %u",
37 (unsigned)getuid(),
38 (unsigned)getgid());
39 #endif /* DEBUG */
40 return POP_SUCCESS;
43 /*
44 * dropcopy: Make a temporary copy of the user's mail drop and
45 * save a stream pointer for it.
48 int
49 pop_dropcopy(POP *p, struct passwd *pwp)
51 int mfd; /* File descriptor for
52 the user's maildrop */
53 int dfd; /* File descriptor for
54 the SERVER maildrop */
55 FILE *tf; /* The temp file */
56 char template[POP_TMPSIZE]; /* Temp name holder */
57 char buffer[BUFSIZ]; /* Read buffer */
58 long offset; /* Old/New boundary */
59 int nchar; /* Bytes written/read */
60 int tf_fd; /* fd for temp file */
61 int ret;
63 /* Create a temporary maildrop into which to copy the updated maildrop */
64 snprintf(p->temp_drop, sizeof(p->temp_drop), POP_DROP,p->user);
66 #ifdef DEBUG
67 if(p->debug)
68 pop_log(p,POP_DEBUG,"Creating temporary maildrop '%s'",
69 p->temp_drop);
70 #endif /* DEBUG */
72 /* Here we work to make sure the user doesn't cause us to remove or
73 * write over existing files by limiting how much work we do while
74 * running as root.
77 strlcpy(template, POP_TMPDROP, sizeof(template));
78 if ((tf_fd = mkstemp(template)) < 0 ||
79 (tf = fdopen(tf_fd, "w+")) == NULL) {
80 pop_log(p,POP_PRIORITY,
81 "Unable to create temporary temporary maildrop '%s': %s",template,
82 strerror(errno));
83 return pop_msg(p,POP_FAILURE,
84 "System error, can't create temporary file.");
87 /* Now give this file to the user */
88 chown(template, pwp->pw_uid, pwp->pw_gid);
89 chmod(template, 0600);
91 /* Now link this file to the temporary maildrop. If this fails it
92 * is probably because the temporary maildrop already exists. If so,
93 * this is ok. We can just go on our way, because by the time we try
94 * to write into the file we will be running as the user.
96 link(template,p->temp_drop);
97 fclose(tf);
98 unlink(template);
100 ret = changeuser(p, pwp);
101 if (ret != POP_SUCCESS)
102 return ret;
104 /* Open for append, this solves the crash recovery problem */
105 if ((dfd = open(p->temp_drop,O_RDWR|O_APPEND|O_CREAT,0600)) == -1){
106 pop_log(p,POP_PRIORITY,
107 "Unable to open temporary maildrop '%s': %s",p->temp_drop,
108 strerror(errno));
109 return pop_msg(p,POP_FAILURE,
110 "System error, can't open temporary file, do you own it?");
113 /* Lock the temporary maildrop */
114 if ( flock (dfd, (LOCK_EX | LOCK_NB)) == -1 )
115 switch(errno) {
116 case EWOULDBLOCK:
117 return pop_msg(p,POP_FAILURE,
118 "%sMaildrop lock busy! Is another session active?",
119 (p->flags & POP_FLAG_CAPA) ? "[IN-USE] " : "");
120 /* NOTREACHED */
121 default:
122 return pop_msg(p,POP_FAILURE,"flock: '%s': %s", p->temp_drop,
123 strerror(errno));
124 /* NOTREACHED */
127 /* May have grown or shrunk between open and lock! */
128 offset = lseek(dfd,0, SEEK_END);
130 /* Open the user's maildrop, If this fails, no harm in assuming empty */
131 if ((mfd = open(p->drop_name,O_RDWR)) > 0) {
133 /* Lock the maildrop */
134 if (flock (mfd, LOCK_EX) == -1) {
135 close(mfd) ;
136 return pop_msg(p,POP_FAILURE, "flock: '%s': %s", p->temp_drop,
137 strerror(errno));
140 /* Copy the actual mail drop into the temporary mail drop */
141 while ( (nchar=read(mfd,buffer,BUFSIZ)) > 0 )
142 if ( nchar != write(dfd,buffer,nchar) ) {
143 nchar = -1 ;
144 break ;
147 if ( nchar != 0 ) {
148 /* Error adding new mail. Truncate to original size,
149 and leave the maildrop as is. The user will not
150 see the new mail until the error goes away.
151 Should let them process the current backlog, in case
152 the error is a quota problem requiring deletions! */
153 ftruncate(dfd,(int)offset) ;
154 } else {
155 /* Mail transferred! Zero the mail drop NOW, that we
156 do not have to do gymnastics to figure out what's new
157 and what is old later */
158 ftruncate(mfd,0) ;
161 /* Close the actual mail drop */
162 close (mfd);
165 /* Acquire a stream pointer for the temporary maildrop */
166 if ( (p->drop = fdopen(dfd,"a+")) == NULL ) {
167 close(dfd) ;
168 return pop_msg(p,POP_FAILURE,"Cannot assign stream for %s",
169 p->temp_drop);
172 rewind (p->drop);
174 return(POP_SUCCESS);