sys.c revision dbe7da2e
1/* 2Copyright (c) 2001 by Juliusz Chroboczek 3 4Permission is hereby granted, free of charge, to any person obtaining a copy 5of this software and associated documentation files (the "Software"), to deal 6in the Software without restriction, including without limitation the rights 7to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8copies of the Software, and to permit persons to whom the Software is 9furnished to do so, subject to the following conditions: 10 11The above copyright notice and this permission notice shall be included in 12all copies or substantial portions of the Software. 13 14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20THE SOFTWARE. 21*/ 22/* $XFree86: xc/programs/luit/sys.c,v 1.9 2003/08/17 20:39:58 dawes Exp $ */ 23 24#include <stdlib.h> 25#include <string.h> 26#include <stdio.h> 27#include <sys/types.h> 28#include <unistd.h> 29#include <fcntl.h> 30#include <sys/ioctl.h> 31#include <sys/stat.h> 32#include <sys/time.h> 33#include <termios.h> 34#include <signal.h> 35#include <errno.h> 36 37#ifdef HAVE_CONFIG_H 38# include "config.h" 39#endif 40 41#ifdef HAVE_POLL 42#include <sys/poll.h> 43#undef HAVE_SELECT 44#endif 45 46#ifdef HAVE_SYS_SELECT_H 47# include <sys/select.h> 48#endif 49 50#ifdef HAVE_PTY_H 51# include <pty.h> 52#endif 53 54#ifdef HAVE_STROPTS_H 55# include <stropts.h> 56#endif 57 58#ifdef HAVE_SYS_PARAM_H 59# include <sys/param.h> 60#endif 61 62#include "sys.h" 63 64static int saved_tio_valid = 0; 65static struct termios saved_tio; 66 67 68#ifdef HAVE_POLL 69int 70waitForOutput(int fd) 71{ 72 struct pollfd pfd[1]; 73 int rc; 74 75 pfd[0].fd = fd; 76 pfd[0].events = POLLOUT; 77 pfd[0].revents = 0; 78 79 rc = poll(pfd, 1, -1); 80 if(rc < 0) 81 return -1; 82 83 if(pfd[0].revents & POLLOUT) 84 return 1; 85 86 return 0; 87} 88 89int 90waitForInput(int fd1, int fd2) 91{ 92 struct pollfd pfd[2]; 93 int ret, rc; 94 95 pfd[0].fd = fd1; 96 pfd[1].fd = fd2; 97 pfd[0].events = pfd[1].events = POLLIN; 98 pfd[0].revents = pfd[1].revents = 0; 99 100 rc = poll(pfd, 2, -1); 101 if(rc < 0) 102 return -1; 103 104 ret = 0; 105 if(pfd[0].revents & (POLLIN | POLLERR | POLLHUP)) 106 ret |= 1; 107 if(pfd[1].revents & (POLLIN | POLLERR | POLLHUP)) 108 ret |= 2; 109 return ret; 110} 111#endif 112 113#ifdef HAVE_SELECT 114int 115waitForOutput(int fd) 116{ 117 fd_set fds; 118 int rc; 119 120 FD_ZERO(&fds); 121 FD_SET(fd, &fds); 122 rc = select(FD_SETSIZE, NULL, &fds, NULL, NULL); 123 if(rc < 0) 124 return -1; 125 126 if(FD_ISSET(fd, &fds)) 127 return 1; 128 129 return 0; 130} 131 132int 133waitForInput(int fd1, int fd2) 134{ 135 fd_set fds; 136 int ret, rc; 137 138 FD_ZERO(&fds); 139 FD_SET(fd1, &fds); 140 FD_SET(fd2, &fds); 141 rc = select(FD_SETSIZE, &fds, NULL, NULL, NULL); 142 if(rc < 0) 143 return -1; 144 145 ret = 0; 146 if(FD_ISSET(fd1, &fds)) 147 ret |= 1; 148 if(FD_ISSET(fd2, &fds)) 149 ret |= 2; 150 return ret; 151} 152#endif 153 154#ifndef HAVE_POLL 155#ifndef HAVE_SELECT 156/* Busy looping implementation */ 157int 158waitForOutput(int fd) 159{ 160 return 1; 161} 162 163int 164waitForInput(int fd1, int fd2) 165{ 166 return 1|2; 167} 168#endif 169#endif 170 171 172int 173setWindowSize(int sfd, int dfd) 174{ 175#ifdef TIOCGWINSZ 176 int rc; 177 struct winsize ws; 178 rc = ioctl(sfd, TIOCGWINSZ, (char*)&ws); 179 if(rc < 0) 180 return -1; 181 rc = ioctl(dfd, TIOCSWINSZ, (char*)&ws); 182 if(rc < 0) 183 return -1; 184#endif 185 return 0; 186} 187 188int 189installHandler(int signum, void (*handler)(int)) 190{ 191 struct sigaction sa; 192 sigset_t ss; 193 int rc; 194 195 sigemptyset(&ss); 196 197 sa.sa_handler = handler; 198 sa.sa_mask = ss; 199 sa.sa_flags = 0; 200 rc = sigaction(signum, &sa, NULL); 201 return rc; 202} 203 204int 205copyTermios(int sfd, int dfd) 206{ 207 struct termios tio; 208 int rc; 209 210 rc = tcgetattr(sfd, &tio); 211 if(rc < 0) 212 return -1; 213 214 rc = tcsetattr(dfd, TCSAFLUSH, &tio); 215 if(rc < 0) 216 return -1; 217 218 return 0; 219} 220 221int 222saveTermios(void) 223{ 224 int rc; 225 rc = tcgetattr(0, &saved_tio); 226 if(rc >= 0) 227 saved_tio_valid = 1; 228 return rc; 229} 230 231int 232restoreTermios(void) 233{ 234 if(!saved_tio_valid) 235 return -1; 236 return tcsetattr(0, TCSAFLUSH, &saved_tio); 237} 238 239int 240setRawTermios(void) 241{ 242 struct termios tio; 243 int rc; 244 245 if(!saved_tio_valid) 246 saveTermios(); 247 rc = tcgetattr(0, &tio); 248 if(rc < 0) 249 return rc; 250 tio.c_lflag &= ~(ECHO|ICANON|ISIG); 251 tio.c_iflag &= ~(ICRNL|IXOFF|IXON|ISTRIP); 252#ifdef ONLCR 253 tio.c_oflag &= ~ONLCR; 254#endif 255#ifdef OCRNL 256 tio.c_oflag &= ~OCRNL; 257#endif 258#ifdef ONOCR 259 tio.c_oflag &= ~ONOCR; 260#endif 261 262#ifdef VMIN 263 tio.c_cc[VMIN] = 0; 264 tio.c_cc[VTIME] = 0; 265#endif 266 rc = tcsetattr(0, TCSAFLUSH, &tio); 267 if(rc < 0) 268 return rc; 269 return 0; 270} 271 272 273char * 274my_basename(char *path) 275{ 276 char *p; 277 278 p = strrchr(path, '/'); 279 if(!p) 280 p = path; 281 else 282 p++; 283 return p; 284} 285 286static int 287fix_pty_perms(char *line) 288{ 289 int rc; 290 struct stat s; 291 int uid = getuid(), gid = getgid(); 292 293 rc = stat(line, &s); 294 if(rc < 0) 295 return -1; 296 if(s.st_uid != uid || s.st_gid != gid) { 297 rc = chown(line, getuid(), getgid()); 298 if(rc < 0) { 299 fprintf(stderr, 300 "Warning: could not change ownership of tty -- " 301 "pty is insecure!\n"); 302 return 0; 303 } 304 } 305 if((s.st_mode & 0777) != (S_IRUSR | S_IWUSR | S_IWGRP)) { 306 rc = chmod(line, S_IRUSR | S_IWUSR | S_IWGRP); 307 if (rc < 0) { 308 fprintf(stderr, 309 "Warning: could not change permissions of tty -- " 310 "pty is insecure!\n"); 311 return 0; 312 } 313 } 314 return 1; 315} 316 317int 318allocatePty(int *pty_return, char **line_return) 319{ 320 char name[12], *line = NULL; 321 int pty = -1; 322 char *name1 = "pqrstuvwxyzPQRST", 323 *name2 = "0123456789abcdefghijklmnopqrstuv"; 324 char *p1, *p2; 325 326#ifdef HAVE_GRANTPT 327 char *temp_line; 328 int rc; 329 330#ifdef __APPLE__ 331 pty = posix_openpt(O_RDWR); 332#else 333 pty = open("/dev/ptmx", O_RDWR); 334#endif 335 336 if(pty < 0) 337 goto bsd; 338 339 rc = grantpt(pty); 340 if(rc < 0) { 341 close(pty); 342 goto bsd; 343 } 344 345 rc = unlockpt(pty); 346 if(rc < 0) { 347 close(pty); 348 goto bsd; 349 } 350 351 temp_line = ptsname(pty); 352 if(!temp_line) { 353 close(pty); 354 goto bsd; 355 } 356 line = strdup(temp_line); 357 if(!line) { 358 close(pty); 359 return -1; 360 } 361 362 fix_pty_perms(line); 363 364 *pty_return = pty; 365 *line_return = line; 366 return 0; 367 368 bsd: 369#endif /* HAVE_GRANTPT */ 370 371 strcpy(name, "/dev/pty??"); 372 for(p1 = name1; *p1; p1++) { 373 name[8] = *p1; 374 for(p2 = name2; *p2; p2++) { 375 name[9] = *p2; 376 pty = open(name, O_RDWR); 377 if(pty >= 0) 378 goto found; 379 /* Systems derived from 4.4BSD differ in their pty names, 380 so ENOENT doesn't necessarily imply we're done. */ 381 continue; 382 } 383 } 384 385 goto bail; 386 387 found: 388 line = strdup(name); 389 if(!line) 390 goto bail; 391 line[5] = 't'; 392 fix_pty_perms(line); 393 *pty_return = pty; 394 *line_return = line; 395 return 0; 396 397 bail: 398 if(pty >= 0) 399 close(pty); 400 if(line) 401 free(line); 402 return -1; 403} 404 405int 406openTty(char *line) 407{ 408 int rc; 409 int tty = -1; 410 411#if !defined(O_NOCTTY) || !defined(TIOCSCTTY) 412 /* e.g. Cygwin has a working O_NOCTTY but no TIOCSCTTY, so the tty 413 must be opened as controlling */ 414 tty = open(line, O_RDWR); 415#else 416 /* The TIOCSCTTY ioctl below will fail if the process already has a 417 controlling tty (even if the current controlling tty is the same 418 as the tty you want to make controlling). So we need to open 419 the tty with O_NOCTTY to make sure this doesn't happen. */ 420 tty = open(line, O_RDWR | O_NOCTTY); 421#endif 422 423 if(tty < 0) 424 goto bail; 425 426#ifdef TIOCSCTTY 427 rc = ioctl(tty, TIOCSCTTY, (char *)0); 428 if(rc < 0) { 429 goto bail; 430 } 431#endif 432 433#if defined(SVR4) || defined(__SVR4) 434 rc = ioctl(tty, I_PUSH, "ptem"); 435 if(rc < 0) 436 goto bail; 437 438 rc = ioctl(tty, I_PUSH, "ldterm"); 439 if(rc < 0) 440 goto bail; 441 442 rc = ioctl(tty, I_PUSH, "ttcompat"); 443 if(rc < 0) 444 goto bail; 445#endif 446 447 return tty; 448 449 bail: 450 if(tty >= 0) 451 close(tty); 452 return -1; 453} 454 455/* Post-4.4 BSD systems have POSIX semantics (_POSIX_SAVED_IDS 456 or not, depending on the version). 4.3BSD and Minix do not have 457 saved IDs at all, so there's no issue. */ 458#if (defined(BSD) && !defined(_POSIX_SAVED_IDS)) || defined(_MINIX) 459int 460droppriv(void) 461{ 462 int rc; 463 rc = setuid(getuid()); 464 if(rc < 0) 465 return rc; 466 return setgid(getgid()); 467} 468#elif defined(_POSIX_SAVED_IDS) 469int 470droppriv(void) 471{ 472 int uid = getuid(); 473 int euid = geteuid(); 474 int gid = getgid(); 475 int egid = getegid(); 476 int rc; 477 478 if((uid != euid || gid != egid) && euid != 0) { 479 errno = ENOSYS; 480 return -1; 481 } 482 rc = setuid(uid); 483 if(rc < 0) 484 return rc; 485 return setgid(gid); 486} 487#else 488int 489droppriv(void) 490{ 491 int uid = getuid(); 492 int euid = geteuid(); 493 int gid = getgid(); 494 int egid = getegid(); 495 496 if(uid != euid || gid != egid) { 497 errno = ENOSYS; 498 return -1; 499 } 500 return 0; 501} 502#endif 503