sys.c revision a8fdb4bc
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 SVR4 38#define HAVE_POLL 39#endif 40 41#ifndef HAVE_POLL 42#ifndef _MINIX 43#define HAVE_SELECT 44#endif 45#endif 46 47#ifdef HAVE_POLL 48#include <sys/poll.h> 49#undef HAVE_SELECT 50#endif 51 52#ifdef __QNX__ 53#include <sys/select.h> 54#endif 55 56 57#if (defined(__GLIBC__) && \ 58 (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 1))) || \ 59 defined(SVR4) 60#define HAVE_GRANTPT 61#endif 62 63#ifdef __GLIBC__ 64#include <pty.h> 65#endif 66 67#ifdef SVR4 68#include <stropts.h> 69#endif 70 71#if (defined(__unix__) || defined(unix)) && !defined(USG) 72#include <sys/param.h> 73#endif 74 75#include "sys.h" 76 77static int saved_tio_valid = 0; 78static struct termios saved_tio; 79 80 81#ifdef HAVE_POLL 82int 83waitForOutput(int fd) 84{ 85 struct pollfd pfd[1]; 86 int rc; 87 88 pfd[0].fd = fd; 89 pfd[0].events = POLLOUT; 90 pfd[0].revents = 0; 91 92 rc = poll(pfd, 1, -1); 93 if(rc < 0) 94 return -1; 95 96 if(pfd[0].revents & POLLOUT) 97 return 1; 98 99 return 0; 100} 101 102int 103waitForInput(int fd1, int fd2) 104{ 105 struct pollfd pfd[2]; 106 int ret, rc; 107 108 pfd[0].fd = fd1; 109 pfd[1].fd = fd2; 110 pfd[0].events = pfd[1].events = POLLIN; 111 pfd[0].revents = pfd[1].revents = 0; 112 113 rc = poll(pfd, 2, -1); 114 if(rc < 0) 115 return -1; 116 117 ret = 0; 118 if(pfd[0].revents & POLLIN) 119 ret |= 1; 120 if(pfd[1].revents & POLLIN) 121 ret |= 2; 122 return ret; 123} 124#endif 125 126#ifdef HAVE_SELECT 127int 128waitForOutput(int fd) 129{ 130 fd_set fds; 131 int rc; 132 133 FD_ZERO(&fds); 134 FD_SET(fd, &fds); 135 rc = select(FD_SETSIZE, NULL, &fds, NULL, NULL); 136 if(rc < 0) 137 return -1; 138 139 if(FD_ISSET(fd, &fds)) 140 return 1; 141 142 return 0; 143} 144 145int 146waitForInput(int fd1, int fd2) 147{ 148 fd_set fds; 149 int ret, rc; 150 151 FD_ZERO(&fds); 152 FD_SET(fd1, &fds); 153 FD_SET(fd2, &fds); 154 rc = select(FD_SETSIZE, &fds, NULL, NULL, NULL); 155 if(rc < 0) 156 return -1; 157 158 ret = 0; 159 if(FD_ISSET(fd1, &fds)) 160 ret |= 1; 161 if(FD_ISSET(fd2, &fds)) 162 ret |= 2; 163 return ret; 164} 165#endif 166 167#ifndef HAVE_POLL 168#ifndef HAVE_SELECT 169/* Busy looping implementation */ 170int 171waitForOutput(int fd) 172{ 173 return 1; 174} 175 176int 177waitForInput(int fd1, int fd2) 178{ 179 return 1|2; 180} 181#endif 182#endif 183 184 185int 186setWindowSize(int sfd, int dfd) 187{ 188#ifdef TIOCGWINSZ 189 int rc; 190 struct winsize ws; 191 rc = ioctl(sfd, TIOCGWINSZ, (char*)&ws); 192 if(rc < 0) 193 return -1; 194 rc = ioctl(dfd, TIOCSWINSZ, (char*)&ws); 195 if(rc < 0) 196 return -1; 197#endif 198 return 0; 199} 200 201int 202installHandler(int signum, void (*handler)(int)) 203{ 204 struct sigaction sa; 205 sigset_t ss; 206 int rc; 207 208 sigemptyset(&ss); 209 210 sa.sa_handler = handler; 211 sa.sa_mask = ss; 212 sa.sa_flags = 0; 213 rc = sigaction(signum, &sa, NULL); 214 return rc; 215} 216 217int 218copyTermios(int sfd, int dfd) 219{ 220 struct termios tio; 221 int rc; 222 223 rc = tcgetattr(sfd, &tio); 224 if(rc < 0) 225 return -1; 226 227 rc = tcsetattr(dfd, TCSAFLUSH, &tio); 228 if(rc < 0) 229 return -1; 230 231 return 0; 232} 233 234int 235saveTermios(void) 236{ 237 int rc; 238 rc = tcgetattr(0, &saved_tio); 239 if(rc >= 0) 240 saved_tio_valid = 1; 241 return rc; 242} 243 244int 245restoreTermios(void) 246{ 247 if(!saved_tio_valid) 248 return -1; 249 return tcsetattr(0, TCSAFLUSH, &saved_tio); 250} 251 252int 253setRawTermios(void) 254{ 255 struct termios tio; 256 int rc; 257 258 if(!saved_tio_valid) 259 saveTermios(); 260 rc = tcgetattr(0, &tio); 261 if(rc < 0) 262 return rc; 263 tio.c_lflag &= ~(ECHO|ICANON|ISIG); 264 tio.c_iflag &= ~(ICRNL|IXOFF|IXON|ISTRIP); 265#ifdef ONLCR 266 tio.c_oflag &= ~ONLCR; 267#endif 268#ifdef OCRNL 269 tio.c_oflag &= ~OCRNL; 270#endif 271#ifdef ONOCR 272 tio.c_oflag &= ~ONOCR; 273#endif 274 275#ifdef VMIN 276 tio.c_cc[VMIN] = 0; 277 tio.c_cc[VTIME] = 0; 278#endif 279 rc = tcsetattr(0, TCSAFLUSH, &tio); 280 if(rc < 0) 281 return rc; 282 return 0; 283} 284 285 286char * 287my_basename(char *path) 288{ 289 char *p; 290 291 p = strrchr(path, '/'); 292 if(!p) 293 p = path; 294 else 295 p++; 296 return p; 297} 298 299static int 300fix_pty_perms(char *line) 301{ 302 int rc; 303 struct stat s; 304 int uid = getuid(), gid = getgid(); 305 306 rc = stat(line, &s); 307 if(rc < 0) 308 return -1; 309 if(s.st_uid != uid || s.st_gid != gid) { 310 rc = chown(line, getuid(), getgid()); 311 if(rc < 0) { 312 fprintf(stderr, 313 "Warning: could not change ownership of tty -- " 314 "pty is insecure!\n"); 315 return 0; 316 } 317 } 318 if((s.st_mode & 0777) != (S_IRUSR | S_IWUSR | S_IWGRP)) { 319 rc = chmod(line, S_IRUSR | S_IWUSR | S_IWGRP); 320 if (rc < 0) { 321 fprintf(stderr, 322 "Warning: could not change permissions of tty -- " 323 "pty is insecure!\n"); 324 return 0; 325 } 326 } 327 return 1; 328} 329 330int 331allocatePty(int *pty_return, char **line_return) 332{ 333 char name[12], *line = NULL; 334 int pty = -1; 335 char *name1 = "pqrstuvwxyzPQRST", 336 *name2 = "0123456789abcdefghijklmnopqrstuv"; 337 char *p1, *p2; 338 339#ifdef HAVE_GRANTPT 340 char *temp_line; 341 int rc; 342 343 pty = open("/dev/ptmx", O_RDWR); 344 if(pty < 0) 345 goto bsd; 346 347 rc = grantpt(pty); 348 if(rc < 0) { 349 close(pty); 350 goto bsd; 351 } 352 353 rc = unlockpt(pty); 354 if(rc < 0) { 355 close(pty); 356 goto bsd; 357 } 358 359 temp_line = ptsname(pty); 360 if(!temp_line) { 361 close(pty); 362 goto bsd; 363 } 364 line = strdup(temp_line); 365 if(!line) { 366 close(pty); 367 return -1; 368 } 369 370 fix_pty_perms(line); 371 372 *pty_return = pty; 373 *line_return = line; 374 return 0; 375 376 bsd: 377#endif /* HAVE_GRANTPT */ 378 379 strcpy(name, "/dev/pty??"); 380 for(p1 = name1; *p1; p1++) { 381 name[8] = *p1; 382 for(p2 = name2; *p2; p2++) { 383 name[9] = *p2; 384 pty = open(name, O_RDWR); 385 if(pty >= 0) 386 goto found; 387 /* Systems derived from 4.4BSD differ in their pty names, 388 so ENOENT doesn't necessarily imply we're done. */ 389 continue; 390 } 391 } 392 393 goto bail; 394 395 found: 396 line = strdup(name); 397 if(!line) 398 goto bail; 399 line[5] = 't'; 400 fix_pty_perms(line); 401 *pty_return = pty; 402 *line_return = line; 403 return 0; 404 405 bail: 406 if(pty >= 0) 407 close(pty); 408 if(line) 409 free(line); 410 return -1; 411} 412 413int 414openTty(char *line) 415{ 416 int rc; 417 int tty = -1; 418 419 tty = open(line, O_RDWR | O_NOCTTY); 420 421 if(tty < 0) 422 goto bail; 423 424#ifdef TIOCSCTTY 425 rc = ioctl(tty, TIOCSCTTY, (char *)0); 426 if(rc < 0) { 427 goto bail; 428 } 429#endif 430 431#ifdef SVR4 432 rc = ioctl(tty, I_PUSH, "ptem"); 433 if(rc < 0) 434 goto bail; 435 436 rc = ioctl(tty, I_PUSH, "ldterm"); 437 if(rc < 0) 438 goto bail; 439 440 rc = ioctl(tty, I_PUSH, "ttcompat"); 441 if(rc < 0) 442 goto bail; 443#endif 444 445 return tty; 446 447 bail: 448 if(tty >= 0) 449 close(tty); 450 return -1; 451} 452 453/* Post-4.4 BSD systems have POSIX semantics (_POSIX_SAVED_IDS 454 or not, depending on the version). 4.3BSD and Minix do not have 455 saved IDs at all, so there's no issue. */ 456#if (defined(BSD) && !defined(_POSIX_SAVED_IDS)) || defined(_MINIX) 457int 458droppriv(void) 459{ 460 int rc; 461 rc = setuid(getuid()); 462 if(rc < 0) 463 return rc; 464 return setgid(getgid()); 465} 466#elif defined(_POSIX_SAVED_IDS) 467int 468droppriv(void) 469{ 470 int uid = getuid(); 471 int euid = geteuid(); 472 int gid = getgid(); 473 int egid = getegid(); 474 int rc; 475 476 if((uid != euid || gid != egid) && euid != 0) { 477 errno = ENOSYS; 478 return -1; 479 } 480 rc = setuid(uid); 481 if(rc < 0) 482 return rc; 483 return setgid(gid); 484} 485#else 486int 487droppriv(void) 488{ 489 int uid = getuid(); 490 int euid = geteuid(); 491 int gid = getgid(); 492 int egid = getegid(); 493 494 if(uid != euid || gid != egid) { 495 errno = ENOSYS; 496 return -1; 497 } 498 return 0; 499} 500#endif 501