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
bool utf8 : 1;
00176
int masterFd;
00177
int slaveFd;
00178
struct winsize winSize;
00179
00180
QCString ttyName;
00181 };
00182
00184
00186
00187 KPty::KPty()
00188 {
00189 d =
new KPtyPrivate;
00190 }
00191
00192 KPty::~KPty()
00193 {
00194
close();
00195
delete d;
00196 }
00197
00198
bool KPty::open()
00199 {
00200
if (d->masterFd >= 0)
00201
return true;
00202
00203
QCString ptyName;
00204
00205
00206
00207
00208
00209
00210
00211
00212
#if defined(HAVE_PTSNAME) && defined(HAVE_GRANTPT)
00213
#ifdef _AIX
00214
d->masterFd = ::open(
"/dev/ptc",O_RDWR);
00215
#else
00216
d->masterFd = ::open(
"/dev/ptmx",O_RDWR);
00217
#endif
00218
if (d->masterFd >= 0)
00219 {
00220
char *ptsn = ptsname(d->masterFd);
00221
if (ptsn) {
00222 grantpt(d->masterFd);
00223 d->ttyName = ptsn;
00224
goto gotpty;
00225 }
else {
00226 ::close(d->masterFd);
00227 d->masterFd = -1;
00228 }
00229 }
00230
#endif
00231
00232
00233
for (
const char* s3 =
"pqrstuvwxyzabcdefghijklmno"; *s3; s3++)
00234 {
00235
for (
const char* s4 =
"0123456789abcdefghijklmnopqrstuvwxyz"; *s4; s4++)
00236 {
00237 ptyName.
sprintf(
"/dev/pty%c%c", *s3, *s4);
00238 d->ttyName.sprintf(
"/dev/tty%c%c", *s3, *s4);
00239
00240 d->masterFd = ::open(ptyName.data(), O_RDWR);
00241
if (d->masterFd >= 0)
00242 {
00243
#ifdef __sun
00244
00245
00246
00247
00248
int pgrp_rtn;
00249
if (ioctl(d->masterFd, TIOCGPGRP, &pgrp_rtn) == 0 || errno != EIO) {
00250 ::close(d->masterFd);
00251 d->masterFd = -1;
00252
continue;
00253 }
00254
#endif
00255
if (!access(d->ttyName.data(),R_OK|W_OK))
00256 {
00257
if (!geteuid())
00258 {
00259
struct group* p = getgrnam(TTY_GROUP);
00260
if (!p)
00261 p = getgrnam(
"wheel");
00262 gid_t gid = p ? p->gr_gid : getgid ();
00263
00264 chown(d->ttyName.data(), getuid(), gid);
00265
chmod(d->ttyName.data(), S_IRUSR|S_IWUSR|S_IWGRP);
00266 }
00267
goto gotpty;
00268 }
00269 ::close(d->masterFd);
00270 d->masterFd = -1;
00271 }
00272 }
00273 }
00274
00275 kdWarning(175) <<
"Can't open a pseudo teletype" <<
endl;
00276
return false;
00277
00278 gotpty:
00279
struct stat st;
00280
if (
stat(d->ttyName.data(), &st))
00281
return false;
00282
00283
00284
if (((st.st_uid != getuid()) ||
00285 (st.st_mode & (S_IRGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH))) &&
00286 !chownpty(
true))
00287 {
00288 kdWarning(175)
00289 <<
"chownpty failed for device " << ptyName <<
"::" << d->ttyName
00290 <<
"\nThis means the communication can be eavesdropped." <<
endl;
00291 }
00292
00293
#ifdef BSD
00294
revoke(d->ttyName.data());
00295
#endif
00296
00297
#ifdef HAVE_UNLOCKPT
00298
unlockpt(d->masterFd);
00299
#endif
00300
00301 d->slaveFd = ::open(d->ttyName.data(), O_RDWR | O_NOCTTY);
00302
if (d->slaveFd < 0)
00303 {
00304 kdWarning(175) <<
"Can't open slave pseudo teletype" <<
endl;
00305 ::close(d->masterFd);
00306 d->masterFd = -1;
00307
return false;
00308 }
00309
00310
#if (defined(__svr4__) || defined(__sgi__))
00311
00312 ioctl(d->slaveFd, I_PUSH,
"ptem");
00313 ioctl(d->slaveFd, I_PUSH,
"ldterm");
00314
#endif
00315
00316
00317
00318
00319
00320 struct ::termios ttmode;
00321
00322 _tcgetattr(d->slaveFd, &ttmode);
00323
00324
if (!d->xonXoff)
00325 ttmode.c_iflag &= ~(IXOFF | IXON);
00326
else
00327 ttmode.c_iflag |= (IXOFF | IXON);
00328
00329
#ifdef IUTF8
00330
if (!d->utf8)
00331 ttmode.c_iflag &= ~IUTF8;
00332
else
00333 ttmode.c_iflag |= IUTF8;
00334
#endif
00335
00336 ttmode.c_cc[VINTR] = CTRL(
'C' -
'@');
00337 ttmode.c_cc[VQUIT] = CTRL(
'\\' -
'@');
00338 ttmode.c_cc[VERASE] = 0177;
00339
00340 _tcsetattr(d->slaveFd, &ttmode);
00341
00342
00343 ioctl(d->slaveFd, TIOCSWINSZ, (
char *)&d->winSize);
00344
00345 fcntl(d->masterFd, F_SETFD, FD_CLOEXEC);
00346 fcntl(d->slaveFd, F_SETFD, FD_CLOEXEC);
00347
00348
return true;
00349 }
00350
00351
void KPty::close()
00352 {
00353
if (d->masterFd < 0)
00354
return;
00355
00356
if (memcmp(d->ttyName.data(),
"/dev/pts/", 9)) {
00357
if (!geteuid()) {
00358
struct stat st;
00359
if (!
stat(d->ttyName.data(), &st)) {
00360 chown(d->ttyName.data(), 0, st.st_gid == getgid() ? 0 : -1);
00361
chmod(d->ttyName.data(), S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
00362 }
00363 }
else {
00364 fcntl(d->masterFd, F_SETFD, 0);
00365 chownpty(
false);
00366 }
00367 }
00368 ::close(d->slaveFd);
00369 ::close(d->masterFd);
00370 d->masterFd = d->slaveFd = -1;
00371 }
00372
00373
void KPty::setCTty()
00374 {
00375
00376
00377
00378
00379 setsid();
00380
00381
00382
#ifdef TIOCSCTTY
00383
ioctl(d->slaveFd, TIOCSCTTY, 0);
00384
#else
00385
00386 ::close(::open(d->ttyName, O_WRONLY, 0));
00387
#endif
00388
00389
00390
int pgrp = getpid();
00391
#if defined(_POSIX_VERSION) || defined(__svr4__)
00392
tcsetpgrp (d->slaveFd, pgrp);
00393
#elif defined(TIOCSPGRP)
00394
ioctl(d->slaveFd, TIOCSPGRP, (
char *)&pgrp);
00395
#endif
00396
}
00397
00398
void KPty::login(
const char *user,
const char *remotehost)
00399 {
00400
#ifdef HAVE_UTEMPTER
00401
KProcess_Utmp utmp;
00402 utmp.cmdFd = d->masterFd;
00403 utmp <<
"/usr/sbin/utempter" <<
"-a" << d->ttyName <<
"";
00404 utmp.start(KProcess::Block);
00405 Q_UNUSED(user);
00406 Q_UNUSED(remotehost);
00407
#elif defined(USE_LOGIN)
00408
const char *str_ptr;
00409
struct utmp l_struct;
00410 memset(&l_struct, 0,
sizeof(
struct utmp));
00411
00412
00413
if (user)
00414 strncpy(l_struct.ut_name, user, UT_NAMESIZE);
00415
00416
if (remotehost)
00417 strncpy(l_struct.ut_host, remotehost, UT_HOSTSIZE);
00418
00419
# ifndef __GLIBC__
00420
str_ptr = d->ttyName.data();
00421
if (!memcmp(str_ptr,
"/dev/", 5))
00422 str_ptr += 5;
00423 strncpy(l_struct.ut_line, str_ptr, UT_LINESIZE);
00424
# endif
00425
00426
00427
00428 {
00429 time_t ut_time_temp;
00430 time(&ut_time_temp);
00431 l_struct.ut_time=ut_time_temp;
00432 }
00433
00434 ::login(&l_struct);
00435
#else
00436
Q_UNUSED(user);
00437 Q_UNUSED(remotehost);
00438
#endif
00439
}
00440
00441
void KPty::logout()
00442 {
00443
#ifdef HAVE_UTEMPTER
00444
KProcess_Utmp utmp;
00445 utmp.cmdFd = d->masterFd;
00446 utmp <<
"/usr/sbin/utempter" <<
"-d" << d->ttyName;
00447 utmp.start(KProcess::Block);
00448
#elif defined(USE_LOGIN)
00449
const char *str_ptr = d->ttyName.data();
00450
if (!memcmp(str_ptr,
"/dev/", 5))
00451 str_ptr += 5;
00452
# ifdef __GLIBC__
00453
else {
00454
const char *sl_ptr = strrchr(str_ptr,
'/');
00455
if (sl_ptr)
00456 str_ptr = sl_ptr + 1;
00457 }
00458
# endif
00459
::logout(str_ptr);
00460
#endif
00461
}
00462
00463
void KPty::setWinSize(
int lines,
int columns)
00464 {
00465 d->winSize.ws_row = (
unsigned short)lines;
00466 d->winSize.ws_col = (
unsigned short)columns;
00467
if (d->masterFd >= 0)
00468 ioctl( d->masterFd, TIOCSWINSZ, (
char *)&d->winSize );
00469 }
00470
00471
void KPty::setXonXoff(
bool useXonXoff)
00472 {
00473 d->xonXoff = useXonXoff;
00474
if (d->masterFd >= 0) {
00475
00476
00477
00478 struct ::termios ttmode;
00479
00480 _tcgetattr(d->masterFd, &ttmode);
00481
00482
if (!useXonXoff)
00483 ttmode.c_iflag &= ~(IXOFF | IXON);
00484
else
00485 ttmode.c_iflag |= (IXOFF | IXON);
00486
00487 _tcsetattr(d->masterFd, &ttmode);
00488 }
00489 }
00490
00491
void KPty::setUtf8Mode(
bool useUtf8)
00492 {
00493 d->utf8 = useUtf8;
00494
if (d->masterFd >= 0) {
00495
00496
00497
00498 struct ::termios ttmode;
00499
00500
#ifdef IUTF8
00501
_tcgetattr(d->masterFd, &ttmode);
00502
00503
if (!useUtf8)
00504 ttmode.c_iflag &= ~IUTF8;
00505
else
00506 ttmode.c_iflag |= IUTF8;
00507
00508 _tcsetattr(d->masterFd, &ttmode);
00509
#endif
00510
}
00511 }
00512
00513
const char *KPty::ttyName()
const
00514
{
00515
return d->ttyName.data();
00516 }
00517
00518
int KPty::masterFd()
const
00519
{
00520
return d->masterFd;
00521 }
00522
00523
int KPty::slaveFd()
const
00524
{
00525
return d->slaveFd;
00526 }
00527
00528
00529
bool KPty::chownpty(
bool grant)
00530 {
00531
KProcess proc;
00532 proc << locate(
"exe", BASE_CHOWN) << (grant?
"--grant":
"--revoke") <<
QString::number(d->masterFd);
00533
return proc.
start(KProcess::Block) && proc.
normalExit() && !proc.
exitStatus();
00534 }
00535