1/* opensr.c
2   Open files for sending and receiving.
3
4   Copyright (C) 1991, 1992, 1993, 2002 Ian Lance Taylor
5
6   This file is part of the Taylor UUCP package.
7
8   This program is free software; you can redistribute it and/or
9   modify it under the terms of the GNU General Public License as
10   published by the Free Software Foundation; either version 2 of the
11   License, or (at your option) any later version.
12
13   This program is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16   General Public License for more details.
17
18   You should have received a copy of the GNU General Public License
19   along with this program; if not, write to the Free Software
20   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA.
21
22   The author of the program may be contacted at ian@airs.com.
23   */
24
25#include "uucp.h"
26
27#include "uudefs.h"
28#include "uuconf.h"
29#include "system.h"
30#include "sysdep.h"
31
32#include <errno.h>
33
34#if HAVE_TIME_H
35#include <time.h>
36#endif
37
38#if HAVE_FCNTL_H
39#include <fcntl.h>
40#else
41#if HAVE_SYS_FILE_H
42#include <sys/file.h>
43#endif
44#endif
45
46#ifndef O_RDONLY
47#define O_RDONLY 0
48#define O_WRONLY 1
49#define O_RDWR 2
50#endif
51
52#ifndef O_NOCTTY
53#define O_NOCTTY 0
54#endif
55
56#ifndef FD_CLOEXEC
57#define FD_CLOEXEC 1
58#endif
59
60#ifndef time
61extern time_t time ();
62#endif
63
64/* Open a file to send to another system, and return the mode and
65   the size.  */
66
67openfile_t
68esysdep_open_send (qsys, zfile, fcheck, zuser)
69     const struct uuconf_system *qsys ATTRIBUTE_UNUSED;
70     const char *zfile;
71     boolean fcheck;
72     const char *zuser;
73{
74  struct stat s;
75  openfile_t e;
76  int o;
77
78  if (fsysdep_directory (zfile))
79    {
80      ulog (LOG_ERROR, "%s: is a directory", zfile);
81      return EFILECLOSED;
82    }
83
84#if USE_STDIO
85  e = fopen (zfile, BINREAD);
86  if (e == NULL)
87    {
88      ulog (LOG_ERROR, "fopen (%s): %s", zfile, strerror (errno));
89      return NULL;
90    }
91  o = fileno (e);
92#else
93  e = open ((char *) zfile, O_RDONLY | O_NOCTTY, 0);
94  if (e == -1)
95    {
96      ulog (LOG_ERROR, "open (%s): %s", zfile, strerror (errno));
97      return -1;
98    }
99  o = e;
100#endif
101
102  if (fcntl (o, F_SETFD, fcntl (o, F_GETFD, 0) | FD_CLOEXEC) < 0)
103    {
104      ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno));
105      (void) ffileclose (e);
106      return EFILECLOSED;
107    }
108
109  if (fstat (o, &s) == -1)
110    {
111      ulog (LOG_ERROR, "fstat: %s", strerror (errno));
112      s.st_mode = 0666;
113    }
114
115  /* We have to recheck the file permission, although we probably
116     checked it already, because otherwise there would be a window in
117     which somebody could change the contents of a symbolic link to
118     point to some file which was only readable by uucp.  */
119  if (fcheck)
120    {
121      if (! fsuser_access (&s, R_OK, zuser))
122	{
123	  ulog (LOG_ERROR, "%s: %s", zfile, strerror (EACCES));
124	  (void) ffileclose (e);
125	  return EFILECLOSED;
126	}
127    }
128
129  return e;
130}
131
132/* Get a temporary file name to receive into.  We use the ztemp
133   argument to pick the file name, so that we restart the file if the
134   transmission is aborted.  */
135
136char *
137zsysdep_receive_temp (qsys, zto, ztemp, frestart)
138     const struct uuconf_system *qsys;
139     const char *zto ATTRIBUTE_UNUSED;
140     const char *ztemp;
141     boolean frestart;
142{
143  if (frestart
144      && ztemp != NULL
145      && *ztemp == 'D'
146      && strcmp (ztemp, "D.0") != 0)
147    return zsappend3 (".Temp", qsys->uuconf_zname, ztemp);
148  else
149    return zstemp_file (qsys);
150}
151
152/* The number of seconds in one week.  We must cast to long for this
153   to be calculated correctly on a machine with 16 bit ints.  */
154#define SECS_PER_WEEK ((long) 7 * (long) 24 * (long) 60 * (long) 60)
155
156/* Open a temporary file to receive into.  This should, perhaps, check
157   that we have write permission on the receiving directory, but it
158   doesn't.  */
159
160openfile_t
161esysdep_open_receive (qsys, zto, ztemp, zreceive, pcrestart)
162     const struct uuconf_system *qsys ATTRIBUTE_UNUSED;
163     const char *zto ATTRIBUTE_UNUSED;
164     const char *ztemp;
165     const char *zreceive;
166     long *pcrestart;
167{
168  int o;
169  openfile_t e;
170
171  /* If we used the ztemp argument in zsysdep_receive_temp, above,
172     then we will have a name consistent across conversations.  In
173     that case, we may have already received some portion of this
174     file.  */
175  o = -1;
176  if (pcrestart != NULL)
177    *pcrestart = -1;
178  if (pcrestart != NULL
179      && ztemp != NULL
180      && *ztemp == 'D'
181      && strcmp (ztemp, "D.0") != 0)
182    {
183      o = open ((char *) zreceive, O_WRONLY);
184      if (o >= 0)
185	{
186	  struct stat s;
187
188	  /* For safety, we insist on the file being less than 1 week
189	     old.  This can still catch people, unfortunately.  I
190	     don't know of any good solution to the problem of old
191	     files hanging around.  If anybody has a file they want
192	     restarted, and they know about this issue, they can touch
193	     it to bring it up to date.  */
194	  if (fstat (o, &s) < 0
195	      || s.st_mtime + SECS_PER_WEEK < time ((time_t *) NULL))
196	    {
197	      (void) close (o);
198	      o = -1;
199	    }
200	  else
201	    {
202	      DEBUG_MESSAGE1 (DEBUG_SPOOLDIR,
203			      "esysdep_open_receive: Reusing %s",
204			      zreceive);
205	      *pcrestart = (long) s.st_size;
206	    }
207	}
208    }
209
210  if (o < 0)
211    o = creat ((char *) zreceive, IPRIVATE_FILE_MODE);
212
213  if (o < 0)
214    {
215      if (errno == ENOENT)
216	{
217	  if (! fsysdep_make_dirs (zreceive, FALSE))
218	    return EFILECLOSED;
219	  o = creat ((char *) zreceive, IPRIVATE_FILE_MODE);
220	}
221      if (o < 0)
222	{
223	  ulog (LOG_ERROR, "creat during esysdep_open_receive (%s): %s", zreceive, strerror (errno));
224	  return EFILECLOSED;
225	}
226    }
227
228  if (fcntl (o, F_SETFD, fcntl (o, F_GETFD, 0) | FD_CLOEXEC) < 0)
229    {
230      ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno));
231      (void) close (o);
232      (void) remove (zreceive);
233      return EFILECLOSED;
234    }
235
236#if USE_STDIO
237  e = fdopen (o, (char *) BINWRITE);
238
239  if (e == NULL)
240    {
241      ulog (LOG_ERROR, "fdopen (%s): %s", zreceive, strerror (errno));
242      (void) close (o);
243      (void) remove (zreceive);
244      return EFILECLOSED;
245    }
246#else
247  e = o;
248#endif
249
250  return e;
251}
252