]> diplodocus.org Git - nmh/blob - docs/historical/mh-6.8.5/miscellany/sendmail/spooler.c
ap: Fix write past end of addrs[] array.
[nmh] / docs / historical / mh-6.8.5 / miscellany / sendmail / spooler.c
1 /* spooler.c -- MH style mailer to write to /usr/spool/mail/<user>
2 *
3 * Mlocal, P=/etc/spooler, F=lsDFSmn, S=10, R=20, A=spooler $u
4 */
5
6
7 #define FLOCK /* uses flock() if defined, lockf() otherwise. */
8
9 #include <stdio.h>
10 #include <sys/types.h>
11 #include <sys/stat.h>
12 #include <sys/file.h>
13 #include <pwd.h>
14 #include "sysexits.h"
15
16 #define SPOOLDIR "/usr/spool/mail"
17
18 char *delim = "\1\1\1\1\n";
19 char *ME = "/etc/spooler";
20
21 FILE *mboxopen();
22 FILE *fp_in;
23
24 main( argc, argv )
25 int argc;
26 char **argv;
27 {
28 register int rc, anyerrs;
29 char tmpfile[100];
30
31 if( *++argv == NULL ) {
32 fprintf( stderr, "%s: no recipients.\n", ME );
33 exit( EX_USAGE );
34 }
35
36 if( argc == 2 ) { /* single recipient, don't need tmp copy */
37 fp_in = stdin;
38 rc = localmail( *argv );
39 }
40 else {
41 if(( rc = copyfile( tmpfile )) == 0 ) { /* sets fp_in */
42 for( anyerrs = 0; *argv; argv++ ) {
43 rewind( fp_in );
44 if(( rc = localmail( *argv )))
45 anyerrs++;
46 }
47 if( !anyerrs )
48 unlink( tmpfile );
49 }
50 }
51
52 exit( rc );
53 }
54
55
56
57 localmail( user )
58 char *user;
59 {
60 register FILE *fp;
61 register int count, n;
62 register char buf[BUFSIZ];
63 register char mailbox[BUFSIZ];
64 register struct stat sb;
65
66 sprintf( mailbox, "%s/%s", SPOOLDIR, user );
67
68 if( stat( mailbox, &sb ) == -1 ) {
69 if( create_mbox( mailbox, user ))
70 return(EX_TEMPFAIL);
71 }
72
73 if(( fp = mboxopen( mailbox )) == 0 )
74 return(EX_TEMPFAIL);
75 fwrite( delim, sizeof(char), strlen(delim), fp );
76 while(( count = fread( buf, sizeof(char), BUFSIZ, fp_in))) {
77 n = fwrite( buf, sizeof(char), count, fp );
78 if( n != count ) {
79 fprintf( stderr, "%s write error: %d read, %d written\n",
80 ME, count, n );
81 mboxclose(fp);
82 return(-1);
83 }
84 }
85 fwrite( delim, sizeof(char), strlen(delim), fp );
86 mboxclose(fp);
87
88 return(0);
89 }
90
91
92 create_mbox( mbox, user )
93 register char *mbox, *user;
94 {
95 register int fd;
96 register struct passwd *pw;
97
98 if(( fd = creat( mbox, 0600 )) == -1 )
99 return -1;
100 if(( pw = getpwnam( user )) != NULL ) {
101 fchown( fd, pw->pw_uid, pw->pw_gid );
102 }
103 close( fd );
104
105 return 0;
106 }
107
108
109 FILE *
110 mboxopen( mailbox )
111 register char *mailbox;
112 {
113 register FILE *fp;
114 register int i;
115
116 if(( fp = fopen( mailbox, "a" )) == NULL ) {
117 fprintf( stderr, "%s: Can't open %s for appending\n", ME, mailbox );
118 return(0);
119 }
120
121 /* lock the mailbox */
122
123 #define NLOCKTRYS 20 /* almost a 2 min. wait should be enough even */
124 /* after a long vacation */
125
126 for( i = 0; i < NLOCKTRYS; i++ ) {
127 #ifdef FLOCK
128 if( flock( fileno(fp), LOCK_EX | LOCK_NB ) == 0) /* got it ok */
129 #else
130 if( lockf( fileno(fp), F_TLOCK, 0) == 0 )
131 #endif FLOCK
132 break;
133 /* fprintf(stderr, "can't lock, sleeping 5 sec...\n"); */
134 sleep(5);
135 }
136 /*
137 * If lockf worked perfectly (ie, rpc.lockd didn't die) this would be
138 * just fine.
139 */
140 #ifdef DontDoThis
141 if( i == NLOCKTRYS ) {
142 fprintf( stderr, "%s: Can't lock %s\n", ME, mailbox);
143 return(0);
144 }
145 #endif
146
147 fseek( fp, 0, 2 );
148
149 return(fp);
150 }
151
152
153 mboxclose(fp)
154 FILE *fp;
155 {
156 /*todo: unlockit. --not really necessary */
157 fclose(fp);
158 }
159
160
161
162 /*
163 * collect stdin to a tmp file
164 */
165 copyfile( tmpfile )
166 register char *tmpfile;
167 {
168 struct stat sb;
169 register int pid, count, n;
170 register char buf[BUFSIZ];
171 register FILE *fp;
172
173 pid = getpid();
174
175 while( 1 ) {
176 sprintf( tmpfile, "/tmp/spooler.%05d", pid );
177 if( stat( tmpfile, &sb ) == -1 ) /* ok, this file doesn't exist */
178 break;
179 pid++;
180 }
181
182 if(( fp = fopen( tmpfile, "w" )) == NULL ) {
183 fprintf( stderr, "%s: Can't open %s\n", ME, tmpfile );
184 return(EX_TEMPFAIL);
185 }
186
187 while(( count = fread( buf, sizeof(char), BUFSIZ, stdin ))) {
188 n = fwrite( buf, sizeof(char), count, fp );
189 if( n != count ) {
190 fprintf( stderr, "%s: copyfile, write error: %d read, %d written\n",
191 ME, count, n );
192 fclose(fp);
193 return(-1);
194 }
195 }
196
197 fp_in = freopen( tmpfile, "r", fp );
198 if( fp_in == NULL ) {
199 fprintf( stderr, "%s: freopen on %s failed\n", ME, tmpfile );
200 return(-1);
201 }
202
203 return(0);
204 }