00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "kpty_p.h"
00024
00025 #include <config.h>
00026
00027 #ifdef __sgi
00028 #define __svr4__
00029 #endif
00030
00031 #ifdef __osf__
00032 #define _OSF_SOURCE
00033 #include <float.h>
00034 #endif
00035
00036 #ifdef _AIX
00037 #define _ALL_SOURCE
00038 #endif
00039
00040
00041
00042 #ifdef __INTEL_COMPILER
00043 # ifndef __USE_XOPEN
00044 # define __USE_XOPEN
00045 # endif
00046 #endif
00047
00048 #include <sys/types.h>
00049 #include <sys/ioctl.h>
00050 #include <sys/time.h>
00051 #include <sys/resource.h>
00052 #include <sys/stat.h>
00053 #include <sys/param.h>
00054
00055 #include <errno.h>
00056 #include <fcntl.h>
00057 #include <time.h>
00058 #include <stdlib.h>
00059 #include <stdio.h>
00060 #include <string.h>
00061 #include <unistd.h>
00062 #include <grp.h>
00063
00064 #if defined(HAVE_PTY_H)
00065 # include <pty.h>
00066 #endif
00067
00068 #ifdef HAVE_LIBUTIL_H
00069 # include <libutil.h>
00070 #elif defined(HAVE_UTIL_H)
00071 # include <util.h>
00072 #endif
00073
00074 #ifdef HAVE_UTEMPTER
00075 extern "C" {
00076 # include <utempter.h>
00077 }
00078 #else
00079 # include <utmp.h>
00080 # ifdef HAVE_UTMPX
00081 # include <utmpx.h>
00082 # endif
00083 # if !defined(_PATH_UTMPX) && defined(_UTMPX_FILE)
00084 # define _PATH_UTMPX _UTMPX_FILE
00085 # endif
00086 # if !defined(_PATH_WTMPX) && defined(_WTMPX_FILE)
00087 # define _PATH_WTMPX _WTMPX_FILE
00088 # endif
00089 #endif
00090
00091
00092
00093 extern "C" {
00094 #include <termios.h>
00095 #if defined(HAVE_TERMIO_H)
00096 # include <termio.h>
00097 #endif
00098 }
00099
00100 #if defined (_HPUX_SOURCE)
00101 # define _TERMIOS_INCLUDED
00102 # include <bsdtty.h>
00103 #endif
00104
00105 #ifdef HAVE_SYS_STROPTS_H
00106 # include <sys/stropts.h>
00107 # define _NEW_TTY_CTRL
00108 #endif
00109
00110 #if defined (__FreeBSD__) || defined (__NetBSD__) || defined (__OpenBSD__) || defined (__bsdi__) || defined(__APPLE__) || defined (__DragonFly__)
00111 # define _tcgetattr(fd, ttmode) ioctl(fd, TIOCGETA, (char *)ttmode)
00112 #else
00113 # if defined(_HPUX_SOURCE) || defined(__Lynx__) || defined (__CYGWIN__)
00114 # define _tcgetattr(fd, ttmode) tcgetattr(fd, ttmode)
00115 # else
00116 # define _tcgetattr(fd, ttmode) ioctl(fd, TCGETS, (char *)ttmode)
00117 # endif
00118 #endif
00119
00120 #if defined (__FreeBSD__) || defined (__NetBSD__) || defined (__OpenBSD__) || defined (__bsdi__) || defined(__APPLE__) || defined (__DragonFly__)
00121 # define _tcsetattr(fd, ttmode) ioctl(fd, TIOCSETA, (char *)ttmode)
00122 #else
00123 # if defined(_HPUX_SOURCE) || defined(__CYGWIN__)
00124 # define _tcsetattr(fd, ttmode) tcsetattr(fd, TCSANOW, ttmode)
00125 # else
00126 # define _tcsetattr(fd, ttmode) ioctl(fd, TCSETS, (char *)ttmode)
00127 # endif
00128 #endif
00129
00130 #include <kdebug.h>
00131 #include <kstandarddirs.h>
00132 #include <kde_file.h>
00133
00134 #include <QtCore/Q_PID>
00135
00136 #define TTY_GROUP "tty"
00137
00139
00141
00143
00145
00146 KPtyPrivate::KPtyPrivate(KPty* parent) :
00147 masterFd(-1), slaveFd(-1), ownMaster(true), q_ptr(parent)
00148 {
00149 }
00150
00151 KPtyPrivate::~KPtyPrivate()
00152 {
00153 }
00154
00155 #ifndef HAVE_OPENPTY
00156 bool KPtyPrivate::chownpty(bool grant)
00157 {
00158 return !QProcess::execute(KStandardDirs::findExe("kgrantpty"),
00159 QStringList() << (grant?"--grant":"--revoke") << QString::number(masterFd));
00160 }
00161 #endif
00162
00164
00166
00167 KPty::KPty() :
00168 d_ptr(new KPtyPrivate(this))
00169 {
00170 }
00171
00172 KPty::KPty(KPtyPrivate *d) :
00173 d_ptr(d)
00174 {
00175 d_ptr->q_ptr = this;
00176 }
00177
00178 KPty::~KPty()
00179 {
00180 close();
00181 delete d_ptr;
00182 }
00183
00184 bool KPty::open()
00185 {
00186 Q_D(KPty);
00187
00188 if (d->masterFd >= 0)
00189 return true;
00190
00191 d->ownMaster = true;
00192
00193 QByteArray ptyName;
00194
00195
00196
00197
00198
00199
00200
00201
00202 #ifdef HAVE_OPENPTY
00203
00204 char ptsn[PATH_MAX];
00205 if (::openpty( &d->masterFd, &d->slaveFd, ptsn, 0, 0))
00206 {
00207 d->masterFd = -1;
00208 d->slaveFd = -1;
00209 kWarning(175) << "Can't open a pseudo teletype";
00210 return false;
00211 }
00212 d->ttyName = ptsn;
00213
00214 #else
00215
00216 #ifdef HAVE__GETPTY // irix
00217
00218 char *ptsn = _getpty(&d->masterFd, O_RDWR|O_NOCTTY, S_IRUSR|S_IWUSR, 0);
00219 if (ptsn) {
00220 d->ttyName = ptsn;
00221 goto grantedpt;
00222 }
00223
00224 #elif defined(HAVE_PTSNAME) || defined(TIOCGPTN)
00225
00226 #ifdef HAVE_POSIX_OPENPT
00227 d->masterFd = ::posix_openpt(O_RDWR|O_NOCTTY);
00228 #elif defined(HAVE_GETPT)
00229 d->masterFd = ::getpt();
00230 #elif defined(PTM_DEVICE)
00231 d->masterFd = KDE_open(PTM_DEVICE, O_RDWR|O_NOCTTY);
00232 #else
00233 # error No method to open a PTY master detected.
00234 #endif
00235 if (d->masterFd >= 0)
00236 {
00237 #ifdef HAVE_PTSNAME
00238 char *ptsn = ptsname(d->masterFd);
00239 if (ptsn) {
00240 d->ttyName = ptsn;
00241 #else
00242 int ptyno;
00243 if (!ioctl(d->masterFd, TIOCGPTN, &ptyno)) {
00244 char buf[32];
00245 sprintf(buf, "/dev/pts/%d", ptyno);
00246 d->ttyName = buf;
00247 #endif
00248 #ifdef HAVE_GRANTPT
00249 if (!grantpt(d->masterFd))
00250 goto grantedpt;
00251 #else
00252 goto gotpty;
00253 #endif
00254 }
00255 ::close(d->masterFd);
00256 d->masterFd = -1;
00257 }
00258 #endif // HAVE_PTSNAME || TIOCGPTN
00259
00260
00261 for (const char* s3 = "pqrstuvwxyzabcde"; *s3; s3++)
00262 {
00263 for (const char* s4 = "0123456789abcdef"; *s4; s4++)
00264 {
00265 ptyName = QString().sprintf("/dev/pty%c%c", *s3, *s4).toAscii();
00266 d->ttyName = QString().sprintf("/dev/tty%c%c", *s3, *s4).toAscii();
00267
00268 d->masterFd = KDE_open(ptyName.data(), O_RDWR);
00269 if (d->masterFd >= 0)
00270 {
00271 #ifdef Q_OS_SOLARIS
00272
00273
00274
00275
00276 int pgrp_rtn;
00277 if (ioctl(d->masterFd, TIOCGPGRP, &pgrp_rtn) == 0 || errno != EIO) {
00278 ::close(d->masterFd);
00279 d->masterFd = -1;
00280 continue;
00281 }
00282 #endif
00283 if (!access(d->ttyName.data(),R_OK|W_OK))
00284 {
00285 if (!geteuid())
00286 {
00287 struct group* p = getgrnam(TTY_GROUP);
00288 if (!p)
00289 p = getgrnam("wheel");
00290 gid_t gid = p ? p->gr_gid : getgid ();
00291
00292 chown(d->ttyName.data(), getuid(), gid);
00293 chmod(d->ttyName.data(), S_IRUSR|S_IWUSR|S_IWGRP);
00294 }
00295 goto gotpty;
00296 }
00297 ::close(d->masterFd);
00298 d->masterFd = -1;
00299 }
00300 }
00301 }
00302
00303 kWarning(175) << "Can't open a pseudo teletype";
00304 return false;
00305
00306 gotpty:
00307 KDE_struct_stat st;
00308 if (KDE_stat(d->ttyName.data(), &st))
00309 return false;
00310
00311
00312 if (((st.st_uid != getuid()) ||
00313 (st.st_mode & (S_IRGRP|S_IXGRP|S_IROTH|S_IWOTH|S_IXOTH))) &&
00314 !d->chownpty(true))
00315 {
00316 kWarning(175)
00317 << "chownpty failed for device " << ptyName << "::" << d->ttyName
00318 << "\nThis means the communication can be eavesdropped." << endl;
00319 }
00320
00321 grantedpt:
00322
00323 #ifdef HAVE_REVOKE
00324 revoke(d->ttyName.data());
00325 #endif
00326
00327 #ifdef HAVE_UNLOCKPT
00328 unlockpt(d->masterFd);
00329 #elif defined(TIOCSPTLCK)
00330 int flag = 0;
00331 ioctl(d->masterFd, TIOCSPTLCK, &flag);
00332 #endif
00333
00334 d->slaveFd = KDE_open(d->ttyName.data(), O_RDWR | O_NOCTTY);
00335 if (d->slaveFd < 0)
00336 {
00337 kWarning(175) << "Can't open slave pseudo teletype";
00338 ::close(d->masterFd);
00339 d->masterFd = -1;
00340 return false;
00341 }
00342
00343 #if (defined(__svr4__) || defined(__sgi__))
00344
00345 ioctl(d->slaveFd, I_PUSH, "ptem");
00346 ioctl(d->slaveFd, I_PUSH, "ldterm");
00347 #endif
00348
00349 #endif
00350
00351 fcntl(d->masterFd, F_SETFD, FD_CLOEXEC);
00352 fcntl(d->slaveFd, F_SETFD, FD_CLOEXEC);
00353
00354 return true;
00355 }
00356
00357 bool KPty::open(int fd)
00358 {
00359 #if !defined(HAVE_PTSNAME) && !defined(TIOCGPTN)
00360 kWarning(175) << "Unsupported attempt to open pty with fd" << fd;
00361 return false;
00362 #else
00363 Q_D(KPty);
00364
00365 if (d->masterFd >= 0) {
00366 kWarning(175) << "Attempting to open an already open pty";
00367 return false;
00368 }
00369
00370 d->ownMaster = false;
00371
00372 # ifdef HAVE_PTSNAME
00373 char *ptsn = ptsname(fd);
00374 if (ptsn) {
00375 d->ttyName = ptsn;
00376 # else
00377 int ptyno;
00378 if (!ioctl(fd, TIOCGPTN, &ptyno)) {
00379 char buf[32];
00380 sprintf(buf, "/dev/pts/%d", ptyno);
00381 d->ttyName = buf;
00382 # endif
00383 } else {
00384 kWarning(175) << "Failed to determine pty slave device for fd" << fd;
00385 return false;
00386 }
00387
00388 d->masterFd = fd;
00389 if (!openSlave()) {
00390 d->masterFd = -1;
00391 return false;
00392 }
00393
00394 return true;
00395 #endif
00396 }
00397
00398 void KPty::closeSlave()
00399 {
00400 Q_D(KPty);
00401
00402 if (d->slaveFd < 0)
00403 return;
00404 ::close(d->slaveFd);
00405 d->slaveFd = -1;
00406 }
00407
00408 bool KPty::openSlave()
00409 {
00410 Q_D(KPty);
00411
00412 if (d->slaveFd >= 0)
00413 return true;
00414 if (d->masterFd < 0) {
00415 kWarning(175) << "Attempting to open pty slave while master is closed";
00416 return false;
00417 }
00418 d->slaveFd = KDE_open(d->ttyName.data(), O_RDWR | O_NOCTTY);
00419 if (d->slaveFd < 0) {
00420 kWarning(175) << "Can't open slave pseudo teletype";
00421 return false;
00422 }
00423 fcntl(d->slaveFd, F_SETFD, FD_CLOEXEC);
00424 return true;
00425 }
00426
00427 void KPty::close()
00428 {
00429 Q_D(KPty);
00430
00431 if (d->masterFd < 0)
00432 return;
00433 closeSlave();
00434 if (d->ownMaster) {
00435 #ifndef HAVE_OPENPTY
00436
00437 if (memcmp(d->ttyName.data(), "/dev/pts/", 9)) {
00438 if (!geteuid()) {
00439 struct stat st;
00440 if (!stat(d->ttyName.data(), &st)) {
00441 chown(d->ttyName.data(), 0, st.st_gid == getgid() ? 0 : -1);
00442 chmod(d->ttyName.data(), S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
00443 }
00444 } else {
00445 fcntl(d->masterFd, F_SETFD, 0);
00446 d->chownpty(false);
00447 }
00448 }
00449 #endif
00450 ::close(d->masterFd);
00451 }
00452 d->masterFd = -1;
00453 }
00454
00455 void KPty::setCTty()
00456 {
00457 Q_D(KPty);
00458
00459
00460
00461
00462
00463 setsid();
00464
00465
00466 #ifdef TIOCSCTTY
00467 ioctl(d->slaveFd, TIOCSCTTY, 0);
00468 #else
00469
00470 ::close(KDE_open(d->ttyName, O_WRONLY, 0));
00471 #endif
00472
00473
00474 int pgrp = getpid();
00475 #if defined(_POSIX_VERSION) || defined(__svr4__)
00476 tcsetpgrp(d->slaveFd, pgrp);
00477 #elif defined(TIOCSPGRP)
00478 ioctl(d->slaveFd, TIOCSPGRP, (char *)&pgrp);
00479 #endif
00480 }
00481
00482 void KPty::login(const char *user, const char *remotehost)
00483 {
00484 #ifdef HAVE_UTEMPTER
00485 Q_D(KPty);
00486
00487 addToUtmp(d->ttyName, remotehost, d->masterFd);
00488 Q_UNUSED(user);
00489 #else
00490 # ifdef HAVE_UTMPX
00491 struct utmpx l_struct;
00492 # else
00493 struct utmp l_struct;
00494 # endif
00495 memset(&l_struct, 0, sizeof(l_struct));
00496
00497
00498 if (user)
00499 strncpy(l_struct.ut_name, user, sizeof(l_struct.ut_name));
00500
00501 if (remotehost) {
00502 strncpy(l_struct.ut_host, remotehost, sizeof(l_struct.ut_host));
00503 # ifdef HAVE_STRUCT_UTMP_UT_SYSLEN
00504 l_struct.ut_syslen = qMin(strlen(remotehost), sizeof(l_struct.ut_host));
00505 # endif
00506 }
00507
00508 # ifndef __GLIBC__
00509 Q_D(KPty);
00510 const char *str_ptr = d->ttyName.data();
00511 if (!memcmp(str_ptr, "/dev/", 5))
00512 str_ptr += 5;
00513 strncpy(l_struct.ut_line, str_ptr, sizeof(l_struct.ut_line));
00514 # ifdef HAVE_STRUCT_UTMP_UT_ID
00515 strncpy(l_struct.ut_id,
00516 str_ptr + strlen(str_ptr) - sizeof(l_struct.ut_id),
00517 sizeof(l_struct.ut_id));
00518 # endif
00519 # endif
00520
00521 # ifdef HAVE_UTMPX
00522 gettimeofday(&l_struct.ut_tv, 0);
00523 # else
00524 l_struct.ut_time = time(0);
00525 # endif
00526
00527 # ifdef HAVE_LOGIN
00528 # ifdef HAVE_LOGINX
00529 ::loginx(&l_struct);
00530 # else
00531 ::login(&l_struct);
00532 # endif
00533 # else
00534 # ifdef HAVE_STRUCT_UTMP_UT_TYPE
00535 l_struct.ut_type = USER_PROCESS;
00536 # endif
00537 # ifdef HAVE_STRUCT_UTMP_UT_PID
00538 l_struct.ut_pid = getpid();
00539 # ifdef HAVE_STRUCT_UTMP_UT_SESSION
00540 l_struct.ut_session = getsid(0);
00541 # endif
00542 # endif
00543 # ifdef HAVE_UTMPX
00544 utmpxname(_PATH_UTMPX);
00545 setutxent();
00546 pututxline(&l_struct);
00547 endutxent();
00548 updwtmpx(_PATH_WTMPX, &l_struct);
00549 # else
00550 utmpname(_PATH_UTMP);
00551 setutent();
00552 pututline(&l_struct);
00553 endutent();
00554 updwtmp(_PATH_WTMP, &l_struct);
00555 # endif
00556 # endif
00557 #endif
00558 }
00559
00560 void KPty::logout()
00561 {
00562 #ifdef HAVE_UTEMPTER
00563 Q_D(KPty);
00564
00565 removeLineFromUtmp(d->ttyName, d->masterFd);
00566 #else
00567 Q_D(KPty);
00568
00569 const char *str_ptr = d->ttyName.data();
00570 if (!memcmp(str_ptr, "/dev/", 5))
00571 str_ptr += 5;
00572 # ifdef __GLIBC__
00573 else {
00574 const char *sl_ptr = strrchr(str_ptr, '/');
00575 if (sl_ptr)
00576 str_ptr = sl_ptr + 1;
00577 }
00578 # endif
00579 # ifdef HAVE_LOGIN
00580 # ifdef HAVE_LOGINX
00581 ::logoutx(str_ptr, 0, DEAD_PROCESS);
00582 # else
00583 ::logout(str_ptr);
00584 # endif
00585 # else
00586 # ifdef HAVE_UTMPX
00587 struct utmpx l_struct, *ut;
00588 # else
00589 struct utmp l_struct, *ut;
00590 # endif
00591 memset(&l_struct, 0, sizeof(l_struct));
00592
00593 strncpy(l_struct.ut_line, str_ptr, sizeof(l_struct.ut_line));
00594
00595 # ifdef HAVE_UTMPX
00596 utmpxname(_PATH_UTMPX);
00597 setutxent();
00598 if ((ut = getutxline(&l_struct))) {
00599 # else
00600 utmpname(_PATH_UTMP);
00601 setutent();
00602 if ((ut = getutline(&l_struct))) {
00603 # endif
00604 memset(ut->ut_name, 0, sizeof(*ut->ut_name));
00605 memset(ut->ut_host, 0, sizeof(*ut->ut_host));
00606 # ifdef HAVE_STRUCT_UTMP_UT_SYSLEN
00607 ut->ut_syslen = 0;
00608 # endif
00609 # ifdef HAVE_STRUCT_UTMP_UT_TYPE
00610 ut->ut_type = DEAD_PROCESS;
00611 # endif
00612 # ifdef HAVE_UTMPX
00613 gettimeofday(&(ut->ut_tv), 0);
00614 pututxline(ut);
00615 }
00616 endutxent();
00617 # else
00618 ut->ut_time = time(0);
00619 pututline(ut);
00620 }
00621 endutent();
00622 # endif
00623 # endif
00624 #endif
00625 }
00626
00627
00628
00629
00630 bool KPty::tcGetAttr(struct ::termios *ttmode) const
00631 {
00632 Q_D(const KPty);
00633
00634 return _tcgetattr(d->masterFd, ttmode) == 0;
00635 }
00636
00637 bool KPty::tcSetAttr(struct ::termios *ttmode)
00638 {
00639 Q_D(KPty);
00640
00641 return _tcsetattr(d->masterFd, ttmode) == 0;
00642 }
00643
00644 bool KPty::setWinSize(int lines, int columns)
00645 {
00646 Q_D(KPty);
00647
00648 struct winsize winSize;
00649 memset(&winSize, 0, sizeof(winSize));
00650 winSize.ws_row = (unsigned short)lines;
00651 winSize.ws_col = (unsigned short)columns;
00652 return ioctl(d->masterFd, TIOCSWINSZ, (char *)&winSize) == 0;
00653 }
00654
00655 bool KPty::setEcho(bool echo)
00656 {
00657 struct ::termios ttmode;
00658 if (!tcGetAttr(&ttmode))
00659 return false;
00660 if (!echo)
00661 ttmode.c_lflag &= ~ECHO;
00662 else
00663 ttmode.c_lflag |= ECHO;
00664 return tcSetAttr(&ttmode);
00665 }
00666
00667 const char *KPty::ttyName() const
00668 {
00669 Q_D(const KPty);
00670
00671 return d->ttyName.data();
00672 }
00673
00674 int KPty::masterFd() const
00675 {
00676 Q_D(const KPty);
00677
00678 return d->masterFd;
00679 }
00680
00681 int KPty::slaveFd() const
00682 {
00683 Q_D(const KPty);
00684
00685 return d->slaveFd;
00686 }