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