1/*
2 * Copyright (c) 2009-2010 Todd C. Miller <Todd.Miller@courtesan.com>
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17#include <config.h>
18
19#include <sys/types.h>
20#include <sys/param.h>
21#include <sys/stat.h>
22#include <sys/ioctl.h>
23#ifdef HAVE_SYS_STROPTS_H
24#include <sys/stropts.h>
25#endif /* HAVE_SYS_STROPTS_H */
26#include <stdio.h>
27#ifdef STDC_HEADERS
28# include <stdlib.h>
29# include <stddef.h>
30#else
31# ifdef HAVE_STDLIB_H
32#  include <stdlib.h>
33# endif
34#endif /* STDC_HEADERS */
35#ifdef HAVE_STRING_H
36# include <string.h>
37#endif /* HAVE_STRING_H */
38#ifdef HAVE_STRINGS_H
39# include <strings.h>
40#endif /* HAVE_STRINGS_H */
41#ifdef HAVE_UNISTD_H
42# include <unistd.h>
43#endif /* HAVE_UNISTD_H */
44#include <errno.h>
45#include <fcntl.h>
46#include <grp.h>
47#include <pwd.h>
48
49#if defined(HAVE_LIBUTIL_H)
50# include <libutil.h>
51#elif defined(HAVE_UTIL_H)
52# include <util.h>
53#endif
54#ifdef HAVE_PTY_H
55# include <pty.h>
56#endif
57
58#include "sudo.h"
59
60#if defined(HAVE_OPENPTY)
61int
62get_pty(master, slave, name, namesz, ttyuid)
63    int *master;
64    int *slave;
65    char *name;
66    size_t namesz;
67    uid_t ttyuid;
68{
69    struct group *gr;
70    gid_t ttygid = -1;
71
72    if ((gr = sudo_getgrnam("tty")) != NULL) {
73	ttygid = gr->gr_gid;
74	gr_delref(gr);
75    }
76
77    if (openpty(master, slave, name, NULL, NULL) != 0)
78	return 0;
79    if (chown(name, ttyuid, ttygid) != 0)
80	return 0;
81    return 1;
82}
83
84#elif defined(HAVE__GETPTY)
85int
86get_pty(master, slave, name, namesz, ttyuid)
87    int *master;
88    int *slave;
89    char *name;
90    size_t namesz;
91    uid_t ttyuid;
92{
93    char *line;
94
95    /* IRIX-style dynamic ptys (may fork) */
96    line = _getpty(master, O_RDWR, S_IRUSR|S_IWUSR|S_IWGRP, 0);
97    if (line == NULL)
98	return 0;
99    *slave = open(line, O_RDWR|O_NOCTTY, 0);
100    if (*slave == -1) {
101	close(*master);
102	return 0;
103    }
104    (void) chown(line, ttyuid, -1);
105    strlcpy(name, line, namesz);
106    return 1;
107}
108#elif defined(HAVE_GRANTPT)
109# ifndef HAVE_POSIX_OPENPT
110static int
111posix_openpt(oflag)
112    int oflag;
113{
114    int fd;
115
116#  ifdef _AIX
117    fd = open("/dev/ptc", oflag);
118#  else
119    fd = open("/dev/ptmx", oflag);
120#  endif
121    return fd;
122}
123# endif /* HAVE_POSIX_OPENPT */
124
125int
126get_pty(master, slave, name, namesz, ttyuid)
127    int *master;
128    int *slave;
129    char *name;
130    size_t namesz;
131    uid_t ttyuid;
132{
133    char *line;
134
135    *master = posix_openpt(O_RDWR|O_NOCTTY);
136    if (*master == -1)
137	return 0;
138
139    (void) grantpt(*master); /* may fork */
140    if (unlockpt(*master) != 0) {
141	close(*master);
142	return 0;
143    }
144    line = ptsname(*master);
145    if (line == NULL) {
146	close(*master);
147	return 0;
148    }
149    *slave = open(line, O_RDWR|O_NOCTTY, 0);
150    if (*slave == -1) {
151	close(*master);
152	return 0;
153    }
154# if defined(I_PUSH) && !defined(_AIX)
155    ioctl(*slave, I_PUSH, "ptem");	/* pseudo tty emulation module */
156    ioctl(*slave, I_PUSH, "ldterm");	/* line discipline module */
157# endif
158    (void) chown(line, ttyuid, -1);
159    strlcpy(name, line, namesz);
160    return 1;
161}
162
163#else /* Old-style BSD ptys */
164
165static char line[] = "/dev/ptyXX";
166
167int
168get_pty(master, slave, name, namesz, ttyuid)
169    int *master;
170    int *slave;
171    char *name;
172    size_t namesz;
173    uid_t ttyuid;
174{
175    char *bank, *cp;
176    struct group *gr;
177    gid_t ttygid = -1;
178
179    if ((gr = sudo_getgrnam("tty")) != NULL)
180	ttygid = gr->gr_gid;
181
182    for (bank = "pqrs"; *bank != '\0'; bank++) {
183	line[sizeof("/dev/ptyX") - 2] = *bank;
184	for (cp = "0123456789abcdef"; *cp != '\0'; cp++) {
185	    line[sizeof("/dev/ptyXX") - 2] = *cp;
186	    *master = open(line, O_RDWR|O_NOCTTY, 0);
187	    if (*master == -1) {
188		if (errno == ENOENT)
189		    return 0; /* out of ptys */
190		continue; /* already in use */
191	    }
192	    line[sizeof("/dev/p") - 2] = 't';
193	    (void) chown(line, ttyuid, ttygid);
194	    (void) chmod(line, S_IRUSR|S_IWUSR|S_IWGRP);
195# ifdef HAVE_REVOKE
196	    (void) revoke(line);
197# endif
198	    *slave = open(line, O_RDWR|O_NOCTTY, 0);
199	    if (*slave != -1) {
200		    strlcpy(name, line, namesz);
201		    return 1; /* success */
202	    }
203	    (void) close(*master);
204	}
205    }
206    return 0;
207}
208#endif /* HAVE_OPENPTY */
209