1/* init.c
2   Initialize the system dependent routines.
3
4   Copyright (C) 1991, 1992, 1993, 1994, 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#include <pwd.h>
34
35#if HAVE_FCNTL_H
36#include <fcntl.h>
37#else
38#if HAVE_SYS_FILE_H
39#include <sys/file.h>
40#endif
41#endif
42
43#ifndef O_RDONLY
44#define O_RDONLY 0
45#define O_WRONLY 1
46#define O_RDWR 2
47#endif
48
49#if ! HAVE_GETHOSTNAME && HAVE_UNAME
50#include <sys/utsname.h>
51#endif
52
53/* Use getcwd in preference to getwd; if we have neither, we will be
54   using a getcwd replacement.  */
55#if HAVE_GETCWD
56#undef HAVE_GETWD
57#define HAVE_GETWD 0
58#else /* ! HAVE_GETCWD */
59#if ! HAVE_GETWD
60#undef HAVE_GETCWD
61#define HAVE_GETCWD 1
62#endif /* ! HAVE_GETWD */
63#endif /* ! HAVE_GETCWD */
64
65#if HAVE_GETWD
66/* Get a value for MAXPATHLEN.  */
67#if HAVE_SYS_PARAMS_H
68#include <sys/params.h>
69#endif
70
71#if HAVE_LIMITS_H
72#include <limits.h>
73#endif
74
75#ifndef MAXPATHLEN
76#ifdef PATH_MAX
77#define MAXPATHLEN PATH_MAX
78#else /* ! defined (PATH_MAX) */
79#define MAXPATHLEN 1024
80#endif /* ! defined (PATH_MAX) */
81#endif /* ! defined (MAXPATHLEN) */
82#endif /* HAVE_GETWD */
83
84/* External functions.  */
85#ifndef getlogin
86extern char *getlogin ();
87#endif
88#if GETPWNAM_DECLARATION_OK
89#ifndef getpwnam
90extern struct passwd *getpwnam ();
91#endif
92#endif
93#if GETPWUID_DECLARATION_OK
94#ifndef getpwuid
95extern struct passwd *getpwuid ();
96#endif
97#endif
98#if HAVE_GETCWD
99#ifndef getcwd
100extern char *getcwd ();
101#endif
102#endif
103#if HAVE_GETWD
104#ifndef getwd
105extern char *getwd ();
106#endif
107#endif
108#if HAVE_SYSCONF
109#ifndef sysconf
110extern long sysconf ();
111#endif
112#endif
113
114/* Initialize the system dependent routines.  We will probably be running
115   suid to uucp, so we make sure that nothing is obviously wrong.  We
116   save the login name since we will be losing the real uid.  */
117static char *zSlogin;
118
119/* The UUCP spool directory.  */
120const char *zSspooldir;
121
122/* The UUCP lock directory.  */
123const char *zSlockdir;
124
125/* The local UUCP name.  */
126const char *zSlocalname;
127
128/* We save the current directory since we will do a chdir to the
129   spool directory.  */
130char *zScwd;
131
132/* The maximum length of a system name is controlled by the type of spool
133   directory we use.  */
134#if SPOOLDIR_V2 || SPOOLDIR_BSD42 || SPOOLDIR_BSD43 || SPOOLDIR_ULTRIX
135size_t cSysdep_max_name_len = 7;
136#endif
137#if SPOOLDIR_HDB || SPOOLDIR_SVR4
138size_t cSysdep_max_name_len = 14;
139#endif
140#if SPOOLDIR_TAYLOR
141#if HAVE_LONG_FILE_NAMES
142size_t cSysdep_max_name_len = 255;
143#else /* ! HAVE_LONG_FILE_NAMES */
144size_t cSysdep_max_name_len = 14;
145#endif /* ! HAVE_LONG_FILE_NAMES */
146#endif /* SPOOLDIR_TAYLOR */
147
148/* Initialize the system dependent routines.  */
149
150void
151usysdep_initialize (puuconf,iflags)
152     pointer puuconf;
153     int iflags;
154{
155  int iuuconf;
156  char *z;
157  struct passwd *q;
158
159  ulog_id (getpid ());
160
161  if ((iflags & INIT_NOCLOSE) == 0)
162    {
163      int cdescs;
164      int o;
165
166      /* Close everything but stdin, stdout and stderr.  */
167#if HAVE_GETDTABLESIZE
168      cdescs = getdtablesize ();
169#else
170#if HAVE_SYSCONF
171      cdescs = sysconf (_SC_OPEN_MAX);
172#else
173#ifdef OPEN_MAX
174      cdescs = OPEN_MAX;
175#else
176#ifdef NOFILE
177      cdescs = NOFILE;
178#else
179      cdescs = 20;
180#endif /* ! defined (NOFILE) */
181#endif /* ! defined (OPEN_MAX) */
182#endif /* ! HAVE_SYSCONF */
183#endif /* ! HAVE_GETDTABLESIZE */
184
185      for (o = 3; o < cdescs; o++)
186	(void) close (o);
187    }
188
189  /* Make sure stdin, stdout and stderr are open.  */
190  if (fcntl (0, F_GETFD, 0) < 0
191      && open ((char *) "/dev/null", O_RDONLY, 0) != 0)
192    exit (EXIT_FAILURE);
193  if (fcntl (1, F_GETFD, 0) < 0
194      && open ((char *) "/dev/null", O_WRONLY, 0) != 1)
195    exit (EXIT_FAILURE);
196  if (fcntl (2, F_GETFD, 0) < 0
197      && open ((char *) "/dev/null", O_WRONLY, 0) != 2)
198    exit (EXIT_FAILURE);
199
200  iuuconf = uuconf_spooldir (puuconf, &zSspooldir);
201  if (iuuconf != UUCONF_SUCCESS)
202    ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
203
204  iuuconf = uuconf_lockdir (puuconf, &zSlockdir);
205  if (iuuconf != UUCONF_SUCCESS)
206    ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
207
208  iuuconf = uuconf_localname (puuconf, &zSlocalname);
209  if (iuuconf == UUCONF_NOT_FOUND)
210    {
211#if HAVE_GETHOSTNAME
212      char ab[256];
213
214      if (gethostname (ab, sizeof ab - 1) < 0)
215	ulog (LOG_FATAL, "gethostname: %s", strerror (errno));
216      ab[sizeof ab - 1] = '\0';
217      ab[strcspn (ab, ".")] = '\0';
218      zSlocalname = zbufcpy (ab);
219#else /* ! HAVE_GETHOSTNAME */
220#if HAVE_UNAME
221      struct utsname s;
222
223      if (uname (&s) < 0)
224	ulog (LOG_FATAL, "uname: %s", strerror (errno));
225      zSlocalname = zbufcpy (s.nodename);
226#else /* ! HAVE_UNAME */
227      ulog (LOG_FATAL, "Don't know how to get local node name");
228#endif /* ! HAVE_UNAME */
229#endif /* ! HAVE_GETHOSTNAME */
230    }
231  else if (iuuconf != UUCONF_SUCCESS)
232    ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
233
234  /* We always set our file modes to exactly what we want.  */
235  umask (0);
236
237  /* Get the login name, making sure that it matches the uid.  Many
238     systems truncate the getlogin return value to 8 characters, but
239     keep the full name in the password file, so we prefer the name in
240     the password file.  */
241  z = getenv ("LOGNAME");
242  if (z == NULL)
243    z = getenv ("USER");
244  if (z == NULL)
245    z = getlogin ();
246  if (z == NULL)
247    q = NULL;
248  else
249    {
250      q = getpwnam (z);
251      if (q != NULL)
252	z = q->pw_name;
253    }
254  if (q == NULL || q->pw_uid != getuid ())
255    {
256      q = getpwuid (getuid ());
257      if (q == NULL)
258	z = NULL;
259      else
260	z = q->pw_name;
261    }
262  if (z != NULL)
263    zSlogin = zbufcpy (z);
264
265
266  {
267      char *zlf;
268      if (getuid() == 4 && UUCONF_SUCCESS == uuconf_logfile (puuconf, &zlf)) {
269	  chmod(zlf, 0777);
270      }
271  }
272
273  /* On some old systems, an suid program run by root is started with
274     an euid of 0.  If this happens, we look up the uid we should have
275     and set ourselves to it manually.  This means that on such a
276     system root will not be able to uucp or uux files that are not
277     readable by uucp.  */
278  if ((iflags & INIT_SUID) != 0
279      && geteuid () == 0)
280    {
281      q = getpwnam (OWNER);
282      if (q != NULL)
283	setuid (q->pw_uid);
284    }
285
286  if ((iflags & INIT_GETCWD) != 0)
287    {
288      const char *zenv;
289      struct stat senv, sdot;
290
291      /* Get the current working directory.  We have to get it now,
292	 since we're about to do a chdir.  We use PWD if it's defined
293	 and if it really names the working directory, since if it's
294	 not the same as whatever getcwd returns it's probably more
295	 appropriate.  */
296      zenv = getenv ("PWD");
297      if (zenv != NULL
298	  && stat ((char *) zenv, &senv) == 0
299	  && stat ((char *) ".", &sdot) == 0
300	  && senv.st_ino == sdot.st_ino
301	  && senv.st_dev == sdot.st_dev)
302	zScwd = zbufcpy (zenv);
303      else
304	{
305
306#if HAVE_GETCWD
307	  {
308	    size_t c;
309
310	    c = 128;
311	    while (TRUE)
312	      {
313		zScwd = (char *) xmalloc (c);
314		if (getcwd (zScwd, c) != NULL)
315		  break;
316		xfree ((pointer) zScwd);
317		zScwd = NULL;
318		if (errno != ERANGE)
319		  break;
320		c <<= 1;
321	      }
322	  }
323#endif /* HAVE_GETCWD */
324
325#if HAVE_GETWD
326	  zScwd = (char *) xmalloc (MAXPATHLEN);
327	  if (getwd (zScwd) == NULL)
328	    {
329	      xfree ((pointer) zScwd);
330	      zScwd = NULL;
331	    }
332#endif /* HAVE_GETWD */
333
334	  if (zScwd != NULL)
335	    zScwd = (char *) xrealloc ((pointer) zScwd,
336				       strlen (zScwd) + 1);
337	}
338    }
339
340  if ((iflags & INIT_NOCHDIR) == 0)
341    {
342      /* Connect to the spool directory, and create it if it doesn't
343	 exist.  */
344      if (chdir (zSspooldir) < 0)
345	{
346	  if (errno == ENOENT
347	      && mkdir ((char *) zSspooldir, IDIRECTORY_MODE) < 0)
348	    ulog (LOG_FATAL, "mkdir (%s): %s", zSspooldir,
349		  strerror (errno));
350	  if (chdir (zSspooldir) < 0)
351	    ulog (LOG_FATAL, "chdir (%s): %s", zSspooldir,
352		  strerror (errno));
353	}
354    }
355}
356
357/* Exit the program.  */
358
359void
360usysdep_exit (fsuccess)
361     boolean fsuccess;
362{
363  exit (fsuccess ? EXIT_SUCCESS : EXIT_FAILURE);
364}
365
366/* This is called when a non-standard configuration file is used, to
367   make sure the program doesn't hand out privileged file access.
368   This means that to test non-standard configuration files, you
369   should be logged in as uucp.  This is called before
370   usysdep_initialize.  It ensures that someone can't simply use an
371   alternate configuration file to steal UUCP transfers from other
372   systems.  This will still permit people to set up their own
373   configuration file and pretend to be whatever system they choose.
374   The only real security is to use a high level of protection on the
375   modem ports.  */
376
377/*ARGSUSED*/
378boolean fsysdep_other_config (z)
379     const char *z ATTRIBUTE_UNUSED;
380{
381  (void) setuid (getuid ());
382  (void) setgid (getgid ());
383  return TRUE;
384}
385
386/* Get the node name to use if it was not specified in the configuration
387   file.  */
388
389const char *
390zsysdep_localname ()
391{
392  return zSlocalname;
393}
394
395/* Get the login name.  We actually get the login name in
396   usysdep_initialize, because after that we may switch away from the
397   real uid.  */
398
399const char *
400zsysdep_login_name ()
401{
402  if (zSlogin == NULL)
403    ulog (LOG_FATAL, "Can't get login name");
404  return zSlogin;
405}
406