1 /* Tests for opening/closing pseudo terminals - by D.C. van Moolenbroek */ 2 /* 3 * As of the introduction of Unix98 PTY support, this test set actually relies 4 * on the ability to create Unix98 PTYs. The system still supports old-style 5 * PTYs but there is no way to force openpty(3) to use them. However, part of 6 * this test set can still be used to test old-style PTYs: first disable Unix98 7 * PTYs, for example by unmounting PTYFS or temporarily removing /dev/ptmx, and 8 * then run the a-f subtests from this test set as root. 9 */ 10 #include <stdlib.h> 11 #include <stdio.h> 12 #include <string.h> 13 #include <signal.h> 14 #include <termios.h> 15 #include <sys/wait.h> 16 #include <sys/syslimits.h> 17 #include <paths.h> 18 #include <dirent.h> 19 #include <grp.h> 20 #include <fcntl.h> 21 #include <util.h> 22 23 #define ITERATIONS 10 24 25 #define MIN_PTYS 4 26 27 #include "common.h" 28 29 static int sighups; /* number of SIGHUP signals received */ 30 31 /* 32 * Signal handler for SIGHUP and SIGUSR1. 33 */ 34 static void 35 signal_handler(int sig) 36 { 37 if (sig == SIGHUP) 38 sighups++; 39 } 40 41 /* 42 * Set the slave side of the pseudo terminal to raw mode. This simplifies 43 * testing communication. 44 */ 45 static void 46 make_raw(int slavefd) 47 { 48 struct termios tios; 49 50 if (tcgetattr(slavefd, &tios) < 0) e(0); 51 52 cfmakeraw(&tios); 53 54 if (tcsetattr(slavefd, TCSANOW, &tios) < 0) e(0); 55 } 56 57 /* 58 * See if the given pseudo terminal can successfully perform basic 59 * communication between master and slave. 60 */ 61 static void 62 test_comm(int masterfd, int slavefd) 63 { 64 char c; 65 66 make_raw(slavefd); 67 68 c = 'A'; 69 if (write(masterfd, &c, sizeof(c)) != sizeof(c)) e(0); 70 if (read(slavefd, &c, sizeof(c)) != sizeof(c)) e(0); 71 if (c != 'A') e(0); 72 73 c = 'B'; 74 if (write(slavefd, &c, sizeof(c)) != sizeof(c)) e(0); 75 if (read(masterfd, &c, sizeof(c)) != sizeof(c)) e(0); 76 if (c != 'B') e(0); 77 78 c = 'C'; 79 if (write(masterfd, &c, sizeof(c)) != sizeof(c)) e(0); 80 if (read(slavefd, &c, sizeof(c)) != sizeof(c)) e(0); 81 if (c != 'C') e(0); 82 83 c = 'D'; 84 if (write(slavefd, &c, sizeof(c)) != sizeof(c)) e(0); 85 if (read(masterfd, &c, sizeof(c)) != sizeof(c)) e(0); 86 if (c != 'D') e(0); 87 } 88 89 /* 90 * Obtain a pseudo terminal. The master end is opened and its file descriptor 91 * stored in 'pfd'. The slave path name is stored in 'tname'. For old-style 92 * PTYs, the function returns 1 and stores the master name in 'pname' if not 93 * NULL. For Unix98 PTYs, the function returns 0, in which case no master name 94 * is available. For old-style PTYs, the caller may close and reopen the 95 * master. In that case, we make the assumption that nobody snatches the pair 96 * while we are running. For Unix98 PTYs, the master must be kept open. 97 */ 98 static int 99 get_pty(int *pfd, char pname[PATH_MAX], char tname[PATH_MAX]) 100 { 101 char *name; 102 int len, masterfd, slavefd; 103 104 /* 105 * First try Unix98 PTY allocation, mainly to avoid opening the slave 106 * end immediately. If this fails, try openpty(3) as well. 107 */ 108 if ((masterfd = posix_openpt(O_RDWR | O_NOCTTY)) != -1) { 109 if (grantpt(masterfd) != -1 && unlockpt(masterfd) != -1 && 110 (name = ptsname(masterfd)) != NULL) { 111 *pfd = masterfd; 112 strlcpy(tname, name, PATH_MAX); 113 114 return 0; 115 } 116 if (close(masterfd) < 0) e(0); 117 } 118 119 if (openpty(&masterfd, &slavefd, tname, NULL, NULL) < 0) e(0); 120 121 test_comm(masterfd, slavefd); 122 123 *pfd = masterfd; 124 125 if (close(slavefd) < 0) e(0); 126 127 /* 128 * openpty(3) gives us only the slave name, but we also want the master 129 * name. 130 */ 131 len = strlen(_PATH_DEV); 132 if (strncmp(tname, _PATH_DEV, len)) e(0); 133 134 if (strncmp(&tname[len], "tty", 3)) 135 return 0; /* Unix98 after all? Well okay, whatever.. */ 136 137 if (pname != NULL) { 138 strlcpy(pname, tname, PATH_MAX); 139 pname[len] = 'p'; 140 } 141 142 return 1; 143 } 144 145 /* 146 * Test various orders of opening and closing the master and slave sides of a 147 * pseudo terminal, as well as opening/closing one side without ever opening 148 * the other. This test is meaningful mainly for old-style pseudoterminals. 149 */ 150 static void 151 test77a(void) 152 { 153 struct sigaction act, oact; 154 char pname[PATH_MAX], tname[PATH_MAX]; 155 int oldstyle, masterfd, slavefd; 156 157 subtest = 1; 158 159 /* We do not want to get SIGHUP signals in this test. */ 160 memset(&act, 0, sizeof(act)); 161 act.sa_handler = SIG_IGN; 162 if (sigaction(SIGHUP, &act, &oact) < 0) e(0); 163 164 /* Obtain a pseudo terminal. */ 165 oldstyle = get_pty(&masterfd, pname, tname); 166 167 if (oldstyle) { 168 /* Try closing the master. */ 169 if (close(masterfd) < 0) e(0); 170 171 /* See if we can reopen the master. */ 172 if ((masterfd = open(pname, O_RDWR | O_NOCTTY)) < 0) e(0); 173 } 174 175 if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(0); 176 177 test_comm(masterfd, slavefd); 178 179 /* In the meantime, test different closing orders. This is order A. */ 180 if (close(slavefd) < 0) e(0); 181 if (close(masterfd) < 0) e(0); 182 183 /* Now try opening the pair (or a new pair) again. */ 184 if (!oldstyle) 185 oldstyle = get_pty(&masterfd, pname, tname); 186 else 187 if ((masterfd = open(pname, O_RDWR | O_NOCTTY)) < 0) e(0); 188 189 if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(0); 190 191 test_comm(masterfd, slavefd); 192 193 if (close(slavefd) < 0) e(0); 194 195 /* 196 * Try reopening the slave after closing it. It is not very important 197 * that this works, but the TTY driver should currently support it. 198 */ 199 if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(0); 200 201 test_comm(masterfd, slavefd); 202 203 /* This is closing order B. This may or may not cause a SIGHUP. */ 204 if (close(masterfd) < 0) e(0); 205 if (close(slavefd) < 0) e(0); 206 207 /* Try the normal open procedure. */ 208 if (!oldstyle) 209 oldstyle = get_pty(&masterfd, pname, tname); 210 else 211 if ((masterfd = open(pname, O_RDWR | O_NOCTTY)) < 0) e(0); 212 213 if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(0); 214 215 test_comm(masterfd, slavefd); 216 217 if (close(slavefd) < 0) e(0); 218 if (close(masterfd) < 0) e(0); 219 220 /* 221 * Try reopening and closing the slave, without opening the master. 222 * This should work on old-style PTYS, but not on Unix98 PTYs. 223 */ 224 if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) >= 0) { 225 if (!oldstyle) e(0); 226 227 if (close(slavefd) < 0) e(0); 228 } else 229 if (oldstyle) e(0); 230 231 /* Again, try the normal open procedure. */ 232 if (!oldstyle) 233 oldstyle = get_pty(&masterfd, pname, tname); 234 else 235 if ((masterfd = open(pname, O_RDWR | O_NOCTTY)) < 0) e(0); 236 237 if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(0); 238 239 test_comm(masterfd, slavefd); 240 241 if (close(slavefd) < 0) e(0); 242 if (close(masterfd) < 0) e(0); 243 244 /* 245 * Finally, try opening the slave first. This does not work with 246 * Unix98 PTYs. 247 */ 248 if (oldstyle) { 249 if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(0); 250 if ((masterfd = open(pname, O_RDWR | O_NOCTTY)) < 0) e(0); 251 252 test_comm(masterfd, slavefd); 253 254 if (close(slavefd) < 0) e(0); 255 if (close(masterfd) < 0) e(0); 256 } 257 258 if (sigaction(SIGHUP, &oact, NULL) < 0) e(0); 259 } 260 261 /* 262 * Test opening a single side multiple times. 263 */ 264 static void 265 test77b(void) 266 { 267 char pname[PATH_MAX], tname[PATH_MAX]; 268 int oldstyle, masterfd, slavefd, extrafd; 269 270 subtest = 2; 271 272 /* Obtain a pseudo terminal. */ 273 oldstyle = get_pty(&masterfd, pname, tname); 274 275 if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(0); 276 277 /* 278 * It must not be possible to open the master multiple times. Doing so 279 * is possible only if we have a named master, i.e., an old-style PTY. 280 */ 281 test_comm(masterfd, slavefd); 282 283 if (oldstyle) { 284 if ((extrafd = open(pname, O_RDWR | O_NOCTTY)) >= 0) e(0); 285 if (errno != EIO) e(0); 286 } 287 288 test_comm(masterfd, slavefd); 289 290 if (close(slavefd) < 0) e(0); 291 if (close(masterfd) < 0) e(0); 292 293 /* The slave can be opened multiple times, though. */ 294 oldstyle = get_pty(&masterfd, pname, tname); 295 296 if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(0); 297 298 test_comm(masterfd, slavefd); 299 300 if ((extrafd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(0); 301 302 test_comm(masterfd, extrafd); 303 test_comm(masterfd, slavefd); 304 305 if (close(slavefd) < 0) e(0); 306 if (close(extrafd) < 0) e(0); 307 if (close(masterfd) < 0) e(0); 308 } 309 310 /* 311 * Test communication on half-open pseudo terminals. 312 */ 313 static void 314 test77c(void) 315 { 316 struct sigaction act, oact; 317 char pname[PATH_MAX], tname[PATH_MAX]; 318 int oldstyle, masterfd, slavefd; 319 char c; 320 321 subtest = 3; 322 323 /* We do not want to get SIGHUP signals in this test. */ 324 memset(&act, 0, sizeof(act)); 325 act.sa_handler = SIG_IGN; 326 if (sigaction(SIGHUP, &act, &oact) < 0) e(0); 327 328 /* Obtain a pseudo terminal. */ 329 oldstyle = get_pty(&masterfd, pname, tname); 330 331 /* 332 * For old-style pseudo terminals, we have just opened and closed the 333 * slave end, which alters the behavior we are testing below. Close 334 * and reopen the master to start fresh. 335 */ 336 if (oldstyle) { 337 if (close(masterfd) < 0) e(0); 338 339 if ((masterfd = open(pname, O_RDWR | O_NOCTTY)) < 0) e(0); 340 } 341 342 /* Writes to the master should be buffered until there is a slave. */ 343 c = 'E'; 344 if (write(masterfd, &c, sizeof(c)) != sizeof(c)) e(0); 345 346 if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(0); 347 348 make_raw(slavefd); 349 350 if (read(slavefd, &c, sizeof(c)) != sizeof(c)) e(0); 351 if (c != 'E') e(0); 352 353 /* Discard the echo on the master. */ 354 if (tcflush(slavefd, TCOFLUSH) != 0) e(0); 355 356 test_comm(masterfd, slavefd); 357 358 if (close(slavefd) < 0) e(0); 359 360 /* Writes to the master after the slave has been closed should fail. */ 361 if (write(masterfd, &c, sizeof(c)) >= 0) e(0); 362 if (errno != EIO) e(0); 363 364 if (oldstyle) 365 if (close(masterfd) < 0) e(0); 366 367 /* 368 * Writes to the slave should be buffered until there is a master. 369 * This applies to old-style PTYs only. 370 */ 371 if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(0); 372 373 if (oldstyle) { 374 make_raw(slavefd); 375 376 c = 'F'; 377 if (write(slavefd, &c, sizeof(c)) != sizeof(c)) e(0); 378 379 if ((masterfd = open(pname, O_RDWR | O_NOCTTY)) < 0) e(0); 380 381 if (read(masterfd, &c, sizeof(c)) != sizeof(c)) e(0); 382 if (c != 'F') e(0); 383 } 384 385 test_comm(masterfd, slavefd); 386 387 if (close(masterfd) < 0) e(0); 388 389 if (write(slavefd, &c, sizeof(c)) >= 0) e(0); 390 if (errno != EIO) e(0); 391 392 /* Reads from the slave should return EOF if the master is gone. */ 393 if (read(slavefd, &c, sizeof(c)) != 0) e(0); 394 395 if (close(slavefd) < 0) e(0); 396 397 if (sigaction(SIGHUP, &oact, NULL) < 0) e(0); 398 } 399 400 /* 401 * Wait for a child process to terminate. Return 0 if the child exited without 402 * errors, -1 otherwise. 403 */ 404 static int 405 waitchild(void) 406 { 407 int status; 408 409 if (wait(&status) <= 0) return -1; 410 if (!WIFEXITED(status)) return -1; 411 if (WEXITSTATUS(status) != 0) return -1; 412 413 return 0; 414 } 415 416 /* 417 * Test opening the slave side with and without the O_NOCTTY flag. 418 */ 419 static void 420 test77d(void) 421 { 422 char pname[PATH_MAX], tname[PATH_MAX]; 423 int masterfd, slavefd; 424 425 subtest = 4; 426 427 /* Make ourselves process group leader if we aren't already. */ 428 (void)setsid(); 429 430 /* Obtain a pseudo terminal. */ 431 (void)get_pty(&masterfd, NULL, tname); 432 433 /* 434 * Opening the slave with O_NOCTTY should not change its controlling 435 * terminal. 436 */ 437 switch (fork()) { 438 case 0: 439 if (close(masterfd) < 0) e(0); 440 441 if (setsid() < 0) e(0); 442 443 if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(0); 444 445 if (open("/dev/tty", O_RDWR) >= 0) e(0); 446 if (errno != ENXIO) e(0); 447 448 exit(errct); 449 case -1: 450 e(0); 451 default: 452 break; 453 } 454 455 if (waitchild() < 0) e(0); 456 457 if (close(masterfd) < 0) e(0); 458 459 (void)get_pty(&masterfd, pname, tname); 460 461 /* 462 * Opening the slave without O_NOCTTY should change its controlling 463 * terminal, though. 464 */ 465 switch (fork()) { 466 case 0: 467 if (close(masterfd) < 0) e(0); 468 469 if (setsid() < 0) e(0); 470 471 if ((slavefd = open(tname, O_RDWR)) < 0) e(0); 472 473 if (open("/dev/tty", O_RDWR) < 0) e(0); 474 475 exit(errct); 476 case -1: 477 e(0); 478 default: 479 break; 480 } 481 482 if (waitchild() < 0) e(0); 483 484 if (close(masterfd) < 0) e(0); 485 } 486 487 /* 488 * Test receiving of SIGHUP on master hang-up. All of the tests so far have 489 * ignored SIGHUP, and probably would not have received one anyway, since the 490 * process was not its own session leader. Time to test this aspect. 491 */ 492 static void 493 test77e(void) 494 { 495 struct sigaction act, hup_oact, usr_oact; 496 sigset_t set, oset; 497 char tname[PATH_MAX]; 498 int masterfd, slavefd; 499 500 subtest = 5; 501 502 memset(&act, 0, sizeof(act)); 503 act.sa_handler = signal_handler; 504 if (sigaction(SIGHUP, &act, &hup_oact) < 0) e(0); 505 506 memset(&act, 0, sizeof(act)); 507 act.sa_handler = signal_handler; 508 if (sigaction(SIGUSR1, &act, &usr_oact) < 0) e(0); 509 510 sigemptyset(&set); 511 sigaddset(&set, SIGHUP); 512 sigaddset(&set, SIGUSR1); 513 if (sigprocmask(SIG_BLOCK, &set, &oset) < 0) e(0); 514 515 sighups = 0; 516 517 /* Make ourselves process group leader if we aren't already. */ 518 (void)setsid(); 519 520 /* Obtain a pseudo terminal. */ 521 (void)get_pty(&masterfd, NULL, tname); 522 523 switch (fork()) { 524 case 0: 525 if (close(masterfd) < 0) e(0); 526 527 /* Become session leader. */ 528 if (setsid() < 0) e(0); 529 530 if ((slavefd = open(tname, O_RDWR)) < 0) e(0); 531 532 /* Tell the parent we are ready. */ 533 kill(getppid(), SIGUSR1); 534 535 /* We should now get a SIGHUP. */ 536 set = oset; 537 if (sigsuspend(&set) >= 0) e(0); 538 539 if (sighups != 1) e(0); 540 541 exit(errct); 542 case -1: 543 e(0); 544 default: 545 break; 546 } 547 548 /* Wait for SIGUSR1 from the child. */ 549 set = oset; 550 if (sigsuspend(&set) >= 0) e(0); 551 552 /* Closing the master should now raise a SIGHUP signal in the child. */ 553 if (close(masterfd) < 0) e(0); 554 555 if (waitchild() < 0) e(0); 556 557 if (sigprocmask(SIG_SETMASK, &oset, NULL) < 0) e(0); 558 559 if (sigaction(SIGHUP, &hup_oact, NULL) < 0) e(0); 560 if (sigaction(SIGUSR1, &usr_oact, NULL) < 0) e(0); 561 } 562 563 /* 564 * Test basic select functionality on /dev/tty. While this test should not be 565 * part of this test set, we already have all the infrastructure we need here. 566 */ 567 static void 568 test77f(void) 569 { 570 struct sigaction act, oact; 571 char c, tname[PATH_MAX]; 572 struct timeval tv; 573 fd_set fd_set; 574 int fd, maxfd, masterfd, slavefd; 575 576 subtest = 6; 577 578 /* We do not want to get SIGHUP signals in this test. */ 579 memset(&act, 0, sizeof(act)); 580 act.sa_handler = SIG_IGN; 581 if (sigaction(SIGHUP, &act, &oact) < 0) e(0); 582 583 /* Obtain a pseudo terminal. */ 584 (void)get_pty(&masterfd, NULL, tname); 585 586 switch (fork()) { 587 case 0: 588 if (close(masterfd) < 0) e(0); 589 590 if (setsid() < 0) e(0); 591 592 if ((slavefd = open(tname, O_RDWR)) < 0) e(0); 593 594 if ((fd = open("/dev/tty", O_RDWR)) < 0) e(0); 595 596 make_raw(fd); 597 598 /* Without slave input, /dev/tty is not ready for reading. */ 599 FD_ZERO(&fd_set); 600 FD_SET(fd, &fd_set); 601 tv.tv_sec = 0; 602 tv.tv_usec = 0; 603 604 if (select(fd + 1, &fd_set, NULL, NULL, &tv) != 0) e(0); 605 if (FD_ISSET(fd, &fd_set)) e(0); 606 607 FD_SET(fd, &fd_set); 608 tv.tv_sec = 0; 609 tv.tv_usec = 10000; 610 611 if (select(fd + 1, &fd_set, NULL, NULL, &tv) != 0) e(0); 612 if (FD_ISSET(fd, &fd_set)) e(0); 613 614 /* It will be ready for writing, though. */ 615 FD_SET(fd, &fd_set); 616 617 if (select(fd + 1, NULL, &fd_set, NULL, NULL) != 1) e(0); 618 if (!FD_ISSET(fd, &fd_set)) e(0); 619 620 /* Test mixing file descriptors to the same terminal. */ 621 FD_ZERO(&fd_set); 622 FD_SET(fd, &fd_set); 623 FD_SET(slavefd, &fd_set); 624 tv.tv_sec = 0; 625 tv.tv_usec = 10000; 626 627 maxfd = fd > slavefd ? fd : slavefd; 628 if (select(maxfd + 1, &fd_set, NULL, NULL, &tv) != 0) e(0); 629 if (FD_ISSET(fd, &fd_set)) e(0); 630 if (FD_ISSET(slavefd, &fd_set)) e(0); 631 632 /* The delayed echo on the master must wake up our select. */ 633 c = 'A'; 634 if (write(slavefd, &c, sizeof(c)) != sizeof(c)) e(0); 635 636 FD_ZERO(&fd_set); 637 FD_SET(fd, &fd_set); 638 639 if (select(fd + 1, &fd_set, NULL, NULL, NULL) != 1) e(0); 640 if (!FD_ISSET(fd, &fd_set)) e(0); 641 642 /* Select must now still flag readiness for reading. */ 643 tv.tv_sec = 0; 644 tv.tv_usec = 0; 645 646 if (select(fd + 1, &fd_set, NULL, NULL, &tv) != 1) e(0); 647 if (!FD_ISSET(fd, &fd_set)) e(0); 648 649 /* That is, until we read the byte. */ 650 if (read(slavefd, &c, sizeof(c)) != sizeof(c)) e(0); 651 if (c != 'B') e(0); 652 653 if (select(fd + 1, &fd_set, NULL, NULL, &tv) != 0) e(0); 654 if (FD_ISSET(fd, &fd_set)) e(0); 655 656 /* Ask the parent to close the master. */ 657 c = 'C'; 658 if (write(slavefd, &c, sizeof(c)) != sizeof(c)) e(0); 659 660 FD_SET(fd, &fd_set); 661 662 /* The closure must cause an EOF condition on the slave. */ 663 if (select(fd + 1, &fd_set, NULL, NULL, NULL) != 1) e(0); 664 if (!FD_ISSET(fd, &fd_set)) e(0); 665 666 if (select(fd + 1, &fd_set, NULL, NULL, NULL) != 1) e(0); 667 if (!FD_ISSET(fd, &fd_set)) e(0); 668 669 if (read(slavefd, &c, sizeof(c)) != 0) e(0); 670 671 exit(errct); 672 case -1: 673 e(0); 674 default: 675 /* Wait for the child to write something to the slave. */ 676 FD_ZERO(&fd_set); 677 FD_SET(masterfd, &fd_set); 678 679 if (select(masterfd + 1, &fd_set, NULL, NULL, NULL) != 1) 680 e(0); 681 if (!FD_ISSET(masterfd, &fd_set)) e(0); 682 683 if (read(masterfd, &c, sizeof(c)) != sizeof(c)) e(0); 684 if (c != 'A') e(0); 685 686 /* Write a reply once the child is blocked in its select. */ 687 tv.tv_sec = 1; 688 tv.tv_usec = 0; 689 if (select(masterfd + 1, &fd_set, NULL, NULL, &tv) != 0) 690 e(0); 691 692 c = 'B'; 693 if (write(masterfd, &c, sizeof(c)) != sizeof(c)) e(0); 694 695 /* Wait for the child to request closing the master. */ 696 if (read(masterfd, &c, sizeof(c)) != sizeof(c)) e(0); 697 if (c != 'C') e(0); 698 699 /* Close the master once the child is blocked in its select. */ 700 sleep(1); 701 702 close(masterfd); 703 704 break; 705 } 706 707 if (waitchild() < 0) e(0); 708 709 if (sigaction(SIGHUP, &oact, NULL) < 0) e(0); 710 } 711 712 /* 713 * See if the directory contents of /dev/pts are as we expect. We have to keep 714 * in mind that other programs may have pseudo terminals open while we are 715 * running, although we assume that those programs do not open or close PTYs 716 * while we are running. 717 */ 718 static void 719 test_getdents(int nindex, int array[3], int present[3]) 720 { 721 struct group *group; 722 DIR *dirp; 723 struct dirent *dp; 724 struct stat buf; 725 char path[PATH_MAX], *endp; 726 gid_t tty_gid; 727 int i, n, seen_dot, seen_dotdot, seen_index[3], *seen; 728 729 seen_dot = seen_dotdot = 0; 730 for (i = 0; i < nindex; i++) 731 seen_index[i] = 0; 732 733 if ((group = getgrnam("tty")) == NULL) e(0); 734 tty_gid = group->gr_gid; 735 736 if ((dirp = opendir(_PATH_DEV_PTS)) == NULL) e(0); 737 738 while ((dp = readdir(dirp)) != NULL) { 739 snprintf(path, sizeof(path), _PATH_DEV_PTS "%s", dp->d_name); 740 if (stat(path, &buf) < 0) e(0); 741 742 if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) { 743 seen = 744 (dp->d_name[1] == '.') ? &seen_dot : &seen_dotdot; 745 if (*seen) e(0); 746 *seen = 1; 747 748 /* Check basic dirent and stat fields. */ 749 if (dp->d_type != DT_DIR) e(0); 750 if (dp->d_name[1] == '\0' && 751 buf.st_ino != dp->d_fileno) e(0); 752 if (!S_ISDIR(buf.st_mode)) e(0); 753 if (buf.st_nlink < 2) e(0); 754 } else { 755 /* The file name must be a number. */ 756 errno = 0; 757 n = strtol(dp->d_name, &endp, 10); 758 if (errno != 0) e(0); 759 if (dp->d_name[0] == '\0' || *endp != '\0') e(0); 760 if (n < 0) e(0); 761 762 /* Check basic dirent and stat fields. */ 763 if (dp->d_type != DT_CHR) e(0); 764 if (buf.st_ino != dp->d_fileno) e(0); 765 if (!S_ISCHR(buf.st_mode)) e(0); 766 if (buf.st_nlink != 1) e(0); 767 if (buf.st_size != 0) e(0); 768 if (buf.st_rdev == 0) e(0); 769 770 /* Is this one of the PTYs we created? */ 771 for (i = 0; i < nindex; i++) { 772 if (array[i] == n) { 773 if (seen_index[i]) e(0); 774 seen_index[i] = 1; 775 776 break; 777 } 778 } 779 780 /* If so, perform some extra tests. */ 781 if (i < nindex) { 782 if ((buf.st_mode & ALLPERMS) != 0620) e(0); 783 if (buf.st_uid != getuid()) e(0); 784 if (buf.st_gid != tty_gid) e(0); 785 } 786 } 787 } 788 789 if (closedir(dirp) < 0) e(0); 790 791 if (!seen_dot) e(0); 792 if (!seen_dotdot) e(0); 793 for (i = 0; i < nindex; i++) 794 if (seen_index[i] != present[i]) e(0); 795 } 796 797 /* 798 * Obtain a Unix98 PTY. Return an open file descriptor for the master side, 799 * and store the name of the slave side in 'tptr'. 800 */ 801 static int 802 get_unix98_pty(char ** tptr) 803 { 804 int masterfd; 805 806 if ((masterfd = posix_openpt(O_RDWR | O_NOCTTY)) < 0) e(0); 807 808 if (grantpt(masterfd) < 0) e(0); 809 810 /* This call is a no-op on MINIX3. */ 811 if (unlockpt(masterfd) < 0) e(0); 812 813 if ((*tptr = ptsname(masterfd)) == NULL) e(0); 814 815 return masterfd; 816 } 817 818 /* 819 * Test for Unix98 PTY support and PTYFS. 820 */ 821 static void 822 test77g(void) 823 { 824 char *tname; 825 struct stat buf; 826 size_t len; 827 int i, masterfd, slavefd, fd[3], array[3], present[3]; 828 829 subtest = 7; 830 831 /* 832 * Test basic operation, and verify that the slave node disappears 833 * after both sides of the pseudo terminal have been closed. We check 834 * different combinations of open master and slave ends (with 'i'): 835 * 0) opening and closing the master only, 1) closing a slave before 836 * the master, and 2) closing the slave after the master. 837 */ 838 for (i = 0; i <= 2; i++) { 839 masterfd = get_unix98_pty(&tname); 840 841 if (access(tname, R_OK | W_OK) < 0) e(0); 842 843 if (i > 0) { 844 if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) 845 e(0); 846 847 if (access(tname, R_OK | W_OK) < 0) e(0); 848 849 if (i > 1) { 850 if (close(masterfd) < 0) e(0); 851 852 masterfd = slavefd; /* ugly but saving code */ 853 } else 854 if (close(slavefd) < 0) e(0); 855 } 856 857 if (access(tname, R_OK | W_OK) < 0) e(0); 858 859 if (close(masterfd) < 0) e(0); 860 861 if (access(tname, R_OK | W_OK) == 0) e(0); 862 } 863 864 /* 865 * Test whether we can open multiple pseudo terminals. We need to be 866 * able to open three PTYs. Verify that they are properly listed in 867 * the /dev/pts directory contents, and have proper attributes set. 868 */ 869 test_getdents(0, NULL, NULL); 870 871 for (i = 0; i < 3; i++) { 872 fd[i] = get_unix98_pty(&tname); 873 874 /* Figure out the slave index number. */ 875 len = strlen(_PATH_DEV_PTS); 876 if (strncmp(tname, _PATH_DEV_PTS, strlen(_PATH_DEV_PTS))) e(0); 877 array[i] = atoi(&tname[len]); 878 present[i] = 1; 879 } 880 881 test_getdents(3, array, present); 882 883 if (close(fd[0]) < 0) e(0); 884 present[0] = 0; 885 886 test_getdents(3, array, present); 887 888 if (close(fd[2]) < 0) e(0); 889 present[2] = 0; 890 891 test_getdents(3, array, present); 892 893 if (close(fd[1]) < 0) e(0); 894 present[1] = 0; 895 896 test_getdents(3, array, present); 897 898 /* 899 * Test chmod(2) on a slave node, and multiple calls to grantpt(3). 900 * The first grantpt(3) call should create the slave node (we currently 901 * can not test this: the slave node may be created earlier as well, 902 * but we do not know its name), whereas subsequent grantpt(3) calls 903 * should reset its mode, uid, and gid. Testing the latter two and 904 * chown(2) on the slave node requires root, so we skip that part. 905 * 906 * Finally, NetBSD revokes access to existing slave file descriptors 907 * upon a call to grantpt(3). This is not a POSIX requirement, but 908 * NetBSD needs this for security reasons because it already creates 909 * the slave node when the master is opened (and it does not lock the 910 * slave until a call to unlockpt(3)). MINIX3 does not implement 911 * revocation this way, because the slave node is created only upon the 912 * call to grantpt(3), thus leaving no insecure window for the slave 913 * side between posix_openpt(3) and grantpt(3). While this behavior 914 * may be changed later, we test for the lack of revocation here now. 915 */ 916 masterfd = get_unix98_pty(&tname); 917 918 if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(0); 919 920 if (stat(tname, &buf) != 0) e(0); 921 if (buf.st_mode != (S_IFCHR | 0620)) e(0); 922 923 if (chmod(tname, S_IFCHR | 0630) != 0) e(0); 924 925 if (stat(tname, &buf) != 0) e(0); 926 if (buf.st_mode != (S_IFCHR | 0630)) e(0); 927 928 if (grantpt(masterfd) != 0) e(0); 929 930 if (stat(tname, &buf) != 0) e(0); 931 if (buf.st_mode != (S_IFCHR | 0620)) e(0); 932 933 test_comm(masterfd, slavefd); 934 935 if (close(slavefd) < 0) e(0); 936 if (close(masterfd) < 0) e(0); 937 938 test_getdents(0, NULL, NULL); 939 } 940 941 /* 942 * Check that the given PTY index, which is in use for an old-style PTY, is not 943 * allocated through Unix98 PTY allocation. This test is not foolproof, but it 944 * does the job well enough. 945 */ 946 static void 947 test_overlap(int m) 948 { 949 char *tname; 950 size_t len; 951 int i, n, fd[MIN_PTYS]; 952 953 for (i = 0; i < MIN_PTYS; i++) { 954 if ((fd[i] = posix_openpt(O_RDWR | O_NOCTTY)) < 0) 955 break; /* out of PTYs */ 956 if (grantpt(fd[i]) < 0) e(0); 957 if (unlockpt(fd[i]) < 0) e(0); 958 if ((tname = ptsname(fd[i])) == NULL) e(0); 959 960 len = strlen(_PATH_DEV_PTS); 961 if (strncmp(tname, _PATH_DEV_PTS, strlen(_PATH_DEV_PTS))) e(0); 962 n = atoi(&tname[len]); 963 if (n < 0 || n > 9) e(0); 964 965 if (m == n) e(0); 966 } 967 968 for (i--; i >= 0; i--) 969 if (close(fd[i]) < 0) e(0); 970 } 971 972 /* 973 * Test for mixing access to old-style and Unix98 PTYs. Since the PTY service 974 * internally shares the set of pseudo terminals between the two types, it has 975 * to implement checks to prevent that a PTY opened as one type is also 976 * accessed through the other type. We test some of those checks here. 977 */ 978 static void 979 test77h(void) 980 { 981 char *tname, ptest[PATH_MAX], ttest[PATH_MAX]; 982 struct sigaction act, oact; 983 size_t len; 984 int i, n, masterfd, slavefd; 985 986 subtest = 8; 987 988 /* We do not want to get SIGHUP signals in this test. */ 989 memset(&act, 0, sizeof(act)); 990 act.sa_handler = SIG_IGN; 991 if (sigaction(SIGHUP, &act, &oact) < 0) e(0); 992 993 /* 994 * Check that Unix98 PTYs cannot be accessed through old-style device 995 * nodes. We check different combinations of open master and 996 * slave ends for the Unix98 side (with 'i'): 0) opening and closing 997 * the master only, 1) closing a slave before the master, and 2) 998 * closing the slave after the master. 999 * 1000 * This test relies on the implementation aspect that /dev/ttypN and 1001 * /dev/pts/N (with N in the range 0..9) map to the same PTY. It also 1002 * relies on lack of concurrent PTY allocation outside the test. 1003 */ 1004 for (i = 0; i <= 2; i++) { 1005 /* Open a Unix98 PTY and get the slave name. */ 1006 masterfd = get_unix98_pty(&tname); 1007 1008 /* Figure out the slave index number. */ 1009 len = strlen(_PATH_DEV_PTS); 1010 if (strncmp(tname, _PATH_DEV_PTS, strlen(_PATH_DEV_PTS))) e(0); 1011 n = atoi(&tname[len]); 1012 if (n < 0 || n > 9) e(0); 1013 1014 /* Use this index number to create old-style device names. */ 1015 snprintf(ptest, sizeof(ptest), _PATH_DEV "ptyp%u", n); 1016 snprintf(ttest, sizeof(ttest), _PATH_DEV "ttyp%u", n); 1017 1018 /* 1019 * Now make sure that opening the old-style master and slave 1020 * fails as long as either side of the Unix98 PTY is open. 1021 */ 1022 if (open(ptest, O_RDWR | O_NOCTTY) >= 0) e(0); 1023 if (errno != EACCES && errno != EIO) e(0); 1024 if (open(ttest, O_RDWR | O_NOCTTY) >= 0) e(0); 1025 if (errno != EACCES && errno != EIO) e(0); 1026 1027 if (i > 0) { 1028 if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) 1029 e(0); 1030 1031 if (open(ptest, O_RDWR | O_NOCTTY) >= 0) e(0); 1032 if (errno != EACCES && errno != EIO) e(0); 1033 if (open(ttest, O_RDWR | O_NOCTTY) >= 0) e(0); 1034 if (errno != EACCES && errno != EIO) e(0); 1035 1036 if (close(slavefd) < 0) e(0); 1037 1038 if (i > 1) { 1039 if (open(ptest, O_RDWR | O_NOCTTY) >= 0) e(0); 1040 if (errno != EACCES && errno != EIO) e(0); 1041 if (open(ttest, O_RDWR | O_NOCTTY) >= 0) e(0); 1042 if (errno != EACCES && errno != EIO) e(0); 1043 1044 if ((slavefd = 1045 open(tname, O_RDWR | O_NOCTTY)) < 0) e(0); 1046 1047 if (open(ptest, O_RDWR | O_NOCTTY) >= 0) e(0); 1048 if (errno != EACCES && errno != EIO) e(0); 1049 if (open(ttest, O_RDWR | O_NOCTTY) >= 0) e(0); 1050 if (errno != EACCES && errno != EIO) e(0); 1051 1052 if (close(masterfd) < 0) e(0); 1053 1054 masterfd = slavefd; /* ugly but saving code */ 1055 } 1056 1057 if (open(ptest, O_RDWR | O_NOCTTY) >= 0) e(0); 1058 if (errno != EACCES && errno != EIO) e(0); 1059 if (open(ttest, O_RDWR | O_NOCTTY) >= 0) e(0); 1060 if (errno != EACCES && errno != EIO) e(0); 1061 } 1062 1063 if (close(masterfd) < 0) e(0); 1064 1065 /* 1066 * Once both Unix98 sides are closed, the pseudo terminal can 1067 * be reused. Thus, opening the old-style master should now 1068 * succeed. However, it is possible that we do not have 1069 * permission to open the master at all. 1070 */ 1071 if ((masterfd = open(ptest, O_RDWR | O_NOCTTY)) < 0 && 1072 errno != EACCES) e(0); 1073 1074 if (masterfd >= 0 && close(masterfd) < 0) e(0); 1075 } 1076 1077 /* 1078 * The reverse test, which would check that old-style PTYs cannot be 1079 * accessed through Unix98 device nodes, is impossible to perform 1080 * properly without root privileges, as we would have to create device 1081 * nodes manually with mknod(2). All we can do here is ensure that if 1082 * an old-style PTY is opened, it will not also be allocated as a 1083 * Unix98 PTY. We do a rather basic check, but only if we can open an 1084 * old-style master at all. We check two closing orders (with 'i'): 1085 * 0) the slave first, 1) the master first. Here, we make the hard 1086 * assumption that the system supports at least four pseudo terminals, 1087 * of which at least one is currently free. 1088 */ 1089 for (i = 0; i <= 1; i++) { 1090 for (n = 0; n < MIN_PTYS; n++) { 1091 snprintf(ptest, sizeof(ptest), _PATH_DEV "ptyp%u", n); 1092 1093 if ((masterfd = open(ptest, O_RDWR | O_NOCTTY)) >= 0) 1094 break; 1095 } 1096 1097 if (n >= MIN_PTYS) 1098 break; 1099 1100 test_overlap(n); 1101 1102 snprintf(ttest, sizeof(ttest), _PATH_DEV "ttyp%u", n); 1103 1104 /* We can do part of the test only if we can open the slave. */ 1105 if ((slavefd = open(ttest, O_RDWR | O_NOCTTY)) >= 0) { 1106 test_overlap(n); 1107 1108 if (i > 0) { 1109 if (close(masterfd) < 0) e(0); 1110 1111 masterfd = slavefd; /* again, ugly */ 1112 } else 1113 if (close(slavefd) < 0) e(0); 1114 1115 test_overlap(n); 1116 } 1117 1118 if (close(masterfd) < 0) e(0); 1119 } 1120 1121 if (sigaction(SIGHUP, &oact, NULL) < 0) e(0); 1122 } 1123 1124 int 1125 main(int argc, char **argv) 1126 { 1127 int i, m; 1128 1129 start(77); 1130 1131 if (argc == 2) 1132 m = atoi(argv[1]); 1133 else 1134 m = 0xFF; 1135 1136 for (i = 0; i < ITERATIONS; i++) { 1137 if (m & 0x01) test77a(); 1138 if (m & 0x02) test77b(); 1139 if (m & 0x04) test77c(); 1140 if (m & 0x08) test77d(); 1141 if (m & 0x10) test77e(); 1142 if (m & 0x20) test77f(); 1143 if (m & 0x40) test77g(); 1144 if (m & 0x80) test77h(); 1145 } 1146 1147 quit(); 1148 } 1149