1126274Sdes/* 2126274Sdes * Please note: this implementation of openpty() is far from complete. 3126274Sdes * it is just enough for portable OpenSSH's needs. 4126274Sdes */ 5126274Sdes 6126274Sdes/* 7126274Sdes * Copyright (c) 2004 Damien Miller <djm@mindrot.org> 8126274Sdes * 9126274Sdes * Permission to use, copy, modify, and distribute this software for any 10126274Sdes * purpose with or without fee is hereby granted, provided that the above 11126274Sdes * copyright notice and this permission notice appear in all copies. 12126274Sdes * 13126274Sdes * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 14126274Sdes * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 15126274Sdes * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 16126274Sdes * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 17126274Sdes * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 18126274Sdes * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 19126274Sdes * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 20126274Sdes */ 21126274Sdes 22126274Sdes/* 23126274Sdes * Author: Tatu Ylonen <ylo@cs.hut.fi> 24126274Sdes * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 25126274Sdes * All rights reserved 26126274Sdes * Allocating a pseudo-terminal, and making it the controlling tty. 27126274Sdes * 28126274Sdes * As far as I am concerned, the code I have written for this software 29126274Sdes * can be used freely for any purpose. Any derived versions of this 30126274Sdes * software must be clearly marked as such, and if the derived work is 31126274Sdes * incompatible with the protocol description in the RFC file, it must be 32126274Sdes * called by a name other than "ssh" or "Secure Shell". 33126274Sdes */ 34126274Sdes 35126274Sdes#include "includes.h" 36126274Sdes#if !defined(HAVE_OPENPTY) 37126274Sdes 38162852Sdes#include <sys/types.h> 39162852Sdes 40162852Sdes#include <stdlib.h> 41162852Sdes 42162852Sdes#ifdef HAVE_SYS_STAT_H 43162852Sdes# include <sys/stat.h> 44162852Sdes#endif 45162852Sdes#ifdef HAVE_SYS_IOCTL_H 46162852Sdes# include <sys/ioctl.h> 47162852Sdes#endif 48162852Sdes 49162852Sdes#ifdef HAVE_FCNTL_H 50162852Sdes# include <fcntl.h> 51162852Sdes#endif 52162852Sdes 53126274Sdes#ifdef HAVE_UTIL_H 54126274Sdes# include <util.h> 55126274Sdes#endif /* HAVE_UTIL_H */ 56126274Sdes 57126274Sdes#ifdef HAVE_PTY_H 58126274Sdes# include <pty.h> 59126274Sdes#endif 60126274Sdes#if defined(HAVE_DEV_PTMX) && defined(HAVE_SYS_STROPTS_H) 61126274Sdes# include <sys/stropts.h> 62126274Sdes#endif 63126274Sdes 64162852Sdes#include <signal.h> 65162852Sdes#include <string.h> 66162852Sdes#include <unistd.h> 67162852Sdes 68126274Sdes#ifndef O_NOCTTY 69126274Sdes#define O_NOCTTY 0 70126274Sdes#endif 71126274Sdes 72126274Sdesint 73126274Sdesopenpty(int *amaster, int *aslave, char *name, struct termios *termp, 74126274Sdes struct winsize *winp) 75126274Sdes{ 76126274Sdes#if defined(HAVE__GETPTY) 77126274Sdes /* 78126274Sdes * _getpty(3) exists in SGI Irix 4.x, 5.x & 6.x -- it generates more 79126274Sdes * pty's automagically when needed 80126274Sdes */ 81126274Sdes char *slave; 82126274Sdes 83126274Sdes if ((slave = _getpty(amaster, O_RDWR, 0622, 0)) == NULL) 84126274Sdes return (-1); 85126274Sdes 86126274Sdes /* Open the slave side. */ 87126274Sdes if ((*aslave = open(slave, O_RDWR | O_NOCTTY)) == -1) { 88126274Sdes close(*amaster); 89126274Sdes return (-1); 90126274Sdes } 91126274Sdes return (0); 92126274Sdes 93126274Sdes#elif defined(HAVE_DEV_PTMX) 94126274Sdes /* 95126274Sdes * This code is used e.g. on Solaris 2.x. (Note that Solaris 2.3 96126274Sdes * also has bsd-style ptys, but they simply do not work.) 97126274Sdes */ 98126274Sdes int ptm; 99126274Sdes char *pts; 100126274Sdes mysig_t old_signal; 101126274Sdes 102126274Sdes if ((ptm = open("/dev/ptmx", O_RDWR | O_NOCTTY)) == -1) 103126274Sdes return (-1); 104126274Sdes 105126274Sdes /* XXX: need to close ptm on error? */ 106126274Sdes old_signal = signal(SIGCHLD, SIG_DFL); 107126274Sdes if (grantpt(ptm) < 0) 108126274Sdes return (-1); 109126274Sdes signal(SIGCHLD, old_signal); 110126274Sdes 111126274Sdes if (unlockpt(ptm) < 0) 112126274Sdes return (-1); 113126274Sdes 114126274Sdes if ((pts = ptsname(ptm)) == NULL) 115126274Sdes return (-1); 116126274Sdes *amaster = ptm; 117126274Sdes 118126274Sdes /* Open the slave side. */ 119126274Sdes if ((*aslave = open(pts, O_RDWR | O_NOCTTY)) == -1) { 120126274Sdes close(*amaster); 121126274Sdes return (-1); 122126274Sdes } 123126274Sdes 124126274Sdes /* 125126274Sdes * Try to push the appropriate streams modules, as described 126126274Sdes * in Solaris pts(7). 127126274Sdes */ 128126274Sdes ioctl(*aslave, I_PUSH, "ptem"); 129126274Sdes ioctl(*aslave, I_PUSH, "ldterm"); 130126274Sdes# ifndef __hpux 131126274Sdes ioctl(*aslave, I_PUSH, "ttcompat"); 132126274Sdes# endif /* __hpux */ 133126274Sdes 134126274Sdes return (0); 135126274Sdes 136126274Sdes#elif defined(HAVE_DEV_PTS_AND_PTC) 137126274Sdes /* AIX-style pty code. */ 138126274Sdes const char *ttname; 139126274Sdes 140126274Sdes if ((*amaster = open("/dev/ptc", O_RDWR | O_NOCTTY)) == -1) 141126274Sdes return (-1); 142126274Sdes if ((ttname = ttyname(*amaster)) == NULL) 143126274Sdes return (-1); 144126274Sdes if ((*aslave = open(ttname, O_RDWR | O_NOCTTY)) == -1) { 145126274Sdes close(*amaster); 146126274Sdes return (-1); 147126274Sdes } 148126274Sdes return (0); 149126274Sdes 150126274Sdes#elif defined(_UNICOS) 151126274Sdes char ptbuf[64], ttbuf[64]; 152126274Sdes int i; 153126274Sdes int highpty; 154126274Sdes 155126274Sdes highpty = 128; 156126274Sdes#ifdef _SC_CRAY_NPTY 157126274Sdes if ((highpty = sysconf(_SC_CRAY_NPTY)) == -1) 158126274Sdes highpty = 128; 159126274Sdes#endif /* _SC_CRAY_NPTY */ 160126274Sdes 161126274Sdes for (i = 0; i < highpty; i++) { 162126274Sdes snprintf(ptbuf, sizeof(ptbuf), "/dev/pty/%03d", i); 163126274Sdes snprintf(ttbuf, sizeof(ttbuf), "/dev/ttyp%03d", i); 164126274Sdes if ((*amaster = open(ptbuf, O_RDWR|O_NOCTTY)) == -1) 165126274Sdes continue; 166126274Sdes /* Open the slave side. */ 167126274Sdes if ((*aslave = open(ttbuf, O_RDWR|O_NOCTTY)) == -1) { 168126274Sdes close(*amaster); 169126274Sdes return (-1); 170126274Sdes } 171126274Sdes return (0); 172126274Sdes } 173126274Sdes return (-1); 174126274Sdes 175126274Sdes#else 176126274Sdes /* BSD-style pty code. */ 177126274Sdes char ptbuf[64], ttbuf[64]; 178126274Sdes int i; 179126274Sdes const char *ptymajors = "pqrstuvwxyzabcdefghijklmno" 180126274Sdes "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 181126274Sdes const char *ptyminors = "0123456789abcdef"; 182126274Sdes int num_minors = strlen(ptyminors); 183126274Sdes int num_ptys = strlen(ptymajors) * num_minors; 184126274Sdes struct termios tio; 185126274Sdes 186126274Sdes for (i = 0; i < num_ptys; i++) { 187126274Sdes snprintf(ptbuf, sizeof(ptbuf), "/dev/pty%c%c", 188126274Sdes ptymajors[i / num_minors], ptyminors[i % num_minors]); 189126274Sdes snprintf(ttbuf, sizeof(ttbuf), "/dev/tty%c%c", 190126274Sdes ptymajors[i / num_minors], ptyminors[i % num_minors]); 191126274Sdes 192126274Sdes if ((*amaster = open(ptbuf, O_RDWR | O_NOCTTY)) == -1) { 193126274Sdes /* Try SCO style naming */ 194126274Sdes snprintf(ptbuf, sizeof(ptbuf), "/dev/ptyp%d", i); 195126274Sdes snprintf(ttbuf, sizeof(ttbuf), "/dev/ttyp%d", i); 196126274Sdes if ((*amaster = open(ptbuf, O_RDWR | O_NOCTTY)) == -1) 197126274Sdes continue; 198126274Sdes } 199126274Sdes 200126274Sdes /* Open the slave side. */ 201126274Sdes if ((*aslave = open(ttbuf, O_RDWR | O_NOCTTY)) == -1) { 202126274Sdes close(*amaster); 203126274Sdes return (-1); 204126274Sdes } 205126274Sdes /* set tty modes to a sane state for broken clients */ 206126274Sdes if (tcgetattr(*amaster, &tio) != -1) { 207126274Sdes tio.c_lflag |= (ECHO | ISIG | ICANON); 208126274Sdes tio.c_oflag |= (OPOST | ONLCR); 209126274Sdes tio.c_iflag |= ICRNL; 210126274Sdes tcsetattr(*amaster, TCSANOW, &tio); 211126274Sdes } 212126274Sdes 213126274Sdes return (0); 214126274Sdes } 215126274Sdes return (-1); 216126274Sdes#endif 217126274Sdes} 218126274Sdes 219126274Sdes#endif /* !defined(HAVE_OPENPTY) */ 220126274Sdes 221