Avoid VTE lastline update glitch (#23699).
[screen-lua.git] / src / attacher.c
blobedba8d0878d004c25bc47f88e0547e9e3c4a73fd
1 /* Copyright (c) 1993-2002
2 * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
3 * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
4 * Copyright (c) 1987 Oliver Laumann
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program (see the file COPYING); if not, write to the
18 * Free Software Foundation, Inc.,
19 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
21 ****************************************************************
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <sys/ioctl.h>
27 #include <fcntl.h>
28 #include <signal.h>
29 #include "config.h"
30 #include "screen.h"
31 #include "extern.h"
33 #include <pwd.h>
35 static int WriteMessage __P((int, struct msg *));
36 static sigret_t AttacherSigInt __P(SIGPROTOARG);
37 #if defined(SIGWINCH) && defined(TIOCGWINSZ)
38 static sigret_t AttacherWinch __P(SIGPROTOARG);
39 #endif
40 #ifdef LOCK
41 static sigret_t DoLock __P(SIGPROTOARG);
42 static void LockTerminal __P((void));
43 static sigret_t LockHup __P(SIGPROTOARG);
44 static void screen_builtin_lck __P((void));
45 #endif
46 #ifdef DEBUG
47 static sigret_t AttacherChld __P(SIGPROTOARG);
48 #endif
49 #ifdef MULTIUSER
50 static sigret_t AttachSigCont __P(SIGPROTOARG);
51 #endif
53 extern int real_uid, real_gid, eff_uid, eff_gid;
54 extern char *SockName, *SockMatch, SockPath[];
55 extern struct passwd *ppp;
56 extern char *attach_tty, *attach_term, *LoginName, *preselect;
57 extern int xflag, dflag, rflag, quietflag, adaptflag;
58 extern struct mode attach_Mode;
59 extern struct NewWindow nwin_options;
60 extern int MasterPid, attach_fd;
62 #ifdef MULTIUSER
63 extern char *multi;
64 extern int multiattach, multi_uid, own_uid;
65 extern int tty_mode, tty_oldmode;
66 # ifndef USE_SETEUID
67 static int multipipe[2];
68 # endif
69 #endif
72 #ifdef MULTIUSER
73 static int ContinuePlease;
75 static sigret_t
76 AttachSigCont SIGDEFARG
78 debug("SigCont()\n");
79 ContinuePlease = 1;
80 SIGRETURN;
82 #endif
86 * Send message to a screen backend.
87 * returns 1 if we could attach one, or 0 if none.
88 * Understands MSG_ATTACH, MSG_DETACH, MSG_POW_DETACH
89 * MSG_CONT, MSG_WINCH and nothing else!
91 * if type == MSG_ATTACH and sockets are used, attaches
92 * tty filedescriptor.
95 static int
96 WriteMessage(s, m)
97 int s;
98 struct msg *m;
100 int r, l = sizeof(*m);
102 #ifndef NAMEDPIPE
103 if (m->type == MSG_ATTACH)
104 return SendAttachMsg(s, m, attach_fd);
105 #endif
107 while(l > 0)
109 r = write(s, (char *)m + (sizeof(*m) - l), l);
110 if (r == -1 && errno == EINTR)
111 continue;
112 if (r == -1 || r == 0)
113 return -1;
114 l -= r;
116 return 0;
121 Attach(how)
122 int how;
124 int n, lasts;
125 struct msg m;
126 struct stat st;
127 char *s;
129 debug2("Attach: how=%d, tty=%s\n", how, attach_tty);
130 #ifdef MULTIUSER
131 # ifndef USE_SETEUID
132 while ((how == MSG_ATTACH || how == MSG_CONT) && multiattach)
134 int ret;
136 if (pipe(multipipe))
137 Panic(errno, "pipe");
138 if (chmod(attach_tty, 0666))
139 Panic(errno, "chmod %s", attach_tty);
140 tty_oldmode = tty_mode;
141 eff_uid = -1; /* make UserContext fork */
142 real_uid = multi_uid;
143 if ((ret = UserContext()) <= 0)
145 char dummy;
146 eff_uid = 0;
147 real_uid = own_uid;
148 if (ret < 0)
149 Panic(errno, "UserContext");
150 close(multipipe[1]);
151 read(multipipe[0], &dummy, 1);
152 if (tty_oldmode >= 0)
154 chmod(attach_tty, tty_oldmode);
155 tty_oldmode = -1;
157 ret = UserStatus();
158 #ifdef LOCK
159 if (ret == SIG_LOCK)
160 LockTerminal();
161 else
162 #endif
163 #ifdef SIGTSTP
164 if (ret == SIG_STOP)
165 kill(getpid(), SIGTSTP);
166 else
167 #endif
168 if (ret == SIG_POWER_BYE)
170 int ppid;
171 setgid(real_gid);
172 setuid(real_uid);
173 if ((ppid = getppid()) > 1)
174 Kill(ppid, SIGHUP);
175 exit(0);
177 else
178 exit(ret);
179 dflag = 0;
180 #ifdef MULTI
181 xflag = 1;
182 #endif
183 how = MSG_ATTACH;
184 continue;
186 close(multipipe[0]);
187 eff_uid = real_uid;
188 break;
190 # else /* USE_SETEUID */
191 if ((how == MSG_ATTACH || how == MSG_CONT) && multiattach)
193 real_uid = multi_uid;
194 eff_uid = own_uid;
195 #ifdef HAVE_SETRESUID
196 if (setresuid(multi_uid, own_uid, multi_uid))
197 Panic(errno, "setresuid");
198 #else
199 xseteuid(multi_uid);
200 xseteuid(own_uid);
201 #endif
202 if (chmod(attach_tty, 0666))
203 Panic(errno, "chmod %s", attach_tty);
204 tty_oldmode = tty_mode;
206 # endif /* USE_SETEUID */
207 #endif /* MULTIUSER */
209 bzero((char *) &m, sizeof(m));
210 m.type = how;
211 m.protocol_revision = MSG_REVISION;
212 strncpy(m.m_tty, attach_tty, sizeof(m.m_tty) - 1);
213 m.m_tty[sizeof(m.m_tty) - 1] = 0;
215 if (how == MSG_WINCH)
217 if ((lasts = MakeClientSocket(0)) >= 0)
219 WriteMessage(lasts, &m);
220 close(lasts);
222 return 0;
225 if (how == MSG_CONT)
227 if ((lasts = MakeClientSocket(0)) < 0)
229 Panic(0, "Sorry, cannot contact session \"%s\" again.\r\n",
230 SockName);
233 else
235 n = FindSocket(&lasts, (int *)0, (int *)0, SockMatch);
236 switch (n)
238 case 0:
239 if (rflag && (rflag & 1) == 0)
240 return 0;
241 if (quietflag)
242 eexit(10);
243 Panic(0, SockMatch && *SockMatch ? "There is no screen to be %sed matching %s." : "There is no screen to be %sed.",
244 xflag ? "attach" :
245 dflag ? "detach" :
246 "resum", SockMatch);
247 /* NOTREACHED */
248 case 1:
249 break;
250 default:
251 if (rflag < 3)
253 if (quietflag)
254 eexit(10 + n);
255 Panic(0, "Type \"screen [-d] -r [pid.]tty.host\" to resume one of them.");
257 /* NOTREACHED */
261 * Go in UserContext. Advantage is, you can kill your attacher
262 * when things go wrong. Any disadvantages? jw.
263 * Do this before the attach to prevent races!
265 #ifdef MULTIUSER
266 if (!multiattach)
267 #endif
268 setuid(real_uid);
269 #if defined(MULTIUSER) && defined(USE_SETEUID)
270 else
272 /* This call to xsetuid should also set the saved uid */
273 xseteuid(real_uid); /* multi_uid, allow backend to send signals */
275 #endif
276 setgid(real_gid);
277 eff_uid = real_uid;
278 eff_gid = real_gid;
280 debug2("Attach: uid %d euid %d\n", (int)getuid(), (int)geteuid());
281 MasterPid = 0;
282 for (s = SockName; *s; s++)
284 if (*s > '9' || *s < '0')
285 break;
286 MasterPid = 10 * MasterPid + (*s - '0');
288 debug1("Attach decided, it is '%s'\n", SockPath);
289 debug1("Attach found MasterPid == %d\n", MasterPid);
290 if (stat(SockPath, &st) == -1)
291 Panic(errno, "stat %s", SockPath);
292 if ((st.st_mode & 0600) != 0600)
293 Panic(0, "Socket is in wrong mode (%03o)", (int)st.st_mode);
296 * Change: if -x or -r ignore failing -d
298 if ((xflag || rflag) && dflag && (st.st_mode & 0700) == 0600)
299 dflag = 0;
302 * Without -x, the mode must match.
303 * With -x the mode is irrelevant unless -d.
305 if ((dflag || !xflag) && (st.st_mode & 0700) != (dflag ? 0700 : 0600))
306 Panic(0, "That screen is %sdetached.", dflag ? "already " : "not ");
307 #ifdef REMOTE_DETACH
308 if (dflag &&
309 (how == MSG_ATTACH || how == MSG_DETACH || how == MSG_POW_DETACH))
311 m.m.detach.dpid = getpid();
312 strncpy(m.m.detach.duser, LoginName, sizeof(m.m.detach.duser) - 1);
313 m.m.detach.duser[sizeof(m.m.detach.duser) - 1] = 0;
314 # ifdef POW_DETACH
315 if (dflag == 2)
316 m.type = MSG_POW_DETACH;
317 else
318 # endif
319 m.type = MSG_DETACH;
320 if (WriteMessage(lasts, &m))
321 Panic(errno, "WriteMessage");
322 close(lasts);
323 if (how != MSG_ATTACH)
324 return 0; /* we detached it. jw. */
325 sleep(1); /* we dont want to overrun our poor backend. jw. */
326 if ((lasts = MakeClientSocket(0)) == -1)
327 Panic(0, "Cannot contact screen again. Sigh.");
328 m.type = how;
330 #endif
331 ASSERT(how == MSG_ATTACH || how == MSG_CONT);
332 strncpy(m.m.attach.envterm, attach_term, sizeof(m.m.attach.envterm) - 1);
333 m.m.attach.envterm[sizeof(m.m.attach.envterm) - 1] = 0;
334 debug1("attach: sending %d bytes... ", (int)sizeof(m));
336 strncpy(m.m.attach.auser, LoginName, sizeof(m.m.attach.auser) - 1);
337 m.m.attach.auser[sizeof(m.m.attach.auser) - 1] = 0;
338 m.m.attach.esc = DefaultEsc;
339 m.m.attach.meta_esc = DefaultMetaEsc;
340 strncpy(m.m.attach.preselect, preselect ? preselect : "", sizeof(m.m.attach.preselect) - 1);
341 m.m.attach.preselect[sizeof(m.m.attach.preselect) - 1] = 0;
342 m.m.attach.apid = getpid();
343 m.m.attach.adaptflag = adaptflag;
344 m.m.attach.lines = m.m.attach.columns = 0;
345 if ((s = getenv("LINES")))
346 m.m.attach.lines = atoi(s);
347 if ((s = getenv("COLUMNS")))
348 m.m.attach.columns = atoi(s);
349 m.m.attach.encoding = nwin_options.encoding > 0 ? nwin_options.encoding + 1 : 0;
351 #ifdef MULTIUSER
352 /* setup CONT signal handler to repair the terminal mode */
353 if (multi && (how == MSG_ATTACH || how == MSG_CONT))
354 signal(SIGCONT, AttachSigCont);
355 #endif
357 if (WriteMessage(lasts, &m))
358 Panic(errno, "WriteMessage");
359 close(lasts);
360 debug1("Attach(%d): sent\n", m.type);
361 #ifdef MULTIUSER
362 if (multi && (how == MSG_ATTACH || how == MSG_CONT))
364 while (!ContinuePlease)
365 pause(); /* wait for SIGCONT */
366 signal(SIGCONT, SIG_DFL);
367 ContinuePlease = 0;
368 # ifndef USE_SETEUID
369 close(multipipe[1]);
370 # else
371 xseteuid(own_uid);
372 if (tty_oldmode >= 0)
373 if (chmod(attach_tty, tty_oldmode))
374 Panic(errno, "chmod %s", attach_tty);
375 tty_oldmode = -1;
376 xseteuid(real_uid);
377 # endif
379 #endif
380 rflag = 0;
381 return 1;
385 #if defined(DEBUG) || !defined(DO_NOT_POLL_MASTER)
386 static int AttacherPanic = 0;
387 #endif
389 #ifdef DEBUG
390 static sigret_t
391 AttacherChld SIGDEFARG
393 AttacherPanic = 1;
394 SIGRETURN;
396 #endif
398 static sigret_t
399 AttacherSigAlarm SIGDEFARG
401 #ifdef DEBUG
402 static int tick_cnt = 0;
403 if ((tick_cnt = (tick_cnt + 1) % 4) == 0)
404 debug("tick\n");
405 #endif
406 SIGRETURN;
410 * the frontend's Interrupt handler
411 * we forward SIGINT to the poor backend
413 static sigret_t
414 AttacherSigInt SIGDEFARG
416 signal(SIGINT, AttacherSigInt);
417 Kill(MasterPid, SIGINT);
418 SIGRETURN;
422 * Unfortunatelly this is also the SIGHUP handler, so we have to
423 * check if the backend is already detached.
426 sigret_t
427 AttacherFinit SIGDEFARG
429 struct stat statb;
430 struct msg m;
431 int s;
433 debug("AttacherFinit();\n");
434 signal(SIGHUP, SIG_IGN);
435 /* Check if signal comes from backend */
436 if (stat(SockPath, &statb) == 0 && (statb.st_mode & 0777) != 0600)
438 debug("Detaching backend!\n");
439 bzero((char *) &m, sizeof(m));
440 strncpy(m.m_tty, attach_tty, sizeof(m.m_tty) - 1);
441 m.m_tty[sizeof(m.m_tty) - 1] = 0;
442 debug1("attach_tty is %s\n", attach_tty);
443 m.m.detach.dpid = getpid();
444 m.type = MSG_HANGUP;
445 m.protocol_revision = MSG_REVISION;
446 if ((s = MakeClientSocket(0)) >= 0)
448 WriteMessage(s, &m);
449 close(s);
452 #ifdef MULTIUSER
453 if (tty_oldmode >= 0)
455 setuid(own_uid);
456 chmod(attach_tty, tty_oldmode);
458 #endif
459 exit(0);
460 SIGRETURN;
463 #ifdef POW_DETACH
464 static sigret_t
465 AttacherFinitBye SIGDEFARG
467 int ppid;
468 debug("AttacherFintBye()\n");
469 #if defined(MULTIUSER) && !defined(USE_SETEUID)
470 if (multiattach)
471 exit(SIG_POWER_BYE);
472 #endif
473 setgid(real_gid);
474 #ifdef MULTIUSER
475 setuid(own_uid);
476 #else
477 setuid(real_uid);
478 #endif
479 /* we don't want to disturb init (even if we were root), eh? jw */
480 if ((ppid = getppid()) > 1)
481 Kill(ppid, SIGHUP); /* carefully say good bye. jw. */
482 exit(0);
483 SIGRETURN;
485 #endif
487 #if defined(DEBUG) && defined(SIG_NODEBUG)
488 static sigret_t
489 AttacherNoDebug SIGDEFARG
491 debug("AttacherNoDebug()\n");
492 signal(SIG_NODEBUG, AttacherNoDebug);
493 if (dfp)
495 debug("debug: closing debug file.\n");
496 fflush(dfp);
497 fclose(dfp);
498 dfp = NULL;
500 SIGRETURN;
502 #endif /* SIG_NODEBUG */
504 static int SuspendPlease;
506 static sigret_t
507 SigStop SIGDEFARG
509 debug("SigStop()\n");
510 SuspendPlease = 1;
511 SIGRETURN;
514 #ifdef LOCK
515 static int LockPlease;
517 static sigret_t
518 DoLock SIGDEFARG
520 # ifdef SYSVSIGS
521 signal(SIG_LOCK, DoLock);
522 # endif
523 debug("DoLock()\n");
524 LockPlease = 1;
525 SIGRETURN;
527 #endif
529 #if defined(SIGWINCH) && defined(TIOCGWINSZ)
530 static int SigWinchPlease;
532 static sigret_t
533 AttacherWinch SIGDEFARG
535 debug("AttacherWinch()\n");
536 SigWinchPlease = 1;
537 SIGRETURN;
539 #endif
543 * Attacher loop - no return
546 void
547 Attacher()
549 signal(SIGHUP, AttacherFinit);
550 signal(SIG_BYE, AttacherFinit);
551 #ifdef POW_DETACH
552 signal(SIG_POWER_BYE, AttacherFinitBye);
553 #endif
554 #if defined(DEBUG) && defined(SIG_NODEBUG)
555 signal(SIG_NODEBUG, AttacherNoDebug);
556 #endif
557 #ifdef LOCK
558 signal(SIG_LOCK, DoLock);
559 #endif
560 signal(SIGINT, AttacherSigInt);
561 #ifdef BSDJOBS
562 signal(SIG_STOP, SigStop);
563 #endif
564 #if defined(SIGWINCH) && defined(TIOCGWINSZ)
565 signal(SIGWINCH, AttacherWinch);
566 #endif
567 #ifdef DEBUG
568 signal(SIGCHLD, AttacherChld);
569 #endif
570 debug("attacher: going for a nap.\n");
571 dflag = 0;
572 #ifdef MULTI
573 xflag = 1;
574 #endif
575 for (;;)
577 #ifndef DO_NOT_POLL_MASTER
578 signal(SIGALRM, AttacherSigAlarm);
579 alarm(15);
580 pause();
581 alarm(0);
582 if (kill(MasterPid, 0) < 0 && errno != EPERM)
584 debug1("attacher: Panic! MasterPid %d does not exist.\n", MasterPid);
585 AttacherPanic++;
587 #else
588 pause();
589 #endif
590 #if defined(DEBUG) || !defined(DO_NOT_POLL_MASTER)
591 if (AttacherPanic)
593 fcntl(0, F_SETFL, 0);
594 SetTTY(0, &attach_Mode);
595 printf("\nSuddenly the Dungeon collapses!! - You die...\n");
596 eexit(1);
598 #endif
599 #ifdef BSDJOBS
600 if (SuspendPlease)
602 SuspendPlease = 0;
603 #if defined(MULTIUSER) && !defined(USE_SETEUID)
604 if (multiattach)
605 exit(SIG_STOP);
606 #endif
607 signal(SIGTSTP, SIG_DFL);
608 debug("attacher: killing myself SIGTSTP\n");
609 kill(getpid(), SIGTSTP);
610 debug("attacher: continuing from stop\n");
611 signal(SIG_STOP, SigStop);
612 (void) Attach(MSG_CONT);
614 #endif
615 #ifdef LOCK
616 if (LockPlease)
618 LockPlease = 0;
619 #if defined(MULTIUSER) && !defined(USE_SETEUID)
620 if (multiattach)
621 exit(SIG_LOCK);
622 #endif
623 LockTerminal();
624 # ifdef SYSVSIGS
625 signal(SIG_LOCK, DoLock);
626 # endif
627 (void) Attach(MSG_CONT);
629 #endif /* LOCK */
630 #if defined(SIGWINCH) && defined(TIOCGWINSZ)
631 if (SigWinchPlease)
633 SigWinchPlease = 0;
634 # ifdef SYSVSIGS
635 signal(SIGWINCH, AttacherWinch);
636 # endif
637 (void) Attach(MSG_WINCH);
639 #endif /* SIGWINCH */
643 #ifdef LOCK
645 /* ADDED by Rainer Pruy 10/15/87 */
646 /* POLISHED by mls. 03/10/91 */
648 static char LockEnd[] = "Welcome back to screen !!\n";
650 static sigret_t
651 LockHup SIGDEFARG
653 int ppid = getppid();
654 setgid(real_gid);
655 #ifdef MULTIUSER
656 setuid(own_uid);
657 #else
658 setuid(real_uid);
659 #endif
660 if (ppid > 1)
661 Kill(ppid, SIGHUP);
662 exit(0);
665 static void
666 LockTerminal()
668 char *prg;
669 int sig, pid;
670 sigret_t (*sigs[NSIG])__P(SIGPROTOARG);
672 for (sig = 1; sig < NSIG; sig++)
673 sigs[sig] = signal(sig, sig == SIGCHLD ? SIG_DFL : SIG_IGN);
674 signal(SIGHUP, LockHup);
675 printf("\n");
677 prg = getenv("LOCKPRG");
678 if (prg && strcmp(prg, "builtin") && !access(prg, X_OK))
680 signal(SIGCHLD, SIG_DFL);
681 debug1("lockterminal: '%s' seems executable, execl it!\n", prg);
682 if ((pid = fork()) == 0)
684 /* Child */
685 setgid(real_gid);
686 #ifdef MULTIUSER
687 setuid(own_uid);
688 #else
689 setuid(real_uid); /* this should be done already */
690 #endif
691 closeallfiles(0); /* important: /etc/shadow may be open */
692 execl(prg, "SCREEN-LOCK", NULL);
693 exit(errno);
695 if (pid == -1)
696 Msg(errno, "Cannot lock terminal - fork failed");
697 else
699 #ifdef BSDWAIT
700 union wait wstat;
701 #else
702 int wstat;
703 #endif
704 int wret;
706 #ifdef hpux
707 signal(SIGCHLD, SIG_DFL);
708 #endif
709 errno = 0;
710 while (((wret = wait(&wstat)) != pid) ||
711 ((wret == -1) && (errno == EINTR))
713 errno = 0;
715 if (errno)
717 Msg(errno, "Lock");
718 sleep(2);
720 else if (WTERMSIG(wstat) != 0)
722 fprintf(stderr, "Lock: %s: Killed by signal: %d%s\n", prg,
723 WTERMSIG(wstat), WIFCORESIG(wstat) ? " (Core dumped)" : "");
724 sleep(2);
726 else if (WEXITSTATUS(wstat))
728 debug2("Lock: %s: return code %d\n", prg, WEXITSTATUS(wstat));
730 else
731 printf(LockEnd);
734 else
736 if (prg)
738 debug1("lockterminal: '%s' seems NOT executable, we use our builtin\n", prg);
740 else
742 debug("lockterminal: using buitin.\n");
744 screen_builtin_lck();
746 /* reset signals */
747 for (sig = 1; sig < NSIG; sig++)
749 if (sigs[sig] != (sigret_t(*)__P(SIGPROTOARG)) -1)
750 signal(sig, sigs[sig]);
752 } /* LockTerminal */
754 #ifdef USE_PAM
757 * PAM support by Pablo Averbuj <pablo@averbuj.com>
760 #include <security/pam_appl.h>
762 static int PAM_conv __P((int, const struct pam_message **, struct pam_response **, void *));
764 static int
765 PAM_conv(num_msg, msg, resp, appdata_ptr)
766 int num_msg;
767 const struct pam_message **msg;
768 struct pam_response **resp;
769 void *appdata_ptr;
771 int replies = 0;
772 struct pam_response *reply = NULL;
774 reply = malloc(sizeof(struct pam_response)*num_msg);
775 if (!reply)
776 return PAM_CONV_ERR;
777 #define COPY_STRING(s) (s) ? strdup(s) : NULL
779 for (replies = 0; replies < num_msg; replies++)
781 switch (msg[replies]->msg_style)
783 case PAM_PROMPT_ECHO_OFF:
784 /* wants password */
785 reply[replies].resp_retcode = PAM_SUCCESS;
786 reply[replies].resp = appdata_ptr ? strdup((char *)appdata_ptr) : 0;
787 break;
788 case PAM_TEXT_INFO:
789 /* ignore the informational mesage */
790 /* but first clear out any drek left by malloc */
791 reply[replies].resp = NULL;
792 break;
793 case PAM_PROMPT_ECHO_ON:
794 /* user name given to PAM already */
795 /* fall through */
796 default:
797 /* unknown or PAM_ERROR_MSG */
798 free(reply);
799 return PAM_CONV_ERR;
802 *resp = reply;
803 return PAM_SUCCESS;
806 static struct pam_conv PAM_conversation = {
807 &PAM_conv,
808 NULL
812 #endif
814 /* -- original copyright by Luigi Cannelloni 1985 (luigi@faui70.UUCP) -- */
815 static void
816 screen_builtin_lck()
818 char fullname[100], *cp1, message[100 + 100];
819 #ifdef USE_PAM
820 pam_handle_t *pamh = 0;
821 int pam_error;
822 #else
823 char *pass, mypass[16 + 1], salt[3];
824 #endif
826 #ifndef USE_PAM
827 pass = ppp->pw_passwd;
828 if (pass == 0 || *pass == 0)
830 if ((pass = getpass("Key: ")))
832 strncpy(mypass, pass, sizeof(mypass) - 1);
833 mypass[sizeof(mypass) - 1] = 0;
834 if (*mypass == 0)
835 return;
836 if ((pass = getpass("Again: ")))
838 if (strcmp(mypass, pass))
840 fprintf(stderr, "Passwords don't match.\007\n");
841 sleep(2);
842 return;
846 if (pass == 0)
848 fprintf(stderr, "Getpass error.\007\n");
849 sleep(2);
850 return;
853 salt[0] = 'A' + (int)(time(0) % 26);
854 salt[1] = 'A' + (int)((time(0) >> 6) % 26);
855 salt[2] = 0;
856 pass = crypt(mypass, salt);
857 pass = ppp->pw_passwd = SaveStr(pass);
859 #endif
861 debug("screen_builtin_lck looking in gcos field\n");
862 strncpy(fullname, ppp->pw_gecos, sizeof(fullname) - 9);
863 fullname[sizeof(fullname) - 9] = 0;
865 if ((cp1 = index(fullname, ',')) != NULL)
866 *cp1 = '\0';
867 if ((cp1 = index(fullname, '&')) != NULL)
869 strncpy(cp1, ppp->pw_name, 8);
870 cp1[8] = 0;
871 if (*cp1 >= 'a' && *cp1 <= 'z')
872 *cp1 -= 'a' - 'A';
875 sprintf(message, "Screen used by %s%s<%s>.\nPassword:\007",
876 fullname, fullname[0] ? " " : "", ppp->pw_name);
878 /* loop here to wait for correct password */
879 for (;;)
881 debug("screen_builtin_lck awaiting password\n");
882 errno = 0;
883 if ((cp1 = getpass(message)) == NULL)
885 AttacherFinit(SIGARG);
886 /* NOTREACHED */
888 #ifdef USE_PAM
889 PAM_conversation.appdata_ptr = cp1;
890 pam_error = pam_start("screen", ppp->pw_name, &PAM_conversation, &pamh);
891 if (pam_error != PAM_SUCCESS)
892 AttacherFinit(SIGARG); /* goodbye */
893 pam_error = pam_authenticate(pamh, 0);
894 pam_end(pamh, pam_error);
895 PAM_conversation.appdata_ptr = 0;
896 if (pam_error == PAM_SUCCESS)
897 break;
898 #else
899 if (!strncmp(crypt(cp1, pass), pass, strlen(pass)))
900 break;
901 #endif
902 debug("screen_builtin_lck: NO!!!!!\n");
903 bzero(cp1, strlen(cp1));
905 bzero(cp1, strlen(cp1));
906 debug("password ok.\n");
909 #endif /* LOCK */
912 void
913 SendCmdMessage(sty, match, av)
914 char *sty;
915 char *match;
916 char **av;
918 int i, s;
919 struct msg m;
920 char *p;
921 int len, n;
923 if (sty == 0)
925 i = FindSocket(&s, (int *)0, (int *)0, match);
926 if (i == 0)
927 Panic(0, "No screen session found.");
928 if (i != 1)
929 Panic(0, "Use -S to specify a session.");
931 else
933 #ifdef NAME_MAX
934 if (strlen(sty) > NAME_MAX)
935 sty[NAME_MAX] = 0;
936 #endif
937 if (strlen(sty) > 2 * MAXSTR - 1)
938 sty[2 * MAXSTR - 1] = 0;
939 sprintf(SockPath + strlen(SockPath), "/%s", sty);
940 if ((s = MakeClientSocket(1)) == -1)
941 exit(1);
943 bzero((char *)&m, sizeof(m));
944 m.type = MSG_COMMAND;
945 if (attach_tty)
947 strncpy(m.m_tty, attach_tty, sizeof(m.m_tty) - 1);
948 m.m_tty[sizeof(m.m_tty) - 1] = 0;
950 p = m.m.command.cmd;
951 n = 0;
952 for (; *av && n < MAXARGS - 1; ++av, ++n)
954 len = strlen(*av) + 1;
955 if (p + len >= m.m.command.cmd + sizeof(m.m.command.cmd) - 1)
956 break;
957 strcpy(p, *av);
958 p += len;
960 *p = 0;
961 m.m.command.nargs = n;
962 strncpy(m.m.attach.auser, LoginName, sizeof(m.m.attach.auser) - 1);
963 m.m.command.auser[sizeof(m.m.command.auser) - 1] = 0;
964 m.protocol_revision = MSG_REVISION;
965 strncpy(m.m.command.preselect, preselect ? preselect : "", sizeof(m.m.command.preselect) - 1);
966 m.m.command.preselect[sizeof(m.m.command.preselect) - 1] = 0;
967 m.m.command.apid = getpid();
968 debug1("SendCommandMsg writing '%s'\n", m.m.command.cmd);
969 if (WriteMessage(s, &m))
970 Msg(errno, "write");
971 close(s);