xref: /freebsd/contrib/sendmail/libsm/mpeix.c (revision d39bd2c1388b520fcba9abed1932acacead60fba)
140266059SGregory Neil Shapiro /*
25dd76dd0SGregory Neil Shapiro  * Copyright (c) 2001-2002 Proofpoint, Inc. and its suppliers.
340266059SGregory Neil Shapiro  *	All rights reserved.
440266059SGregory Neil Shapiro  *
540266059SGregory Neil Shapiro  * By using this file, you agree to the terms and conditions set
640266059SGregory Neil Shapiro  * forth in the LICENSE file which can be found at the top level of
740266059SGregory Neil Shapiro  * the sendmail distribution.
840266059SGregory Neil Shapiro  *
940266059SGregory Neil Shapiro  */
1040266059SGregory Neil Shapiro 
1140266059SGregory Neil Shapiro #include <sm/gen.h>
124313cc83SGregory Neil Shapiro SM_RCSID("@(#)$Id: mpeix.c,v 1.8 2013-11-22 20:51:43 ca Exp $")
1340266059SGregory Neil Shapiro 
1440266059SGregory Neil Shapiro #ifdef MPE
1540266059SGregory Neil Shapiro /*
1640266059SGregory Neil Shapiro **	MPE lacks many common functions required across all sendmail programs
1740266059SGregory Neil Shapiro **	so we define implementations for these functions here.
1840266059SGregory Neil Shapiro */
1940266059SGregory Neil Shapiro 
2040266059SGregory Neil Shapiro # include <errno.h>
2140266059SGregory Neil Shapiro # include <fcntl.h>
2240266059SGregory Neil Shapiro # include <limits.h>
2340266059SGregory Neil Shapiro # include <mpe.h>
2440266059SGregory Neil Shapiro # include <netinet/in.h>
2540266059SGregory Neil Shapiro # include <pwd.h>
2640266059SGregory Neil Shapiro # include <sys/socket.h>
2740266059SGregory Neil Shapiro # include <sys/stat.h>
2840266059SGregory Neil Shapiro # include <unistd.h>
2940266059SGregory Neil Shapiro # include <sm/conf.h>
3040266059SGregory Neil Shapiro 
3140266059SGregory Neil Shapiro /*
3240266059SGregory Neil Shapiro **  CHROOT -- dummy chroot() function
3340266059SGregory Neil Shapiro **
3440266059SGregory Neil Shapiro **	The MPE documentation for sendmail says that chroot-based
3540266059SGregory Neil Shapiro **	functionality is not implemented because MPE lacks chroot.  But
3640266059SGregory Neil Shapiro **	rather than mucking around with all the sendmail calls to chroot,
3740266059SGregory Neil Shapiro **	we define this dummy function to return an ENOSYS failure just in
3840266059SGregory Neil Shapiro **	case a sendmail user attempts to enable chroot-based functionality.
3940266059SGregory Neil Shapiro **
4040266059SGregory Neil Shapiro **	Parameters:
4140266059SGregory Neil Shapiro **		path -- pathname of new root (ignored).
4240266059SGregory Neil Shapiro **
4340266059SGregory Neil Shapiro **	Returns:
4440266059SGregory Neil Shapiro **		-1 and errno == ENOSYS (function not implemented)
4540266059SGregory Neil Shapiro */
4640266059SGregory Neil Shapiro 
4740266059SGregory Neil Shapiro int
4840266059SGregory Neil Shapiro chroot(path)
4940266059SGregory Neil Shapiro 	char *path;
5040266059SGregory Neil Shapiro {
5140266059SGregory Neil Shapiro 	errno = ENOSYS;
5240266059SGregory Neil Shapiro 	return -1;
5340266059SGregory Neil Shapiro }
5440266059SGregory Neil Shapiro 
5540266059SGregory Neil Shapiro /*
5640266059SGregory Neil Shapiro **  ENDPWENT -- dummy endpwent() function
5740266059SGregory Neil Shapiro **
5840266059SGregory Neil Shapiro **	Parameters:
5940266059SGregory Neil Shapiro **		none
6040266059SGregory Neil Shapiro **
6140266059SGregory Neil Shapiro **	Returns:
6240266059SGregory Neil Shapiro **		none
6340266059SGregory Neil Shapiro */
6440266059SGregory Neil Shapiro 
6540266059SGregory Neil Shapiro void
endpwent()6640266059SGregory Neil Shapiro endpwent()
6740266059SGregory Neil Shapiro {
6840266059SGregory Neil Shapiro 	return;
6940266059SGregory Neil Shapiro }
7040266059SGregory Neil Shapiro 
7140266059SGregory Neil Shapiro /*
7240266059SGregory Neil Shapiro **  In addition to missing functions, certain existing MPE functions have
7340266059SGregory Neil Shapiro **  slightly different semantics (or bugs) compared to normal Unix OSes.
7440266059SGregory Neil Shapiro **
7540266059SGregory Neil Shapiro **  Here we define wrappers for these functions to make them behave in the
7640266059SGregory Neil Shapiro **  manner expected by sendmail.
7740266059SGregory Neil Shapiro */
7840266059SGregory Neil Shapiro 
7940266059SGregory Neil Shapiro /*
8040266059SGregory Neil Shapiro **  SENDMAIL_MPE_BIND -- shadow function for the standard socket bind()
8140266059SGregory Neil Shapiro **
8240266059SGregory Neil Shapiro **	MPE requires GETPRIVMODE() for AF_INET sockets less than port 1024.
8340266059SGregory Neil Shapiro **
8440266059SGregory Neil Shapiro **	Parameters:
8540266059SGregory Neil Shapiro **		sd -- socket descriptor.
8640266059SGregory Neil Shapiro **		addr -- socket address.
8740266059SGregory Neil Shapiro **		addrlen -- length of socket address.
8840266059SGregory Neil Shapiro **
8940266059SGregory Neil Shapiro **	Results:
9040266059SGregory Neil Shapiro **		0 -- success
9140266059SGregory Neil Shapiro **		!= 0 -- failure
9240266059SGregory Neil Shapiro */
9340266059SGregory Neil Shapiro 
9440266059SGregory Neil Shapiro #undef bind
9540266059SGregory Neil Shapiro int
sendmail_mpe_bind(sd,addr,addrlen)9640266059SGregory Neil Shapiro sendmail_mpe_bind(sd, addr, addrlen)
9740266059SGregory Neil Shapiro 	int sd;
9840266059SGregory Neil Shapiro 	void *addr;
9940266059SGregory Neil Shapiro 	int addrlen;
10040266059SGregory Neil Shapiro {
10140266059SGregory Neil Shapiro 	bool priv = false;
10240266059SGregory Neil Shapiro 	int result;
10340266059SGregory Neil Shapiro 	extern void GETPRIVMODE __P((void));
10440266059SGregory Neil Shapiro 	extern void GETUSERMODE __P((void));
10540266059SGregory Neil Shapiro 
10640266059SGregory Neil Shapiro 	if (addrlen == sizeof(struct sockaddr_in) &&
10740266059SGregory Neil Shapiro 	    ((struct sockaddr_in *)addr)->sin_family == AF_INET)
10840266059SGregory Neil Shapiro 	{
10940266059SGregory Neil Shapiro 		/* AF_INET */
11040266059SGregory Neil Shapiro 		if (((struct sockaddr_in *)addr)->sin_port > 0 &&
11140266059SGregory Neil Shapiro 		    ((struct sockaddr_in *)addr)->sin_port < 1024)
11240266059SGregory Neil Shapiro 		{
11340266059SGregory Neil Shapiro 			priv = true;
11440266059SGregory Neil Shapiro 			GETPRIVMODE();
11540266059SGregory Neil Shapiro 		}
11640266059SGregory Neil Shapiro 		((struct sockaddr_in *)addr)->sin_addr.s_addr = 0;
11740266059SGregory Neil Shapiro 		result = bind(sd, addr, addrlen);
11840266059SGregory Neil Shapiro 		if (priv)
11940266059SGregory Neil Shapiro 			GETUSERMODE();
12040266059SGregory Neil Shapiro 		return result;
12140266059SGregory Neil Shapiro 	}
12240266059SGregory Neil Shapiro 
12340266059SGregory Neil Shapiro 	/* AF_UNIX */
12440266059SGregory Neil Shapiro 	return bind(sd, addr, addrlen);
12540266059SGregory Neil Shapiro }
12640266059SGregory Neil Shapiro 
12740266059SGregory Neil Shapiro /*
12840266059SGregory Neil Shapiro **  SENDMAIL_MPE__EXIT -- wait for children to terminate, then _exit()
12940266059SGregory Neil Shapiro **
13040266059SGregory Neil Shapiro **	Child processes cannot survive the death of their parent on MPE, so
13140266059SGregory Neil Shapiro **	we must call wait() before _exit() in order to prevent this
13240266059SGregory Neil Shapiro **	infanticide.
13340266059SGregory Neil Shapiro **
13440266059SGregory Neil Shapiro **	Parameters:
13540266059SGregory Neil Shapiro **		status -- _exit status value.
13640266059SGregory Neil Shapiro **
13740266059SGregory Neil Shapiro **	Returns:
13840266059SGregory Neil Shapiro **		none.
13940266059SGregory Neil Shapiro */
14040266059SGregory Neil Shapiro 
14140266059SGregory Neil Shapiro #undef _exit
14240266059SGregory Neil Shapiro void
sendmail_mpe__exit(status)14340266059SGregory Neil Shapiro sendmail_mpe__exit(status)
14440266059SGregory Neil Shapiro 	int status;
14540266059SGregory Neil Shapiro {
14640266059SGregory Neil Shapiro 	int result;
14740266059SGregory Neil Shapiro 
14840266059SGregory Neil Shapiro 	/* Wait for all children to terminate. */
14940266059SGregory Neil Shapiro 	do
15040266059SGregory Neil Shapiro 	{
15140266059SGregory Neil Shapiro 		result = wait(NULL);
15240266059SGregory Neil Shapiro 	} while (result > 0 || errno == EINTR);
15340266059SGregory Neil Shapiro 	_exit(status);
15440266059SGregory Neil Shapiro }
15540266059SGregory Neil Shapiro 
15640266059SGregory Neil Shapiro /*
15740266059SGregory Neil Shapiro **  SENDMAIL_MPE_EXIT -- wait for children to terminate, then exit()
15840266059SGregory Neil Shapiro **
15940266059SGregory Neil Shapiro **	Child processes cannot survive the death of their parent on MPE, so
16040266059SGregory Neil Shapiro **	we must call wait() before exit() in order to prevent this
16140266059SGregory Neil Shapiro **	infanticide.
16240266059SGregory Neil Shapiro **
16340266059SGregory Neil Shapiro **	Parameters:
16440266059SGregory Neil Shapiro **		status -- exit status value.
16540266059SGregory Neil Shapiro **
16640266059SGregory Neil Shapiro **	Returns:
16740266059SGregory Neil Shapiro **		none.
16840266059SGregory Neil Shapiro */
16940266059SGregory Neil Shapiro 
17040266059SGregory Neil Shapiro #undef exit
17140266059SGregory Neil Shapiro void
sendmail_mpe_exit(status)17240266059SGregory Neil Shapiro sendmail_mpe_exit(status)
17340266059SGregory Neil Shapiro 	int status;
17440266059SGregory Neil Shapiro {
17540266059SGregory Neil Shapiro 	int result;
17640266059SGregory Neil Shapiro 
17740266059SGregory Neil Shapiro 	/* Wait for all children to terminate. */
17840266059SGregory Neil Shapiro 	do
17940266059SGregory Neil Shapiro 	{
18040266059SGregory Neil Shapiro 		result = wait(NULL);
18140266059SGregory Neil Shapiro 	} while (result > 0 || errno == EINTR);
18240266059SGregory Neil Shapiro 	exit(status);
18340266059SGregory Neil Shapiro }
18440266059SGregory Neil Shapiro 
18540266059SGregory Neil Shapiro /*
18640266059SGregory Neil Shapiro **  SENDMAIL_MPE_FCNTL -- shadow function for fcntl()
18740266059SGregory Neil Shapiro **
18840266059SGregory Neil Shapiro **	MPE requires sfcntl() for sockets, and fcntl() for everything
18940266059SGregory Neil Shapiro **	else.  This shadow routine determines the descriptor type and
19040266059SGregory Neil Shapiro **	makes the appropriate call.
19140266059SGregory Neil Shapiro **
19240266059SGregory Neil Shapiro **	Parameters:
19340266059SGregory Neil Shapiro **		same as fcntl().
19440266059SGregory Neil Shapiro **
19540266059SGregory Neil Shapiro **	Returns:
19640266059SGregory Neil Shapiro **		same as fcntl().
19740266059SGregory Neil Shapiro */
19840266059SGregory Neil Shapiro 
19940266059SGregory Neil Shapiro #undef fcntl
20040266059SGregory Neil Shapiro int
sendmail_mpe_fcntl(int fildes,int cmd,...)20140266059SGregory Neil Shapiro sendmail_mpe_fcntl(int fildes, int cmd, ...)
20240266059SGregory Neil Shapiro {
20340266059SGregory Neil Shapiro 	int len, result;
20440266059SGregory Neil Shapiro 	struct sockaddr sa;
20540266059SGregory Neil Shapiro 
20640266059SGregory Neil Shapiro 	void *arg;
20740266059SGregory Neil Shapiro 	va_list ap;
20840266059SGregory Neil Shapiro 
20940266059SGregory Neil Shapiro 	va_start(ap, cmd);
21040266059SGregory Neil Shapiro 	arg = va_arg(ap, void *);
21140266059SGregory Neil Shapiro 	va_end(ap);
21240266059SGregory Neil Shapiro 
21340266059SGregory Neil Shapiro 	len = sizeof sa;
21440266059SGregory Neil Shapiro 	if (getsockname(fildes, &sa, &len) == -1)
21540266059SGregory Neil Shapiro 	{
21640266059SGregory Neil Shapiro 		if (errno == EAFNOSUPPORT)
21740266059SGregory Neil Shapiro 		{
21840266059SGregory Neil Shapiro 			/* AF_UNIX socket */
21940266059SGregory Neil Shapiro 			return sfcntl(fildes, cmd, arg);
22040266059SGregory Neil Shapiro 		}
22140266059SGregory Neil Shapiro 		else if (errno == ENOTSOCK)
22240266059SGregory Neil Shapiro 		{
22340266059SGregory Neil Shapiro 			/* file or pipe */
22440266059SGregory Neil Shapiro 			return fcntl(fildes, cmd, arg);
22540266059SGregory Neil Shapiro 		}
22640266059SGregory Neil Shapiro 
22740266059SGregory Neil Shapiro 		/* unknown getsockname() failure */
22840266059SGregory Neil Shapiro 		return (-1);
22940266059SGregory Neil Shapiro 	}
23040266059SGregory Neil Shapiro 	else
23140266059SGregory Neil Shapiro 	{
23240266059SGregory Neil Shapiro 		/* AF_INET socket */
23340266059SGregory Neil Shapiro 		if ((result = sfcntl(fildes, cmd, arg)) != -1 &&
23440266059SGregory Neil Shapiro 		    cmd == F_GETFL)
23540266059SGregory Neil Shapiro 			result |= O_RDWR;  /* fill in some missing flags */
23640266059SGregory Neil Shapiro 		return result;
23740266059SGregory Neil Shapiro 	}
23840266059SGregory Neil Shapiro }
23940266059SGregory Neil Shapiro 
24040266059SGregory Neil Shapiro /*
24140266059SGregory Neil Shapiro **  SENDMAIL_MPE_GETPWNAM - shadow function for getpwnam()
24240266059SGregory Neil Shapiro **
24340266059SGregory Neil Shapiro **	Several issues apply here:
24440266059SGregory Neil Shapiro **
24540266059SGregory Neil Shapiro **	- MPE user names MUST have one '.' separator character
24640266059SGregory Neil Shapiro **	- MPE user names MUST be in upper case
24740266059SGregory Neil Shapiro **	- MPE does not initialize all fields in the passwd struct
24840266059SGregory Neil Shapiro **
24940266059SGregory Neil Shapiro **	Parameters:
25040266059SGregory Neil Shapiro **		name -- username string.
25140266059SGregory Neil Shapiro **
25240266059SGregory Neil Shapiro **	Returns:
25340266059SGregory Neil Shapiro **		pointer to struct passwd if found else NULL
25440266059SGregory Neil Shapiro */
25540266059SGregory Neil Shapiro 
25640266059SGregory Neil Shapiro static char *sendmail_mpe_nullstr = "";
25740266059SGregory Neil Shapiro 
25840266059SGregory Neil Shapiro #undef getpwnam
25940266059SGregory Neil Shapiro extern struct passwd *getpwnam(const char *);
26040266059SGregory Neil Shapiro 
26140266059SGregory Neil Shapiro struct passwd *
sendmail_mpe_getpwnam(name)26240266059SGregory Neil Shapiro sendmail_mpe_getpwnam(name)
26340266059SGregory Neil Shapiro 	const char *name;
26440266059SGregory Neil Shapiro {
26540266059SGregory Neil Shapiro 	int dots = 0;
26640266059SGregory Neil Shapiro 	int err;
26740266059SGregory Neil Shapiro 	int i = strlen(name);
26840266059SGregory Neil Shapiro 	char *upper;
26940266059SGregory Neil Shapiro 	struct passwd *result = NULL;
27040266059SGregory Neil Shapiro 
27140266059SGregory Neil Shapiro 	if (i <= 0)
27240266059SGregory Neil Shapiro 	{
27340266059SGregory Neil Shapiro 		errno = EINVAL;
27440266059SGregory Neil Shapiro 		return result;
27540266059SGregory Neil Shapiro 	}
27640266059SGregory Neil Shapiro 
27740266059SGregory Neil Shapiro 	if ((upper = (char *)malloc(i + 1)) != NULL)
27840266059SGregory Neil Shapiro 	{
27940266059SGregory Neil Shapiro 		/* upshift the username parameter and count the dots */
28040266059SGregory Neil Shapiro 		while (i >= 0)
28140266059SGregory Neil Shapiro 		{
28240266059SGregory Neil Shapiro 			if (name[i] == '.')
28340266059SGregory Neil Shapiro 			{
28440266059SGregory Neil Shapiro 				dots++;
28540266059SGregory Neil Shapiro 				upper[i] = '.';
28640266059SGregory Neil Shapiro 			}
28740266059SGregory Neil Shapiro 			else
28840266059SGregory Neil Shapiro 				upper[i] = toupper(name[i]);
28940266059SGregory Neil Shapiro 			i--;
29040266059SGregory Neil Shapiro 		}
29140266059SGregory Neil Shapiro 
29240266059SGregory Neil Shapiro 		if (dots != 1)
29340266059SGregory Neil Shapiro 		{
29440266059SGregory Neil Shapiro 			/* prevent bug when dots == 0 */
29540266059SGregory Neil Shapiro 			err = EINVAL;
29640266059SGregory Neil Shapiro 		}
29740266059SGregory Neil Shapiro 		else if ((result = getpwnam(upper)) != NULL)
29840266059SGregory Neil Shapiro 		{
29940266059SGregory Neil Shapiro 			/* init the uninitialized fields */
30040266059SGregory Neil Shapiro 			result->pw_gecos = sendmail_mpe_nullstr;
30140266059SGregory Neil Shapiro 			result->pw_passwd = sendmail_mpe_nullstr;
30240266059SGregory Neil Shapiro 			result->pw_age = sendmail_mpe_nullstr;
30340266059SGregory Neil Shapiro 			result->pw_comment = sendmail_mpe_nullstr;
30440266059SGregory Neil Shapiro 			result->pw_audid = 0;
30540266059SGregory Neil Shapiro 			result->pw_audflg = 0;
30640266059SGregory Neil Shapiro 		}
30740266059SGregory Neil Shapiro 		err = errno;
30840266059SGregory Neil Shapiro 		free(upper);
30940266059SGregory Neil Shapiro 	}
31040266059SGregory Neil Shapiro 	errno = err;
31140266059SGregory Neil Shapiro 	return result;
31240266059SGregory Neil Shapiro }
31340266059SGregory Neil Shapiro 
31440266059SGregory Neil Shapiro /*
31540266059SGregory Neil Shapiro **  SENDMAIL_MPE_GETPWUID -- shadow function for getpwuid()
31640266059SGregory Neil Shapiro **
317*d39bd2c1SGregory Neil Shapiro **	Initializes the uninitialized fields in the passwd struct.
31840266059SGregory Neil Shapiro **
31940266059SGregory Neil Shapiro **	Parameters:
32040266059SGregory Neil Shapiro **		uid -- uid to obtain passwd data for
32140266059SGregory Neil Shapiro **
32240266059SGregory Neil Shapiro **	Returns:
32340266059SGregory Neil Shapiro **		pointer to struct passwd or NULL if not found
32440266059SGregory Neil Shapiro */
32540266059SGregory Neil Shapiro 
32640266059SGregory Neil Shapiro #undef getpwuid
32740266059SGregory Neil Shapiro extern struct passwd *getpwuid __P((uid_t));
32840266059SGregory Neil Shapiro 
32940266059SGregory Neil Shapiro struct passwd *
sendmail_mpe_getpwuid(uid)33040266059SGregory Neil Shapiro sendmail_mpe_getpwuid(uid)
33140266059SGregory Neil Shapiro 	uid_t uid;
33240266059SGregory Neil Shapiro {
33340266059SGregory Neil Shapiro 	struct passwd *result;
33440266059SGregory Neil Shapiro 
33540266059SGregory Neil Shapiro 	if ((result = getpwuid(uid)) != NULL)
33640266059SGregory Neil Shapiro 	{
33740266059SGregory Neil Shapiro 		/* initialize the uninitialized fields */
33840266059SGregory Neil Shapiro 		result->pw_gecos = sendmail_mpe_nullstr;
33940266059SGregory Neil Shapiro 		result->pw_passwd = sendmail_mpe_nullstr;
34040266059SGregory Neil Shapiro 		result->pw_age = sendmail_mpe_nullstr;
34140266059SGregory Neil Shapiro 		result->pw_comment = sendmail_mpe_nullstr;
34240266059SGregory Neil Shapiro 		result->pw_audid = 0;
34340266059SGregory Neil Shapiro 		result->pw_audflg = 0;
34440266059SGregory Neil Shapiro 	}
34540266059SGregory Neil Shapiro 	return result;
34640266059SGregory Neil Shapiro }
34740266059SGregory Neil Shapiro 
34840266059SGregory Neil Shapiro /*
34940266059SGregory Neil Shapiro **  OK boys and girls, time for some serious voodoo!
35040266059SGregory Neil Shapiro **
35140266059SGregory Neil Shapiro **  MPE does not have a complete implementation of POSIX users and groups:
35240266059SGregory Neil Shapiro **
35340266059SGregory Neil Shapiro **  - there is no uid 0 superuser
35440266059SGregory Neil Shapiro **  - setuid/setgid file permission bits exist but have no-op functionality
35540266059SGregory Neil Shapiro **  - setgid() exists, but only supports new gid == current gid (boring!)
35640266059SGregory Neil Shapiro **  - setuid() forces a gid change to the new uid's primary (and only) gid
35740266059SGregory Neil Shapiro **
35840266059SGregory Neil Shapiro **  ...all of which thoroughly annoys sendmail.
35940266059SGregory Neil Shapiro **
36040266059SGregory Neil Shapiro **  So what to do?  We can't go on an #ifdef MPE rampage throughout
36140266059SGregory Neil Shapiro **  sendmail, because there are only about a zillion references to uid 0
36240266059SGregory Neil Shapiro **  and so success (and security) would probably be rather dubious by the
36340266059SGregory Neil Shapiro **  time we finished.
36440266059SGregory Neil Shapiro **
36540266059SGregory Neil Shapiro **  Instead we take the approach of defining wrapper functions for the
36640266059SGregory Neil Shapiro **  gid/uid management functions getegid(), geteuid(), setgid(), and
36740266059SGregory Neil Shapiro **  setuid() in order to implement the following model:
36840266059SGregory Neil Shapiro **
36940266059SGregory Neil Shapiro **  - the sendmail program thinks it is a setuid-root (uid 0) program
37040266059SGregory Neil Shapiro **  - uid 0 is recognized as being valid, but does not grant extra powers
37140266059SGregory Neil Shapiro **	- MPE priv mode allows sendmail to call setuid(), not uid 0
37240266059SGregory Neil Shapiro **	- file access is still controlled by the real non-zero uid
37340266059SGregory Neil Shapiro **  - the other programs (vacation, etc) have standard MPE POSIX behavior
37440266059SGregory Neil Shapiro **
37540266059SGregory Neil Shapiro **  This emulation model is activated by use of the program file setgid and
37640266059SGregory Neil Shapiro **  setuid mode bits which exist but are unused by MPE.  If the setgid mode
37740266059SGregory Neil Shapiro **  bit is on, then gid emulation will be enabled.  If the setuid mode bit is
37840266059SGregory Neil Shapiro **  on, then uid emulation will be enabled.  So for the mail daemon, we need
37940266059SGregory Neil Shapiro **  to do chmod u+s,g+s /SENDMAIL/CURRENT/SENDMAIL.
38040266059SGregory Neil Shapiro **
38140266059SGregory Neil Shapiro **  The following flags determine the current emulation state:
38240266059SGregory Neil Shapiro **
38340266059SGregory Neil Shapiro **  true == emulation enabled
38440266059SGregory Neil Shapiro **  false == emulation disabled, use unmodified MPE semantics
38540266059SGregory Neil Shapiro */
38640266059SGregory Neil Shapiro 
38740266059SGregory Neil Shapiro static bool sendmail_mpe_flaginit = false;
38840266059SGregory Neil Shapiro static bool sendmail_mpe_gidflag = false;
38940266059SGregory Neil Shapiro static bool sendmail_mpe_uidflag = false;
39040266059SGregory Neil Shapiro 
39140266059SGregory Neil Shapiro /*
39240266059SGregory Neil Shapiro **  SENDMAIL_MPE_GETMODE -- return the mode bits for the current process
39340266059SGregory Neil Shapiro **
39440266059SGregory Neil Shapiro **	Parameters:
39540266059SGregory Neil Shapiro **		none.
39640266059SGregory Neil Shapiro **
39740266059SGregory Neil Shapiro **	Returns:
39840266059SGregory Neil Shapiro **		file mode bits for the current process program file.
39940266059SGregory Neil Shapiro */
40040266059SGregory Neil Shapiro 
40140266059SGregory Neil Shapiro mode_t
sendmail_mpe_getmode()40240266059SGregory Neil Shapiro sendmail_mpe_getmode()
40340266059SGregory Neil Shapiro {
40440266059SGregory Neil Shapiro 	int status = 666;
40540266059SGregory Neil Shapiro 	int myprogram_length;
40640266059SGregory Neil Shapiro 	int myprogram_syntax = 2;
40740266059SGregory Neil Shapiro 	char formaldesig[28];
40840266059SGregory Neil Shapiro 	char myprogram[PATH_MAX + 2];
40940266059SGregory Neil Shapiro 	char path[PATH_MAX + 1];
41040266059SGregory Neil Shapiro 	struct stat st;
41140266059SGregory Neil Shapiro 	extern HPMYPROGRAM __P((int parms, char *formaldesig, int *status,
41240266059SGregory Neil Shapiro 				int *length, char *myprogram,
41340266059SGregory Neil Shapiro 				int *myprogram_length, int *myprogram_syntax));
41440266059SGregory Neil Shapiro 
41540266059SGregory Neil Shapiro 	myprogram_length = sizeof(myprogram);
41640266059SGregory Neil Shapiro 	HPMYPROGRAM(6, formaldesig, &status, NULL, myprogram,
41740266059SGregory Neil Shapiro 		    &myprogram_length, &myprogram_syntax);
41840266059SGregory Neil Shapiro 
41940266059SGregory Neil Shapiro 	/* should not occur, do not attempt emulation */
42040266059SGregory Neil Shapiro 	if (status != 0)
42140266059SGregory Neil Shapiro 		return 0;
42240266059SGregory Neil Shapiro 
42340266059SGregory Neil Shapiro 	memcpy(&path, &myprogram[1], myprogram_length - 2);
42440266059SGregory Neil Shapiro 	path[myprogram_length - 2] = '\0';
42540266059SGregory Neil Shapiro 
42640266059SGregory Neil Shapiro 	/* should not occur, do not attempt emulation */
42740266059SGregory Neil Shapiro 	if (stat(path, &st) < 0)
42840266059SGregory Neil Shapiro 		return 0;
42940266059SGregory Neil Shapiro 
43040266059SGregory Neil Shapiro 	return st.st_mode;
43140266059SGregory Neil Shapiro }
43240266059SGregory Neil Shapiro 
43340266059SGregory Neil Shapiro /*
43440266059SGregory Neil Shapiro **  SENDMAIL_MPE_EMULGID -- should we perform gid emulation?
43540266059SGregory Neil Shapiro **
43640266059SGregory Neil Shapiro **	If !sendmail_mpe_flaginit then obtain the mode bits to determine
43740266059SGregory Neil Shapiro **	if the setgid bit is on, we want gid emulation and so set
43840266059SGregory Neil Shapiro **	sendmail_mpe_gidflag to true.  Otherwise we do not want gid emulation
43940266059SGregory Neil Shapiro **	and so set sendmail_mpe_gidflag to false.
44040266059SGregory Neil Shapiro **
44140266059SGregory Neil Shapiro **	Parameters:
44240266059SGregory Neil Shapiro **		none.
44340266059SGregory Neil Shapiro **
44440266059SGregory Neil Shapiro **	Returns:
44540266059SGregory Neil Shapiro **		true -- perform gid emulation
44640266059SGregory Neil Shapiro **		false -- do not perform gid emulation
44740266059SGregory Neil Shapiro */
44840266059SGregory Neil Shapiro 
44940266059SGregory Neil Shapiro bool
sendmail_mpe_emulgid()45040266059SGregory Neil Shapiro sendmail_mpe_emulgid()
45140266059SGregory Neil Shapiro {
45240266059SGregory Neil Shapiro 	if (!sendmail_mpe_flaginit)
45340266059SGregory Neil Shapiro 	{
45440266059SGregory Neil Shapiro 		mode_t mode;
45540266059SGregory Neil Shapiro 
45640266059SGregory Neil Shapiro 		mode = sendmail_mpe_getmode();
45740266059SGregory Neil Shapiro 		sendmail_mpe_gidflag = ((mode & S_ISGID) == S_ISGID);
45840266059SGregory Neil Shapiro 		sendmail_mpe_uidflag = ((mode & S_ISUID) == S_ISUID);
45940266059SGregory Neil Shapiro 		sendmail_mpe_flaginit = true;
46040266059SGregory Neil Shapiro 	}
46140266059SGregory Neil Shapiro 	return sendmail_mpe_gidflag;
46240266059SGregory Neil Shapiro }
46340266059SGregory Neil Shapiro 
46440266059SGregory Neil Shapiro /*
46540266059SGregory Neil Shapiro **  SENDMAIL_MPE_EMULUID -- should we perform uid emulation?
46640266059SGregory Neil Shapiro **
46740266059SGregory Neil Shapiro **	If sendmail_mpe_uidflag == -1 then obtain the mode bits to determine
46840266059SGregory Neil Shapiro **	if the setuid bit is on, we want uid emulation and so set
46940266059SGregory Neil Shapiro **	sendmail_mpe_uidflag to true.  Otherwise we do not want uid emulation
47040266059SGregory Neil Shapiro **	and so set sendmail_mpe_uidflag to false.
47140266059SGregory Neil Shapiro **
47240266059SGregory Neil Shapiro **	Parameters:
47340266059SGregory Neil Shapiro **		none.
47440266059SGregory Neil Shapiro **
47540266059SGregory Neil Shapiro **	Returns:
47640266059SGregory Neil Shapiro **		true -- perform uid emulation
47740266059SGregory Neil Shapiro **		false -- do not perform uid emulation
47840266059SGregory Neil Shapiro */
47940266059SGregory Neil Shapiro 
48040266059SGregory Neil Shapiro bool
sendmail_mpe_emuluid()48140266059SGregory Neil Shapiro sendmail_mpe_emuluid()
48240266059SGregory Neil Shapiro {
48340266059SGregory Neil Shapiro 	if (!sendmail_mpe_flaginit)
48440266059SGregory Neil Shapiro 	{
48540266059SGregory Neil Shapiro 		mode_t mode;
48640266059SGregory Neil Shapiro 
48740266059SGregory Neil Shapiro 		mode = sendmail_mpe_getmode();
48840266059SGregory Neil Shapiro 		sendmail_mpe_gidflag = ((mode & S_ISGID) == S_ISGID);
48940266059SGregory Neil Shapiro 		sendmail_mpe_uidflag = ((mode & S_ISUID) == S_ISUID);
49040266059SGregory Neil Shapiro 		sendmail_mpe_flaginit = true;
49140266059SGregory Neil Shapiro 	}
49240266059SGregory Neil Shapiro 	return sendmail_mpe_uidflag;
49340266059SGregory Neil Shapiro }
49440266059SGregory Neil Shapiro 
49540266059SGregory Neil Shapiro /*
49640266059SGregory Neil Shapiro **  SENDMAIL_MPE_GETEGID -- shadow function for getegid()
49740266059SGregory Neil Shapiro **
49840266059SGregory Neil Shapiro **	If emulation mode is in effect and the saved egid has been
49940266059SGregory Neil Shapiro **	initialized, return the saved egid; otherwise return the value of the
50040266059SGregory Neil Shapiro **	real getegid() function.
50140266059SGregory Neil Shapiro **
50240266059SGregory Neil Shapiro **	Parameters:
50340266059SGregory Neil Shapiro **		none.
50440266059SGregory Neil Shapiro **
50540266059SGregory Neil Shapiro **	Returns:
50640266059SGregory Neil Shapiro **		emulated egid if present, else true egid.
50740266059SGregory Neil Shapiro */
50840266059SGregory Neil Shapiro 
509ffb83623SGregory Neil Shapiro static gid_t sendmail_mpe_egid = -1;
51040266059SGregory Neil Shapiro 
51140266059SGregory Neil Shapiro #undef getegid
51240266059SGregory Neil Shapiro gid_t
sendmail_mpe_getegid()51340266059SGregory Neil Shapiro sendmail_mpe_getegid()
51440266059SGregory Neil Shapiro {
51540266059SGregory Neil Shapiro 	if (sendmail_mpe_emulgid() && sendmail_mpe_egid != -1)
51640266059SGregory Neil Shapiro 		return sendmail_mpe_egid;
51740266059SGregory Neil Shapiro 	return getegid();
51840266059SGregory Neil Shapiro }
51940266059SGregory Neil Shapiro 
52040266059SGregory Neil Shapiro /*
52140266059SGregory Neil Shapiro **  SENDMAIL_MPE_GETEUID -- shadow function for geteuid()
52240266059SGregory Neil Shapiro **
52340266059SGregory Neil Shapiro **	If emulation mode is in effect, return the saved euid; otherwise
52440266059SGregory Neil Shapiro **	return the value of the real geteuid() function.
52540266059SGregory Neil Shapiro **
52640266059SGregory Neil Shapiro **	Note that the initial value of the saved euid is zero, to simulate
52740266059SGregory Neil Shapiro **	a setuid-root program.
52840266059SGregory Neil Shapiro **
52940266059SGregory Neil Shapiro **	Parameters:
53040266059SGregory Neil Shapiro **		none
53140266059SGregory Neil Shapiro **
53240266059SGregory Neil Shapiro **	Returns:
53340266059SGregory Neil Shapiro **		emulated euid if in emulation mode, else true euid.
53440266059SGregory Neil Shapiro */
53540266059SGregory Neil Shapiro 
53640266059SGregory Neil Shapiro static uid_t sendmail_mpe_euid = 0;
53740266059SGregory Neil Shapiro 
53840266059SGregory Neil Shapiro #undef geteuid
53940266059SGregory Neil Shapiro uid_t
sendmail_mpe_geteuid()54040266059SGregory Neil Shapiro sendmail_mpe_geteuid()
54140266059SGregory Neil Shapiro {
54240266059SGregory Neil Shapiro 	if (sendmail_mpe_emuluid())
54340266059SGregory Neil Shapiro 		return sendmail_mpe_euid;
54440266059SGregory Neil Shapiro 	return geteuid();
54540266059SGregory Neil Shapiro }
54640266059SGregory Neil Shapiro 
54740266059SGregory Neil Shapiro /*
54840266059SGregory Neil Shapiro **  SENDMAIL_MPE_SETGID -- shadow function for setgid()
54940266059SGregory Neil Shapiro **
55040266059SGregory Neil Shapiro **	Simulate a call to setgid() without actually calling the real
55140266059SGregory Neil Shapiro **	function.  Implement the expected uid 0 semantics.
55240266059SGregory Neil Shapiro **
55340266059SGregory Neil Shapiro **	Note that sendmail will also be calling setuid() which will force an
55440266059SGregory Neil Shapiro **	implicit real setgid() to the proper primary gid.  So it doesn't matter
55540266059SGregory Neil Shapiro **	that we don't actually alter the real gid in this shadow function.
55640266059SGregory Neil Shapiro **
55740266059SGregory Neil Shapiro **	Parameters:
55840266059SGregory Neil Shapiro **		gid -- desired gid.
55940266059SGregory Neil Shapiro **
56040266059SGregory Neil Shapiro **	Returns:
56140266059SGregory Neil Shapiro **		0 -- emulated success
56240266059SGregory Neil Shapiro **		-1 -- emulated failure
56340266059SGregory Neil Shapiro */
56440266059SGregory Neil Shapiro 
56540266059SGregory Neil Shapiro #undef setgid
56640266059SGregory Neil Shapiro int
sendmail_mpe_setgid(gid)56740266059SGregory Neil Shapiro sendmail_mpe_setgid(gid)
56840266059SGregory Neil Shapiro 	gid_t gid;
56940266059SGregory Neil Shapiro {
57040266059SGregory Neil Shapiro 	if (sendmail_mpe_emulgid())
57140266059SGregory Neil Shapiro 	{
57240266059SGregory Neil Shapiro 		if (gid == getgid() || sendmail_mpe_euid == 0)
57340266059SGregory Neil Shapiro 		{
57440266059SGregory Neil Shapiro 			sendmail_mpe_egid = gid;
57540266059SGregory Neil Shapiro 			return 0;
57640266059SGregory Neil Shapiro 		}
57740266059SGregory Neil Shapiro 		errno = EINVAL;
57840266059SGregory Neil Shapiro 		return -1;
57940266059SGregory Neil Shapiro 	}
58040266059SGregory Neil Shapiro 	return setgid(gid);
58140266059SGregory Neil Shapiro }
58240266059SGregory Neil Shapiro 
58340266059SGregory Neil Shapiro /*
58440266059SGregory Neil Shapiro **  SENDMAIL_MPE_SETUID -- shadow function for setuid()
58540266059SGregory Neil Shapiro **
58640266059SGregory Neil Shapiro **	setuid() is broken as of MPE 7.0 in that it changes the current
58740266059SGregory Neil Shapiro **	working directory to be the home directory of the new uid.  Thus
58840266059SGregory Neil Shapiro **	we must obtain the cwd and restore it after the setuid().
58940266059SGregory Neil Shapiro **
59040266059SGregory Neil Shapiro **	Note that expected uid 0 semantics have been added, as well as
59140266059SGregory Neil Shapiro **	remembering the new uid for later use by the other shadow functions.
59240266059SGregory Neil Shapiro **
59340266059SGregory Neil Shapiro **	Parameters:
59440266059SGregory Neil Shapiro **		uid -- desired uid.
59540266059SGregory Neil Shapiro **
59640266059SGregory Neil Shapiro **	Returns:
59740266059SGregory Neil Shapiro **		0 -- success
59840266059SGregory Neil Shapiro **		-1 -- failure
59940266059SGregory Neil Shapiro **
60040266059SGregory Neil Shapiro **	Globals:
60140266059SGregory Neil Shapiro **		sendmail_mpe_euid
60240266059SGregory Neil Shapiro */
60340266059SGregory Neil Shapiro 
60440266059SGregory Neil Shapiro #undef setuid
60540266059SGregory Neil Shapiro int
sendmail_mpe_setuid(uid)60640266059SGregory Neil Shapiro sendmail_mpe_setuid(uid)
60740266059SGregory Neil Shapiro 	uid_t uid;
60840266059SGregory Neil Shapiro {
60940266059SGregory Neil Shapiro 	char *cwd;
61040266059SGregory Neil Shapiro 	char cwd_buf[PATH_MAX + 1];
61140266059SGregory Neil Shapiro 	int result;
61240266059SGregory Neil Shapiro 	extern void GETPRIVMODE __P((void));
61340266059SGregory Neil Shapiro 	extern void GETUSERMODE __P((void));
61440266059SGregory Neil Shapiro 
61540266059SGregory Neil Shapiro 	if (sendmail_mpe_emuluid())
61640266059SGregory Neil Shapiro 	{
61740266059SGregory Neil Shapiro 		if (uid == 0)
61840266059SGregory Neil Shapiro 		{
61940266059SGregory Neil Shapiro 			if (sendmail_mpe_euid != 0)
62040266059SGregory Neil Shapiro 			{
62140266059SGregory Neil Shapiro 				errno = EINVAL;
62240266059SGregory Neil Shapiro 				return -1;
62340266059SGregory Neil Shapiro 			}
62440266059SGregory Neil Shapiro 			sendmail_mpe_euid = 0;
62540266059SGregory Neil Shapiro 			return 0;
62640266059SGregory Neil Shapiro 		}
62740266059SGregory Neil Shapiro 
62840266059SGregory Neil Shapiro 		/* Preserve the current working directory */
62940266059SGregory Neil Shapiro 		if ((cwd = getcwd(cwd_buf, PATH_MAX + 1)) == NULL)
63040266059SGregory Neil Shapiro 			return -1;
63140266059SGregory Neil Shapiro 
63240266059SGregory Neil Shapiro 		GETPRIVMODE();
63340266059SGregory Neil Shapiro 		result = setuid(uid);
63440266059SGregory Neil Shapiro 		GETUSERMODE();
63540266059SGregory Neil Shapiro 
63640266059SGregory Neil Shapiro 		/* Restore the current working directory */
63740266059SGregory Neil Shapiro 		chdir(cwd_buf);
63840266059SGregory Neil Shapiro 
63940266059SGregory Neil Shapiro 		if (result == 0)
64040266059SGregory Neil Shapiro 			sendmail_mpe_euid = uid;
64140266059SGregory Neil Shapiro 
64240266059SGregory Neil Shapiro 		return result;
64340266059SGregory Neil Shapiro 	}
64440266059SGregory Neil Shapiro 	return setuid(uid);
64540266059SGregory Neil Shapiro }
64640266059SGregory Neil Shapiro #endif /* MPE */
647