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