1
0
Files
irix-657m-src/eoe/cmd/bsd/mkpts.c
2022-09-29 17:59:04 +03:00

413 lines
8.4 KiB
C

/* Get a PTY
* This file appears as both lib/libc/src/gen/getpty.c
* and cmd/bsd/mkpts.c
*
* Copyright 1991, Silicon Graphics, Inc.
* All Rights Reserved.
*
* This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
* the contents of this file may not be disclosed to third parties, copied or
* duplicated in any form, in whole or in part, without the prior written
* permission of Silicon Graphics, Inc.
*
* RESTRICTED RIGHTS LEGEND:
* Use, duplication or disclosure by the Government is subject to restrictions
* as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
* and Computer Software clause at DFARS 252.227-7013, and/or in similar or
* successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
* rights reserved under the Copyright Laws of the United States.
*/
#ident "$Revision: 1.20 $"
#ifndef MKPTS
#ifdef __STDC__
#pragma weak ptsname = _ptsname
#pragma weak grantpt = _grantpt
#pragma weak unlockpt = _unlockpt
#endif
#include "synonyms.h"
#endif
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <paths.h>
#include <grp.h>
#include <errno.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/major.h>
#include <sys/sysmacros.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/file.h>
#include <sys/termios.h>
#include <sys/stropts.h>
#include <fcntl.h> /* for prototyping */
#include <sys/mac.h>
#include <sys/mac_label.h>
#include <sys/capability.h>
#define PTC_HELP_PATH "/usr/sbin/mkpts"
#define PTC_CMD_NAME "mkpts"
#define IRIX_FORM 0
#define SVR4_FORM 1
#define MAX_SLAVENAME_FORMS 2
char __slave0[] = "/dev/ttypadpadpad";
char __slave1[] = "/dev/pts/padpadpad";
static char *slave[MAX_SLAVENAME_FORMS] = {__slave0, __slave1};
static int group_known = 0;
static gid_t pty_gid = 0;
static int spty_mode(int, mode_t, int, u_char);
static int fork_help(int, int *);
/*
* spty_mode flag
*/
#define MD_SLAVENAME 0x1
#define MD_GRANTPT 0x2
#define MD_GETPTY 0x4
#define MD_MKPTS 0x8
char *
ptsname(int fd)
{
struct strioctl istr;
if (spty_mode(fd, 0, 0, MD_SLAVENAME) < 0)
return NULL;
istr.ic_cmd = SVR4SOPEN;
istr.ic_len = 0;
istr.ic_timout = 0;
istr.ic_dp = NULL;
if (ioctl(fd, I_STR, &istr) < 0)
return NULL;
return slave[SVR4_FORM];
}
int
grantpt(int fd)
{
return (spty_mode(fd, 0620, 0, MD_GRANTPT));
}
int
unlockpt(int fd)
{
struct strioctl istr;
istr.ic_cmd = UNLKPT;
istr.ic_len = 0;
istr.ic_timout = 0;
istr.ic_dp = NULL;
if (ioctl(fd, I_STR, &istr) < 0)
return(-1);
return(0);
}
/*
* Get a PTY
*/
char * /* 0=failed or pointer to name */
_getpty(int *fildes, /* place for ptc fd */
int oflag, /* open with these flags */
mode_t mode, /* give it these modes */
int nofork) /* 0=ok to use capable helper */
{
int c;
/*
* Open the controlling side.
*/
if (0 > (c = open(_PATH_DEVPTC, oflag)))
return 0;
if (0 > spty_mode(c, mode & 0666, nofork, MD_GETPTY))
return 0;
if (0 > unlockpt(c))
return 0;
/*
* return file descriptor if asked. Close it if no one can ever
* discover it.
*/
if (0 != fildes) {
*fildes = c;
} else {
(void)close(c);
}
return slave[IRIX_FORM];
}
static const char wildcard[]= {MSEN_EQUAL_LABEL,MINT_EQUAL_LABEL,0,0,0,0,0,0};
static const cap_value_t caps_ch[] = {
CAP_FOWNER,
CAP_MAC_RELABEL_OPEN,
CAP_MAC_UPGRADE,
CAP_MAC_DOWNGRADE,
};
/*
* give slave pty correct ownership and modes,
* given its name implicitly and the controlling
*/
static int /* -1=failed */
spty_mode(int fd, /* controller file descriptor */
mode_t mode, /* target mode */
int nofork, /* 1=do not use helper program */
u_char flags) /* everybody needs some */
{
int fam, mc, form;
dev_t slv_dev;
uid_t uid = getuid();
int mac_enabled; /* MAC Option */
struct stat s_stb[MAX_SLAVENAME_FORMS], c_stb;
cap_t ocap;
mac_enabled = (sysconf(_SC_MAC) > 0);
/*
* Discover correct group ID for ptys
*/
if (!group_known && !(flags & MD_SLAVENAME)) {
#ifdef PTYGRP
struct group *grent;
setgrent();
grent = getgrname(PTYGRP);
if (0 != grent)
pty_gid = grent.gr_gid;
endgrent();
#endif
group_known = 1;
}
/*
* compute the correct file name
*/
if (fstat(fd, &c_stb) < 0)
return -1;
mc = minor(c_stb.st_rdev);
if (mc >= 200) {
setoserror(EINVAL);
return -1;
}
switch (major(c_stb.st_rdev)) {
case PTC_MAJOR:
slv_dev = makedev(PTS_MAJOR, mc);
fam = 0;
break;
case PTC1_MAJOR:
slv_dev = makedev(PTS1_MAJOR, mc);
fam = 2;
break;
case PTC2_MAJOR:
slv_dev = makedev(PTS2_MAJOR, mc);
fam = 4;
break;
case PTC3_MAJOR:
slv_dev = makedev(PTS3_MAJOR, mc);
fam = 6;
break;
case PTC4_MAJOR:
slv_dev = makedev(PTS4_MAJOR, mc);
fam = 8;
break;
default:
setoserror(EINVAL);
return -1;
}
fam += mc / 100;
mc %= 100;
(void)sprintf(slave[IRIX_FORM], "/dev/tty%c%d", "qrstuvwxyz"[fam], mc);
(void)sprintf(slave[SVR4_FORM], "/dev/pts/%d", (fam * 100) + mc);
if (flags & MD_SLAVENAME)
return 0;
for (form = 0; form < MAX_SLAVENAME_FORMS; form++) {
/*
* Create the slave node if it does not exist.
*/
if (0 > stat(slave[form], &s_stb[form])) {
if (errno != ENOENT)
return -1;
if (form) {
/* link to original form */
if (0 > link(slave[0], slave[form])) {
if (nofork || 0 > fork_help(fd,&nofork))
return -1;
}
} else if (0 > mknod(slave[form],
S_IFCHR|mode, slv_dev)) {
if (nofork || 0 > fork_help(fd, &nofork))
return -1;
}
if (mac_enabled) {
int r;
/* Label the new pty */
ocap = cap_acquire (4, caps_ch);
r = mac_set_file(slave[form], (mac_t) wildcard);
cap_surrender (ocap);
if (r == -1)
return r;
}
if (0 > stat(slave[form], &s_stb[form]))
return -1;
} else if (form && !S_ISCHR(s_stb[form].st_mode)) {
if (0 > unlink(slave[form])) {
if (nofork || 0 > fork_help(fd, &nofork))
return -1;
} else {
form--;
continue;
}
/* Helper succeeded. */
if (0 > stat(slave[form], &s_stb[form]))
return -1;
}
/*
* Check that the slave is the right sort of beast.
*/
if (s_stb[form].st_rdev != slv_dev) {
setoserror(EINVAL);
return -1;
}
/*
* Give the pty private ownership
*/
if (s_stb[form].st_uid != uid || s_stb[form].st_gid != pty_gid){
int i;
ocap = cap_acquire (1, caps_ch);
i = chown(slave[form], uid, pty_gid);
cap_surrender (ocap);
if (i < 0) {
if (nofork || 0 > fork_help(fd, &nofork))
return -1;
if (0 > stat(slave[form], &s_stb[form]))
return -1;
}
}
/*
* Give the pty correct mode.
*/
if (s_stb[form].st_mode != mode) {
int i;
ocap = cap_acquire (1, caps_ch);
i = chmod(slave[form], mode);
cap_surrender (ocap);
if (i < 0)
return -1;
}
}
return 0;
}
/*
* Use privileged program to creat() and chown() a slave pty.
* When capabilities are in use the behaviour differs from the
* vanilla set-uid case.
*/
static int /* <0 if it failed */
fork_help(int fd, int *doneonce)
{
pid_t pid;
int wstat;
if (*doneonce)
return -1;
*doneonce = 1;
/*
* give up if we have sufficient privilege to preform the
* operation without help.
*/
switch (sysconf(_SC_CAP)) {
case CAP_SYS_DISABLED:
default:
if (!geteuid())
return -1;
break;
case CAP_SYS_SUPERUSER:
if (!geteuid())
return -1;
/* NO BREAK */
case CAP_SYS_NO_SUPERUSER:
/*
* For now, always proceed.
*/
break;
}
pid = fork();
if (pid < 0)
return -1;
if (0 != pid) {
if (0 > waitpid(pid, &wstat, 0))
return -1;
if (!WIFEXITED(wstat)) {
setoserror(EINVAL);
(void)kill(pid, SIGKILL);
}
errno = WEXITSTATUS(wstat); /* get errno from child */
return (errno != 0) ? -1 : 0;
}
if (0 > dup2(fd, 0))
exit(errno);
(void)execl(PTC_HELP_PATH, PTC_CMD_NAME, (char*)0);
/*
* exit with the errno to give to our parent. Use "return"
* instead of exit(2) to make lint happy.
*/
return errno;
}
#ifdef MKPTS /* generate the suid program */
/*
* Create or chown the slave pty corresponding to the controller opened
* as file descriptor 0.
* This program is safely setuid, because it only does things based on
* an open file descriptor and because the file descriptor does not
* have a node in the file system (i.e. it is from a clone device).
*
* The most a bad guy can do is to change the ower of a slave pty
* corresponding to a controlling pty that only he has open.
*/
main()
{
if (0 > spty_mode(0, 0600, 1, MD_MKPTS))
return errno;
return 0;
}
#endif /* MKPTS */