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