FreeBSD 10 clang port
[oweals/cde.git] / cde / lib / DtTerm / TermPrim / TermPrimGetPty-bsd.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 #ifndef lint
24 #ifdef  VERBOSE_REV_INFO
25 static char rcs_id[] = "$XConsortium: TermPrimGetPty-bsd.c /main/4 1996/11/21 19:58:32 drk $";
26 #endif  /* VERBOSE_REV_INFO */
27 #endif  /* lint */
28
29 /*                                                                      *
30  * (c) Copyright 1993, 1994 Hewlett-Packard Company                     *
31  * (c) Copyright 1993, 1994 International Business Machines Corp.       *
32  * (c) Copyright 1993, 1994 Sun Microsystems, Inc.                      *
33  * (c) Copyright 1993, 1994 Novell, Inc.                                *
34  */
35
36 #include <fcntl.h>
37 #include <termios.h>
38 #if defined(CSRG_BASED)
39 #include <sys/stat.h>
40 #include <sys/types.h>
41 #include <sys/ioctl.h>
42 #if defined(__FreeBSD__)
43 #include <libutil.h>
44 #else
45 #include <util.h>
46 #endif
47 #endif
48 #include <sys/wait.h>
49 #include <ctype.h>
50 #include <errno.h>
51 #include <signal.h>
52 #include <Xm/Xm.h>
53 #define X_INCLUDE_GRP_H
54 #define X_INCLUDE_UNISTD_H
55 #define XOS_USE_XT_LOCKING
56 #include <X11/Xos_r.h>
57 #include "TermPrim.h"
58 #include "TermHeader.h"
59 #include "TermPrimDebug.h"
60 #include "TermPrimUtil.h"
61
62 typedef struct _ptyInfo {
63     char *ptyName;
64     struct _ptyInfo *next;
65     struct _ptyInfo *prev;
66 } ptyInfo;
67
68 static ptyInfo _ptyInfoHead;
69 static ptyInfo *ptyInfoHead = &_ptyInfoHead;
70
71 static void
72 AddPtyInfo
73 (
74     char                 *ptyName
75 )
76 {
77     ptyInfo              *ptyInfoTmp;
78     sigset_t              newSigs;
79     sigset_t              oldSigs;
80
81     /* malloc a new entry... */
82     ptyInfoTmp = (ptyInfo *) XtMalloc(sizeof(ptyInfo));
83     (void) memset(ptyInfoTmp, '\0', sizeof(ptyInfo));
84
85     /* fill in the structure... */
86     ptyInfoTmp->ptyName = (char *) XtMalloc(strlen(ptyName) + 1);
87     (void) strcpy(ptyInfoTmp->ptyName, ptyName);
88
89     /* insert it after the head of the list...
90      */
91     /* block all signals... */
92     (void) sigfillset(&newSigs);
93     (void) sigemptyset(&oldSigs);
94     (void) sigprocmask(SIG_BLOCK, &newSigs, &oldSigs);
95     /* insert the entry into the list... */
96     ptyInfoTmp->prev = ptyInfoHead;
97     ptyInfoTmp->next = ptyInfoHead->next;
98     ptyInfoHead->next = ptyInfoTmp;
99     if (ptyInfoTmp->next) {
100         ptyInfoTmp->next->prev = ptyInfoTmp;
101     }
102     /* restore signals... */
103     (void) sigprocmask(SIG_SETMASK, &oldSigs, (sigset_t *) 0);
104 }
105
106 static void
107 DeletePtyInfo
108 (
109     char                 *ptyName
110 )
111 {
112     ptyInfo              *ptyInfoTmp;
113     sigset_t              newSigs;
114     sigset_t              oldSigs;
115
116     /* find the entry... */
117     for (ptyInfoTmp = ptyInfoHead->next; ptyInfoTmp;
118             ptyInfoTmp = ptyInfoTmp->next) {
119         if (!strcmp(ptyInfoTmp->ptyName, ptyName)) {
120             break;
121         }
122     }
123
124     /* did we find anything... */
125     if (!ptyInfoTmp) {
126         /* not found... */
127         return;
128     }
129
130     /* delete entry from the list...
131      */
132     /* block all signals... */
133     (void) sigfillset(&newSigs);
134     (void) sigemptyset(&oldSigs);
135     (void) sigprocmask(SIG_BLOCK, &newSigs, &oldSigs);
136     /* remove it... */
137     ptyInfoTmp->prev->next = ptyInfoTmp->next;
138     if (ptyInfoTmp->next) {
139         ptyInfoTmp->next->prev = ptyInfoTmp->prev;
140     }
141     /* restore signals... */
142     (void) sigprocmask(SIG_SETMASK, &oldSigs, (sigset_t *) 0);
143
144     /* free up the data... */
145     if (ptyInfoTmp->ptyName) {
146         (void) XtFree(ptyInfoTmp->ptyName);
147         ptyInfoTmp->ptyName = (char *) 0;
148     }
149     (void) XtFree((char *) ptyInfoTmp);
150 }
151
152 #define True    1
153 #define False   0
154
155 static char PTY_dev[]           = "/dev";
156 static char PTY_dev_pty[]       = "/dev/pty";
157 static char PTY_dev_ptym[]      = "/dev/ptym";
158 static char PTY_a_ce_o[]        = "abcefghijklmno";
159 static char PTY_a_ce_z[]        = "abcefghijklmnopqrstuvwxyz";
160 static char PTY_0_9[]           = "0123456789";
161 static char PTY_0_9a_f[]        = "0123456789abcdef";
162 static char PTY_p_z[]           = "pqrstuvwxyz";
163 static char PTY_p_r[]           = "pqr";
164 #define         PTY_null        (char *) 0
165 static struct _pty_dirs {
166     char *pty_dir;
167     char *ptym_dir;
168     char *char_1;
169     char *char_2;
170     char *char_3;
171     int fast;
172 } pty_dirs[] = {
173     {PTY_dev_pty, PTY_dev_ptym, PTY_a_ce_o, PTY_0_9,    PTY_0_9,  True},
174     {PTY_dev_pty, PTY_dev_ptym, PTY_p_z,    PTY_0_9,    PTY_0_9,  True},
175     {PTY_dev_pty, PTY_dev_ptym, PTY_a_ce_o, PTY_0_9a_f, PTY_null, True},
176     {PTY_dev_pty, PTY_dev_ptym, PTY_p_z,    PTY_0_9a_f, PTY_null, False},
177     {PTY_dev,     PTY_dev,      PTY_p_r,    PTY_0_9a_f, PTY_null, False},
178     {PTY_null,    PTY_null,     PTY_null,   PTY_null,   PTY_null, False},
179 };
180
181 #if defined(ALPHA_ARCHITECTURE) || defined(CSRG_BASED)
182 /* Use openpty() to open Master/Slave pseudo-terminal pair */
183 /* Current version of openpty() uses non-STREAM device. BSD name space */
184 #define TTYNAMELEN      25
185   static int
186   GetPty(char **ptySlave, char **ptyMaster)
187   {
188     int master, slave;
189
190     *ptySlave = malloc(TTYNAMELEN);
191     /* malloc error */
192     if (!(*ptySlave)) return -1;
193
194     if(!openpty(&master, &slave, *ptySlave, NULL, NULL))
195     {
196         /* success */
197         close(slave);
198
199         /* add it to the list... */
200         (void) AddPtyInfo(*ptySlave);
201
202         return master;
203     }
204     else    /* failure */
205         return -1;
206 }
207 #else
208 static int
209 GetPty(char **ptySlave, char **ptyMaster)
210 {
211     struct _pty_dirs *pty_dirs_ptr;
212     char *char_1;
213     char *char_2;
214     char *char_3;
215     int first;
216     int ptyFd;
217     int ttyFd;
218
219     char *ttyDev = (char *) 0;
220     char *ptyDev = (char *) 0;
221
222     for (pty_dirs_ptr = pty_dirs;
223             pty_dirs_ptr->pty_dir && pty_dirs_ptr->ptym_dir; pty_dirs_ptr++) {
224         ttyDev = realloc(ttyDev,
225                 (unsigned) (strlen(pty_dirs_ptr->pty_dir) + 8));
226         ptyDev = realloc(ptyDev,
227                 (unsigned) (strlen(pty_dirs_ptr->ptym_dir) + 8));
228         if (!ttyDev || !ptyDev) {
229             (void) perror("malloc");
230             return(-1);
231         }
232
233         if (isDebugFSet('p', 10)) {
234 #ifdef  BBA
235 #pragma BBA_IGNORE
236 #endif  /*BBA*/
237             return(-1);
238         }
239
240         for (first = 1, char_1 = pty_dirs_ptr->char_1;
241                 (first || !pty_dirs_ptr->fast) && *char_1; char_1++) {
242             for (char_2 = pty_dirs_ptr->char_2;
243                     (first || !pty_dirs_ptr->fast) && *char_2; char_2++) {
244                 for (char_3 = pty_dirs_ptr->char_3;
245                         (first || !pty_dirs_ptr->fast); ) {
246                     (void) sprintf(ttyDev, char_3 ? "%s/tty%c%c%c" :
247                             "%s/tty%c%c", pty_dirs_ptr->pty_dir,
248                             *char_1, *char_2, char_3 ? *char_3 : 0);
249                     (void) sprintf(ptyDev, char_3 ? "%s/pty%c%c%c" :
250                             "%s/pty%c%c", pty_dirs_ptr->ptym_dir,
251                             *char_1, *char_2, char_3 ? *char_3 : 0);
252                     ptyFd = -1;
253                     ttyFd = -1;
254                     errno = 0;
255                     if ((ptyFd = open(ptyDev, O_RDWR, 0)) >= 0) {
256                         if ((ttyFd = open(ttyDev, O_RDWR | O_NOCTTY, 0)) < 0) {
257                             if (isDebugSet('p'))
258                                 (void) perror(ttyDev);
259                         } else {
260                             /* Success...
261                              */
262                             char *c1;
263                             _Xttynameparams tty_buf;
264
265                             /* use ttyname so that we get the same
266                              * name for the tty that everyone else will
267                              * use...
268                              */
269 #if defined(XTHREADS)
270                             if (c1 = _XTtyname(ttyFd, tty_buf)) {
271 #else
272                             if (c1 = _XTtyname(ttyFd)) {
273 #endif
274                                 ttyDev = realloc(ttyDev, strlen(c1) + 1);
275                                 (void) strcpy(ttyDev, c1);
276                             }
277
278                             /* change the ownership and mode of the pty.
279                              * This allows us to access the pty when we
280                              * are no longer suid root...
281                              */
282 #ifdef  HP_ARCHITECTURE
283                             {
284                                 struct group *grp;
285                                 gid_t gid;
286                                 _Xgetgrparams grp_buf;
287
288                                 if (grp = _XGetgrnam("tty", grp_buf)) {
289                                     gid = grp->gr_gid;
290                                 } else {
291                                     gid = 0;
292                                 }
293                                 (void) endgrent();
294                                 (void) chown(ttyDev, getuid(), gid);
295                                 (void) chmod(ttyDev, 0620);
296                             }
297 #else   /* HP_ARCHITECTURE */
298                             (void) chown(ttyDev, getuid(), getgid());
299                             (void) chmod(ttyDev, 0622);
300 #endif  /* HP_ARCHITECTURE */
301
302                             /* close off the pty slave... */
303                             (void) close(ttyFd);
304
305                             /* add it to the list... */
306                             (void) AddPtyInfo(ttyDev);
307
308                             /* return file names and pty master... */
309                             *ptySlave = ttyDev;
310                             *ptyMaster = ptyDev;
311                             return(ptyFd);
312                         }
313                     } else {
314                         if (isDebugSet('p'))
315                             (void) perror(ptyDev);
316                     }
317
318                     /* Failed to open...
319                      */
320                     if (ptyFd >= 0)
321                         (void) close(ptyFd);
322                     if (ttyFd >= 0)
323                         (void) close(ttyFd);
324
325                     /* If we either were able to open the pty master (i.e.,
326                      * slave open failed), or the device was busy, keep
327                      * going...
328                      */
329                     if ((ptyFd < 0) && (errno != EBUSY)) {
330                         first = False;
331                     }
332
333                     if (!char_3)
334                         break;
335                     (void) char_3++;
336                     if (!*char_3)
337                         break;
338                 }
339             }
340         }
341     }
342
343     return(-1);
344 }
345 #endif /* ALPHA_ARCHITECTURE */
346
347 /* this is a public wrapper around the previous function that runs the
348  * previous function setuid root...
349  */
350 int
351 _DtTermPrimGetPty(char **ptySlave, char **ptyMaster)
352 {
353     int retValue;
354
355     /* this function needs to be suid root... */
356     (void) _DtTermPrimToggleSuidRoot(True);
357     retValue = GetPty(ptySlave, ptyMaster);
358     /* we now need to turn off setuid root... */
359     (void) _DtTermPrimToggleSuidRoot(False);
360
361     return(retValue);
362 }
363
364 static int
365 SetupPty(char *ptySlave, int ptyFd)
366 {
367 #ifdef  HP_ARCHITECTURE
368     {
369         struct group *grp;
370         gid_t gid;
371         _Xgetgrparams grp_buf;
372
373         if (grp = _XGetgrnam("tty", grp_buf)) {
374             gid = grp->gr_gid;
375         } else {
376             gid = 0;
377         }
378         (void) endgrent();
379         (void) chown(ptySlave, getuid(), gid);
380         (void) chmod(ptySlave, 0620);
381     }
382 #else   /* HP_ARCHITECTURE */
383 #ifdef ALPHA_ARCHITECTURE
384     /* code from xterm to setup ownership and permission */
385     {
386         struct group *ttygrp;
387         _Xgetgrparams grp_buf;
388
389         if (ttygrp = _XGetgrnam("tty", grp_buf)) {
390            /* change ownership of tty to real uid, "tty" gid */
391            chown (ptySlave, getuid(), ttygrp->gr_gid);
392            chmod (ptySlave, 0620);
393         }
394         else {
395            /* change ownership of tty to real group and user id */
396            chown (ptySlave, getuid(), getgid());
397            chmod (ptySlave, 0622);
398         }
399         endgrent();
400     }
401 #else   /* ALPHA_ARCHITECTURE */
402     (void) chown(ptySlave, getuid(), getgid());
403     (void) chmod(ptySlave, 0622);
404 #endif /* ALPHA_ARCHITECTURE */
405 #endif  /* HP_ARCHITECTURE */
406     return 0;
407 }
408     
409 int
410 _DtTermPrimSetupPty(char *ptySlave, int ptyFd)
411 {
412     int retValue;
413
414     /* this function needs to be suid root... */
415     (void) _DtTermPrimToggleSuidRoot(True);
416     retValue = SetupPty(ptySlave, ptyFd);
417     /* we now need to turn off setuid root... */
418     (void) _DtTermPrimToggleSuidRoot(False);
419
420     return(retValue);
421 }
422
423 static void
424 ReleasePty(char *ptySlave)
425 {
426     (void) chown(ptySlave, 0, 0);
427     (void) chmod(ptySlave, 0666);
428     (void) DeletePtyInfo(ptySlave);
429 }
430     
431 void
432 _DtTermPrimReleasePty(char *ptySlave)
433 {
434     /* this function needs to be suid root... */
435     (void) _DtTermPrimToggleSuidRoot(True);
436     (void) ReleasePty(ptySlave);
437     /* we now need to turn off setuid root... */
438     (void) _DtTermPrimToggleSuidRoot(False);
439 }
440
441 void
442 _DtTermPrimPtyCleanup()
443 {
444     DebugF('s', 10, fprintf(stderr, ">>_DtTermPrimPtyCleanup() starting\n"));
445     while (ptyInfoHead->next && ptyInfoHead->next->ptyName) {
446         DebugF('s', 10, fprintf(stderr, ">>releasing pty \"%s\"\n",
447                 ptyInfoHead->next->ptyName));
448         (void) _DtTermPrimReleasePty(ptyInfoHead->next->ptyName);
449     }
450     DebugF('s', 10, fprintf(stderr, ">>_DtTermPrimPtyCleanup() finished\n"));
451 }