DO_NOT_POLL_MASTER is never defined.
[screen-lua.git] / src / attacher.c
blob5db238f0d0689ed835c6bb58d99972a5cf1dc325
1 /* Copyright (c) 2008
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 <sys/types.h>
30 #include <sys/stat.h>
31 #include <sys/ioctl.h>
32 #include <fcntl.h>
33 #include <signal.h>
34 #include "config.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;
88 * Send message to a screen backend.
89 * returns 1 if we could attach one, or 0 if none.
90 * Understands MSG_ATTACH, MSG_DETACH, MSG_POW_DETACH
91 * MSG_CONT, MSG_WINCH and nothing else!
93 * if type == MSG_ATTACH and sockets are used, attaches
94 * tty filedescriptor.
97 static int
98 WriteMessage(s, m)
99 int s;
100 struct msg *m;
102 int r, l = sizeof(*m);
104 #ifndef NAMEDPIPE
105 if (m->type == MSG_ATTACH)
106 return SendAttachMsg(s, m, attach_fd);
107 #endif
109 while(l > 0)
111 r = write(s, (char *)m + (sizeof(*m) - l), l);
112 if (r == -1 && errno == EINTR)
113 continue;
114 if (r == -1 || r == 0)
115 return -1;
116 l -= r;
118 return 0;
123 Attach(how)
124 int how;
126 int n, lasts;
127 struct msg m;
128 struct stat st;
129 char *s;
131 debug2("Attach: how=%d, tty=%s\n", how, attach_tty);
132 #ifdef MULTIUSER
133 # ifndef USE_SETEUID
134 while ((how == MSG_ATTACH || how == MSG_CONT) && multiattach)
136 int ret;
138 if (pipe(multipipe))
139 Panic(errno, "pipe");
140 if (chmod(attach_tty, 0666))
141 Panic(errno, "chmod %s", attach_tty);
142 tty_oldmode = tty_mode;
143 eff_uid = -1; /* make UserContext fork */
144 real_uid = multi_uid;
145 if ((ret = UserContext()) <= 0)
147 char dummy;
148 eff_uid = 0;
149 real_uid = own_uid;
150 if (ret < 0)
151 Panic(errno, "UserContext");
152 close(multipipe[1]);
153 read(multipipe[0], &dummy, 1);
154 if (tty_oldmode >= 0)
156 chmod(attach_tty, tty_oldmode);
157 tty_oldmode = -1;
159 ret = UserStatus();
160 #ifdef LOCK
161 if (ret == SIG_LOCK)
162 LockTerminal();
163 else
164 #endif
165 #ifdef SIGTSTP
166 if (ret == SIG_STOP)
167 kill(getpid(), SIGTSTP);
168 else
169 #endif
170 if (ret == SIG_POWER_BYE)
172 int ppid;
173 setgid(real_gid);
174 setuid(real_uid);
175 if ((ppid = getppid()) > 1)
176 Kill(ppid, SIGHUP);
177 exit(0);
179 else
180 exit(ret);
181 dflag = 0;
182 #ifdef MULTI
183 xflag = 1;
184 #endif
185 how = MSG_ATTACH;
186 continue;
188 close(multipipe[0]);
189 eff_uid = real_uid;
190 break;
192 # else /* USE_SETEUID */
193 if ((how == MSG_ATTACH || how == MSG_CONT) && multiattach)
195 real_uid = multi_uid;
196 eff_uid = own_uid;
197 #ifdef HAVE_SETRESUID
198 if (setresuid(multi_uid, own_uid, multi_uid))
199 Panic(errno, "setresuid");
200 #else
201 xseteuid(multi_uid);
202 xseteuid(own_uid);
203 #endif
204 if (chmod(attach_tty, 0666))
205 Panic(errno, "chmod %s", attach_tty);
206 tty_oldmode = tty_mode;
208 # endif /* USE_SETEUID */
209 #endif /* MULTIUSER */
211 bzero((char *) &m, sizeof(m));
212 m.type = how;
213 m.protocol_revision = MSG_REVISION;
214 strncpy(m.m_tty, attach_tty, sizeof(m.m_tty) - 1);
215 m.m_tty[sizeof(m.m_tty) - 1] = 0;
217 if (how == MSG_WINCH)
219 if ((lasts = MakeClientSocket(0)) >= 0)
221 WriteMessage(lasts, &m);
222 close(lasts);
224 return 0;
227 if (how == MSG_CONT)
229 if ((lasts = MakeClientSocket(0)) < 0)
231 Panic(0, "Sorry, cannot contact session \"%s\" again.\r\n",
232 SockName);
235 else
237 n = FindSocket(&lasts, (int *)0, (int *)0, SockMatch);
238 switch (n)
240 case 0:
241 if (rflag && (rflag & 1) == 0)
242 return 0;
243 if (quietflag)
244 eexit(10);
245 Panic(0, SockMatch && *SockMatch ? "There is no screen to be %sed matching %s." : "There is no screen to be %sed.",
246 xflag ? "attach" :
247 dflag ? "detach" :
248 "resum", SockMatch);
249 /* NOTREACHED */
250 case 1:
251 break;
252 default:
253 if (rflag < 3)
255 if (quietflag)
256 eexit(10 + n);
257 Panic(0, "Type \"screen [-d] -r [pid.]tty.host\" to resume one of them.");
259 /* NOTREACHED */
263 * Go in UserContext. Advantage is, you can kill your attacher
264 * when things go wrong. Any disadvantages? jw.
265 * Do this before the attach to prevent races!
267 #ifdef MULTIUSER
268 if (!multiattach)
269 #endif
270 setuid(real_uid);
271 #if defined(MULTIUSER) && defined(USE_SETEUID)
272 else
274 /* This call to xsetuid should also set the saved uid */
275 xseteuid(real_uid); /* multi_uid, allow backend to send signals */
277 #endif
278 setgid(real_gid);
279 eff_uid = real_uid;
280 eff_gid = real_gid;
282 debug2("Attach: uid %d euid %d\n", (int)getuid(), (int)geteuid());
283 MasterPid = 0;
284 for (s = SockName; *s; s++)
286 if (*s > '9' || *s < '0')
287 break;
288 MasterPid = 10 * MasterPid + (*s - '0');
290 debug1("Attach decided, it is '%s'\n", SockPath);
291 debug1("Attach found MasterPid == %d\n", MasterPid);
292 if (stat(SockPath, &st) == -1)
293 Panic(errno, "stat %s", SockPath);
294 if ((st.st_mode & 0600) != 0600)
295 Panic(0, "Socket is in wrong mode (%03o)", (int)st.st_mode);
298 * Change: if -x or -r ignore failing -d
300 if ((xflag || rflag) && dflag && (st.st_mode & 0700) == 0600)
301 dflag = 0;
304 * Without -x, the mode must match.
305 * With -x the mode is irrelevant unless -d.
307 if ((dflag || !xflag) && (st.st_mode & 0700) != (dflag ? 0700 : 0600))
308 Panic(0, "That screen is %sdetached.", dflag ? "already " : "not ");
309 #ifdef REMOTE_DETACH
310 if (dflag &&
311 (how == MSG_DETACH || how == MSG_POW_DETACH))
313 m.m.detach.dpid = getpid();
314 strncpy(m.m.detach.duser, LoginName, sizeof(m.m.detach.duser) - 1);
315 m.m.detach.duser[sizeof(m.m.detach.duser) - 1] = 0;
316 # ifdef POW_DETACH
317 if (dflag == 2)
318 m.type = MSG_POW_DETACH;
319 else
320 # endif
321 m.type = MSG_DETACH;
322 /* If there is no password for the session, or the user enters the correct
323 * password, then we get a SIGCONT. Otherwise we get a SIG_BYE */
324 signal(SIGCONT, AttachSigCont);
325 if (WriteMessage(lasts, &m))
326 Panic(errno, "WriteMessage");
327 close(lasts);
328 while (!ContinuePlease)
329 pause(); /* wait for SIGCONT */
330 signal(SIGCONT, SIG_DFL);
331 ContinuePlease = 0;
332 if (how != MSG_ATTACH)
333 return 0; /* we detached it. jw. */
334 sleep(1); /* we dont want to overrun our poor backend. jw. */
335 if ((lasts = MakeClientSocket(0)) == -1)
336 Panic(0, "Cannot contact screen again. Sigh.");
337 m.type = how;
339 #endif
340 ASSERT(how == MSG_ATTACH || how == MSG_CONT);
341 strncpy(m.m.attach.envterm, attach_term, sizeof(m.m.attach.envterm) - 1);
342 m.m.attach.envterm[sizeof(m.m.attach.envterm) - 1] = 0;
343 debug1("attach: sending %d bytes... ", (int)sizeof(m));
345 strncpy(m.m.attach.auser, LoginName, sizeof(m.m.attach.auser) - 1);
346 m.m.attach.auser[sizeof(m.m.attach.auser) - 1] = 0;
347 m.m.attach.esc = DefaultEsc;
348 m.m.attach.meta_esc = DefaultMetaEsc;
349 strncpy(m.m.attach.preselect, preselect ? preselect : "", sizeof(m.m.attach.preselect) - 1);
350 m.m.attach.preselect[sizeof(m.m.attach.preselect) - 1] = 0;
351 m.m.attach.apid = getpid();
352 m.m.attach.adaptflag = adaptflag;
353 m.m.attach.lines = m.m.attach.columns = 0;
354 if ((s = getenv("LINES")))
355 m.m.attach.lines = atoi(s);
356 if ((s = getenv("COLUMNS")))
357 m.m.attach.columns = atoi(s);
358 m.m.attach.encoding = nwin_options.encoding > 0 ? nwin_options.encoding + 1 : 0;
360 #ifdef REMOTE_DETACH
361 #ifdef POW_DETACH
362 if (dflag == 2)
363 m.m.attach.detachfirst = MSG_POW_DETACH;
364 else
365 #endif
366 if (dflag)
367 m.m.attach.detachfirst = MSG_DETACH;
368 else
369 #endif
370 m.m.attach.detachfirst = MSG_ATTACH;
372 #ifdef MULTIUSER
373 /* setup CONT signal handler to repair the terminal mode */
374 if (multi && (how == MSG_ATTACH || how == MSG_CONT))
375 signal(SIGCONT, AttachSigCont);
376 #endif
378 if (WriteMessage(lasts, &m))
379 Panic(errno, "WriteMessage");
380 close(lasts);
381 debug1("Attach(%d): sent\n", m.type);
382 #ifdef MULTIUSER
383 if (multi && (how == MSG_ATTACH || how == MSG_CONT))
385 while (!ContinuePlease)
386 pause(); /* wait for SIGCONT */
387 signal(SIGCONT, SIG_DFL);
388 ContinuePlease = 0;
389 # ifndef USE_SETEUID
390 close(multipipe[1]);
391 # else
392 xseteuid(own_uid);
393 if (tty_oldmode >= 0)
394 if (chmod(attach_tty, tty_oldmode))
395 Panic(errno, "chmod %s", attach_tty);
396 tty_oldmode = -1;
397 xseteuid(real_uid);
398 # endif
400 #endif
401 rflag = 0;
402 return 1;
406 static int AttacherPanic = 0;
408 #ifdef DEBUG
409 static sigret_t
410 AttacherChld SIGDEFARG
412 AttacherPanic = 1;
413 SIGRETURN;
415 #endif
417 static sigret_t
418 AttacherSigAlarm SIGDEFARG
420 #ifdef DEBUG
421 static int tick_cnt = 0;
422 if ((tick_cnt = (tick_cnt + 1) % 4) == 0)
423 debug("tick\n");
424 #endif
425 SIGRETURN;
429 * the frontend's Interrupt handler
430 * we forward SIGINT to the poor backend
432 static sigret_t
433 AttacherSigInt SIGDEFARG
435 signal(SIGINT, AttacherSigInt);
436 Kill(MasterPid, SIGINT);
437 SIGRETURN;
441 * Unfortunatelly this is also the SIGHUP handler, so we have to
442 * check if the backend is already detached.
445 sigret_t
446 AttacherFinit SIGDEFARG
448 struct stat statb;
449 struct msg m;
450 int s;
452 debug("AttacherFinit();\n");
453 signal(SIGHUP, SIG_IGN);
454 /* Check if signal comes from backend */
455 if (stat(SockPath, &statb) == 0 && (statb.st_mode & 0777) != 0600)
457 debug("Detaching backend!\n");
458 bzero((char *) &m, sizeof(m));
459 strncpy(m.m_tty, attach_tty, sizeof(m.m_tty) - 1);
460 m.m_tty[sizeof(m.m_tty) - 1] = 0;
461 debug1("attach_tty is %s\n", attach_tty);
462 m.m.detach.dpid = getpid();
463 m.type = MSG_HANGUP;
464 m.protocol_revision = MSG_REVISION;
465 if ((s = MakeClientSocket(0)) >= 0)
467 WriteMessage(s, &m);
468 close(s);
471 #ifdef MULTIUSER
472 if (tty_oldmode >= 0)
474 setuid(own_uid);
475 chmod(attach_tty, tty_oldmode);
477 #endif
478 exit(0);
479 SIGRETURN;
482 #ifdef POW_DETACH
483 static sigret_t
484 AttacherFinitBye SIGDEFARG
486 int ppid;
487 debug("AttacherFintBye()\n");
488 #if defined(MULTIUSER) && !defined(USE_SETEUID)
489 if (multiattach)
490 exit(SIG_POWER_BYE);
491 #endif
492 setgid(real_gid);
493 #ifdef MULTIUSER
494 setuid(own_uid);
495 #else
496 setuid(real_uid);
497 #endif
498 /* we don't want to disturb init (even if we were root), eh? jw */
499 if ((ppid = getppid()) > 1)
500 Kill(ppid, SIGHUP); /* carefully say good bye. jw. */
501 exit(0);
502 SIGRETURN;
504 #endif
506 #if defined(DEBUG) && defined(SIG_NODEBUG)
507 static sigret_t
508 AttacherNoDebug SIGDEFARG
510 debug("AttacherNoDebug()\n");
511 signal(SIG_NODEBUG, AttacherNoDebug);
512 if (dfp)
514 debug("debug: closing debug file.\n");
515 fflush(dfp);
516 fclose(dfp);
517 dfp = NULL;
519 SIGRETURN;
521 #endif /* SIG_NODEBUG */
523 static int SuspendPlease;
525 static sigret_t
526 SigStop SIGDEFARG
528 debug("SigStop()\n");
529 SuspendPlease = 1;
530 SIGRETURN;
533 #ifdef LOCK
534 static int LockPlease;
536 static sigret_t
537 DoLock SIGDEFARG
539 # ifdef SYSVSIGS
540 signal(SIG_LOCK, DoLock);
541 # endif
542 debug("DoLock()\n");
543 LockPlease = 1;
544 SIGRETURN;
546 #endif
548 #if defined(SIGWINCH) && defined(TIOCGWINSZ)
549 static int SigWinchPlease;
551 static sigret_t
552 AttacherWinch SIGDEFARG
554 debug("AttacherWinch()\n");
555 SigWinchPlease = 1;
556 SIGRETURN;
558 #endif
562 * Attacher loop - no return
565 void
566 Attacher()
568 signal(SIGHUP, AttacherFinit);
569 signal(SIG_BYE, AttacherFinit);
570 #ifdef POW_DETACH
571 signal(SIG_POWER_BYE, AttacherFinitBye);
572 #endif
573 #if defined(DEBUG) && defined(SIG_NODEBUG)
574 signal(SIG_NODEBUG, AttacherNoDebug);
575 #endif
576 #ifdef LOCK
577 signal(SIG_LOCK, DoLock);
578 #endif
579 signal(SIGINT, AttacherSigInt);
580 #ifdef BSDJOBS
581 signal(SIG_STOP, SigStop);
582 #endif
583 #if defined(SIGWINCH) && defined(TIOCGWINSZ)
584 signal(SIGWINCH, AttacherWinch);
585 #endif
586 #ifdef DEBUG
587 signal(SIGCHLD, AttacherChld);
588 #endif
589 debug("attacher: going for a nap.\n");
590 dflag = 0;
591 #ifdef MULTI
592 xflag = 1;
593 #endif
594 for (;;)
596 signal(SIGALRM, AttacherSigAlarm);
597 alarm(15);
598 pause();
599 alarm(0);
600 if (kill(MasterPid, 0) < 0 && errno != EPERM)
602 debug1("attacher: Panic! MasterPid %d does not exist.\n", MasterPid);
603 AttacherPanic++;
605 if (AttacherPanic)
607 fcntl(0, F_SETFL, 0);
608 SetTTY(0, &attach_Mode);
609 printf("\nSuddenly the Dungeon collapses!! - You die...\n");
610 eexit(1);
612 #ifdef BSDJOBS
613 if (SuspendPlease)
615 SuspendPlease = 0;
616 #if defined(MULTIUSER) && !defined(USE_SETEUID)
617 if (multiattach)
618 exit(SIG_STOP);
619 #endif
620 signal(SIGTSTP, SIG_DFL);
621 debug("attacher: killing myself SIGTSTP\n");
622 kill(getpid(), SIGTSTP);
623 debug("attacher: continuing from stop\n");
624 signal(SIG_STOP, SigStop);
625 (void) Attach(MSG_CONT);
627 #endif
628 #ifdef LOCK
629 if (LockPlease)
631 LockPlease = 0;
632 #if defined(MULTIUSER) && !defined(USE_SETEUID)
633 if (multiattach)
634 exit(SIG_LOCK);
635 #endif
636 LockTerminal();
637 # ifdef SYSVSIGS
638 signal(SIG_LOCK, DoLock);
639 # endif
640 (void) Attach(MSG_CONT);
642 #endif /* LOCK */
643 #if defined(SIGWINCH) && defined(TIOCGWINSZ)
644 if (SigWinchPlease)
646 SigWinchPlease = 0;
647 # ifdef SYSVSIGS
648 signal(SIGWINCH, AttacherWinch);
649 # endif
650 (void) Attach(MSG_WINCH);
652 #endif /* SIGWINCH */
656 #ifdef LOCK
658 /* ADDED by Rainer Pruy 10/15/87 */
659 /* POLISHED by mls. 03/10/91 */
661 static char LockEnd[] = "Welcome back to screen !!\n";
663 static sigret_t
664 LockHup SIGDEFARG
666 int ppid = getppid();
667 setgid(real_gid);
668 #ifdef MULTIUSER
669 setuid(own_uid);
670 #else
671 setuid(real_uid);
672 #endif
673 if (ppid > 1)
674 Kill(ppid, SIGHUP);
675 exit(0);
678 static void
679 LockTerminal()
681 char *prg;
682 int sig, pid;
683 sigret_t (*sigs[NSIG])__P(SIGPROTOARG);
685 for (sig = 1; sig < NSIG; sig++)
686 sigs[sig] = signal(sig, sig == SIGCHLD ? SIG_DFL : SIG_IGN);
687 signal(SIGHUP, LockHup);
688 printf("\n");
690 prg = getenv("LOCKPRG");
691 if (prg && strcmp(prg, "builtin") && !access(prg, X_OK))
693 signal(SIGCHLD, SIG_DFL);
694 debug1("lockterminal: '%s' seems executable, execl it!\n", prg);
695 if ((pid = fork()) == 0)
697 /* Child */
698 setgid(real_gid);
699 #ifdef MULTIUSER
700 setuid(own_uid);
701 #else
702 setuid(real_uid); /* this should be done already */
703 #endif
704 closeallfiles(0); /* important: /etc/shadow may be open */
705 execl(prg, "SCREEN-LOCK", NULL);
706 exit(errno);
708 if (pid == -1)
709 Msg(errno, "Cannot lock terminal - fork failed");
710 else
712 #ifdef BSDWAIT
713 union wait wstat;
714 #else
715 int wstat;
716 #endif
717 int wret;
719 #ifdef hpux
720 signal(SIGCHLD, SIG_DFL);
721 #endif
722 errno = 0;
723 while (((wret = wait(&wstat)) != pid) ||
724 ((wret == -1) && (errno == EINTR))
726 errno = 0;
728 if (errno)
730 Msg(errno, "Lock");
731 sleep(2);
733 else if (WTERMSIG(wstat) != 0)
735 fprintf(stderr, "Lock: %s: Killed by signal: %d%s\n", prg,
736 WTERMSIG(wstat), WIFCORESIG(wstat) ? " (Core dumped)" : "");
737 sleep(2);
739 else if (WEXITSTATUS(wstat))
741 debug2("Lock: %s: return code %d\n", prg, WEXITSTATUS(wstat));
743 else
744 printf(LockEnd);
747 else
749 if (prg)
751 debug1("lockterminal: '%s' seems NOT executable, we use our builtin\n", prg);
753 else
755 debug("lockterminal: using buitin.\n");
757 screen_builtin_lck();
759 /* reset signals */
760 for (sig = 1; sig < NSIG; sig++)
762 if (sigs[sig] != (sigret_t(*)__P(SIGPROTOARG)) -1)
763 signal(sig, sigs[sig]);
765 } /* LockTerminal */
767 #ifdef USE_PAM
770 * PAM support by Pablo Averbuj <pablo@averbuj.com>
773 #include <security/pam_appl.h>
775 static int PAM_conv __P((int, const struct pam_message **, struct pam_response **, void *));
777 static int
778 PAM_conv(num_msg, msg, resp, appdata_ptr)
779 int num_msg;
780 const struct pam_message **msg;
781 struct pam_response **resp;
782 void *appdata_ptr;
784 int replies = 0;
785 struct pam_response *reply = NULL;
787 reply = malloc(sizeof(struct pam_response)*num_msg);
788 if (!reply)
789 return PAM_CONV_ERR;
790 #define COPY_STRING(s) (s) ? strdup(s) : NULL
792 for (replies = 0; replies < num_msg; replies++)
794 switch (msg[replies]->msg_style)
796 case PAM_PROMPT_ECHO_OFF:
797 /* wants password */
798 reply[replies].resp_retcode = PAM_SUCCESS;
799 reply[replies].resp = appdata_ptr ? strdup((char *)appdata_ptr) : 0;
800 break;
801 case PAM_TEXT_INFO:
802 /* ignore the informational mesage */
803 /* but first clear out any drek left by malloc */
804 reply[replies].resp = NULL;
805 break;
806 case PAM_PROMPT_ECHO_ON:
807 /* user name given to PAM already */
808 /* fall through */
809 default:
810 /* unknown or PAM_ERROR_MSG */
811 free(reply);
812 return PAM_CONV_ERR;
815 *resp = reply;
816 return PAM_SUCCESS;
819 static struct pam_conv PAM_conversation = {
820 &PAM_conv,
821 NULL
825 #endif
827 /* -- original copyright by Luigi Cannelloni 1985 (luigi@faui70.UUCP) -- */
828 static void
829 screen_builtin_lck()
831 char fullname[100], *cp1, message[100 + 100];
832 #ifdef USE_PAM
833 pam_handle_t *pamh = 0;
834 int pam_error;
835 #else
836 char *pass, mypass[16 + 1], salt[3];
837 #endif
839 #ifndef USE_PAM
840 pass = ppp->pw_passwd;
841 if (pass == 0 || *pass == 0)
843 if ((pass = getpass("Key: ")))
845 strncpy(mypass, pass, sizeof(mypass) - 1);
846 mypass[sizeof(mypass) - 1] = 0;
847 if (*mypass == 0)
848 return;
849 if ((pass = getpass("Again: ")))
851 if (strcmp(mypass, pass))
853 fprintf(stderr, "Passwords don't match.\007\n");
854 sleep(2);
855 return;
859 if (pass == 0)
861 fprintf(stderr, "Getpass error.\007\n");
862 sleep(2);
863 return;
866 salt[0] = 'A' + (int)(time(0) % 26);
867 salt[1] = 'A' + (int)((time(0) >> 6) % 26);
868 salt[2] = 0;
869 pass = crypt(mypass, salt);
870 pass = ppp->pw_passwd = SaveStr(pass);
872 #endif
874 debug("screen_builtin_lck looking in gcos field\n");
875 strncpy(fullname, ppp->pw_gecos, sizeof(fullname) - 9);
876 fullname[sizeof(fullname) - 9] = 0;
878 if ((cp1 = index(fullname, ',')) != NULL)
879 *cp1 = '\0';
880 if ((cp1 = index(fullname, '&')) != NULL)
882 strncpy(cp1, ppp->pw_name, 8);
883 cp1[8] = 0;
884 if (*cp1 >= 'a' && *cp1 <= 'z')
885 *cp1 -= 'a' - 'A';
888 sprintf(message, "Screen used by %s%s<%s> on %s.\nPassword:\007",
889 fullname, fullname[0] ? " " : "", ppp->pw_name, HostName);
891 /* loop here to wait for correct password */
892 for (;;)
894 debug("screen_builtin_lck awaiting password\n");
895 errno = 0;
896 if ((cp1 = getpass(message)) == NULL)
898 AttacherFinit(SIGARG);
899 /* NOTREACHED */
901 #ifdef USE_PAM
902 PAM_conversation.appdata_ptr = cp1;
903 pam_error = pam_start("screen", ppp->pw_name, &PAM_conversation, &pamh);
904 if (pam_error != PAM_SUCCESS)
905 AttacherFinit(SIGARG); /* goodbye */
906 pam_error = pam_authenticate(pamh, 0);
907 pam_end(pamh, pam_error);
908 PAM_conversation.appdata_ptr = 0;
909 if (pam_error == PAM_SUCCESS)
910 break;
911 #else
912 if (!strncmp(crypt(cp1, pass), pass, strlen(pass)))
913 break;
914 #endif
915 debug("screen_builtin_lck: NO!!!!!\n");
916 bzero(cp1, strlen(cp1));
918 bzero(cp1, strlen(cp1));
919 debug("password ok.\n");
922 #endif /* LOCK */
925 void
926 SendCmdMessage(sty, match, av)
927 char *sty;
928 char *match;
929 char **av;
931 int i, s;
932 struct msg m;
933 char *p;
934 int len, n;
936 if (sty == 0)
938 i = FindSocket(&s, (int *)0, (int *)0, match);
939 if (i == 0)
940 Panic(0, "No screen session found.");
941 if (i != 1)
942 Panic(0, "Use -S to specify a session.");
944 else
946 #ifdef NAME_MAX
947 if (strlen(sty) > NAME_MAX)
948 sty[NAME_MAX] = 0;
949 #endif
950 if (strlen(sty) > 2 * MAXSTR - 1)
951 sty[2 * MAXSTR - 1] = 0;
952 sprintf(SockPath + strlen(SockPath), "/%s", sty);
953 if ((s = MakeClientSocket(1)) == -1)
954 exit(1);
956 bzero((char *)&m, sizeof(m));
957 m.type = MSG_COMMAND;
958 if (attach_tty)
960 strncpy(m.m_tty, attach_tty, sizeof(m.m_tty) - 1);
961 m.m_tty[sizeof(m.m_tty) - 1] = 0;
963 p = m.m.command.cmd;
964 n = 0;
965 for (; *av && n < MAXARGS - 1; ++av, ++n)
967 len = strlen(*av) + 1;
968 if (p + len >= m.m.command.cmd + sizeof(m.m.command.cmd) - 1)
969 break;
970 strcpy(p, *av);
971 p += len;
973 *p = 0;
974 m.m.command.nargs = n;
975 strncpy(m.m.attach.auser, LoginName, sizeof(m.m.attach.auser) - 1);
976 m.m.command.auser[sizeof(m.m.command.auser) - 1] = 0;
977 m.protocol_revision = MSG_REVISION;
978 strncpy(m.m.command.preselect, preselect ? preselect : "", sizeof(m.m.command.preselect) - 1);
979 m.m.command.preselect[sizeof(m.m.command.preselect) - 1] = 0;
980 m.m.command.apid = getpid();
981 debug1("SendCommandMsg writing '%s'\n", m.m.command.cmd);
982 if (WriteMessage(s, &m))
983 Msg(errno, "write");
984 close(s);