ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Unix/sshpty.c
Revision: 1.3
Committed: 2011-03-11T16:41:18Z (13 years, 8 months ago) by asvitkine
Content type: text/plain
Branch: MAIN
Changes since 1.2: +1 -1 lines
Log Message:
Fix fatal() macro

File Contents

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