395 lines
9.5 KiB
C
395 lines
9.5 KiB
C
/* init.c
|
||
Initialize the system dependent routines.
|
||
|
||
Copyright (C) 1991, 1992 Ian Lance Taylor
|
||
|
||
This file is part of the Taylor UUCP package.
|
||
|
||
This program is free software; you can redistribute it and/or
|
||
modify it under the terms of the GNU General Public License as
|
||
published by the Free Software Foundation; either version 2 of the
|
||
License, or (at your option) any later version.
|
||
|
||
This program is distributed in the hope that it will be useful, but
|
||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
General Public License for more details.
|
||
|
||
You should have received a copy of the GNU General Public License
|
||
along with this program; if not, write to the Free Software
|
||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||
|
||
The author of the program may be contacted at ian@airs.com or
|
||
c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254.
|
||
*/
|
||
|
||
#include "uucp.h"
|
||
|
||
#include "uudefs.h"
|
||
#include "uuconf.h"
|
||
#include "system.h"
|
||
#include "sysdep.h"
|
||
|
||
#include <errno.h>
|
||
#include <pwd.h>
|
||
|
||
#if HAVE_FCNTL_H
|
||
#include <fcntl.h>
|
||
#else
|
||
#if HAVE_SYS_FILE_H
|
||
#include <sys/file.h>
|
||
#endif
|
||
#endif
|
||
|
||
#ifndef O_RDONLY
|
||
#define O_RDONLY 0
|
||
#define O_WRONLY 1
|
||
#define O_RDWR 2
|
||
#endif
|
||
|
||
#if ! HAVE_GETHOSTNAME && HAVE_UNAME
|
||
#include <sys/utsname.h>
|
||
#endif
|
||
|
||
/* Use getcwd in preference to getwd; if we have neither, we will be
|
||
using a getcwd replacement. */
|
||
#if HAVE_GETCWD
|
||
#undef HAVE_GETWD
|
||
#define HAVE_GETWD 0
|
||
#else /* ! HAVE_GETCWD */
|
||
#if ! HAVE_GETWD
|
||
#undef HAVE_GETCWD
|
||
#define HAVE_GETCWD 1
|
||
#endif /* ! HAVE_GETWD */
|
||
#endif /* ! HAVE_GETCWD */
|
||
|
||
#if HAVE_GETWD
|
||
/* Get a value for MAXPATHLEN. */
|
||
#if HAVE_SYS_PARAMS_H
|
||
#include <sys/params.h>
|
||
#endif
|
||
|
||
#if HAVE_LIMITS_H
|
||
#include <limits.h>
|
||
#endif
|
||
|
||
#ifndef MAXPATHLEN
|
||
#ifdef PATH_MAX
|
||
#define MAXPATHLEN PATH_MAX
|
||
#else /* ! defined (PATH_MAX) */
|
||
#define MAXPATHLEN 1024
|
||
#endif /* ! defined (PATH_MAX) */
|
||
#endif /* ! defined (MAXPATHLEN) */
|
||
#endif /* HAVE_GETWD */
|
||
|
||
/* External functions. */
|
||
#ifndef getlogin
|
||
extern char *getlogin ();
|
||
#endif
|
||
#if GETPWNAM_DECLARATION_OK
|
||
#ifndef getpwnam
|
||
extern struct passwd *getpwnam ();
|
||
#endif
|
||
#endif
|
||
#if GETPWUID_DECLARATION_OK
|
||
#ifndef getpwuid
|
||
extern struct passwd *getpwuid ();
|
||
#endif
|
||
#endif
|
||
#if HAVE_GETCWD
|
||
#ifndef getcwd
|
||
extern char *getcwd ();
|
||
#endif
|
||
#endif
|
||
#if HAVE_GETWD
|
||
#ifndef getwd
|
||
extern char *getwd ();
|
||
#endif
|
||
#endif
|
||
#if HAVE_SYSCONF
|
||
#ifndef sysconf
|
||
extern long sysconf ();
|
||
#endif
|
||
#endif
|
||
|
||
/* Initialize the system dependent routines. We will probably be running
|
||
suid to uucp, so we make sure that nothing is obviously wrong. We
|
||
save the login name since we will be losing the real uid. */
|
||
static char *zSlogin;
|
||
|
||
/* The UUCP spool directory. */
|
||
const char *zSspooldir;
|
||
|
||
/* The UUCP lock directory. */
|
||
const char *zSlockdir;
|
||
|
||
/* The local UUCP name. */
|
||
const char *zSlocalname;
|
||
|
||
/* We save the current directory since we will do a chdir to the
|
||
spool directory. */
|
||
char *zScwd;
|
||
|
||
/* The maximum length of a system name is controlled by the type of spool
|
||
directory we use. */
|
||
#if SPOOLDIR_V2 || SPOOLDIR_BSD42 || SPOOLDIR_BSD43 || SPOOLDIR_ULTRIX
|
||
size_t cSysdep_max_name_len = 7;
|
||
#endif
|
||
#if SPOOLDIR_HDB || SPOOLDIR_SVR4
|
||
size_t cSysdep_max_name_len = 14;
|
||
#endif
|
||
#if SPOOLDIR_TAYLOR
|
||
#if HAVE_LONG_FILE_NAMES
|
||
size_t cSysdep_max_name_len = 255;
|
||
#else /* ! HAVE_LONG_FILE_NAMES */
|
||
size_t cSysdep_max_name_len = 14;
|
||
#endif /* ! HAVE_LONG_FILE_NAMES */
|
||
#endif /* SPOOLDIR_TAYLOR */
|
||
|
||
/* Initialize the system dependent routines. */
|
||
|
||
void
|
||
usysdep_initialize (puuconf,iflags)
|
||
pointer puuconf;
|
||
int iflags;
|
||
{
|
||
int cdescs;
|
||
int o;
|
||
int iuuconf;
|
||
char *z;
|
||
struct passwd *q;
|
||
|
||
ulog_id (getpid ());
|
||
|
||
/* Close everything but stdin, stdout and stderr. */
|
||
#if HAVE_GETDTABLESIZE
|
||
cdescs = getdtablesize ();
|
||
#else
|
||
#if HAVE_SYSCONF
|
||
cdescs = sysconf (_SC_OPEN_MAX);
|
||
#else
|
||
#ifdef OPEN_MAX
|
||
cdescs = OPEN_MAX;
|
||
#else
|
||
#ifdef NOFILE
|
||
cdescs = NOFILE;
|
||
#else
|
||
cdescs = 20;
|
||
#endif /* ! defined (NOFILE) */
|
||
#endif /* ! defined (OPEN_MAX) */
|
||
#endif /* ! HAVE_SYSCONF */
|
||
#endif /* ! HAVE_GETDTABLESIZE */
|
||
|
||
for (o = 3; o < cdescs; o++)
|
||
(void) close (o);
|
||
|
||
/* Make sure stdin, stdout and stderr are open. */
|
||
if (fcntl (0, F_GETFD, 0) < 0
|
||
&& open ((char *) "/dev/null", O_RDONLY, 0) != 0)
|
||
exit (EXIT_FAILURE);
|
||
if (fcntl (1, F_GETFD, 0) < 0
|
||
&& open ((char *) "/dev/null", O_WRONLY, 0) != 1)
|
||
exit (EXIT_FAILURE);
|
||
if (fcntl (2, F_GETFD, 0) < 0
|
||
&& open ((char *) "/dev/null", O_WRONLY, 0) != 2)
|
||
exit (EXIT_FAILURE);
|
||
|
||
iuuconf = uuconf_spooldir (puuconf, &zSspooldir);
|
||
if (iuuconf != UUCONF_SUCCESS)
|
||
ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
|
||
|
||
iuuconf = uuconf_lockdir (puuconf, &zSlockdir);
|
||
if (iuuconf != UUCONF_SUCCESS)
|
||
ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
|
||
|
||
iuuconf = uuconf_localname (puuconf, &zSlocalname);
|
||
if (iuuconf == UUCONF_NOT_FOUND)
|
||
{
|
||
#if HAVE_GETHOSTNAME
|
||
char ab[256];
|
||
|
||
if (gethostname (ab, sizeof ab - 1) < 0)
|
||
ulog (LOG_FATAL, "gethostname: %s", strerror (errno));
|
||
ab[sizeof ab - 1] = '\0';
|
||
ab[strcspn (ab, ".")] = '\0';
|
||
zSlocalname = zbufcpy (ab);
|
||
#else /* ! HAVE_GETHOSTNAME */
|
||
#if HAVE_UNAME
|
||
struct utsname s;
|
||
|
||
if (uname (&s) < 0)
|
||
ulog (LOG_FATAL, "uname: %s", strerror (errno));
|
||
zSlocalname = zbufcpy (s.nodename);
|
||
#else /* ! HAVE_UNAME */
|
||
ulog (LOG_FATAL, "Don't know how to get local node name");
|
||
#endif /* ! HAVE_UNAME */
|
||
#endif /* ! HAVE_GETHOSTNAME */
|
||
}
|
||
else if (iuuconf != UUCONF_SUCCESS)
|
||
ulog_uuconf (LOG_FATAL, puuconf, iuuconf);
|
||
|
||
/* We always set our file modes to exactly what we want. */
|
||
umask (0);
|
||
|
||
/* Get the login name, making sure that it matches the uid. Many
|
||
systems truncate the getlogin return value to 8 characters, but
|
||
keep the full name in the password file, so we prefer the name in
|
||
the password file. */
|
||
z = getenv ("LOGNAME");
|
||
if (z == NULL)
|
||
z = getenv ("USER");
|
||
if (z == NULL)
|
||
z = getlogin ();
|
||
if (z == NULL)
|
||
q = NULL;
|
||
else
|
||
{
|
||
q = getpwnam (z);
|
||
if (q != NULL)
|
||
z = q->pw_name;
|
||
}
|
||
if (q == NULL || q->pw_uid != getuid ())
|
||
{
|
||
q = getpwuid (getuid ());
|
||
if (q == NULL)
|
||
z = NULL;
|
||
else
|
||
z = q->pw_name;
|
||
}
|
||
if (z != NULL)
|
||
zSlogin = zbufcpy (z);
|
||
|
||
/* On some old systems, an suid program run by root is started with
|
||
an euid of 0. If this happens, we look up the uid we should have
|
||
and set ourselves to it manually. This means that on such a
|
||
system root will not be able to uucp or uux files that are not
|
||
readable by uucp. */
|
||
if ((iflags & INIT_SUID) != 0
|
||
&& geteuid () == 0)
|
||
{
|
||
q = getpwnam (OWNER);
|
||
if (q != NULL)
|
||
setuid (q->pw_uid);
|
||
}
|
||
|
||
if ((iflags & INIT_GETCWD) != 0)
|
||
{
|
||
const char *zenv;
|
||
struct stat senv, sdot;
|
||
|
||
/* Get the current working directory. We have to get it now,
|
||
since we're about to do a chdir. We use PWD if it's defined
|
||
and if it really names the working directory, since if it's
|
||
not the same as whatever getcwd returns it's probably more
|
||
appropriate. */
|
||
zenv = getenv ("PWD");
|
||
if (zenv != NULL
|
||
&& stat ((char *) zenv, &senv) == 0
|
||
&& stat ((char *) ".", &sdot) == 0
|
||
&& senv.st_ino == sdot.st_ino
|
||
&& senv.st_dev == sdot.st_dev)
|
||
zScwd = zbufcpy (zenv);
|
||
else
|
||
{
|
||
|
||
#if HAVE_GETCWD
|
||
{
|
||
size_t c;
|
||
|
||
c = 128;
|
||
while (TRUE)
|
||
{
|
||
zScwd = (char *) xmalloc (c);
|
||
if (getcwd (zScwd, c) != NULL)
|
||
break;
|
||
xfree ((pointer) zScwd);
|
||
zScwd = NULL;
|
||
if (errno != ERANGE)
|
||
break;
|
||
c <<= 1;
|
||
}
|
||
}
|
||
#endif /* HAVE_GETCWD */
|
||
|
||
#if HAVE_GETWD
|
||
zScwd = (char *) xmalloc (MAXPATHLEN);
|
||
if (getwd (zScwd) == NULL)
|
||
{
|
||
xfree ((pointer) zScwd);
|
||
zScwd = NULL;
|
||
}
|
||
#endif /* HAVE_GETWD */
|
||
|
||
if (zScwd != NULL)
|
||
zScwd = (char *) xrealloc ((pointer) zScwd,
|
||
strlen (zScwd) + 1);
|
||
}
|
||
}
|
||
|
||
if ((iflags & INIT_NOCHDIR) == 0)
|
||
{
|
||
/* Connect to the spool directory, and create it if it doesn't
|
||
exist. */
|
||
if (chdir (zSspooldir) < 0)
|
||
{
|
||
if (errno == ENOENT
|
||
&& mkdir ((char *) zSspooldir, IDIRECTORY_MODE) < 0)
|
||
ulog (LOG_FATAL, "mkdir (%s): %s", zSspooldir,
|
||
strerror (errno));
|
||
if (chdir (zSspooldir) < 0)
|
||
ulog (LOG_FATAL, "chdir (%s): %s", zSspooldir,
|
||
strerror (errno));
|
||
}
|
||
}
|
||
}
|
||
|
||
/* Exit the program. */
|
||
|
||
void
|
||
usysdep_exit (fsuccess)
|
||
boolean fsuccess;
|
||
{
|
||
exit (fsuccess ? EXIT_SUCCESS : EXIT_FAILURE);
|
||
}
|
||
|
||
/* This is called when a non-standard configuration file is used, to
|
||
make sure the program doesn't hand out privileged file access.
|
||
This means that to test non-standard configuration files, you
|
||
should be logged in as uucp. This is called before
|
||
usysdep_initialize. It ensures that someone can't simply use an
|
||
alternate configuration file to steal UUCP transfers from other
|
||
systems. This will still permit people to set up their own
|
||
configuration file and pretend to be whatever system they choose.
|
||
The only real security is to use a high level of protection on the
|
||
modem ports. */
|
||
|
||
/*ARGSUSED*/
|
||
boolean fsysdep_other_config (z)
|
||
const char *z;
|
||
{
|
||
(void) setuid (getuid ());
|
||
(void) setgid (getgid ());
|
||
return TRUE;
|
||
}
|
||
|
||
/* Get the node name to use if it was not specified in the configuration
|
||
file. */
|
||
|
||
const char *
|
||
zsysdep_localname ()
|
||
{
|
||
return zSlocalname;
|
||
}
|
||
|
||
/* Get the login name. We actually get the login name in
|
||
usysdep_initialize, because after that we may switch away from the
|
||
real uid. */
|
||
|
||
const char *
|
||
zsysdep_login_name ()
|
||
{
|
||
if (zSlogin == NULL)
|
||
ulog (LOG_FATAL, "Can't get login name");
|
||
return zSlogin;
|
||
}
|