/*
* Copyright (c) 2001-2002 Proofpoint, Inc. and its suppliers.
* All rights reserved.
*
* By using this file, you agree to the terms and conditions set
* forth in the LICENSE file which can be found at the top level of
* the sendmail distribution.
*
*/
#ifdef MPE
/*
** MPE lacks many common functions required across all sendmail programs
** so we define implementations for these functions here.
*/
# include <errno.h>
# include <fcntl.h>
# include <limits.h>
# include <mpe.h>
# include <pwd.h>
# include <unistd.h>
/*
** CHROOT -- dummy chroot() function
**
** The MPE documentation for sendmail says that chroot-based
** functionality is not implemented because MPE lacks chroot. But
** rather than mucking around with all the sendmail calls to chroot,
** we define this dummy function to return an ENOSYS failure just in
** case a sendmail user attempts to enable chroot-based functionality.
**
** Parameters:
** path -- pathname of new root (ignored).
**
** Returns:
** -1 and errno == ENOSYS (function not implemented)
*/
int
char *path;
{
return -1;
}
/*
** ENDPWENT -- dummy endpwent() function
**
** Parameters:
** none
**
** Returns:
** none
*/
void
endpwent()
{
return;
}
/*
** In addition to missing functions, certain existing MPE functions have
** slightly different semantics (or bugs) compared to normal Unix OSes.
**
** Here we define wrappers for these functions to make them behave in the
** manner expected by sendmail.
*/
/*
** SENDMAIL_MPE_BIND -- shadow function for the standard socket bind()
**
** MPE requires GETPRIVMODE() for AF_INET sockets less than port 1024.
**
** Parameters:
** sd -- socket descriptor.
** addr -- socket address.
** addrlen -- length of socket address.
**
** Results:
** 0 -- success
** != 0 -- failure
*/
int
int sd;
void *addr;
int addrlen;
{
bool priv = false;
int result;
extern void GETPRIVMODE __P((void));
extern void GETUSERMODE __P((void));
if (addrlen == sizeof(struct sockaddr_in) &&
{
/* AF_INET */
{
priv = true;
GETPRIVMODE();
}
if (priv)
GETUSERMODE();
return result;
}
/* AF_UNIX */
}
/*
** SENDMAIL_MPE__EXIT -- wait for children to terminate, then _exit()
**
** Child processes cannot survive the death of their parent on MPE, so
** we must call wait() before _exit() in order to prevent this
** infanticide.
**
** Parameters:
** status -- _exit status value.
**
** Returns:
** none.
*/
void
int status;
{
int result;
/* Wait for all children to terminate. */
do
{
}
/*
** SENDMAIL_MPE_EXIT -- wait for children to terminate, then exit()
**
** Child processes cannot survive the death of their parent on MPE, so
** we must call wait() before exit() in order to prevent this
** infanticide.
**
** Parameters:
** status -- exit status value.
**
** Returns:
** none.
*/
void
int status;
{
int result;
/* Wait for all children to terminate. */
do
{
}
/*
** SENDMAIL_MPE_FCNTL -- shadow function for fcntl()
**
** MPE requires sfcntl() for sockets, and fcntl() for everything
** else. This shadow routine determines the descriptor type and
** makes the appropriate call.
**
** Parameters:
** same as fcntl().
**
** Returns:
** same as fcntl().
*/
int
{
void *arg;
{
if (errno == EAFNOSUPPORT)
{
/* AF_UNIX socket */
}
{
/* file or pipe */
}
/* unknown getsockname() failure */
return (-1);
}
else
{
/* AF_INET socket */
return result;
}
}
/*
** SENDMAIL_MPE_GETPWNAM - shadow function for getpwnam()
**
** Several issues apply here:
**
** - MPE user names MUST have one '.' separator character
** - MPE user names MUST be in upper case
** - MPE does not initialize all fields in the passwd struct
**
** Parameters:
** name -- username string.
**
** Returns:
** pointer to struct passwd if found else NULL
*/
struct passwd *
const char *name;
{
int dots = 0;
int err;
char *upper;
if (i <= 0)
{
return result;
}
{
/* upshift the username parameter and count the dots */
while (i >= 0)
{
if (name[i] == '.')
{
dots++;
upper[i] = '.';
}
else
i--;
}
if (dots != 1)
{
/* prevent bug when dots == 0 */
}
{
/* init the uninitialized fields */
}
}
return result;
}
/*
** SENDMAIL_MPE_GETPWUID -- shadow function for getpwuid()
**
** Initializes the uninitalized fields in the passwd struct.
**
** Parameters:
** uid -- uid to obtain passwd data for
**
** Returns:
** pointer to struct passwd or NULL if not found
*/
struct passwd *
{
{
/* initialize the uninitialized fields */
}
return result;
}
/*
** OK boys and girls, time for some serious voodoo!
**
** MPE does not have a complete implementation of POSIX users and groups:
**
** - there is no uid 0 superuser
** - setgid() exists, but only supports new gid == current gid (boring!)
** - setuid() forces a gid change to the new uid's primary (and only) gid
**
** ...all of which thoroughly annoys sendmail.
**
** So what to do? We can't go on an #ifdef MPE rampage throughout
** sendmail, because there are only about a zillion references to uid 0
** and so success (and security) would probably be rather dubious by the
** time we finished.
**
** Instead we take the approach of defining wrapper functions for the
** setuid() in order to implement the following model:
**
** - the sendmail program thinks it is a setuid-root (uid 0) program
** - uid 0 is recognized as being valid, but does not grant extra powers
** - MPE priv mode allows sendmail to call setuid(), not uid 0
** - file access is still controlled by the real non-zero uid
** - the other programs (vacation, etc) have standard MPE POSIX behavior
**
** This emulation model is activated by use of the program file setgid and
** setuid mode bits which exist but are unused by MPE. If the setgid mode
** bit is on, then gid emulation will be enabled. If the setuid mode bit is
** on, then uid emulation will be enabled. So for the mail daemon, we need
**
** The following flags determine the current emulation state:
**
** true == emulation enabled
** false == emulation disabled, use unmodified MPE semantics
*/
static bool sendmail_mpe_flaginit = false;
static bool sendmail_mpe_gidflag = false;
static bool sendmail_mpe_uidflag = false;
/*
** SENDMAIL_MPE_GETMODE -- return the mode bits for the current process
**
** Parameters:
** none.
**
** Returns:
** file mode bits for the current process program file.
*/
{
int myprogram_length;
int *myprogram_length, int *myprogram_syntax));
myprogram_length = sizeof(myprogram);
/* should not occur, do not attempt emulation */
if (status != 0)
return 0;
/* should not occur, do not attempt emulation */
return 0;
}
/*
** SENDMAIL_MPE_EMULGID -- should we perform gid emulation?
**
** If !sendmail_mpe_flaginit then obtain the mode bits to determine
** if the setgid bit is on, we want gid emulation and so set
** sendmail_mpe_gidflag to true. Otherwise we do not want gid emulation
** and so set sendmail_mpe_gidflag to false.
**
** Parameters:
** none.
**
** Returns:
** true -- perform gid emulation
** false -- do not perform gid emulation
*/
bool
{
if (!sendmail_mpe_flaginit)
{
mode = sendmail_mpe_getmode();
sendmail_mpe_flaginit = true;
}
return sendmail_mpe_gidflag;
}
/*
** SENDMAIL_MPE_EMULUID -- should we perform uid emulation?
**
** If sendmail_mpe_uidflag == -1 then obtain the mode bits to determine
** if the setuid bit is on, we want uid emulation and so set
** sendmail_mpe_uidflag to true. Otherwise we do not want uid emulation
** and so set sendmail_mpe_uidflag to false.
**
** Parameters:
** none.
**
** Returns:
** true -- perform uid emulation
** false -- do not perform uid emulation
*/
bool
{
if (!sendmail_mpe_flaginit)
{
mode = sendmail_mpe_getmode();
sendmail_mpe_flaginit = true;
}
return sendmail_mpe_uidflag;
}
/*
** SENDMAIL_MPE_GETEGID -- shadow function for getegid()
**
** If emulation mode is in effect and the saved egid has been
** initialized, return the saved egid; otherwise return the value of the
** real getegid() function.
**
** Parameters:
** none.
**
** Returns:
** emulated egid if present, else true egid.
*/
{
return sendmail_mpe_egid;
return getegid();
}
/*
** SENDMAIL_MPE_GETEUID -- shadow function for geteuid()
**
** If emulation mode is in effect, return the saved euid; otherwise
** return the value of the real geteuid() function.
**
** Note that the initial value of the saved euid is zero, to simulate
** a setuid-root program.
**
** Parameters:
** none
**
** Returns:
** emulated euid if in emulation mode, else true euid.
*/
{
if (sendmail_mpe_emuluid())
return sendmail_mpe_euid;
return geteuid();
}
/*
** SENDMAIL_MPE_SETGID -- shadow function for setgid()
**
** Simulate a call to setgid() without actually calling the real
** function. Implement the expected uid 0 semantics.
**
** Note that sendmail will also be calling setuid() which will force an
** implicit real setgid() to the proper primary gid. So it doesn't matter
** that we don't actually alter the real gid in this shadow function.
**
** Parameters:
** gid -- desired gid.
**
** Returns:
** 0 -- emulated success
** -1 -- emulated failure
*/
int
{
if (sendmail_mpe_emulgid())
{
{
return 0;
}
return -1;
}
}
/*
** SENDMAIL_MPE_SETUID -- shadow function for setuid()
**
** setuid() is broken as of MPE 7.0 in that it changes the current
** working directory to be the home directory of the new uid. Thus
** we must obtain the cwd and restore it after the setuid().
**
** Note that expected uid 0 semantics have been added, as well as
** remembering the new uid for later use by the other shadow functions.
**
** Parameters:
** uid -- desired uid.
**
** Returns:
** 0 -- success
** -1 -- failure
**
** Globals:
** sendmail_mpe_euid
*/
int
{
char *cwd;
int result;
extern void GETPRIVMODE __P((void));
extern void GETUSERMODE __P((void));
if (sendmail_mpe_emuluid())
{
if (uid == 0)
{
if (sendmail_mpe_euid != 0)
{
return -1;
}
sendmail_mpe_euid = 0;
return 0;
}
/* Preserve the current working directory */
return -1;
GETPRIVMODE();
GETUSERMODE();
/* Restore the current working directory */
if (result == 0)
return result;
}
}
#endif /* MPE */