00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
#include <config.h>
00025
00026
#include "kpty.h"
00027
#include "kprocess.h"
00028
00029
#ifdef __sgi
00030
#define __svr4__
00031
#endif
00032
00033
#ifdef __osf__
00034
#define _OSF_SOURCE
00035
#include <float.h>
00036
#endif
00037
00038
#ifdef _AIX
00039
#define _ALL_SOURCE
00040
#endif
00041
00042
00043
00044
#ifdef __INTEL_COMPILER
00045
# ifndef __USE_XOPEN
00046
# define __USE_XOPEN
00047
# endif
00048
#endif
00049
00050
#include <sys/types.h>
00051
#include <sys/ioctl.h>
00052
#include <sys/time.h>
00053
#include <sys/resource.h>
00054
#include <sys/stat.h>
00055
#include <sys/param.h>
00056
00057
#ifdef HAVE_SYS_STROPTS_H
00058
# include <sys/stropts.h>
00059
# define _NEW_TTY_CTRL
00060
#endif
00061
00062
#include <errno.h>
00063
#include <fcntl.h>
00064
#include <time.h>
00065
#include <stdlib.h>
00066
#include <stdio.h>
00067
#include <string.h>
00068
#include <unistd.h>
00069
#include <grp.h>
00070
00071
#ifdef HAVE_LIBUTIL_H
00072
# include <libutil.h>
00073
# define USE_LOGIN
00074
#elif defined(HAVE_UTIL_H)
00075
# include <util.h>
00076
# define USE_LOGIN
00077
#endif
00078
00079
#ifdef USE_LOGIN
00080
# include <utmp.h>
00081
#endif
00082
00083
#ifdef HAVE_TERMIOS_H
00084
00085
00086
extern "C" {
00087
# include <termios.h>
00088 }
00089
#endif
00090
00091
#if !defined(__osf__)
00092
# ifdef HAVE_TERMIO_H
00093
00094
# include <termio.h>
00095
# endif
00096
#endif
00097
00098
#if defined (__FreeBSD__) || defined (__NetBSD__) || defined (__OpenBSD__) || defined (__bsdi__) || defined(__APPLE__)
00099
# define _tcgetattr(fd, ttmode) ioctl(fd, TIOCGETA, (char *)ttmode)
00100
#else
00101
# if defined(_HPUX_SOURCE) || defined(__Lynx__)
00102
# define _tcgetattr(fd, ttmode) tcgetattr(fd, ttmode)
00103
# else
00104
# define _tcgetattr(fd, ttmode) ioctl(fd, TCGETS, (char *)ttmode)
00105
# endif
00106
#endif
00107
00108
#if defined (__FreeBSD__) || defined (__NetBSD__) || defined (__OpenBSD__) || defined (__bsdi__) || defined(__APPLE__)
00109
# define _tcsetattr(fd, ttmode) ioctl(fd, TIOCSETA, (char *)ttmode)
00110
#else
00111
# ifdef _HPUX_SOURCE
00112
# define _tcsetattr(fd, ttmode) tcsetattr(fd, TCSANOW, ttmode)
00113
# else
00114
# define _tcsetattr(fd, ttmode) ioctl(fd, TCSETS, (char *)ttmode)
00115
# endif
00116
#endif
00117
00118
#if defined (_HPUX_SOURCE)
00119
# define _TERMIOS_INCLUDED
00120
# include <bsdtty.h>
00121
#endif
00122
00123
#if defined(HAVE_PTY_H)
00124
# include <pty.h>
00125
#endif
00126
00127
#include <kdebug.h>
00128
#include <kstandarddirs.h>
00129
00130
00131
#ifndef CTRL
00132
# define CTRL(x) ((x) & 037)
00133
#endif
00134
00135
#define TTY_GROUP "tty"
00136
00138
00140
00141
#ifdef HAVE_UTEMPTER
00142
class KProcess_Utmp :
public KProcess
00143 {
00144
public:
00145
int commSetupDoneC()
00146 {
00147 dup2(cmdFd, 0);
00148 dup2(cmdFd, 1);
00149 dup2(cmdFd, 3);
00150
return 1;
00151 }
00152
int cmdFd;
00153 };
00154
#endif
00155
00156
#define BASE_CHOWN "kgrantpty"
00157
00158
00159
00161
00163
00164
struct KPtyPrivate {
00165 KPtyPrivate() :
00166 xonXoff(false),
00167 masterFd(-1), slaveFd(-1)
00168 {
00169 memset(&winSize, 0,
sizeof(winSize));
00170 winSize.ws_row = 24;
00171 winSize.ws_col = 80;
00172 }
00173
00174
bool xonXoff : 1;
00175
int masterFd;
00176
int slaveFd;
00177
struct winsize winSize;
00178
00179
QCString ttyName;
00180 };
00181
00183
00185
00186 KPty::KPty()
00187 {
00188 d =
new KPtyPrivate;
00189 }
00190
00191 KPty::~KPty()
00192 {
00193
close();
00194
delete d;
00195 }
00196
00197 bool KPty::open()
00198 {
00199
if (d->masterFd >= 0)
00200
return true;
00201
00202
QCString ptyName;
00203
00204
00205
00206
00207
00208
00209
00210
00211
#if defined(HAVE_PTSNAME) && defined(HAVE_GRANTPT)
00212
#ifdef _AIX
00213
d->masterFd = ::open(
"/dev/ptc",O_RDWR);
00214
#else
00215
d->masterFd = ::open(
"/dev/ptmx",O_RDWR);
00216
#endif
00217
if (d->masterFd >= 0)
00218 {
00219
char *ptsn = ptsname(d->masterFd);
00220
if (ptsn) {
00221 grantpt(d->masterFd);
00222 d->ttyName = ptsn;
00223
goto gotpty;
00224 }
else {
00225 ::close(d->masterFd);
00226 d->masterFd = -1;
00227 }
00228 }
00229
#endif
00230
00231
00232
for (
const char* s3 =
"pqrstuvwxyzabcdefghijklmno"; *s3; s3++)
00233 {
00234
for (
const char* s4 =
"0123456789abcdefghijklmnopqrstuvwxyz"; *s4; s4++)
00235 {
00236 ptyName.sprintf(
"/dev/pty%c%c", *s3, *s4);
00237 d->ttyName.sprintf(
"/dev/tty%c%c", *s3, *s4);
00238
00239 d->masterFd = ::open(ptyName.data(), O_RDWR);
00240
if (d->masterFd >= 0)
00241 {
00242
#ifdef __sun
00243
00244
00245
00246
00247
int pgrp_rtn;
00248
if (ioctl(d->masterFd, TIOCGPGRP, &pgrp_rtn) == 0 || errno != EIO) {
00249 ::close(d->masterFd);
00250 d->masterFd = -1;
00251
continue;
00252 }
00253
#endif
00254
if (!access(d->ttyName.data(),R_OK|W_OK))
00255 {
00256
if (!geteuid())
00257 {
00258
struct group* p = getgrnam(TTY_GROUP);
00259
if (!p)
00260 p = getgrnam(
"wheel");
00261 gid_t gid = p ? p->gr_gid : getgid ();
00262
00263 chown(d->ttyName.data(), getuid(), gid);
00264 chmod(d->ttyName.data(), S_IRUSR|S_IWUSR|S_IWGRP);
00265 }
00266
goto gotpty;
00267 }
00268 ::close(d->masterFd);
00269 d->masterFd = -1;
00270 }
00271 }
00272 }
00273
00274 kdWarning(175) <<
"Can't open a pseudo teletype" <<
endl;
00275
return false;
00276
00277 gotpty:
00278
struct stat st;
00279
if (stat(d->ttyName.data(), &st))
00280
return false;
00281
if (((st.st_uid != getuid()) ||
00282 (st.st_mode & (S_IRGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH))) &&
00283 !chownpty(
true))
00284 {
00285 kdWarning(175)
00286 <<
"chownpty failed for device " << ptyName <<
"::" << d->ttyName
00287 <<
"\nThis means the communication can be eavesdropped." <<
endl;
00288 }
00289
00290
#ifdef BSD
00291
revoke(d->ttyName.data());
00292
#endif
00293
00294
#ifdef HAVE_UNLOCKPT
00295
unlockpt(d->masterFd);
00296
#endif
00297
00298 d->slaveFd = ::open(d->ttyName.data(), O_RDWR | O_NOCTTY);
00299
if (d->slaveFd < 0)
00300 {
00301 kdWarning(175) <<
"Can't open slave pseudo teletype" <<
endl;
00302 ::close(d->masterFd);
00303 d->masterFd = -1;
00304
return false;
00305 }
00306
00307
#if (defined(__svr4__) || defined(__sgi__))
00308
00309 ioctl(d->slaveFd, I_PUSH,
"ptem");
00310 ioctl(d->slaveFd, I_PUSH,
"ldterm");
00311
#endif
00312
00313
00314
00315
00316
00317 struct ::termios ttmode;
00318
00319 _tcgetattr(d->slaveFd, &ttmode);
00320
00321
if (!d->xonXoff)
00322 ttmode.c_iflag &= ~(IXOFF | IXON);
00323
else
00324 ttmode.c_iflag |= (IXOFF | IXON);
00325
00326 ttmode.c_cc[VINTR] = CTRL(
'C' -
'@');
00327 ttmode.c_cc[VQUIT] = CTRL(
'\\' -
'@');
00328 ttmode.c_cc[VERASE] = 0177;
00329
00330 _tcsetattr(d->slaveFd, &ttmode);
00331
00332
00333 ioctl(d->slaveFd, TIOCSWINSZ, (
char *)&d->winSize);
00334
00335 fcntl(d->masterFd, F_SETFD, FD_CLOEXEC);
00336 fcntl(d->slaveFd, F_SETFD, FD_CLOEXEC);
00337
00338
return true;
00339 }
00340
00341 void KPty::close()
00342 {
00343
if (d->masterFd < 0)
00344
return;
00345
00346
if (memcmp(d->ttyName.data(),
"/dev/pts/", 9)) {
00347
if (!geteuid()) {
00348
struct stat st;
00349
if (!stat(d->ttyName.data(), &st)) {
00350 chown(d->ttyName.data(), 0, st.st_gid == getgid() ? 0 : -1);
00351 chmod(d->ttyName.data(), S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
00352 }
00353 }
else {
00354 fcntl(d->masterFd, F_SETFD, 0);
00355 chownpty(
false);
00356 }
00357 }
00358 ::close(d->slaveFd);
00359 ::close(d->masterFd);
00360 d->masterFd = d->slaveFd = -1;
00361 }
00362
00363 void KPty::setCTty()
00364 {
00365
00366
00367
00368
00369 setsid();
00370
00371
00372
#ifdef TIOCSCTTY
00373
ioctl(d->slaveFd, TIOCSCTTY, 0);
00374
#else
00375
00376 ::close(::open(d->ttyName, O_WRONLY, 0));
00377
#endif
00378
00379
00380
int pgrp = getpid();
00381
#if defined(_POSIX_VERSION) || defined(__svr4__)
00382
tcsetpgrp (d->slaveFd, pgrp);
00383
#elif defined(TIOCSPGRP)
00384
ioctl(d->slaveFd, TIOCSPGRP, (
char *)&pgrp);
00385
#endif
00386
}
00387
00388 void KPty::login(
const char *user,
const char *remotehost)
00389 {
00390
#ifdef HAVE_UTEMPTER
00391
KProcess_Utmp utmp;
00392 utmp.cmdFd = d->masterFd;
00393 utmp <<
"/usr/sbin/utempter" <<
"-a" << d->ttyName <<
"";
00394 utmp.start(KProcess::Block);
00395 Q_UNUSED(user);
00396 Q_UNUSED(remotehost);
00397
#elif defined(USE_LOGIN)
00398
const char *str_ptr;
00399
struct utmp l_struct;
00400 memset(&l_struct, 0,
sizeof(
struct utmp));
00401
00402
00403
if (user)
00404 strncpy(l_struct.ut_name, user, UT_NAMESIZE);
00405
00406
if (remotehost)
00407 strncpy(l_struct.ut_host, remotehost, UT_HOSTSIZE);
00408
00409
# ifndef __GLIBC__
00410
str_ptr = d->ttyName.data();
00411
if (!memcmp(str_ptr,
"/dev/", 5))
00412 str_ptr += 5;
00413 strncpy(l_struct.ut_line, str_ptr, UT_LINESIZE);
00414
# endif
00415
00416
00417
00418 {
00419 time_t ut_time_temp;
00420 time(&ut_time_temp);
00421 l_struct.ut_time=ut_time_temp;
00422 }
00423
00424 ::login(&l_struct);
00425
#else
00426
Q_UNUSED(user);
00427 Q_UNUSED(remotehost);
00428
#endif
00429
}
00430
00431 void KPty::logout()
00432 {
00433
#ifdef HAVE_UTEMPTER
00434
KProcess_Utmp utmp;
00435 utmp.cmdFd = d->masterFd;
00436 utmp <<
"/usr/sbin/utempter" <<
"-d" << d->ttyName;
00437 utmp.start(KProcess::Block);
00438
#elif defined(USE_LOGIN)
00439
const char *str_ptr = d->ttyName.data();
00440
if (!memcmp(str_ptr,
"/dev/", 5))
00441 str_ptr += 5;
00442
# ifdef __GLIBC__
00443
else {
00444
const char *sl_ptr = strrchr(str_ptr,
'/');
00445
if (sl_ptr)
00446 str_ptr = sl_ptr + 1;
00447 }
00448
# endif
00449
::logout(str_ptr);
00450
#endif
00451
}
00452
00453 void KPty::setWinSize(
int lines,
int columns)
00454 {
00455 d->winSize.ws_row = (
unsigned short)lines;
00456 d->winSize.ws_col = (
unsigned short)columns;
00457
if (d->masterFd >= 0)
00458 ioctl( d->masterFd, TIOCSWINSZ, (
char *)&d->winSize );
00459 }
00460
00461 void KPty::setXonXoff(
bool useXonXoff)
00462 {
00463 d->xonXoff = useXonXoff;
00464
if (d->masterFd >= 0) {
00465
00466
00467
00468 struct ::termios ttmode;
00469
00470 _tcgetattr(d->masterFd, &ttmode);
00471
00472
if (!useXonXoff)
00473 ttmode.c_iflag &= ~(IXOFF | IXON);
00474
else
00475 ttmode.c_iflag |= (IXOFF | IXON);
00476
00477 _tcsetattr(d->masterFd, &ttmode);
00478 }
00479 }
00480
00481 const char *
KPty::ttyName()
const
00482
{
00483
return d->ttyName.data();
00484 }
00485
00486 int KPty::masterFd()
const
00487
{
00488
return d->masterFd;
00489 }
00490
00491 int KPty::slaveFd()
const
00492
{
00493
return d->slaveFd;
00494 }
00495
00496
00497
bool KPty::chownpty(
bool grant)
00498 {
00499
KProcess proc;
00500 proc << locate(
"exe", BASE_CHOWN) << (grant?
"--grant":
"--revoke") << QString::number(d->masterFd);
00501
return proc.
start(KProcess::Block) && proc.
normalExit() && !proc.
exitStatus();
00502 }
00503