Bring back --with-sys-screenrc configure flag.
[screen-lua.git] / src / attacher.c
blob370d594853f117bb6a05db4a5bbe3c0017bb566a
1 /* Copyright (c) 2008, 2009
2 * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
3 * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
4 * Micah Cowan (micah@cowan.name)
5 * Sadrul Habib Chowdhury (sadrul@users.sourceforge.net)
6 * Copyright (c) 1993-2002, 2003, 2005, 2006, 2007
7 * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
8 * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
9 * Copyright (c) 1987 Oliver Laumann
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 3, or (at your option)
14 * any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program (see the file COPYING); if not, see
23 * http://www.gnu.org/licenses/, or contact Free Software Foundation, Inc.,
24 * 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
26 ****************************************************************
29 #include "config.h"
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <sys/ioctl.h>
33 #include <fcntl.h>
34 #include <signal.h>
35 #include "screen.h"
36 #include "extern.h"
38 #include <pwd.h>
40 static int WriteMessage __P((int, struct msg *));
41 static sigret_t AttacherSigInt __P(SIGPROTOARG);
42 #if defined(SIGWINCH) && defined(TIOCGWINSZ)
43 static sigret_t AttacherWinch __P(SIGPROTOARG);
44 #endif
45 #ifdef LOCK
46 static sigret_t DoLock __P(SIGPROTOARG);
47 static void LockTerminal __P((void));
48 static sigret_t LockHup __P(SIGPROTOARG);
49 static void screen_builtin_lck __P((void));
50 #endif
51 #ifdef DEBUG
52 static sigret_t AttacherChld __P(SIGPROTOARG);
53 #endif
54 static sigret_t AttachSigCont __P(SIGPROTOARG);
56 extern int real_uid, real_gid, eff_uid, eff_gid;
57 extern char *SockName, *SockMatch, SockPath[];
58 extern char HostName[];
59 extern struct passwd *ppp;
60 extern char *attach_tty, *attach_term, *LoginName, *preselect;
61 extern int xflag, dflag, rflag, quietflag, adaptflag;
62 extern struct mode attach_Mode;
63 extern struct NewWindow nwin_options;
64 extern int MasterPid, attach_fd;
66 #ifdef MULTIUSER
67 extern char *multi;
68 extern int multiattach, multi_uid, own_uid;
69 extern int tty_mode, tty_oldmode;
70 # ifndef USE_SETEUID
71 static int multipipe[2];
72 # endif
73 #endif
76 static int ContinuePlease;
78 static sigret_t
79 AttachSigCont SIGDEFARG
81 debug("SigCont()\n");
82 ContinuePlease = 1;
83 SIGRETURN;
86 static int QueryResult;
88 static sigret_t
89 QueryResultSuccess SIGDEFARG
91 QueryResult = 1;
92 SIGRETURN;
95 static sigret_t
96 QueryResultFail SIGDEFARG
98 QueryResult = 2;
99 SIGRETURN;
103 * Send message to a screen backend.
104 * returns 1 if we could attach one, or 0 if none.
105 * Understands MSG_ATTACH, MSG_DETACH, MSG_POW_DETACH
106 * MSG_CONT, MSG_WINCH and nothing else!
108 * if type == MSG_ATTACH and sockets are used, attaches
109 * tty filedescriptor.
112 static int
113 WriteMessage(s, m)
114 int s;
115 struct msg *m;
117 int r, l = sizeof(*m);
119 #ifndef NAMEDPIPE
120 if (m->type == MSG_ATTACH)
121 return SendAttachMsg(s, m, attach_fd);
122 #endif
124 while(l > 0)
126 r = write(s, (char *)m + (sizeof(*m) - l), l);
127 if (r == -1 && errno == EINTR)
128 continue;
129 if (r == -1 || r == 0)
130 return -1;
131 l -= r;
133 return 0;
138 Attach(how)
139 int how;
141 int n, lasts;
142 struct msg m;
143 struct stat st;
144 char *s;
146 debug2("Attach: how=%d, tty=%s\n", how, attach_tty);
147 #ifdef MULTIUSER
148 # ifndef USE_SETEUID
149 while ((how == MSG_ATTACH || how == MSG_CONT) && multiattach)
151 int ret;
153 if (pipe(multipipe))
154 Panic(errno, "pipe");
155 if (chmod(attach_tty, 0666))
156 Panic(errno, "chmod %s", attach_tty);
157 tty_oldmode = tty_mode;
158 eff_uid = -1; /* make UserContext fork */
159 real_uid = multi_uid;
160 if ((ret = UserContext()) <= 0)
162 char dummy;
163 eff_uid = 0;
164 real_uid = own_uid;
165 if (ret < 0)
166 Panic(errno, "UserContext");
167 close(multipipe[1]);
168 read(multipipe[0], &dummy, 1);
169 if (tty_oldmode >= 0)
171 chmod(attach_tty, tty_oldmode);
172 tty_oldmode = -1;
174 ret = UserStatus();
175 #ifdef LOCK
176 if (ret == SIG_LOCK)
177 LockTerminal();
178 else
179 #endif
180 #ifdef SIGTSTP
181 if (ret == SIG_STOP)
182 kill(getpid(), SIGTSTP);
183 else
184 #endif
185 if (ret == SIG_POWER_BYE)
187 int ppid;
188 setgid(real_gid);
189 setuid(real_uid);
190 if ((ppid = getppid()) > 1)
191 Kill(ppid, SIGHUP);
192 exit(0);
194 else
195 exit(ret);
196 dflag = 0;
197 #ifdef MULTI
198 xflag = 1;
199 #endif
200 how = MSG_ATTACH;
201 continue;
203 close(multipipe[0]);
204 eff_uid = real_uid;
205 break;
207 # else /* USE_SETEUID */
208 if ((how == MSG_ATTACH || how == MSG_CONT) && multiattach)
210 real_uid = multi_uid;
211 eff_uid = own_uid;
212 #ifdef HAVE_SETRESUID
213 if (setresuid(multi_uid, own_uid, multi_uid))
214 Panic(errno, "setresuid");
215 #else
216 xseteuid(multi_uid);
217 xseteuid(own_uid);
218 #endif
219 if (chmod(attach_tty, 0666))
220 Panic(errno, "chmod %s", attach_tty);
221 tty_oldmode = tty_mode;
223 # endif /* USE_SETEUID */
224 #endif /* MULTIUSER */
226 bzero((char *) &m, sizeof(m));
227 m.type = how;
228 m.protocol_revision = MSG_REVISION;
229 strncpy(m.m_tty, attach_tty, sizeof(m.m_tty) - 1);
230 m.m_tty[sizeof(m.m_tty) - 1] = 0;
232 if (how == MSG_WINCH)
234 if ((lasts = MakeClientSocket(0)) >= 0)
236 WriteMessage(lasts, &m);
237 close(lasts);
239 return 0;
242 if (how == MSG_CONT)
244 if ((lasts = MakeClientSocket(0)) < 0)
246 Panic(0, "Sorry, cannot contact session \"%s\" again.\r\n",
247 SockName);
250 else
252 n = FindSocket(&lasts, (int *)0, (int *)0, SockMatch);
253 switch (n)
255 case 0:
256 if (rflag && (rflag & 1) == 0)
257 return 0;
258 if (quietflag)
259 eexit(10);
260 Panic(0, SockMatch && *SockMatch ? "There is no screen to be %sed matching %s." : "There is no screen to be %sed.",
261 xflag ? "attach" :
262 dflag ? "detach" :
263 "resum", SockMatch);
264 /* NOTREACHED */
265 case 1:
266 break;
267 default:
268 if (rflag < 3)
270 if (quietflag)
271 eexit(10 + n);
272 Panic(0, "Type \"screen [-d] -r [pid.]tty.host\" to resume one of them.");
274 /* NOTREACHED */
278 * Go in UserContext. Advantage is, you can kill your attacher
279 * when things go wrong. Any disadvantages? jw.
280 * Do this before the attach to prevent races!
282 #ifdef MULTIUSER
283 if (!multiattach)
284 #endif
285 setuid(real_uid);
286 #if defined(MULTIUSER) && defined(USE_SETEUID)
287 else
289 /* This call to xsetuid should also set the saved uid */
290 xseteuid(real_uid); /* multi_uid, allow backend to send signals */
292 #endif
293 setgid(real_gid);
294 eff_uid = real_uid;
295 eff_gid = real_gid;
297 debug2("Attach: uid %d euid %d\n", (int)getuid(), (int)geteuid());
298 MasterPid = 0;
299 for (s = SockName; *s; s++)
301 if (*s > '9' || *s < '0')
302 break;
303 MasterPid = 10 * MasterPid + (*s - '0');
305 debug1("Attach decided, it is '%s'\n", SockPath);
306 debug1("Attach found MasterPid == %d\n", MasterPid);
307 if (stat(SockPath, &st) == -1)
308 Panic(errno, "stat %s", SockPath);
309 if ((st.st_mode & 0600) != 0600)
310 Panic(0, "Socket is in wrong mode (%03o)", (int)st.st_mode);
313 * Change: if -x or -r ignore failing -d
315 if ((xflag || rflag) && dflag && (st.st_mode & 0700) == 0600)
316 dflag = 0;
319 * Without -x, the mode must match.
320 * With -x the mode is irrelevant unless -d.
322 if ((dflag || !xflag) && (st.st_mode & 0700) != (dflag ? 0700 : 0600))
323 Panic(0, "That screen is %sdetached.", dflag ? "already " : "not ");
324 #ifdef REMOTE_DETACH
325 if (dflag &&
326 (how == MSG_DETACH || how == MSG_POW_DETACH))
328 m.m.detach.dpid = getpid();
329 strncpy(m.m.detach.duser, LoginName, sizeof(m.m.detach.duser) - 1);
330 m.m.detach.duser[sizeof(m.m.detach.duser) - 1] = 0;
331 # ifdef POW_DETACH
332 if (dflag == 2)
333 m.type = MSG_POW_DETACH;
334 else
335 # endif
336 m.type = MSG_DETACH;
337 /* If there is no password for the session, or the user enters the correct
338 * password, then we get a SIGCONT. Otherwise we get a SIG_BYE */
339 signal(SIGCONT, AttachSigCont);
340 if (WriteMessage(lasts, &m))
341 Panic(errno, "WriteMessage");
342 close(lasts);
343 while (!ContinuePlease)
344 pause(); /* wait for SIGCONT */
345 signal(SIGCONT, SIG_DFL);
346 ContinuePlease = 0;
347 if (how != MSG_ATTACH)
348 return 0; /* we detached it. jw. */
349 sleep(1); /* we dont want to overrun our poor backend. jw. */
350 if ((lasts = MakeClientSocket(0)) == -1)
351 Panic(0, "Cannot contact screen again. Sigh.");
352 m.type = how;
354 #endif
355 ASSERT(how == MSG_ATTACH || how == MSG_CONT);
356 strncpy(m.m.attach.envterm, attach_term, sizeof(m.m.attach.envterm) - 1);
357 m.m.attach.envterm[sizeof(m.m.attach.envterm) - 1] = 0;
358 debug1("attach: sending %d bytes... ", (int)sizeof(m));
360 strncpy(m.m.attach.auser, LoginName, sizeof(m.m.attach.auser) - 1);
361 m.m.attach.auser[sizeof(m.m.attach.auser) - 1] = 0;
362 m.m.attach.esc = DefaultEsc;
363 m.m.attach.meta_esc = DefaultMetaEsc;
364 strncpy(m.m.attach.preselect, preselect ? preselect : "", sizeof(m.m.attach.preselect) - 1);
365 m.m.attach.preselect[sizeof(m.m.attach.preselect) - 1] = 0;
366 m.m.attach.apid = getpid();
367 m.m.attach.adaptflag = adaptflag;
368 m.m.attach.lines = m.m.attach.columns = 0;
369 if ((s = getenv("LINES")))
370 m.m.attach.lines = atoi(s);
371 if ((s = getenv("COLUMNS")))
372 m.m.attach.columns = atoi(s);
373 m.m.attach.encoding = nwin_options.encoding > 0 ? nwin_options.encoding + 1 : 0;
375 #ifdef REMOTE_DETACH
376 #ifdef POW_DETACH
377 if (dflag == 2)
378 m.m.attach.detachfirst = MSG_POW_DETACH;
379 else
380 #endif
381 if (dflag)
382 m.m.attach.detachfirst = MSG_DETACH;
383 else
384 #endif
385 m.m.attach.detachfirst = MSG_ATTACH;
387 #ifdef MULTIUSER
388 /* setup CONT signal handler to repair the terminal mode */
389 if (multi && (how == MSG_ATTACH || how == MSG_CONT))
390 signal(SIGCONT, AttachSigCont);
391 #endif
393 if (WriteMessage(lasts, &m))
394 Panic(errno, "WriteMessage");
395 close(lasts);
396 debug1("Attach(%d): sent\n", m.type);
397 #ifdef MULTIUSER
398 if (multi && (how == MSG_ATTACH || how == MSG_CONT))
400 while (!ContinuePlease)
401 pause(); /* wait for SIGCONT */
402 signal(SIGCONT, SIG_DFL);
403 ContinuePlease = 0;
404 # ifndef USE_SETEUID
405 close(multipipe[1]);
406 # else
407 xseteuid(own_uid);
408 if (tty_oldmode >= 0)
409 if (chmod(attach_tty, tty_oldmode))
410 Panic(errno, "chmod %s", attach_tty);
411 tty_oldmode = -1;
412 xseteuid(real_uid);
413 # endif
415 #endif
416 rflag = 0;
417 return 1;
421 static int AttacherPanic = 0;
423 #ifdef DEBUG
424 static sigret_t
425 AttacherChld SIGDEFARG
427 AttacherPanic = 1;
428 SIGRETURN;
430 #endif
432 static sigret_t
433 AttacherSigAlarm SIGDEFARG
435 #ifdef DEBUG
436 static int tick_cnt = 0;
437 if ((tick_cnt = (tick_cnt + 1) % 4) == 0)
438 debug("tick\n");
439 #endif
440 SIGRETURN;
444 * the frontend's Interrupt handler
445 * we forward SIGINT to the poor backend
447 static sigret_t
448 AttacherSigInt SIGDEFARG
450 signal(SIGINT, AttacherSigInt);
451 Kill(MasterPid, SIGINT);
452 SIGRETURN;
456 * Unfortunately this is also the SIGHUP handler, so we have to
457 * check if the backend is already detached.
460 sigret_t
461 AttacherFinit SIGDEFARG
463 struct stat statb;
464 struct msg m;
465 int s;
467 debug("AttacherFinit();\n");
468 signal(SIGHUP, SIG_IGN);
469 /* Check if signal comes from backend */
470 if (stat(SockPath, &statb) == 0 && (statb.st_mode & 0777) != 0600)
472 debug("Detaching backend!\n");
473 bzero((char *) &m, sizeof(m));
474 strncpy(m.m_tty, attach_tty, sizeof(m.m_tty) - 1);
475 m.m_tty[sizeof(m.m_tty) - 1] = 0;
476 debug1("attach_tty is %s\n", attach_tty);
477 m.m.detach.dpid = getpid();
478 m.type = MSG_HANGUP;
479 m.protocol_revision = MSG_REVISION;
480 if ((s = MakeClientSocket(0)) >= 0)
482 WriteMessage(s, &m);
483 close(s);
486 #ifdef MULTIUSER
487 if (tty_oldmode >= 0)
489 setuid(own_uid);
490 chmod(attach_tty, tty_oldmode);
492 #endif
493 exit(0);
494 SIGRETURN;
497 #ifdef POW_DETACH
498 static sigret_t
499 AttacherFinitBye SIGDEFARG
501 int ppid;
502 debug("AttacherFintBye()\n");
503 #if defined(MULTIUSER) && !defined(USE_SETEUID)
504 if (multiattach)
505 exit(SIG_POWER_BYE);
506 #endif
507 setgid(real_gid);
508 #ifdef MULTIUSER
509 setuid(own_uid);
510 #else
511 setuid(real_uid);
512 #endif
513 /* we don't want to disturb init (even if we were root), eh? jw */
514 if ((ppid = getppid()) > 1)
515 Kill(ppid, SIGHUP); /* carefully say good bye. jw. */
516 exit(0);
517 SIGRETURN;
519 #endif
521 #if defined(DEBUG) && defined(SIG_NODEBUG)
522 static sigret_t
523 AttacherNoDebug SIGDEFARG
525 debug("AttacherNoDebug()\n");
526 signal(SIG_NODEBUG, AttacherNoDebug);
527 if (dfp)
529 debug("debug: closing debug file.\n");
530 fflush(dfp);
531 fclose(dfp);
532 dfp = NULL;
534 SIGRETURN;
536 #endif /* SIG_NODEBUG */
538 static int SuspendPlease;
540 static sigret_t
541 SigStop SIGDEFARG
543 debug("SigStop()\n");
544 SuspendPlease = 1;
545 SIGRETURN;
548 #ifdef LOCK
549 static int LockPlease;
551 static sigret_t
552 DoLock SIGDEFARG
554 # ifdef SYSVSIGS
555 signal(SIG_LOCK, DoLock);
556 # endif
557 debug("DoLock()\n");
558 LockPlease = 1;
559 SIGRETURN;
561 #endif
563 #if defined(SIGWINCH) && defined(TIOCGWINSZ)
564 static int SigWinchPlease;
566 static sigret_t
567 AttacherWinch SIGDEFARG
569 debug("AttacherWinch()\n");
570 SigWinchPlease = 1;
571 SIGRETURN;
573 #endif
577 * Attacher loop - no return
580 void
581 Attacher()
583 signal(SIGHUP, AttacherFinit);
584 signal(SIG_BYE, AttacherFinit);
585 #ifdef POW_DETACH
586 signal(SIG_POWER_BYE, AttacherFinitBye);
587 #endif
588 #if defined(DEBUG) && defined(SIG_NODEBUG)
589 signal(SIG_NODEBUG, AttacherNoDebug);
590 #endif
591 #ifdef LOCK
592 signal(SIG_LOCK, DoLock);
593 #endif
594 signal(SIGINT, AttacherSigInt);
595 #ifdef BSDJOBS
596 signal(SIG_STOP, SigStop);
597 #endif
598 #if defined(SIGWINCH) && defined(TIOCGWINSZ)
599 signal(SIGWINCH, AttacherWinch);
600 #endif
601 #ifdef DEBUG
602 signal(SIGCHLD, AttacherChld);
603 #endif
604 debug("attacher: going for a nap.\n");
605 dflag = 0;
606 #ifdef MULTI
607 xflag = 1;
608 #endif
609 for (;;)
611 signal(SIGALRM, AttacherSigAlarm);
612 alarm(15);
613 pause();
614 alarm(0);
615 if (kill(MasterPid, 0) < 0 && errno != EPERM)
617 debug1("attacher: Panic! MasterPid %d does not exist.\n", MasterPid);
618 AttacherPanic++;
620 if (AttacherPanic)
622 fcntl(0, F_SETFL, 0);
623 SetTTY(0, &attach_Mode);
624 printf("\nSuddenly the Dungeon collapses!! - You die...\n");
625 eexit(1);
627 #ifdef BSDJOBS
628 if (SuspendPlease)
630 SuspendPlease = 0;
631 #if defined(MULTIUSER) && !defined(USE_SETEUID)
632 if (multiattach)
633 exit(SIG_STOP);
634 #endif
635 signal(SIGTSTP, SIG_DFL);
636 debug("attacher: killing myself SIGTSTP\n");
637 kill(getpid(), SIGTSTP);
638 debug("attacher: continuing from stop\n");
639 signal(SIG_STOP, SigStop);
640 (void) Attach(MSG_CONT);
642 #endif
643 #ifdef LOCK
644 if (LockPlease)
646 LockPlease = 0;
647 #if defined(MULTIUSER) && !defined(USE_SETEUID)
648 if (multiattach)
649 exit(SIG_LOCK);
650 #endif
651 LockTerminal();
652 # ifdef SYSVSIGS
653 signal(SIG_LOCK, DoLock);
654 # endif
655 (void) Attach(MSG_CONT);
657 #endif /* LOCK */
658 #if defined(SIGWINCH) && defined(TIOCGWINSZ)
659 if (SigWinchPlease)
661 SigWinchPlease = 0;
662 # ifdef SYSVSIGS
663 signal(SIGWINCH, AttacherWinch);
664 # endif
665 (void) Attach(MSG_WINCH);
667 #endif /* SIGWINCH */
671 #ifdef LOCK
673 /* ADDED by Rainer Pruy 10/15/87 */
674 /* POLISHED by mls. 03/10/91 */
676 static char LockEnd[] = "Welcome back to screen !!\n";
678 static sigret_t
679 LockHup SIGDEFARG
681 int ppid = getppid();
682 setgid(real_gid);
683 #ifdef MULTIUSER
684 setuid(own_uid);
685 #else
686 setuid(real_uid);
687 #endif
688 if (ppid > 1)
689 Kill(ppid, SIGHUP);
690 exit(0);
693 static void
694 LockTerminal()
696 char *prg;
697 int sig, pid;
698 sigret_t (*sigs[NSIG])__P(SIGPROTOARG);
700 for (sig = 1; sig < NSIG; sig++)
701 sigs[sig] = signal(sig, sig == SIGCHLD ? SIG_DFL : SIG_IGN);
702 signal(SIGHUP, LockHup);
703 printf("\n");
705 prg = getenv("LOCKPRG");
706 if (prg && strcmp(prg, "builtin") && !access(prg, X_OK))
708 signal(SIGCHLD, SIG_DFL);
709 debug1("lockterminal: '%s' seems executable, execl it!\n", prg);
710 if ((pid = fork()) == 0)
712 /* Child */
713 setgid(real_gid);
714 #ifdef MULTIUSER
715 setuid(own_uid);
716 #else
717 setuid(real_uid); /* this should be done already */
718 #endif
719 closeallfiles(0); /* important: /etc/shadow may be open */
720 execl(prg, "SCREEN-LOCK", NULL);
721 exit(errno);
723 if (pid == -1)
724 Msg(errno, "Cannot lock terminal - fork failed");
725 else
727 #ifdef BSDWAIT
728 union wait wstat;
729 #else
730 int wstat;
731 #endif
732 int wret;
734 #ifdef hpux
735 signal(SIGCHLD, SIG_DFL);
736 #endif
737 errno = 0;
738 while (((wret = wait(&wstat)) != pid) ||
739 ((wret == -1) && (errno == EINTR))
741 errno = 0;
743 if (errno)
745 Msg(errno, "Lock");
746 sleep(2);
748 else if (WTERMSIG(wstat) != 0)
750 fprintf(stderr, "Lock: %s: Killed by signal: %d%s\n", prg,
751 WTERMSIG(wstat), WIFCORESIG(wstat) ? " (Core dumped)" : "");
752 sleep(2);
754 else if (WEXITSTATUS(wstat))
756 debug2("Lock: %s: return code %d\n", prg, WEXITSTATUS(wstat));
758 else
759 printf("%s", LockEnd);
762 else
764 if (prg)
766 debug1("lockterminal: '%s' seems NOT executable, we use our builtin\n", prg);
768 else
770 debug("lockterminal: using buitin.\n");
772 screen_builtin_lck();
774 /* reset signals */
775 for (sig = 1; sig < NSIG; sig++)
777 if (sigs[sig] != (sigret_t(*)__P(SIGPROTOARG)) -1)
778 signal(sig, sigs[sig]);
780 } /* LockTerminal */
782 #ifdef USE_PAM
785 * PAM support by Pablo Averbuj <pablo@averbuj.com>
788 #include <security/pam_appl.h>
790 static int PAM_conv __P((int, const struct pam_message **, struct pam_response **, void *));
792 static int
793 PAM_conv(num_msg, msg, resp, appdata_ptr)
794 int num_msg;
795 const struct pam_message **msg;
796 struct pam_response **resp;
797 void *appdata_ptr;
799 int replies = 0;
800 struct pam_response *reply = NULL;
802 reply = malloc(sizeof(struct pam_response)*num_msg);
803 if (!reply)
804 return PAM_CONV_ERR;
805 #define COPY_STRING(s) (s) ? strdup(s) : NULL
807 for (replies = 0; replies < num_msg; replies++)
809 switch (msg[replies]->msg_style)
811 case PAM_PROMPT_ECHO_OFF:
812 /* wants password */
813 reply[replies].resp_retcode = PAM_SUCCESS;
814 reply[replies].resp = appdata_ptr ? strdup((char *)appdata_ptr) : 0;
815 break;
816 case PAM_TEXT_INFO:
817 /* ignore the informational mesage */
818 /* but first clear out any drek left by malloc */
819 reply[replies].resp = NULL;
820 break;
821 case PAM_PROMPT_ECHO_ON:
822 /* user name given to PAM already */
823 /* fall through */
824 default:
825 /* unknown or PAM_ERROR_MSG */
826 free(reply);
827 return PAM_CONV_ERR;
830 *resp = reply;
831 return PAM_SUCCESS;
834 static struct pam_conv PAM_conversation = {
835 &PAM_conv,
836 NULL
840 #endif
842 /* -- original copyright by Luigi Cannelloni 1985 (luigi@faui70.UUCP) -- */
843 static void
844 screen_builtin_lck()
846 char fullname[100], *cp1, message[100 + 100];
847 #ifdef USE_PAM
848 pam_handle_t *pamh = 0;
849 int pam_error;
850 #else
851 char *pass, mypass[16 + 1], salt[3];
852 #endif
854 #ifndef USE_PAM
855 pass = ppp->pw_passwd;
856 if (pass == 0 || *pass == 0)
858 if ((pass = getpass("Key: ")))
860 strncpy(mypass, pass, sizeof(mypass) - 1);
861 mypass[sizeof(mypass) - 1] = 0;
862 if (*mypass == 0)
863 return;
864 if ((pass = getpass("Again: ")))
866 if (strcmp(mypass, pass))
868 fprintf(stderr, "Passwords don't match.\007\n");
869 sleep(2);
870 return;
874 if (pass == 0)
876 fprintf(stderr, "Getpass error.\007\n");
877 sleep(2);
878 return;
881 salt[0] = 'A' + (int)(time(0) % 26);
882 salt[1] = 'A' + (int)((time(0) >> 6) % 26);
883 salt[2] = 0;
884 pass = crypt(mypass, salt);
885 pass = ppp->pw_passwd = SaveStr(pass);
887 #endif
889 debug("screen_builtin_lck looking in gcos field\n");
890 strncpy(fullname, ppp->pw_gecos, sizeof(fullname) - 9);
891 fullname[sizeof(fullname) - 9] = 0;
893 if ((cp1 = index(fullname, ',')) != NULL)
894 *cp1 = '\0';
895 if ((cp1 = index(fullname, '&')) != NULL)
897 strncpy(cp1, ppp->pw_name, 8);
898 cp1[8] = 0;
899 if (*cp1 >= 'a' && *cp1 <= 'z')
900 *cp1 -= 'a' - 'A';
903 sprintf(message, "Screen used by %s%s<%s> on %s.\nPassword:\007",
904 fullname, fullname[0] ? " " : "", ppp->pw_name, HostName);
906 /* loop here to wait for correct password */
907 for (;;)
909 debug("screen_builtin_lck awaiting password\n");
910 errno = 0;
911 if ((cp1 = getpass(message)) == NULL)
913 AttacherFinit(SIGARG);
914 /* NOTREACHED */
916 #ifdef USE_PAM
917 PAM_conversation.appdata_ptr = cp1;
918 pam_error = pam_start("screen", ppp->pw_name, &PAM_conversation, &pamh);
919 if (pam_error != PAM_SUCCESS)
920 AttacherFinit(SIGARG); /* goodbye */
921 pam_error = pam_authenticate(pamh, 0);
922 pam_end(pamh, pam_error);
923 PAM_conversation.appdata_ptr = 0;
924 if (pam_error == PAM_SUCCESS)
925 break;
926 #else
927 if (!strncmp(crypt(cp1, pass), pass, strlen(pass)))
928 break;
929 #endif
930 debug("screen_builtin_lck: NO!!!!!\n");
931 bzero(cp1, strlen(cp1));
933 bzero(cp1, strlen(cp1));
934 debug("password ok.\n");
937 #endif /* LOCK */
940 void
941 SendCmdMessage(sty, match, av, query)
942 char *sty;
943 char *match;
944 char **av;
945 int query;
947 int i, s;
948 struct msg m;
949 char *p;
950 int len, n;
952 if (sty == 0)
954 i = FindSocket(&s, (int *)0, (int *)0, match);
955 if (i == 0)
956 Panic(0, "No screen session found.");
957 if (i != 1)
958 Panic(0, "Use -S to specify a session.");
960 else
962 #ifdef NAME_MAX
963 if (strlen(sty) > NAME_MAX)
964 sty[NAME_MAX] = 0;
965 #endif
966 if (strlen(sty) > 2 * MAXSTR - 1)
967 sty[2 * MAXSTR - 1] = 0;
968 sprintf(SockPath + strlen(SockPath), "/%s", sty);
969 if ((s = MakeClientSocket(1)) == -1)
970 exit(1);
972 bzero((char *)&m, sizeof(m));
973 m.type = query ? MSG_QUERY : MSG_COMMAND;
974 if (attach_tty)
976 strncpy(m.m_tty, attach_tty, sizeof(m.m_tty) - 1);
977 m.m_tty[sizeof(m.m_tty) - 1] = 0;
979 p = m.m.command.cmd;
980 n = 0;
981 for (; *av && n < MAXARGS - 1; ++av, ++n)
983 len = strlen(*av) + 1;
984 if (p + len >= m.m.command.cmd + sizeof(m.m.command.cmd) - 1)
985 break;
986 strcpy(p, *av);
987 p += len;
989 *p = 0;
990 m.m.command.nargs = n;
991 strncpy(m.m.attach.auser, LoginName, sizeof(m.m.attach.auser) - 1);
992 m.m.command.auser[sizeof(m.m.command.auser) - 1] = 0;
993 m.protocol_revision = MSG_REVISION;
994 strncpy(m.m.command.preselect, preselect ? preselect : "", sizeof(m.m.command.preselect) - 1);
995 m.m.command.preselect[sizeof(m.m.command.preselect) - 1] = 0;
996 m.m.command.apid = getpid();
997 debug1("SendCommandMsg writing '%s'\n", m.m.command.cmd);
998 if (query)
1000 /* Create a server socket so we can get back the result */
1001 char *sp = SockPath + strlen(SockPath);
1002 char query[] = "-queryX";
1003 char c;
1004 int r = -1;
1005 for (c = 'A'; c <= 'Z'; c++)
1007 query[6] = c;
1008 strcpy(sp, query); /* XXX: strncpy? */
1009 if ((r = MakeServerSocket()) >= 0)
1010 break;
1012 if (r < 0)
1014 for (c = '0'; c <= '9'; c++)
1016 query[6] = c;
1017 strcpy(sp, query);
1018 if ((r = MakeServerSocket()) >= 0)
1019 break;
1023 if (r < 0)
1024 Panic(0, "Could not create a listening socket to read the results.");
1026 strncpy(m.m.command.writeback, SockPath, sizeof(m.m.command.writeback) - 1);
1027 m.m.command.writeback[sizeof(m.m.command.writeback) - 1] = '\0';
1029 /* Send the message, then wait for a response */
1030 signal(SIGCONT, QueryResultSuccess);
1031 signal(SIG_BYE, QueryResultFail);
1032 if (WriteMessage(s, &m))
1033 Msg(errno, "write");
1034 close(s);
1035 while (!QueryResult)
1036 pause();
1037 signal(SIGCONT, SIG_DFL);
1038 signal(SIG_BYE, SIG_DFL);
1040 /* Read the result and spit it out to stdout */
1041 ReceiveRaw(r);
1042 unlink(SockPath);
1043 if (QueryResult == 2) /* An error happened */
1044 exit(1);
1046 else
1048 if (WriteMessage(s, &m))
1049 Msg(errno, "write");
1050 close(s);