1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
28 /*
29 * Copyright (c) 2018, Joyent, Inc.
30 */
31
32
33 #include <stdlib.h>
34 #include <stdio.h>
35 #include <fcntl.h>
36 #include <errno.h>
37 #include <poll.h>
38 #include <string.h>
39 #include <termio.h>
40 #include <signal.h>
41 #include <sys/types.h>
42 #include <sys/stropts.h>
43 #include <unistd.h>
44 #include <sys/wait.h>
45 #include "ttymon.h"
46 #include "tmstruct.h"
47 #include "tmextern.h"
48 #include "sac.h"
49
50 static struct pmtab *find_pid(pid_t);
51 static void kill_subprocesses(void);
52
53 static struct pmtab *find_fd(int);
54 static void pcsync_close(int *, int *, int, int);
55
56 /*
57 * fork_tmchild - fork child on the device
58 */
59 static void
fork_tmchild(struct pmtab * pmptr)60 fork_tmchild(struct pmtab *pmptr)
61 {
62 pid_t pid;
63 sigset_t cset;
64 sigset_t tset;
65 int pcpipe0[2], pcpipe1[2];
66 int p0;
67
68 #ifdef DEBUG
69 debug("in fork_tmchild");
70 #endif
71 pmptr->p_inservice = FALSE;
72
73 /*
74 * initialize pipe.
75 * Child has pcpipe[0] pipe fd for reading and writing
76 * and closes pcpipe[1]. Parent has pcpipe[1] pipe fd for
77 * reading and writing and closes pcpipe[0].
78 *
79 * This way if the child process exits the parent's block
80 * read on pipe will return immediately as the other end of
81 * the pipe has closed. Similarly if the parent process exits
82 * child's blocking read on the pipe will return immediately.
83 */
84
85 if (((p0 = pipe(pcpipe0)) == -1) || (pipe(pcpipe1) == -1)) {
86 if (p0 == 0) {
87 (void) close(pcpipe0[0]);
88 (void) close(pcpipe0[1]);
89 }
90 log("pipe() failed: %s", strerror(errno));
91 pmptr->p_status = VALID;
92 pmptr->p_childpid = 0;
93 Retry = TRUE;
94 }
95
96 /* protect following region from SIGCLD */
97 (void) sigprocmask(SIG_SETMASK, NULL, &cset);
98 tset = cset;
99 (void) sigaddset(&tset, SIGCLD);
100 (void) sigprocmask(SIG_SETMASK, &tset, NULL);
101 if ((pid = fork()) == 0) {
102 /*
103 * Close all file descriptors except pmptr->p_fd
104 * Wait for the parent process to close its fd
105 */
106 pcsync_close(pcpipe0, pcpipe1, pid, pmptr->p_fd);
107 /* The CHILD */
108 tmchild(pmptr);
109 /* tmchild should never return */
110 fatal("tmchild for <%s> returns unexpected", pmptr->p_device);
111 } else if (pid < 0) {
112 log("fork failed: %s", strerror(errno));
113 pmptr->p_status = VALID;
114 pmptr->p_childpid = 0;
115 Retry = TRUE;
116 } else {
117 /*
118 * The PARENT - store pid of child and close the device
119 */
120 pmptr->p_childpid = pid;
121 }
122 if (pmptr->p_fd > 0) {
123 (void) close(pmptr->p_fd);
124 pmptr->p_fd = 0;
125 }
126 (void) sigprocmask(SIG_SETMASK, &cset, NULL);
127 /*
128 * Wait for child to close file descriptors
129 */
130 pcsync_close(pcpipe0, pcpipe1, pid, pmptr->p_fd);
131 }
132
133 /*
134 * got_carrier - carrier is detected on the stream
135 * - depends on the flags, different action is taken
136 * - R_FLAG - wait for data
137 * - C_FLAG - if port is not disabled, fork tmchild
138 * - A_FLAG - wait for data
139 * - otherwise - write out prompt, then wait for data
140 */
141 void
got_carrier(struct pmtab * pmptr)142 got_carrier(struct pmtab *pmptr)
143 {
144 flush_input(pmptr->p_fd);
145
146 if (pmptr->p_ttyflags & R_FLAG) {
147 #ifdef DEBUG
148 debug("R_FLAG");
149 #endif
150 return;
151 } else if ((pmptr->p_ttyflags & (C_FLAG|B_FLAG)) &&
152 (State != PM_DISABLED) &&
153 (!(pmptr->p_flags & X_FLAG))) {
154 fork_tmchild(pmptr);
155 } else if (pmptr->p_ttyflags & A_FLAG) {
156 #ifdef DEBUG
157 debug("A_FLAG");
158 #endif
159 return;
160 } else if (pmptr->p_timeout) {
161 fork_tmchild(pmptr);
162 } else if (!(pmptr->p_ttyflags & X_FLAG)) {
163 write_prompt(pmptr->p_fd, pmptr, TRUE, TRUE);
164 }
165 }
166
167 /*
168 * got_data - data is detected on the stream, fork tmchild
169 */
170 static void
got_data(struct pmtab * pmptr)171 got_data(struct pmtab *pmptr)
172 {
173 struct sigaction sigact;
174
175 if (tm_checklock(pmptr->p_fd) != 0) {
176 pmptr->p_status = LOCKED;
177 (void) close(pmptr->p_fd);
178 pmptr->p_fd = 0;
179 Nlocked++;
180 if (Nlocked == 1) {
181 sigact.sa_flags = 0;
182 sigact.sa_handler = sigalarm;
183 (void) sigemptyset(&sigact.sa_mask);
184 (void) sigaction(SIGALRM, &sigact, NULL);
185 (void) alarm(ALARMTIME);
186 }
187 } else {
188 fork_tmchild(pmptr);
189 }
190 }
191 /*
192 * got_hup - stream hangup is detected, close the device
193 */
194 static void
got_hup(struct pmtab * pmptr)195 got_hup(struct pmtab *pmptr)
196 {
197 #ifdef DEBUG
198 debug("in got hup");
199 #endif
200 (void) close(pmptr->p_fd);
201 pmptr->p_fd = 0;
202 pmptr->p_inservice = 0;
203 Retry = TRUE;
204 }
205
206
207 /*
208 * do_poll - poll device
209 * - if POLLHUP received, close the device
210 * - if POLLIN received, fork tmchild.
211 */
212 void
do_poll(struct pollfd * fdp,int nfds)213 do_poll(struct pollfd *fdp, int nfds)
214 {
215 int i, n;
216 struct pmtab *pmptr;
217
218 n = poll(fdp, (unsigned long)nfds, -1); /* blocked poll */
219 #ifdef DEBUG
220 debug("poll return");
221 #endif
222 if (n < 0) {
223 if (errno == EINTR) /* interrupt by signal */
224 return;
225 fatal("do_poll: poll failed: %s", strerror(errno));
226 }
227 for (i = 0; (i < nfds) && (n != 0); i++, fdp++) {
228 if (fdp->revents != 0) {
229 n--;
230 if ((pmptr = find_fd(fdp->fd)) == NULL) {
231 log("do_poll: cannot find fd %d in pmtab",
232 fdp->fd);
233 continue;
234 } else if (fdp->revents & POLLHUP) {
235 got_hup(pmptr);
236 } else if (fdp->revents & POLLIN) {
237 #ifdef DEBUG
238 debug("got POLLIN");
239 #endif
240 got_data(pmptr);
241 } else if (fdp->revents & POLLERR) {
242 fatal("ttymon[%d]: do_poll: POLLERR on fd %d",
243 getpid(), fdp->fd);
244 }
245 }
246 }
247 }
248
249 /*
250 * sigchild - handler for SIGCLD
251 * - find the pid of dead child
252 * - clean utmp if U_FLAG is set
253 */
254 void
sigchild(int n __unused)255 sigchild(int n __unused)
256 {
257 struct pmtab *pmptr;
258 siginfo_t info;
259 int status;
260 pid_t pid;
261 int rcode;
262
263 #ifdef DEBUG
264 debug("in sigchild");
265 #endif
266
267 /* find all processes that died */
268 for (;;) {
269 rcode = waitid(P_ALL, 0, &info, WNOHANG|WEXITED);
270 if (rcode == -1 && errno == EINTR)
271 continue;
272
273 /* If no more children have exited, just return */
274 if (rcode == -1 || (pid = info.si_pid) == 0)
275 break;
276
277 /* construct status as returned from waitid() */
278 status = info.si_status & 0377;
279 switch (info.si_code) {
280 case CLD_EXITED:
281 status <<= 8;
282 break;
283 case CLD_DUMPED:
284 status |= WCOREFLG;
285 break;
286 case CLD_KILLED:
287 break;
288 }
289
290 if ((pmptr = find_pid(pid)) == NULL) {
291 #ifdef DEBUG
292 log("cannot find dead child (%ld) in pmtab", pid);
293 #endif
294 /*
295 * This may happen if the entry is deleted from pmtab
296 * before the service exits.
297 * We try to cleanup utmp entry
298 */
299 cleanut(pid, status);
300 } else {
301 if (pmptr->p_flags & U_FLAG)
302 cleanut(pid, status);
303 pmptr->p_status = VALID;
304 pmptr->p_fd = 0;
305 pmptr->p_childpid = 0;
306 pmptr->p_inservice = 0;
307 Retry = TRUE;
308 }
309 }
310 }
311
312 /*
313 * sigterm - handler for SIGTERM
314 */
315 void
sigterm(int _s __unused)316 sigterm(int _s __unused)
317 {
318 fatal("caught SIGTERM");
319 }
320
321 /*
322 * state_change - this is called when ttymon changes
323 * its internal state between enabled and disabled
324 */
325 void
state_change(void)326 state_change(void)
327 {
328 struct pmtab *pmptr;
329
330 #ifdef DEBUG
331 debug("in state_change");
332 #endif
333
334 /*
335 * closing PCpipe will cause attached non-service children
336 * to get SIGPOLL and exit
337 */
338 (void) close(PCpipe[0]);
339 (void) close(PCpipe[1]);
340
341 /* reopen PCpipe */
342 setup_PCpipe();
343
344 /*
345 * also close all open ports so ttymon can start over
346 * with new internal state
347 */
348 for (pmptr = PMtab; pmptr; pmptr = pmptr->p_next) {
349 if ((pmptr->p_fd > 0) && (pmptr->p_childpid == 0)) {
350 (void) close(pmptr->p_fd);
351 pmptr->p_fd = 0;
352 }
353 }
354 Retry = TRUE;
355
356 }
357
358 /*
359 * re_read - reread pmtab
360 * - kill tmchild if entry changed
361 */
362 void
re_read(void)363 re_read(void)
364 {
365 sigset_t cset;
366 sigset_t tset;
367
368 (void) sigprocmask(SIG_SETMASK, NULL, &cset);
369 tset = cset;
370 (void) sigaddset(&tset, SIGCLD);
371 (void) sigprocmask(SIG_SETMASK, &tset, NULL);
372 if (Nlocked > 0) {
373 (void) alarm(0);
374 Nlocked = 0;
375 }
376 read_pmtab();
377 kill_subprocesses();
378 (void) sigprocmask(SIG_SETMASK, &cset, NULL);
379 purge();
380
381 if (Nentries > Npollfd) {
382 #ifdef DEBUG
383 debug("Nentries > Npollfd, reallocating pollfds");
384 #endif
385 /* need to malloc more pollfd structure */
386 free(Pollp);
387 Npollfd = Nentries + 10;
388 if (Npollfd > Maxfds)
389 Npollfd = Maxfds;
390 Pollp = malloc((unsigned)(Npollfd * sizeof (struct pollfd)));
391 if (Pollp == NULL)
392 fatal("malloc for Pollp failed");
393 }
394 Retry = TRUE;
395 }
396
397 /*
398 * find_pid(pid) - find the corresponding pmtab entry for the pid
399 */
400 static struct pmtab *
find_pid(pid_t pid)401 find_pid(pid_t pid)
402 {
403 struct pmtab *pmptr;
404
405 for (pmptr = PMtab; pmptr; pmptr = pmptr->p_next) {
406 if (pmptr->p_childpid == pid) {
407 return (pmptr);
408 }
409 }
410 return (NULL);
411 }
412
413 /*
414 * find_fd(fd) - find the corresponding pmtab entry for the fd
415 */
416 static struct pmtab *
find_fd(int fd)417 find_fd(int fd)
418 {
419 struct pmtab *pmptr;
420
421 for (pmptr = PMtab; pmptr; pmptr = pmptr->p_next) {
422 if (pmptr->p_fd == fd) {
423 return (pmptr);
424 }
425 }
426 return (NULL);
427 }
428
429 /*
430 * kill_subprocesses() - if the pmtab entry has been changed,
431 * kill tmchild if it is not in service.
432 * - close the device if there is no tmchild
433 */
434 static void
kill_subprocesses(void)435 kill_subprocesses(void)
436 {
437 struct pmtab *pmptr;
438
439 for (pmptr = PMtab; pmptr; pmptr = pmptr->p_next) {
440 if (pmptr->p_status == VALID)
441 continue;
442 if ((pmptr->p_fd > 0) && (pmptr->p_childpid == 0)) {
443 (void) close(pmptr->p_fd);
444 pmptr->p_fd = 0;
445 } else if ((pmptr->p_fd == 0) && (pmptr->p_childpid > 0) &&
446 (pmptr->p_inservice == FALSE)) {
447 (void) kill(pmptr->p_childpid, SIGTERM);
448 }
449 }
450 }
451
452 static void
mark_service(pid_t pid)453 mark_service(pid_t pid)
454 {
455 struct pmtab *pmptr;
456 #ifdef DEBUG
457 debug("in mark_service");
458 #endif
459 if ((pmptr = find_pid(pid)) == NULL) {
460 log("mark_service: cannot find child (%ld) in pmtab", pid);
461 return;
462 }
463 pmptr->p_inservice = TRUE;
464 }
465
466 /*
467 * read_pid(fd) - read pid info from PCpipe
468 */
469 static void
read_pid(int fd)470 read_pid(int fd)
471 {
472 int ret;
473 pid_t pid;
474
475 for (;;) {
476 if ((ret = read(fd, &pid, sizeof (pid))) < 0) {
477 if (errno == EINTR)
478 continue;
479 if (errno == EAGAIN)
480 return;
481 fatal("read PCpipe failed: %s", strerror(errno));
482 }
483 if (ret == 0)
484 return;
485 if (ret != sizeof (pid))
486 fatal("read return size incorrect, ret = %d", ret);
487
488 mark_service(pid);
489 }
490 }
491
492 /*
493 * sipoll_catch() - signal handle of SIGPOLL for ttymon
494 * - it will check both PCpipe and pmpipe
495 */
496 void
sigpoll_catch(int s __unused)497 sigpoll_catch(int s __unused)
498 {
499 int ret;
500 struct pollfd pfd[2];
501
502 #ifdef DEBUG
503 debug("in sigpoll_catch");
504 #endif
505
506 pfd[0].fd = PCpipe[0];
507 pfd[1].fd = Pfd;
508 pfd[0].events = POLLIN;
509 pfd[1].events = POLLIN;
510 if ((ret = poll(pfd, 2, 0)) < 0)
511 fatal("sigpoll_catch: poll failed: %s", strerror(errno));
512
513 if (ret > 0) {
514 if (pfd[0].revents & POLLIN)
515 read_pid(pfd[0].fd);
516 if (pfd[1].revents & POLLIN)
517 sacpoll();
518 }
519 }
520
521 void
sigalarm(int signo __unused)522 sigalarm(int signo __unused)
523 {
524 struct pmtab *pmptr;
525 struct sigaction sigact;
526 int fd;
527
528 #ifdef DEBUG
529 debug("in sigalarm, Nlocked = %d", Nlocked);
530 #endif
531 for (pmptr = PMtab; pmptr; pmptr = pmptr->p_next) {
532 if ((pmptr->p_status == LOCKED) && (pmptr->p_fd == 0)) {
533 fd = open(pmptr->p_device, O_RDWR | O_NONBLOCK);
534 if (fd == -1) {
535 log("open (%s) failed: %s", pmptr->p_device,
536 strerror(errno));
537 pmptr->p_status = VALID;
538 Nlocked--;
539 Retry = TRUE;
540 } else {
541 if (tm_checklock(fd) == 0) {
542 Nlocked--;
543 pmptr->p_fd = fd;
544 Retry = TRUE;
545 } else {
546 (void) close(fd);
547 }
548 }
549 } else if ((pmptr->p_status == SESSION) && (pmptr->p_fd == 0)) {
550 fd = open(pmptr->p_device, O_RDWR | O_NONBLOCK);
551 if (fd == -1) {
552 log("open (%s) failed: %s", pmptr->p_device,
553 strerror(errno));
554 pmptr->p_status = VALID;
555 Nlocked--;
556 Retry = TRUE;
557 } else {
558 if (check_session(fd) == 0) {
559 Nlocked--;
560 pmptr->p_fd = fd;
561 Retry = TRUE;
562 } else {
563 (void) close(fd);
564 }
565 }
566 } else if ((pmptr->p_status == UNACCESS) &&
567 (pmptr->p_fd == 0)) {
568 fd = open(pmptr->p_device, O_RDWR | O_NONBLOCK);
569 if (fd == -1) {
570 log("open (%s) failed: %s", pmptr->p_device,
571 strerror(errno));
572 pmptr->p_status = VALID;
573 Nlocked--;
574 Retry = TRUE;
575 } else {
576 Nlocked--;
577 pmptr->p_fd = fd;
578 Retry = TRUE;
579 }
580 }
581 }
582 if (Nlocked > 0) {
583 sigact.sa_flags = 0;
584 sigact.sa_handler = sigalarm;
585 (void) sigemptyset(&sigact.sa_mask);
586 (void) sigaction(SIGALRM, &sigact, NULL);
587 (void) alarm(ALARMTIME);
588 } else {
589 sigact.sa_flags = 0;
590 sigact.sa_handler = SIG_IGN;
591 (void) sigemptyset(&sigact.sa_mask);
592 (void) sigaction(SIGALRM, &sigact, NULL);
593 }
594 }
595
596 /*
597 * pcsync_close - For the child process close all open fd's except
598 * the one that is passed to the routine. Coordinate the reads and
599 * writes to the pipes by the parent and child process to ensure
600 * the parent and child processes have closed all the file descriptors
601 * that are not needed any more.
602 */
603 static void
pcsync_close(int * p0,int * p1,int pid,int fd)604 pcsync_close(int *p0, int *p1, int pid, int fd)
605 {
606 char ch;
607
608 if (pid == 0) { /* Child */
609 struct pmtab *tp;
610 for (tp = PMtab; tp; tp = tp->p_next)
611 if ((tp->p_fd > 0) && (tp->p_fd != fd))
612 (void) close(tp->p_fd);
613 (void) close(p0[1]);
614 (void) close(p1[0]);
615 if (read(p0[0], &ch, 1) == 1)
616 (void) write(p1[1], "a", 1);
617 (void) close(p0[0]);
618 (void) close(p1[1]);
619 } else { /* Parent */
620 (void) close(p0[0]);
621 (void) close(p1[1]);
622 if (write(p0[1], "a", 1) == 1)
623 (void) read(p1[0], &ch, 1);
624 (void) close(p0[1]);
625 (void) close(p1[0]);
626 }
627 }
628