190792Sgshapiro/*
2261370Sgshapiro * Copyright (c) 2001-2002 Proofpoint, Inc. and its suppliers.
390792Sgshapiro *	All rights reserved.
490792Sgshapiro *
590792Sgshapiro * By using this file, you agree to the terms and conditions set
690792Sgshapiro * forth in the LICENSE file which can be found at the top level of
790792Sgshapiro * the sendmail distribution.
890792Sgshapiro *
990792Sgshapiro */
1090792Sgshapiro
1190792Sgshapiro#include <sm/gen.h>
12266711SgshapiroSM_RCSID("@(#)$Id: mpeix.c,v 1.8 2013-11-22 20:51:43 ca Exp $")
1390792Sgshapiro
1490792Sgshapiro#ifdef MPE
1590792Sgshapiro/*
1690792Sgshapiro**	MPE lacks many common functions required across all sendmail programs
1790792Sgshapiro**	so we define implementations for these functions here.
1890792Sgshapiro*/
1990792Sgshapiro
2090792Sgshapiro# include <errno.h>
2190792Sgshapiro# include <fcntl.h>
2290792Sgshapiro# include <limits.h>
2390792Sgshapiro# include <mpe.h>
2490792Sgshapiro# include <netinet/in.h>
2590792Sgshapiro# include <pwd.h>
2690792Sgshapiro# include <sys/socket.h>
2790792Sgshapiro# include <sys/stat.h>
2890792Sgshapiro# include <unistd.h>
2990792Sgshapiro# include <sm/conf.h>
3090792Sgshapiro
3190792Sgshapiro/*
3290792Sgshapiro**  CHROOT -- dummy chroot() function
3390792Sgshapiro**
3490792Sgshapiro**	The MPE documentation for sendmail says that chroot-based
3590792Sgshapiro**	functionality is not implemented because MPE lacks chroot.  But
3690792Sgshapiro**	rather than mucking around with all the sendmail calls to chroot,
3790792Sgshapiro**	we define this dummy function to return an ENOSYS failure just in
3890792Sgshapiro**	case a sendmail user attempts to enable chroot-based functionality.
3990792Sgshapiro**
4090792Sgshapiro**	Parameters:
4190792Sgshapiro**		path -- pathname of new root (ignored).
4290792Sgshapiro**
4390792Sgshapiro**	Returns:
4490792Sgshapiro**		-1 and errno == ENOSYS (function not implemented)
4590792Sgshapiro*/
4690792Sgshapiro
4790792Sgshapiroint
4890792Sgshapirochroot(path)
4990792Sgshapiro	char *path;
5090792Sgshapiro{
5190792Sgshapiro	errno = ENOSYS;
5290792Sgshapiro	return -1;
5390792Sgshapiro}
5490792Sgshapiro
5590792Sgshapiro/*
5690792Sgshapiro**  ENDPWENT -- dummy endpwent() function
5790792Sgshapiro**
5890792Sgshapiro**	Parameters:
5990792Sgshapiro**		none
6090792Sgshapiro**
6190792Sgshapiro**	Returns:
6290792Sgshapiro**		none
6390792Sgshapiro*/
6490792Sgshapiro
6590792Sgshapirovoid
6690792Sgshapiroendpwent()
6790792Sgshapiro{
6890792Sgshapiro	return;
6990792Sgshapiro}
7090792Sgshapiro
7190792Sgshapiro/*
7290792Sgshapiro**  In addition to missing functions, certain existing MPE functions have
7390792Sgshapiro**  slightly different semantics (or bugs) compared to normal Unix OSes.
7490792Sgshapiro**
7590792Sgshapiro**  Here we define wrappers for these functions to make them behave in the
7690792Sgshapiro**  manner expected by sendmail.
7790792Sgshapiro*/
7890792Sgshapiro
7990792Sgshapiro/*
8090792Sgshapiro**  SENDMAIL_MPE_BIND -- shadow function for the standard socket bind()
8190792Sgshapiro**
8290792Sgshapiro**	MPE requires GETPRIVMODE() for AF_INET sockets less than port 1024.
8390792Sgshapiro**
8490792Sgshapiro**	Parameters:
8590792Sgshapiro**		sd -- socket descriptor.
8690792Sgshapiro**		addr -- socket address.
8790792Sgshapiro**		addrlen -- length of socket address.
8890792Sgshapiro**
8990792Sgshapiro**	Results:
9090792Sgshapiro**		0 -- success
9190792Sgshapiro**		!= 0 -- failure
9290792Sgshapiro*/
9390792Sgshapiro
9490792Sgshapiro#undef bind
9590792Sgshapiroint
9690792Sgshapirosendmail_mpe_bind(sd, addr, addrlen)
9790792Sgshapiro	int sd;
9890792Sgshapiro	void *addr;
9990792Sgshapiro	int addrlen;
10090792Sgshapiro{
10190792Sgshapiro	bool priv = false;
10290792Sgshapiro	int result;
10390792Sgshapiro	extern void GETPRIVMODE __P((void));
10490792Sgshapiro	extern void GETUSERMODE __P((void));
10590792Sgshapiro
10690792Sgshapiro	if (addrlen == sizeof(struct sockaddr_in) &&
10790792Sgshapiro	    ((struct sockaddr_in *)addr)->sin_family == AF_INET)
10890792Sgshapiro	{
10990792Sgshapiro		/* AF_INET */
11090792Sgshapiro		if (((struct sockaddr_in *)addr)->sin_port > 0 &&
11190792Sgshapiro		    ((struct sockaddr_in *)addr)->sin_port < 1024)
11290792Sgshapiro		{
11390792Sgshapiro			priv = true;
11490792Sgshapiro			GETPRIVMODE();
11590792Sgshapiro		}
11690792Sgshapiro		((struct sockaddr_in *)addr)->sin_addr.s_addr = 0;
11790792Sgshapiro		result = bind(sd, addr, addrlen);
11890792Sgshapiro		if (priv)
11990792Sgshapiro			GETUSERMODE();
12090792Sgshapiro		return result;
12190792Sgshapiro	}
12290792Sgshapiro
12390792Sgshapiro	/* AF_UNIX */
12490792Sgshapiro	return bind(sd, addr, addrlen);
12590792Sgshapiro}
12690792Sgshapiro
12790792Sgshapiro/*
12890792Sgshapiro**  SENDMAIL_MPE__EXIT -- wait for children to terminate, then _exit()
12990792Sgshapiro**
13090792Sgshapiro**	Child processes cannot survive the death of their parent on MPE, so
13190792Sgshapiro**	we must call wait() before _exit() in order to prevent this
13290792Sgshapiro**	infanticide.
13390792Sgshapiro**
13490792Sgshapiro**	Parameters:
13590792Sgshapiro**		status -- _exit status value.
13690792Sgshapiro**
13790792Sgshapiro**	Returns:
13890792Sgshapiro**		none.
13990792Sgshapiro*/
14090792Sgshapiro
14190792Sgshapiro#undef _exit
14290792Sgshapirovoid
14390792Sgshapirosendmail_mpe__exit(status)
14490792Sgshapiro	int status;
14590792Sgshapiro{
14690792Sgshapiro	int result;
14790792Sgshapiro
14890792Sgshapiro	/* Wait for all children to terminate. */
14990792Sgshapiro	do
15090792Sgshapiro	{
15190792Sgshapiro		result = wait(NULL);
15290792Sgshapiro	} while (result > 0 || errno == EINTR);
15390792Sgshapiro	_exit(status);
15490792Sgshapiro}
15590792Sgshapiro
15690792Sgshapiro/*
15790792Sgshapiro**  SENDMAIL_MPE_EXIT -- wait for children to terminate, then exit()
15890792Sgshapiro**
15990792Sgshapiro**	Child processes cannot survive the death of their parent on MPE, so
16090792Sgshapiro**	we must call wait() before exit() in order to prevent this
16190792Sgshapiro**	infanticide.
16290792Sgshapiro**
16390792Sgshapiro**	Parameters:
16490792Sgshapiro**		status -- exit status value.
16590792Sgshapiro**
16690792Sgshapiro**	Returns:
16790792Sgshapiro**		none.
16890792Sgshapiro*/
16990792Sgshapiro
17090792Sgshapiro#undef exit
17190792Sgshapirovoid
17290792Sgshapirosendmail_mpe_exit(status)
17390792Sgshapiro	int status;
17490792Sgshapiro{
17590792Sgshapiro	int result;
17690792Sgshapiro
17790792Sgshapiro	/* Wait for all children to terminate. */
17890792Sgshapiro	do
17990792Sgshapiro	{
18090792Sgshapiro		result = wait(NULL);
18190792Sgshapiro	} while (result > 0 || errno == EINTR);
18290792Sgshapiro	exit(status);
18390792Sgshapiro}
18490792Sgshapiro
18590792Sgshapiro/*
18690792Sgshapiro**  SENDMAIL_MPE_FCNTL -- shadow function for fcntl()
18790792Sgshapiro**
18890792Sgshapiro**	MPE requires sfcntl() for sockets, and fcntl() for everything
18990792Sgshapiro**	else.  This shadow routine determines the descriptor type and
19090792Sgshapiro**	makes the appropriate call.
19190792Sgshapiro**
19290792Sgshapiro**	Parameters:
19390792Sgshapiro**		same as fcntl().
19490792Sgshapiro**
19590792Sgshapiro**	Returns:
19690792Sgshapiro**		same as fcntl().
19790792Sgshapiro*/
19890792Sgshapiro
19990792Sgshapiro#undef fcntl
20090792Sgshapiroint
20190792Sgshapirosendmail_mpe_fcntl(int fildes, int cmd, ...)
20290792Sgshapiro{
20390792Sgshapiro	int len, result;
20490792Sgshapiro	struct sockaddr sa;
20590792Sgshapiro
20690792Sgshapiro	void *arg;
20790792Sgshapiro	va_list ap;
20890792Sgshapiro
20990792Sgshapiro	va_start(ap, cmd);
21090792Sgshapiro	arg = va_arg(ap, void *);
21190792Sgshapiro	va_end(ap);
21290792Sgshapiro
21390792Sgshapiro	len = sizeof sa;
21490792Sgshapiro	if (getsockname(fildes, &sa, &len) == -1)
21590792Sgshapiro	{
21690792Sgshapiro		if (errno == EAFNOSUPPORT)
21790792Sgshapiro		{
21890792Sgshapiro			/* AF_UNIX socket */
21990792Sgshapiro			return sfcntl(fildes, cmd, arg);
22090792Sgshapiro		}
22190792Sgshapiro		else if (errno == ENOTSOCK)
22290792Sgshapiro		{
22390792Sgshapiro			/* file or pipe */
22490792Sgshapiro			return fcntl(fildes, cmd, arg);
22590792Sgshapiro		}
22690792Sgshapiro
22790792Sgshapiro		/* unknown getsockname() failure */
22890792Sgshapiro		return (-1);
22990792Sgshapiro	}
23090792Sgshapiro	else
23190792Sgshapiro	{
23290792Sgshapiro		/* AF_INET socket */
23390792Sgshapiro		if ((result = sfcntl(fildes, cmd, arg)) != -1 &&
23490792Sgshapiro		    cmd == F_GETFL)
23590792Sgshapiro			result |= O_RDWR;  /* fill in some missing flags */
23690792Sgshapiro		return result;
23790792Sgshapiro	}
23890792Sgshapiro}
23990792Sgshapiro
24090792Sgshapiro/*
24190792Sgshapiro**  SENDMAIL_MPE_GETPWNAM - shadow function for getpwnam()
24290792Sgshapiro**
24390792Sgshapiro**	Several issues apply here:
24490792Sgshapiro**
24590792Sgshapiro**	- MPE user names MUST have one '.' separator character
24690792Sgshapiro**	- MPE user names MUST be in upper case
24790792Sgshapiro**	- MPE does not initialize all fields in the passwd struct
24890792Sgshapiro**
24990792Sgshapiro**	Parameters:
25090792Sgshapiro**		name -- username string.
25190792Sgshapiro**
25290792Sgshapiro**	Returns:
25390792Sgshapiro**		pointer to struct passwd if found else NULL
25490792Sgshapiro*/
25590792Sgshapiro
25690792Sgshapirostatic char *sendmail_mpe_nullstr = "";
25790792Sgshapiro
25890792Sgshapiro#undef getpwnam
25990792Sgshapiroextern struct passwd *getpwnam(const char *);
26090792Sgshapiro
26190792Sgshapirostruct passwd *
26290792Sgshapirosendmail_mpe_getpwnam(name)
26390792Sgshapiro	const char *name;
26490792Sgshapiro{
26590792Sgshapiro	int dots = 0;
26690792Sgshapiro	int err;
26790792Sgshapiro	int i = strlen(name);
26890792Sgshapiro	char *upper;
26990792Sgshapiro	struct passwd *result = NULL;
27090792Sgshapiro
27190792Sgshapiro	if (i <= 0)
27290792Sgshapiro	{
27390792Sgshapiro		errno = EINVAL;
27490792Sgshapiro		return result;
27590792Sgshapiro	}
27690792Sgshapiro
27790792Sgshapiro	if ((upper = (char *)malloc(i + 1)) != NULL)
27890792Sgshapiro	{
27990792Sgshapiro		/* upshift the username parameter and count the dots */
28090792Sgshapiro		while (i >= 0)
28190792Sgshapiro		{
28290792Sgshapiro			if (name[i] == '.')
28390792Sgshapiro			{
28490792Sgshapiro				dots++;
28590792Sgshapiro				upper[i] = '.';
28690792Sgshapiro			}
28790792Sgshapiro			else
28890792Sgshapiro				upper[i] = toupper(name[i]);
28990792Sgshapiro			i--;
29090792Sgshapiro		}
29190792Sgshapiro
29290792Sgshapiro		if (dots != 1)
29390792Sgshapiro		{
29490792Sgshapiro			/* prevent bug when dots == 0 */
29590792Sgshapiro			err = EINVAL;
29690792Sgshapiro		}
29790792Sgshapiro		else if ((result = getpwnam(upper)) != NULL)
29890792Sgshapiro		{
29990792Sgshapiro			/* init the uninitialized fields */
30090792Sgshapiro			result->pw_gecos = sendmail_mpe_nullstr;
30190792Sgshapiro			result->pw_passwd = sendmail_mpe_nullstr;
30290792Sgshapiro			result->pw_age = sendmail_mpe_nullstr;
30390792Sgshapiro			result->pw_comment = sendmail_mpe_nullstr;
30490792Sgshapiro			result->pw_audid = 0;
30590792Sgshapiro			result->pw_audflg = 0;
30690792Sgshapiro		}
30790792Sgshapiro		err = errno;
30890792Sgshapiro		free(upper);
30990792Sgshapiro	}
31090792Sgshapiro	errno = err;
31190792Sgshapiro	return result;
31290792Sgshapiro}
31390792Sgshapiro
31490792Sgshapiro/*
31590792Sgshapiro**  SENDMAIL_MPE_GETPWUID -- shadow function for getpwuid()
31690792Sgshapiro**
31790792Sgshapiro**	Initializes the uninitalized fields in the passwd struct.
31890792Sgshapiro**
31990792Sgshapiro**	Parameters:
32090792Sgshapiro**		uid -- uid to obtain passwd data for
32190792Sgshapiro**
32290792Sgshapiro**	Returns:
32390792Sgshapiro**		pointer to struct passwd or NULL if not found
32490792Sgshapiro*/
32590792Sgshapiro
32690792Sgshapiro#undef getpwuid
32790792Sgshapiroextern struct passwd *getpwuid __P((uid_t));
32890792Sgshapiro
32990792Sgshapirostruct passwd *
33090792Sgshapirosendmail_mpe_getpwuid(uid)
33190792Sgshapiro	uid_t uid;
33290792Sgshapiro{
33390792Sgshapiro	struct passwd *result;
33490792Sgshapiro
33590792Sgshapiro	if ((result = getpwuid(uid)) != NULL)
33690792Sgshapiro	{
33790792Sgshapiro		/* initialize the uninitialized fields */
33890792Sgshapiro		result->pw_gecos = sendmail_mpe_nullstr;
33990792Sgshapiro		result->pw_passwd = sendmail_mpe_nullstr;
34090792Sgshapiro		result->pw_age = sendmail_mpe_nullstr;
34190792Sgshapiro		result->pw_comment = sendmail_mpe_nullstr;
34290792Sgshapiro		result->pw_audid = 0;
34390792Sgshapiro		result->pw_audflg = 0;
34490792Sgshapiro	}
34590792Sgshapiro	return result;
34690792Sgshapiro}
34790792Sgshapiro
34890792Sgshapiro/*
34990792Sgshapiro**  OK boys and girls, time for some serious voodoo!
35090792Sgshapiro**
35190792Sgshapiro**  MPE does not have a complete implementation of POSIX users and groups:
35290792Sgshapiro**
35390792Sgshapiro**  - there is no uid 0 superuser
35490792Sgshapiro**  - setuid/setgid file permission bits exist but have no-op functionality
35590792Sgshapiro**  - setgid() exists, but only supports new gid == current gid (boring!)
35690792Sgshapiro**  - setuid() forces a gid change to the new uid's primary (and only) gid
35790792Sgshapiro**
35890792Sgshapiro**  ...all of which thoroughly annoys sendmail.
35990792Sgshapiro**
36090792Sgshapiro**  So what to do?  We can't go on an #ifdef MPE rampage throughout
36190792Sgshapiro**  sendmail, because there are only about a zillion references to uid 0
36290792Sgshapiro**  and so success (and security) would probably be rather dubious by the
36390792Sgshapiro**  time we finished.
36490792Sgshapiro**
36590792Sgshapiro**  Instead we take the approach of defining wrapper functions for the
36690792Sgshapiro**  gid/uid management functions getegid(), geteuid(), setgid(), and
36790792Sgshapiro**  setuid() in order to implement the following model:
36890792Sgshapiro**
36990792Sgshapiro**  - the sendmail program thinks it is a setuid-root (uid 0) program
37090792Sgshapiro**  - uid 0 is recognized as being valid, but does not grant extra powers
37190792Sgshapiro**	- MPE priv mode allows sendmail to call setuid(), not uid 0
37290792Sgshapiro**	- file access is still controlled by the real non-zero uid
37390792Sgshapiro**  - the other programs (vacation, etc) have standard MPE POSIX behavior
37490792Sgshapiro**
37590792Sgshapiro**  This emulation model is activated by use of the program file setgid and
37690792Sgshapiro**  setuid mode bits which exist but are unused by MPE.  If the setgid mode
37790792Sgshapiro**  bit is on, then gid emulation will be enabled.  If the setuid mode bit is
37890792Sgshapiro**  on, then uid emulation will be enabled.  So for the mail daemon, we need
37990792Sgshapiro**  to do chmod u+s,g+s /SENDMAIL/CURRENT/SENDMAIL.
38090792Sgshapiro**
38190792Sgshapiro**  The following flags determine the current emulation state:
38290792Sgshapiro**
38390792Sgshapiro**  true == emulation enabled
38490792Sgshapiro**  false == emulation disabled, use unmodified MPE semantics
38590792Sgshapiro*/
38690792Sgshapiro
38790792Sgshapirostatic bool sendmail_mpe_flaginit = false;
38890792Sgshapirostatic bool sendmail_mpe_gidflag = false;
38990792Sgshapirostatic bool sendmail_mpe_uidflag = false;
39090792Sgshapiro
39190792Sgshapiro/*
39290792Sgshapiro**  SENDMAIL_MPE_GETMODE -- return the mode bits for the current process
39390792Sgshapiro**
39490792Sgshapiro**	Parameters:
39590792Sgshapiro**		none.
39690792Sgshapiro**
39790792Sgshapiro**	Returns:
39890792Sgshapiro**		file mode bits for the current process program file.
39990792Sgshapiro*/
40090792Sgshapiro
40190792Sgshapiromode_t
40290792Sgshapirosendmail_mpe_getmode()
40390792Sgshapiro{
40490792Sgshapiro	int status = 666;
40590792Sgshapiro	int myprogram_length;
40690792Sgshapiro	int myprogram_syntax = 2;
40790792Sgshapiro	char formaldesig[28];
40890792Sgshapiro	char myprogram[PATH_MAX + 2];
40990792Sgshapiro	char path[PATH_MAX + 1];
41090792Sgshapiro	struct stat st;
41190792Sgshapiro	extern HPMYPROGRAM __P((int parms, char *formaldesig, int *status,
41290792Sgshapiro				int *length, char *myprogram,
41390792Sgshapiro				int *myprogram_length, int *myprogram_syntax));
41490792Sgshapiro
41590792Sgshapiro	myprogram_length = sizeof(myprogram);
41690792Sgshapiro	HPMYPROGRAM(6, formaldesig, &status, NULL, myprogram,
41790792Sgshapiro		    &myprogram_length, &myprogram_syntax);
41890792Sgshapiro
41990792Sgshapiro	/* should not occur, do not attempt emulation */
42090792Sgshapiro	if (status != 0)
42190792Sgshapiro		return 0;
42290792Sgshapiro
42390792Sgshapiro	memcpy(&path, &myprogram[1], myprogram_length - 2);
42490792Sgshapiro	path[myprogram_length - 2] = '\0';
42590792Sgshapiro
42690792Sgshapiro	/* should not occur, do not attempt emulation */
42790792Sgshapiro	if (stat(path, &st) < 0)
42890792Sgshapiro		return 0;
42990792Sgshapiro
43090792Sgshapiro	return st.st_mode;
43190792Sgshapiro}
43290792Sgshapiro
43390792Sgshapiro/*
43490792Sgshapiro**  SENDMAIL_MPE_EMULGID -- should we perform gid emulation?
43590792Sgshapiro**
43690792Sgshapiro**	If !sendmail_mpe_flaginit then obtain the mode bits to determine
43790792Sgshapiro**	if the setgid bit is on, we want gid emulation and so set
43890792Sgshapiro**	sendmail_mpe_gidflag to true.  Otherwise we do not want gid emulation
43990792Sgshapiro**	and so set sendmail_mpe_gidflag to false.
44090792Sgshapiro**
44190792Sgshapiro**	Parameters:
44290792Sgshapiro**		none.
44390792Sgshapiro**
44490792Sgshapiro**	Returns:
44590792Sgshapiro**		true -- perform gid emulation
44690792Sgshapiro**		false -- do not perform gid emulation
44790792Sgshapiro*/
44890792Sgshapiro
44990792Sgshapirobool
45090792Sgshapirosendmail_mpe_emulgid()
45190792Sgshapiro{
45290792Sgshapiro	if (!sendmail_mpe_flaginit)
45390792Sgshapiro	{
45490792Sgshapiro		mode_t mode;
45590792Sgshapiro
45690792Sgshapiro		mode = sendmail_mpe_getmode();
45790792Sgshapiro		sendmail_mpe_gidflag = ((mode & S_ISGID) == S_ISGID);
45890792Sgshapiro		sendmail_mpe_uidflag = ((mode & S_ISUID) == S_ISUID);
45990792Sgshapiro		sendmail_mpe_flaginit = true;
46090792Sgshapiro	}
46190792Sgshapiro	return sendmail_mpe_gidflag;
46290792Sgshapiro}
46390792Sgshapiro
46490792Sgshapiro/*
46590792Sgshapiro**  SENDMAIL_MPE_EMULUID -- should we perform uid emulation?
46690792Sgshapiro**
46790792Sgshapiro**	If sendmail_mpe_uidflag == -1 then obtain the mode bits to determine
46890792Sgshapiro**	if the setuid bit is on, we want uid emulation and so set
46990792Sgshapiro**	sendmail_mpe_uidflag to true.  Otherwise we do not want uid emulation
47090792Sgshapiro**	and so set sendmail_mpe_uidflag to false.
47190792Sgshapiro**
47290792Sgshapiro**	Parameters:
47390792Sgshapiro**		none.
47490792Sgshapiro**
47590792Sgshapiro**	Returns:
47690792Sgshapiro**		true -- perform uid emulation
47790792Sgshapiro**		false -- do not perform uid emulation
47890792Sgshapiro*/
47990792Sgshapiro
48090792Sgshapirobool
48190792Sgshapirosendmail_mpe_emuluid()
48290792Sgshapiro{
48390792Sgshapiro	if (!sendmail_mpe_flaginit)
48490792Sgshapiro	{
48590792Sgshapiro		mode_t mode;
48690792Sgshapiro
48790792Sgshapiro		mode = sendmail_mpe_getmode();
48890792Sgshapiro		sendmail_mpe_gidflag = ((mode & S_ISGID) == S_ISGID);
48990792Sgshapiro		sendmail_mpe_uidflag = ((mode & S_ISUID) == S_ISUID);
49090792Sgshapiro		sendmail_mpe_flaginit = true;
49190792Sgshapiro	}
49290792Sgshapiro	return sendmail_mpe_uidflag;
49390792Sgshapiro}
49490792Sgshapiro
49590792Sgshapiro/*
49690792Sgshapiro**  SENDMAIL_MPE_GETEGID -- shadow function for getegid()
49790792Sgshapiro**
49890792Sgshapiro**	If emulation mode is in effect and the saved egid has been
49990792Sgshapiro**	initialized, return the saved egid; otherwise return the value of the
50090792Sgshapiro**	real getegid() function.
50190792Sgshapiro**
50290792Sgshapiro**	Parameters:
50390792Sgshapiro**		none.
50490792Sgshapiro**
50590792Sgshapiro**	Returns:
50690792Sgshapiro**		emulated egid if present, else true egid.
50790792Sgshapiro*/
50890792Sgshapiro
509173340Sgshapirostatic gid_t sendmail_mpe_egid = -1;
51090792Sgshapiro
51190792Sgshapiro#undef getegid
51290792Sgshapirogid_t
51390792Sgshapirosendmail_mpe_getegid()
51490792Sgshapiro{
51590792Sgshapiro	if (sendmail_mpe_emulgid() && sendmail_mpe_egid != -1)
51690792Sgshapiro		return sendmail_mpe_egid;
51790792Sgshapiro	return getegid();
51890792Sgshapiro}
51990792Sgshapiro
52090792Sgshapiro/*
52190792Sgshapiro**  SENDMAIL_MPE_GETEUID -- shadow function for geteuid()
52290792Sgshapiro**
52390792Sgshapiro**	If emulation mode is in effect, return the saved euid; otherwise
52490792Sgshapiro**	return the value of the real geteuid() function.
52590792Sgshapiro**
52690792Sgshapiro**	Note that the initial value of the saved euid is zero, to simulate
52790792Sgshapiro**	a setuid-root program.
52890792Sgshapiro**
52990792Sgshapiro**	Parameters:
53090792Sgshapiro**		none
53190792Sgshapiro**
53290792Sgshapiro**	Returns:
53390792Sgshapiro**		emulated euid if in emulation mode, else true euid.
53490792Sgshapiro*/
53590792Sgshapiro
53690792Sgshapirostatic uid_t sendmail_mpe_euid = 0;
53790792Sgshapiro
53890792Sgshapiro#undef geteuid
53990792Sgshapirouid_t
54090792Sgshapirosendmail_mpe_geteuid()
54190792Sgshapiro{
54290792Sgshapiro	if (sendmail_mpe_emuluid())
54390792Sgshapiro		return sendmail_mpe_euid;
54490792Sgshapiro	return geteuid();
54590792Sgshapiro}
54690792Sgshapiro
54790792Sgshapiro/*
54890792Sgshapiro**  SENDMAIL_MPE_SETGID -- shadow function for setgid()
54990792Sgshapiro**
55090792Sgshapiro**	Simulate a call to setgid() without actually calling the real
55190792Sgshapiro**	function.  Implement the expected uid 0 semantics.
55290792Sgshapiro**
55390792Sgshapiro**	Note that sendmail will also be calling setuid() which will force an
55490792Sgshapiro**	implicit real setgid() to the proper primary gid.  So it doesn't matter
55590792Sgshapiro**	that we don't actually alter the real gid in this shadow function.
55690792Sgshapiro**
55790792Sgshapiro**	Parameters:
55890792Sgshapiro**		gid -- desired gid.
55990792Sgshapiro**
56090792Sgshapiro**	Returns:
56190792Sgshapiro**		0 -- emulated success
56290792Sgshapiro**		-1 -- emulated failure
56390792Sgshapiro*/
56490792Sgshapiro
56590792Sgshapiro#undef setgid
56690792Sgshapiroint
56790792Sgshapirosendmail_mpe_setgid(gid)
56890792Sgshapiro	gid_t gid;
56990792Sgshapiro{
57090792Sgshapiro	if (sendmail_mpe_emulgid())
57190792Sgshapiro	{
57290792Sgshapiro		if (gid == getgid() || sendmail_mpe_euid == 0)
57390792Sgshapiro		{
57490792Sgshapiro			sendmail_mpe_egid = gid;
57590792Sgshapiro			return 0;
57690792Sgshapiro		}
57790792Sgshapiro		errno = EINVAL;
57890792Sgshapiro		return -1;
57990792Sgshapiro	}
58090792Sgshapiro	return setgid(gid);
58190792Sgshapiro}
58290792Sgshapiro
58390792Sgshapiro/*
58490792Sgshapiro**  SENDMAIL_MPE_SETUID -- shadow function for setuid()
58590792Sgshapiro**
58690792Sgshapiro**	setuid() is broken as of MPE 7.0 in that it changes the current
58790792Sgshapiro**	working directory to be the home directory of the new uid.  Thus
58890792Sgshapiro**	we must obtain the cwd and restore it after the setuid().
58990792Sgshapiro**
59090792Sgshapiro**	Note that expected uid 0 semantics have been added, as well as
59190792Sgshapiro**	remembering the new uid for later use by the other shadow functions.
59290792Sgshapiro**
59390792Sgshapiro**	Parameters:
59490792Sgshapiro**		uid -- desired uid.
59590792Sgshapiro**
59690792Sgshapiro**	Returns:
59790792Sgshapiro**		0 -- success
59890792Sgshapiro**		-1 -- failure
59990792Sgshapiro**
60090792Sgshapiro**	Globals:
60190792Sgshapiro**		sendmail_mpe_euid
60290792Sgshapiro*/
60390792Sgshapiro
60490792Sgshapiro#undef setuid
60590792Sgshapiroint
60690792Sgshapirosendmail_mpe_setuid(uid)
60790792Sgshapiro	uid_t uid;
60890792Sgshapiro{
60990792Sgshapiro	char *cwd;
61098121Sgshapiro	char cwd_buf[PATH_MAX + 1];
61190792Sgshapiro	int result;
61290792Sgshapiro	extern void GETPRIVMODE __P((void));
61390792Sgshapiro	extern void GETUSERMODE __P((void));
61490792Sgshapiro
61590792Sgshapiro	if (sendmail_mpe_emuluid())
61690792Sgshapiro	{
61790792Sgshapiro		if (uid == 0)
61890792Sgshapiro		{
61990792Sgshapiro			if (sendmail_mpe_euid != 0)
62090792Sgshapiro			{
62190792Sgshapiro				errno = EINVAL;
62290792Sgshapiro				return -1;
62390792Sgshapiro			}
62490792Sgshapiro			sendmail_mpe_euid = 0;
62590792Sgshapiro			return 0;
62690792Sgshapiro		}
62790792Sgshapiro
62890792Sgshapiro		/* Preserve the current working directory */
62990792Sgshapiro		if ((cwd = getcwd(cwd_buf, PATH_MAX + 1)) == NULL)
63090792Sgshapiro			return -1;
63190792Sgshapiro
63290792Sgshapiro		GETPRIVMODE();
63390792Sgshapiro		result = setuid(uid);
63490792Sgshapiro		GETUSERMODE();
63590792Sgshapiro
63690792Sgshapiro		/* Restore the current working directory */
63790792Sgshapiro		chdir(cwd_buf);
63890792Sgshapiro
63990792Sgshapiro		if (result == 0)
64090792Sgshapiro			sendmail_mpe_euid = uid;
64190792Sgshapiro
64290792Sgshapiro		return result;
64390792Sgshapiro	}
64490792Sgshapiro	return setuid(uid);
64590792Sgshapiro}
64690792Sgshapiro#endif /* MPE */
647