ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/sshpty.c
Revision: 1.7
Committed: 2012-06-17T23:15:10Z (11 years, 10 months ago) by asvitkine
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 1.6: +4 -1 lines
Log Message:
another try to get sshpty.c compiling on bsd

File Contents

# Content
1 /*
2 * Author: Tatu Ylonen <ylo@cs.hut.fi>
3 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
4 * All rights reserved
5 * Allocating a pseudo-terminal, and making it the controlling tty.
6 *
7 * As far as I am concerned, the code I have written for this software
8 * can be used freely for any purpose. Any derived versions of this
9 * software must be clearly marked as such, and if the derived work is
10 * incompatible with the protocol description in the RFC file, it must be
11 * called by a name other than "ssh" or "Secure Shell".
12 */
13
14 #if 0 /* not in BasiliskII */
15 #include "includes.h"
16 RCSID("$OpenBSD: sshpty.c,v 1.4 2001/12/19 07:18:56 deraadt Exp $");
17 #else /* not in BasiliskII */
18 /* Selections from openssh's "includes.h" */
19 #include "config.h"
20
21 #include <stdio.h>
22 #include <ctype.h>
23 #include <errno.h>
24 #include <fcntl.h> /* For O_NONBLOCK */
25 #include <stdlib.h>
26 #include <string.h>
27 #include <pwd.h>
28
29 #include <unistd.h> /* For STDIN_FILENO, etc */
30 #include <termios.h> /* Struct winsize */
31
32 /*
33 *-*-nto-qnx needs these headers for strcasecmp and LASTLOG_FILE respectively
34 */
35 #ifdef HAVE_STRINGS_H
36 # include <strings.h>
37 #endif
38 #ifdef HAVE_LOGIN_H
39 # include <login.h>
40 #endif
41
42 #include <sys/ioctl.h>
43
44 #ifdef HAVE_SYS_BSDTTY_H
45 # include <sys/bsdtty.h>
46 #endif
47
48 #ifdef HAVE_SYS_STAT_H
49 # include <sys/stat.h> /* For S_* constants and macros */
50 #endif
51
52 #ifndef _PATH_TTY
53 # define _PATH_TTY "/dev/tty"
54 #endif
55
56 #include "strlcpy.h"
57
58 #define debug(x) ;
59
60 #endif /* not in BasiliskII */
61
62 #ifdef HAVE_UTIL_H
63 # include <util.h>
64 #endif /* HAVE_UTIL_H */
65
66 #include "sshpty.h"
67 #if 0 /* not in BasiliskII */
68 #include "log.h"
69 #include "misc.h"
70 #else /* stubs for BasiliskII */
71 #define log printf
72 #define error printf
73 #define fatal(x) do { printf("Fatal error: %s", x); return 0; } while(0)
74 #endif /* not in BasiliskII */
75
76 #define mysig_t sig_t
77 #define mysignal signal
78 #include <signal.h>
79
80 /* Pty allocated with _getpty gets broken if we do I_PUSH:es to it. */
81 #if defined(HAVE__GETPTY) || defined(HAVE_OPENPTY)
82 #undef HAVE_DEV_PTMX
83 #endif
84
85 #ifdef HAVE_PTY_H
86 # include <pty.h>
87 #endif
88 #if defined(HAVE_DEV_PTMX) && defined(HAVE_SYS_STROPTS_H)
89 # include <sys/stropts.h>
90 #endif
91 #if defined(HAVE_DEV_PTMX) && defined(HAVE_STROPTS_H)
92 # include <stropts.h>
93 #endif
94
95 #ifndef O_NOCTTY
96 #define O_NOCTTY 0
97 #endif
98
99 /*
100 * Allocates and opens a pty. Returns 0 if no pty could be allocated, or
101 * nonzero if a pty was successfully allocated. On success, open file
102 * descriptors for the pty and tty sides and the name of the tty side are
103 * returned (the buffer must be able to hold at least 64 characters).
104 */
105
106 int
107 pty_allocate(int *ptyfd, int *ttyfd, char *namebuf, int namebuflen)
108 {
109 #if defined(HAVE_OPENPTY) || defined(BSD4_4)
110 /* openpty(3) exists in OSF/1 and some other os'es */
111 char *name;
112 int i;
113
114 i = openpty(ptyfd, ttyfd, NULL, NULL, NULL);
115 if (i < 0) {
116 error("openpty: %.100s", strerror(errno));
117 return 0;
118 }
119 name = ttyname(*ttyfd);
120 if (!name)
121 fatal("openpty returns device for which ttyname fails.");
122
123 strlcpy(namebuf, name, namebuflen); /* possible truncation */
124 return 1;
125 #else /* HAVE_OPENPTY */
126 #ifdef HAVE__GETPTY
127 /*
128 * _getpty(3) exists in SGI Irix 4.x, 5.x & 6.x -- it generates more
129 * pty's automagically when needed
130 */
131 char *slave;
132
133 slave = _getpty(ptyfd, O_RDWR, 0622, 0);
134 if (slave == NULL) {
135 error("_getpty: %.100s", strerror(errno));
136 return 0;
137 }
138 strlcpy(namebuf, slave, namebuflen);
139 /* Open the slave side. */
140 *ttyfd = open(namebuf, O_RDWR | O_NOCTTY);
141 if (*ttyfd < 0) {
142 error("%.200s: %.100s", namebuf, strerror(errno));
143 close(*ptyfd);
144 return 0;
145 }
146 return 1;
147 #else /* HAVE__GETPTY */
148 #if defined(HAVE_DEV_PTMX)
149 /*
150 * This code is used e.g. on Solaris 2.x. (Note that Solaris 2.3
151 * also has bsd-style ptys, but they simply do not work.)
152 */
153 int ptm;
154 char *pts;
155 mysig_t old_signal;
156
157 ptm = open("/dev/ptmx", O_RDWR | O_NOCTTY);
158 if (ptm < 0) {
159 error("/dev/ptmx: %.100s", strerror(errno));
160 return 0;
161 }
162 old_signal = mysignal(SIGCHLD, SIG_DFL);
163 if (grantpt(ptm) < 0) {
164 error("grantpt: %.100s", strerror(errno));
165 return 0;
166 }
167 mysignal(SIGCHLD, old_signal);
168 if (unlockpt(ptm) < 0) {
169 error("unlockpt: %.100s", strerror(errno));
170 return 0;
171 }
172 pts = ptsname(ptm);
173 if (pts == NULL)
174 error("Slave pty side name could not be obtained.");
175 strlcpy(namebuf, pts, namebuflen);
176 *ptyfd = ptm;
177
178 /* Open the slave side. */
179 *ttyfd = open(namebuf, O_RDWR | O_NOCTTY);
180 if (*ttyfd < 0) {
181 error("%.100s: %.100s", namebuf, strerror(errno));
182 close(*ptyfd);
183 return 0;
184 }
185 #ifndef HAVE_CYGWIN
186 /*
187 * Push the appropriate streams modules, as described in Solaris pts(7).
188 * HP-UX pts(7) doesn't have ttcompat module.
189 */
190 if (ioctl(*ttyfd, I_PUSH, "ptem") < 0)
191 error("ioctl I_PUSH ptem: %.100s", strerror(errno));
192 if (ioctl(*ttyfd, I_PUSH, "ldterm") < 0)
193 error("ioctl I_PUSH ldterm: %.100s", strerror(errno));
194 #ifndef __hpux
195 if (ioctl(*ttyfd, I_PUSH, "ttcompat") < 0)
196 error("ioctl I_PUSH ttcompat: %.100s", strerror(errno));
197 #endif
198 #endif
199 return 1;
200 #else /* HAVE_DEV_PTMX */
201 #ifdef HAVE_DEV_PTS_AND_PTC
202 /* AIX-style pty code. */
203 const char *name;
204
205 *ptyfd = open("/dev/ptc", O_RDWR | O_NOCTTY);
206 if (*ptyfd < 0) {
207 error("Could not open /dev/ptc: %.100s", strerror(errno));
208 return 0;
209 }
210 name = ttyname(*ptyfd);
211 if (!name)
212 fatal("Open of /dev/ptc returns device for which ttyname fails.");
213 strlcpy(namebuf, name, namebuflen);
214 *ttyfd = open(name, O_RDWR | O_NOCTTY);
215 if (*ttyfd < 0) {
216 error("Could not open pty slave side %.100s: %.100s",
217 name, strerror(errno));
218 close(*ptyfd);
219 return 0;
220 }
221 return 1;
222 #else /* HAVE_DEV_PTS_AND_PTC */
223 #ifdef _CRAY
224 char buf[64];
225 int i;
226 int highpty;
227
228 #ifdef _SC_CRAY_NPTY
229 highpty = sysconf(_SC_CRAY_NPTY);
230 if (highpty == -1)
231 highpty = 128;
232 #else
233 highpty = 128;
234 #endif
235
236 for (i = 0; i < highpty; i++) {
237 snprintf(buf, sizeof(buf), "/dev/pty/%03d", i);
238 *ptyfd = open(buf, O_RDWR|O_NOCTTY);
239 if (*ptyfd < 0)
240 continue;
241 snprintf(namebuf, namebuflen, "/dev/ttyp%03d", i);
242 /* Open the slave side. */
243 *ttyfd = open(namebuf, O_RDWR|O_NOCTTY);
244 if (*ttyfd < 0) {
245 error("%.100s: %.100s", namebuf, strerror(errno));
246 close(*ptyfd);
247 return 0;
248 }
249 return 1;
250 }
251 return 0;
252 #else
253 /* BSD-style pty code. */
254 char buf[64];
255 int i;
256 const char *ptymajors = "pqrstuvwxyzabcdefghijklmnoABCDEFGHIJKLMNOPQRSTUVWXYZ";
257 const char *ptyminors = "0123456789abcdef";
258 int num_minors = strlen(ptyminors);
259 int num_ptys = strlen(ptymajors) * num_minors;
260 struct termios tio;
261
262 for (i = 0; i < num_ptys; i++) {
263 snprintf(buf, sizeof buf, "/dev/pty%c%c", ptymajors[i / num_minors],
264 ptyminors[i % num_minors]);
265 snprintf(namebuf, namebuflen, "/dev/tty%c%c",
266 ptymajors[i / num_minors], ptyminors[i % num_minors]);
267
268 *ptyfd = open(buf, O_RDWR | O_NOCTTY);
269 if (*ptyfd < 0) {
270 /* Try SCO style naming */
271 snprintf(buf, sizeof buf, "/dev/ptyp%d", i);
272 snprintf(namebuf, namebuflen, "/dev/ttyp%d", i);
273 *ptyfd = open(buf, O_RDWR | O_NOCTTY);
274 if (*ptyfd < 0)
275 continue;
276 }
277
278 /* Open the slave side. */
279 *ttyfd = open(namebuf, O_RDWR | O_NOCTTY);
280 if (*ttyfd < 0) {
281 error("%.100s: %.100s", namebuf, strerror(errno));
282 close(*ptyfd);
283 return 0;
284 }
285 /* set tty modes to a sane state for broken clients */
286 if (tcgetattr(*ptyfd, &tio) < 0)
287 log("Getting tty modes for pty failed: %.100s", strerror(errno));
288 else {
289 tio.c_lflag |= (ECHO | ISIG | ICANON);
290 tio.c_oflag |= (OPOST | ONLCR);
291 tio.c_iflag |= ICRNL;
292
293 /* Set the new modes for the terminal. */
294 if (tcsetattr(*ptyfd, TCSANOW, &tio) < 0)
295 log("Setting tty modes for pty failed: %.100s", strerror(errno));
296 }
297
298 return 1;
299 }
300 return 0;
301 #endif /* CRAY */
302 #endif /* HAVE_DEV_PTS_AND_PTC */
303 #endif /* HAVE_DEV_PTMX */
304 #endif /* HAVE__GETPTY */
305 #endif /* HAVE_OPENPTY */
306 }
307
308 /* Releases the tty. Its ownership is returned to root, and permissions to 0666. */
309
310 void
311 pty_release(const char *ttyname)
312 {
313 if (chown(ttyname, (uid_t) 0, (gid_t) 0) < 0)
314 error("chown %.100s 0 0 failed: %.100s", ttyname, strerror(errno));
315 if (chmod(ttyname, (mode_t) 0666) < 0)
316 error("chmod %.100s 0666 failed: %.100s", ttyname, strerror(errno));
317 }
318
319 /* Makes the tty the processes controlling tty and sets it to sane modes. */
320
321 void
322 pty_make_controlling_tty(int *ttyfd, const char *ttyname)
323 {
324 int fd;
325 #ifdef USE_VHANGUP
326 void *old;
327 #endif /* USE_VHANGUP */
328
329 #ifdef _CRAY
330 if (setsid() < 0)
331 error("setsid: %.100s", strerror(errno));
332
333 fd = open(ttyname, O_RDWR|O_NOCTTY);
334 if (fd != -1) {
335 mysignal(SIGHUP, SIG_IGN);
336 ioctl(fd, TCVHUP, (char *)NULL);
337 mysignal(SIGHUP, SIG_DFL);
338 setpgid(0, 0);
339 close(fd);
340 } else {
341 error("Failed to disconnect from controlling tty.");
342 }
343
344 debug("Setting controlling tty using TCSETCTTY.");
345 ioctl(*ttyfd, TCSETCTTY, NULL);
346 fd = open("/dev/tty", O_RDWR);
347 if (fd < 0)
348 error("%.100s: %.100s", ttyname, strerror(errno));
349 close(*ttyfd);
350 *ttyfd = fd;
351 #else /* _CRAY */
352
353 /* First disconnect from the old controlling tty. */
354 #ifdef TIOCNOTTY
355 fd = open(_PATH_TTY, O_RDWR | O_NOCTTY);
356 if (fd >= 0) {
357 (void) ioctl(fd, TIOCNOTTY, NULL);
358 close(fd);
359 }
360 #endif /* TIOCNOTTY */
361 if (setsid() < 0)
362 error("setsid: %.100s", strerror(errno));
363
364 /*
365 * Verify that we are successfully disconnected from the controlling
366 * tty.
367 */
368 fd = open(_PATH_TTY, O_RDWR | O_NOCTTY);
369 if (fd >= 0) {
370 error("Failed to disconnect from controlling tty.");
371 close(fd);
372 }
373 /* Make it our controlling tty. */
374 #ifdef TIOCSCTTY
375 debug("Setting controlling tty using TIOCSCTTY.");
376 if (ioctl(*ttyfd, TIOCSCTTY, NULL) < 0)
377 error("ioctl(TIOCSCTTY): %.100s", strerror(errno));
378 #endif /* TIOCSCTTY */
379 #ifdef HAVE_NEWS4
380 if (setpgrp(0,0) < 0)
381 error("SETPGRP %s",strerror(errno));
382 #endif /* HAVE_NEWS4 */
383 #ifdef USE_VHANGUP
384 old = mysignal(SIGHUP, SIG_IGN);
385 vhangup();
386 mysignal(SIGHUP, old);
387 #endif /* USE_VHANGUP */
388 fd = open(ttyname, O_RDWR);
389 if (fd < 0) {
390 error("%.100s: %.100s", ttyname, strerror(errno));
391 } else {
392 #ifdef USE_VHANGUP
393 close(*ttyfd);
394 *ttyfd = fd;
395 #else /* USE_VHANGUP */
396 close(fd);
397 #endif /* USE_VHANGUP */
398 }
399 /* Verify that we now have a controlling tty. */
400 fd = open(_PATH_TTY, O_WRONLY);
401 if (fd < 0)
402 error("open /dev/tty failed - could not set controlling tty: %.100s",
403 strerror(errno));
404 else {
405 close(fd);
406 }
407 #endif /* _CRAY */
408 }
409
410 #if 0 /* not in BasiliskII */
411 /* Changes the window size associated with the pty. */
412
413 void
414 pty_change_window_size(int ptyfd, int row, int col,
415 int xpixel, int ypixel)
416 {
417 struct winsize w;
418 w.ws_row = row;
419 w.ws_col = col;
420 w.ws_xpixel = xpixel;
421 w.ws_ypixel = ypixel;
422 (void) ioctl(ptyfd, TIOCSWINSZ, &w);
423 }
424
425 void
426 pty_setowner(struct passwd *pw, const char *ttyname)
427 {
428 struct group *grp;
429 gid_t gid;
430 mode_t mode;
431 struct stat st;
432
433 /* Determine the group to make the owner of the tty. */
434 grp = getgrnam("tty");
435 if (grp) {
436 gid = grp->gr_gid;
437 mode = S_IRUSR | S_IWUSR | S_IWGRP;
438 } else {
439 gid = pw->pw_gid;
440 mode = S_IRUSR | S_IWUSR | S_IWGRP | S_IWOTH;
441 }
442
443 /*
444 * Change owner and mode of the tty as required.
445 * Warn but continue if filesystem is read-only and the uids match/
446 * tty is owned by root.
447 */
448 if (stat(ttyname, &st))
449 fatal("stat(%.100s) failed: %.100s", ttyname,
450 strerror(errno));
451
452 if (st.st_uid != pw->pw_uid || st.st_gid != gid) {
453 if (chown(ttyname, pw->pw_uid, gid) < 0) {
454 if (errno == EROFS &&
455 (st.st_uid == pw->pw_uid || st.st_uid == 0))
456 error("chown(%.100s, %d, %d) failed: %.100s",
457 ttyname, pw->pw_uid, gid,
458 strerror(errno));
459 else
460 fatal("chown(%.100s, %d, %d) failed: %.100s",
461 ttyname, pw->pw_uid, gid,
462 strerror(errno));
463 }
464 }
465
466 if ((st.st_mode & (S_IRWXU|S_IRWXG|S_IRWXO)) != mode) {
467 if (chmod(ttyname, mode) < 0) {
468 if (errno == EROFS &&
469 (st.st_mode & (S_IRGRP | S_IROTH)) == 0)
470 error("chmod(%.100s, 0%o) failed: %.100s",
471 ttyname, mode, strerror(errno));
472 else
473 fatal("chmod(%.100s, 0%o) failed: %.100s",
474 ttyname, mode, strerror(errno));
475 }
476 }
477 }
478 #endif /* not in BasiliskII */