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 (12 years 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

# 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 asvitkine 1.4 #define mysig_t sig_t
77 asvitkine 1.5 #define mysignal signal
78 asvitkine 1.4 #include <signal.h>
79    
80 cebix 1.1 /* 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 asvitkine 1.7 #if defined(HAVE_DEV_PTMX) && defined(HAVE_STROPTS_H)
92     # include <stropts.h>
93     #endif
94 cebix 1.1
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 asvitkine 1.7 #ifndef HAVE_CYGWIN
186 cebix 1.1 /*
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 */