Merge branch 'master' into cmd-alias
[screen-lua.git] / src / attacher.c
blob1866582255efbed2dfc1aae1a71192c845d53cd8
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 #ifdef MULTIUSER
55 static sigret_t AttachSigCont __P(SIGPROTOARG);
56 #endif
58 extern int real_uid, real_gid, eff_uid, eff_gid;
59 extern char *SockName, *SockMatch, SockPath[];
60 extern char HostName[];
61 extern struct passwd *ppp;
62 extern char *attach_tty, *attach_term, *LoginName, *preselect;
63 extern int xflag, dflag, rflag, quietflag, adaptflag;
64 extern struct mode attach_Mode;
65 extern struct NewWindow nwin_options;
66 extern int MasterPid, attach_fd;
68 #ifdef MULTIUSER
69 extern char *multi;
70 extern int multiattach, multi_uid, own_uid;
71 extern int tty_mode, tty_oldmode;
72 # ifndef USE_SETEUID
73 static int multipipe[2];
74 # endif
75 #endif
78 #ifdef MULTIUSER
79 static int ContinuePlease;
81 static sigret_t
82 AttachSigCont SIGDEFARG
84 debug("SigCont()\n");
85 ContinuePlease = 1;
86 SIGRETURN;
88 #endif
92 * Send message to a screen backend.
93 * returns 1 if we could attach one, or 0 if none.
94 * Understands MSG_ATTACH, MSG_DETACH, MSG_POW_DETACH
95 * MSG_CONT, MSG_WINCH and nothing else!
97 * if type == MSG_ATTACH and sockets are used, attaches
98 * tty filedescriptor.
101 static int
102 WriteMessage(s, m)
103 int s;
104 struct msg *m;
106 int r, l = sizeof(*m);
108 #ifndef NAMEDPIPE
109 if (m->type == MSG_ATTACH)
110 return SendAttachMsg(s, m, attach_fd);
111 #endif
113 while(l > 0)
115 r = write(s, (char *)m + (sizeof(*m) - l), l);
116 if (r == -1 && errno == EINTR)
117 continue;
118 if (r == -1 || r == 0)
119 return -1;
120 l -= r;
122 return 0;
127 Attach(how)
128 int how;
130 int n, lasts;
131 struct msg m;
132 struct stat st;
133 char *s;
135 debug2("Attach: how=%d, tty=%s\n", how, attach_tty);
136 #ifdef MULTIUSER
137 # ifndef USE_SETEUID
138 while ((how == MSG_ATTACH || how == MSG_CONT) && multiattach)
140 int ret;
142 if (pipe(multipipe))
143 Panic(errno, "pipe");
144 if (chmod(attach_tty, 0666))
145 Panic(errno, "chmod %s", attach_tty);
146 tty_oldmode = tty_mode;
147 eff_uid = -1; /* make UserContext fork */
148 real_uid = multi_uid;
149 if ((ret = UserContext()) <= 0)
151 char dummy;
152 eff_uid = 0;
153 real_uid = own_uid;
154 if (ret < 0)
155 Panic(errno, "UserContext");
156 close(multipipe[1]);
157 read(multipipe[0], &dummy, 1);
158 if (tty_oldmode >= 0)
160 chmod(attach_tty, tty_oldmode);
161 tty_oldmode = -1;
163 ret = UserStatus();
164 #ifdef LOCK
165 if (ret == SIG_LOCK)
166 LockTerminal();
167 else
168 #endif
169 #ifdef SIGTSTP
170 if (ret == SIG_STOP)
171 kill(getpid(), SIGTSTP);
172 else
173 #endif
174 if (ret == SIG_POWER_BYE)
176 int ppid;
177 setgid(real_gid);
178 setuid(real_uid);
179 if ((ppid = getppid()) > 1)
180 Kill(ppid, SIGHUP);
181 exit(0);
183 else
184 exit(ret);
185 dflag = 0;
186 #ifdef MULTI
187 xflag = 1;
188 #endif
189 how = MSG_ATTACH;
190 continue;
192 close(multipipe[0]);
193 eff_uid = real_uid;
194 break;
196 # else /* USE_SETEUID */
197 if ((how == MSG_ATTACH || how == MSG_CONT) && multiattach)
199 real_uid = multi_uid;
200 eff_uid = own_uid;
201 #ifdef HAVE_SETRESUID
202 if (setresuid(multi_uid, own_uid, multi_uid))
203 Panic(errno, "setresuid");
204 #else
205 xseteuid(multi_uid);
206 xseteuid(own_uid);
207 #endif
208 if (chmod(attach_tty, 0666))
209 Panic(errno, "chmod %s", attach_tty);
210 tty_oldmode = tty_mode;
212 # endif /* USE_SETEUID */
213 #endif /* MULTIUSER */
215 bzero((char *) &m, sizeof(m));
216 m.type = how;
217 m.protocol_revision = MSG_REVISION;
218 strncpy(m.m_tty, attach_tty, sizeof(m.m_tty) - 1);
219 m.m_tty[sizeof(m.m_tty) - 1] = 0;
221 if (how == MSG_WINCH)
223 if ((lasts = MakeClientSocket(0)) >= 0)
225 WriteMessage(lasts, &m);
226 close(lasts);
228 return 0;
231 if (how == MSG_CONT)
233 if ((lasts = MakeClientSocket(0)) < 0)
235 Panic(0, "Sorry, cannot contact session \"%s\" again.\r\n",
236 SockName);
239 else
241 n = FindSocket(&lasts, (int *)0, (int *)0, SockMatch);
242 switch (n)
244 case 0:
245 if (rflag && (rflag & 1) == 0)
246 return 0;
247 if (quietflag)
248 eexit(10);
249 Panic(0, SockMatch && *SockMatch ? "There is no screen to be %sed matching %s." : "There is no screen to be %sed.",
250 xflag ? "attach" :
251 dflag ? "detach" :
252 "resum", SockMatch);
253 /* NOTREACHED */
254 case 1:
255 break;
256 default:
257 if (rflag < 3)
259 if (quietflag)
260 eexit(10 + n);
261 Panic(0, "Type \"screen [-d] -r [pid.]tty.host\" to resume one of them.");
263 /* NOTREACHED */
267 * Go in UserContext. Advantage is, you can kill your attacher
268 * when things go wrong. Any disadvantages? jw.
269 * Do this before the attach to prevent races!
271 #ifdef MULTIUSER
272 if (!multiattach)
273 #endif
274 setuid(real_uid);
275 #if defined(MULTIUSER) && defined(USE_SETEUID)
276 else
278 /* This call to xsetuid should also set the saved uid */
279 xseteuid(real_uid); /* multi_uid, allow backend to send signals */
281 #endif
282 setgid(real_gid);
283 eff_uid = real_uid;
284 eff_gid = real_gid;
286 debug2("Attach: uid %d euid %d\n", (int)getuid(), (int)geteuid());
287 MasterPid = 0;
288 for (s = SockName; *s; s++)
290 if (*s > '9' || *s < '0')
291 break;
292 MasterPid = 10 * MasterPid + (*s - '0');
294 debug1("Attach decided, it is '%s'\n", SockPath);
295 debug1("Attach found MasterPid == %d\n", MasterPid);
296 if (stat(SockPath, &st) == -1)
297 Panic(errno, "stat %s", SockPath);
298 if ((st.st_mode & 0600) != 0600)
299 Panic(0, "Socket is in wrong mode (%03o)", (int)st.st_mode);
302 * Change: if -x or -r ignore failing -d
304 if ((xflag || rflag) && dflag && (st.st_mode & 0700) == 0600)
305 dflag = 0;
308 * Without -x, the mode must match.
309 * With -x the mode is irrelevant unless -d.
311 if ((dflag || !xflag) && (st.st_mode & 0700) != (dflag ? 0700 : 0600))
312 Panic(0, "That screen is %sdetached.", dflag ? "already " : "not ");
313 #ifdef REMOTE_DETACH
314 if (dflag &&
315 (how == MSG_DETACH || how == MSG_POW_DETACH))
317 m.m.detach.dpid = getpid();
318 strncpy(m.m.detach.duser, LoginName, sizeof(m.m.detach.duser) - 1);
319 m.m.detach.duser[sizeof(m.m.detach.duser) - 1] = 0;
320 # ifdef POW_DETACH
321 if (dflag == 2)
322 m.type = MSG_POW_DETACH;
323 else
324 # endif
325 m.type = MSG_DETACH;
326 /* If there is no password for the session, or the user enters the correct
327 * password, then we get a SIGCONT. Otherwise we get a SIG_BYE */
328 signal(SIGCONT, AttachSigCont);
329 if (WriteMessage(lasts, &m))
330 Panic(errno, "WriteMessage");
331 close(lasts);
332 while (!ContinuePlease)
333 pause(); /* wait for SIGCONT */
334 signal(SIGCONT, SIG_DFL);
335 ContinuePlease = 0;
336 if (how != MSG_ATTACH)
337 return 0; /* we detached it. jw. */
338 sleep(1); /* we dont want to overrun our poor backend. jw. */
339 if ((lasts = MakeClientSocket(0)) == -1)
340 Panic(0, "Cannot contact screen again. Sigh.");
341 m.type = how;
343 #endif
344 ASSERT(how == MSG_ATTACH || how == MSG_CONT);
345 strncpy(m.m.attach.envterm, attach_term, sizeof(m.m.attach.envterm) - 1);
346 m.m.attach.envterm[sizeof(m.m.attach.envterm) - 1] = 0;
347 debug1("attach: sending %d bytes... ", (int)sizeof(m));
349 strncpy(m.m.attach.auser, LoginName, sizeof(m.m.attach.auser) - 1);
350 m.m.attach.auser[sizeof(m.m.attach.auser) - 1] = 0;
351 m.m.attach.esc = DefaultEsc;
352 m.m.attach.meta_esc = DefaultMetaEsc;
353 strncpy(m.m.attach.preselect, preselect ? preselect : "", sizeof(m.m.attach.preselect) - 1);
354 m.m.attach.preselect[sizeof(m.m.attach.preselect) - 1] = 0;
355 m.m.attach.apid = getpid();
356 m.m.attach.adaptflag = adaptflag;
357 m.m.attach.lines = m.m.attach.columns = 0;
358 if ((s = getenv("LINES")))
359 m.m.attach.lines = atoi(s);
360 if ((s = getenv("COLUMNS")))
361 m.m.attach.columns = atoi(s);
362 m.m.attach.encoding = nwin_options.encoding > 0 ? nwin_options.encoding + 1 : 0;
364 #ifdef REMOTE_DETACH
365 #ifdef POW_DETACH
366 if (dflag == 2)
367 m.m.attach.detachfirst = MSG_POW_DETACH;
368 else
369 #endif
370 if (dflag)
371 m.m.attach.detachfirst = MSG_DETACH;
372 else
373 #endif
374 m.m.attach.detachfirst = MSG_ATTACH;
376 #ifdef MULTIUSER
377 /* setup CONT signal handler to repair the terminal mode */
378 if (multi && (how == MSG_ATTACH || how == MSG_CONT))
379 signal(SIGCONT, AttachSigCont);
380 #endif
382 if (WriteMessage(lasts, &m))
383 Panic(errno, "WriteMessage");
384 close(lasts);
385 debug1("Attach(%d): sent\n", m.type);
386 #ifdef MULTIUSER
387 if (multi && (how == MSG_ATTACH || how == MSG_CONT))
389 while (!ContinuePlease)
390 pause(); /* wait for SIGCONT */
391 signal(SIGCONT, SIG_DFL);
392 ContinuePlease = 0;
393 # ifndef USE_SETEUID
394 close(multipipe[1]);
395 # else
396 xseteuid(own_uid);
397 if (tty_oldmode >= 0)
398 if (chmod(attach_tty, tty_oldmode))
399 Panic(errno, "chmod %s", attach_tty);
400 tty_oldmode = -1;
401 xseteuid(real_uid);
402 # endif
404 #endif
405 rflag = 0;
406 return 1;
410 #if defined(DEBUG) || !defined(DO_NOT_POLL_MASTER)
411 static int AttacherPanic = 0;
412 #endif
414 #ifdef DEBUG
415 static sigret_t
416 AttacherChld SIGDEFARG
418 AttacherPanic = 1;
419 SIGRETURN;
421 #endif
423 static sigret_t
424 AttacherSigAlarm SIGDEFARG
426 #ifdef DEBUG
427 static int tick_cnt = 0;
428 if ((tick_cnt = (tick_cnt + 1) % 4) == 0)
429 debug("tick\n");
430 #endif
431 SIGRETURN;
435 * the frontend's Interrupt handler
436 * we forward SIGINT to the poor backend
438 static sigret_t
439 AttacherSigInt SIGDEFARG
441 signal(SIGINT, AttacherSigInt);
442 Kill(MasterPid, SIGINT);
443 SIGRETURN;
447 * Unfortunatelly this is also the SIGHUP handler, so we have to
448 * check if the backend is already detached.
451 sigret_t
452 AttacherFinit SIGDEFARG
454 struct stat statb;
455 struct msg m;
456 int s;
458 debug("AttacherFinit();\n");
459 signal(SIGHUP, SIG_IGN);
460 /* Check if signal comes from backend */
461 if (stat(SockPath, &statb) == 0 && (statb.st_mode & 0777) != 0600)
463 debug("Detaching backend!\n");
464 bzero((char *) &m, sizeof(m));
465 strncpy(m.m_tty, attach_tty, sizeof(m.m_tty) - 1);
466 m.m_tty[sizeof(m.m_tty) - 1] = 0;
467 debug1("attach_tty is %s\n", attach_tty);
468 m.m.detach.dpid = getpid();
469 m.type = MSG_HANGUP;
470 m.protocol_revision = MSG_REVISION;
471 if ((s = MakeClientSocket(0)) >= 0)
473 WriteMessage(s, &m);
474 close(s);
477 #ifdef MULTIUSER
478 if (tty_oldmode >= 0)
480 setuid(own_uid);
481 chmod(attach_tty, tty_oldmode);
483 #endif
484 exit(0);
485 SIGRETURN;
488 #ifdef POW_DETACH
489 static sigret_t
490 AttacherFinitBye SIGDEFARG
492 int ppid;
493 debug("AttacherFintBye()\n");
494 #if defined(MULTIUSER) && !defined(USE_SETEUID)
495 if (multiattach)
496 exit(SIG_POWER_BYE);
497 #endif
498 setgid(real_gid);
499 #ifdef MULTIUSER
500 setuid(own_uid);
501 #else
502 setuid(real_uid);
503 #endif
504 /* we don't want to disturb init (even if we were root), eh? jw */
505 if ((ppid = getppid()) > 1)
506 Kill(ppid, SIGHUP); /* carefully say good bye. jw. */
507 exit(0);
508 SIGRETURN;
510 #endif
512 #if defined(DEBUG) && defined(SIG_NODEBUG)
513 static sigret_t
514 AttacherNoDebug SIGDEFARG
516 debug("AttacherNoDebug()\n");
517 signal(SIG_NODEBUG, AttacherNoDebug);
518 if (dfp)
520 debug("debug: closing debug file.\n");
521 fflush(dfp);
522 fclose(dfp);
523 dfp = NULL;
525 SIGRETURN;
527 #endif /* SIG_NODEBUG */
529 static int SuspendPlease;
531 static sigret_t
532 SigStop SIGDEFARG
534 debug("SigStop()\n");
535 SuspendPlease = 1;
536 SIGRETURN;
539 #ifdef LOCK
540 static int LockPlease;
542 static sigret_t
543 DoLock SIGDEFARG
545 # ifdef SYSVSIGS
546 signal(SIG_LOCK, DoLock);
547 # endif
548 debug("DoLock()\n");
549 LockPlease = 1;
550 SIGRETURN;
552 #endif
554 #if defined(SIGWINCH) && defined(TIOCGWINSZ)
555 static int SigWinchPlease;
557 static sigret_t
558 AttacherWinch SIGDEFARG
560 debug("AttacherWinch()\n");
561 SigWinchPlease = 1;
562 SIGRETURN;
564 #endif
568 * Attacher loop - no return
571 void
572 Attacher()
574 signal(SIGHUP, AttacherFinit);
575 signal(SIG_BYE, AttacherFinit);
576 #ifdef POW_DETACH
577 signal(SIG_POWER_BYE, AttacherFinitBye);
578 #endif
579 #if defined(DEBUG) && defined(SIG_NODEBUG)
580 signal(SIG_NODEBUG, AttacherNoDebug);
581 #endif
582 #ifdef LOCK
583 signal(SIG_LOCK, DoLock);
584 #endif
585 signal(SIGINT, AttacherSigInt);
586 #ifdef BSDJOBS
587 signal(SIG_STOP, SigStop);
588 #endif
589 #if defined(SIGWINCH) && defined(TIOCGWINSZ)
590 signal(SIGWINCH, AttacherWinch);
591 #endif
592 #ifdef DEBUG
593 signal(SIGCHLD, AttacherChld);
594 #endif
595 debug("attacher: going for a nap.\n");
596 dflag = 0;
597 #ifdef MULTI
598 xflag = 1;
599 #endif
600 for (;;)
602 #ifndef DO_NOT_POLL_MASTER
603 signal(SIGALRM, AttacherSigAlarm);
604 alarm(15);
605 pause();
606 alarm(0);
607 if (kill(MasterPid, 0) < 0 && errno != EPERM)
609 debug1("attacher: Panic! MasterPid %d does not exist.\n", MasterPid);
610 AttacherPanic++;
612 #else
613 pause();
614 #endif
615 #if defined(DEBUG) || !defined(DO_NOT_POLL_MASTER)
616 if (AttacherPanic)
618 fcntl(0, F_SETFL, 0);
619 SetTTY(0, &attach_Mode);
620 printf("\nSuddenly the Dungeon collapses!! - You die...\n");
621 eexit(1);
623 #endif
624 #ifdef BSDJOBS
625 if (SuspendPlease)
627 SuspendPlease = 0;
628 #if defined(MULTIUSER) && !defined(USE_SETEUID)
629 if (multiattach)
630 exit(SIG_STOP);
631 #endif
632 signal(SIGTSTP, SIG_DFL);
633 debug("attacher: killing myself SIGTSTP\n");
634 kill(getpid(), SIGTSTP);
635 debug("attacher: continuing from stop\n");
636 signal(SIG_STOP, SigStop);
637 (void) Attach(MSG_CONT);
639 #endif
640 #ifdef LOCK
641 if (LockPlease)
643 LockPlease = 0;
644 #if defined(MULTIUSER) && !defined(USE_SETEUID)
645 if (multiattach)
646 exit(SIG_LOCK);
647 #endif
648 LockTerminal();
649 # ifdef SYSVSIGS
650 signal(SIG_LOCK, DoLock);
651 # endif
652 (void) Attach(MSG_CONT);
654 #endif /* LOCK */
655 #if defined(SIGWINCH) && defined(TIOCGWINSZ)
656 if (SigWinchPlease)
658 SigWinchPlease = 0;
659 # ifdef SYSVSIGS
660 signal(SIGWINCH, AttacherWinch);
661 # endif
662 (void) Attach(MSG_WINCH);
664 #endif /* SIGWINCH */
668 #ifdef LOCK
670 /* ADDED by Rainer Pruy 10/15/87 */
671 /* POLISHED by mls. 03/10/91 */
673 static char LockEnd[] = "Welcome back to screen !!\n";
675 static sigret_t
676 LockHup SIGDEFARG
678 int ppid = getppid();
679 setgid(real_gid);
680 #ifdef MULTIUSER
681 setuid(own_uid);
682 #else
683 setuid(real_uid);
684 #endif
685 if (ppid > 1)
686 Kill(ppid, SIGHUP);
687 exit(0);
690 static void
691 LockTerminal()
693 char *prg;
694 int sig, pid;
695 sigret_t (*sigs[NSIG])__P(SIGPROTOARG);
697 for (sig = 1; sig < NSIG; sig++)
698 sigs[sig] = signal(sig, sig == SIGCHLD ? SIG_DFL : SIG_IGN);
699 signal(SIGHUP, LockHup);
700 printf("\n");
702 prg = getenv("LOCKPRG");
703 if (prg && strcmp(prg, "builtin") && !access(prg, X_OK))
705 signal(SIGCHLD, SIG_DFL);
706 debug1("lockterminal: '%s' seems executable, execl it!\n", prg);
707 if ((pid = fork()) == 0)
709 /* Child */
710 setgid(real_gid);
711 #ifdef MULTIUSER
712 setuid(own_uid);
713 #else
714 setuid(real_uid); /* this should be done already */
715 #endif
716 closeallfiles(0); /* important: /etc/shadow may be open */
717 execl(prg, "SCREEN-LOCK", NULL);
718 exit(errno);
720 if (pid == -1)
721 Msg(errno, "Cannot lock terminal - fork failed");
722 else
724 #ifdef BSDWAIT
725 union wait wstat;
726 #else
727 int wstat;
728 #endif
729 int wret;
731 #ifdef hpux
732 signal(SIGCHLD, SIG_DFL);
733 #endif
734 errno = 0;
735 while (((wret = wait(&wstat)) != pid) ||
736 ((wret == -1) && (errno == EINTR))
738 errno = 0;
740 if (errno)
742 Msg(errno, "Lock");
743 sleep(2);
745 else if (WTERMSIG(wstat) != 0)
747 fprintf(stderr, "Lock: %s: Killed by signal: %d%s\n", prg,
748 WTERMSIG(wstat), WIFCORESIG(wstat) ? " (Core dumped)" : "");
749 sleep(2);
751 else if (WEXITSTATUS(wstat))
753 debug2("Lock: %s: return code %d\n", prg, WEXITSTATUS(wstat));
755 else
756 printf(LockEnd);
759 else
761 if (prg)
763 debug1("lockterminal: '%s' seems NOT executable, we use our builtin\n", prg);
765 else
767 debug("lockterminal: using buitin.\n");
769 screen_builtin_lck();
771 /* reset signals */
772 for (sig = 1; sig < NSIG; sig++)
774 if (sigs[sig] != (sigret_t(*)__P(SIGPROTOARG)) -1)
775 signal(sig, sigs[sig]);
777 } /* LockTerminal */
779 #ifdef USE_PAM
782 * PAM support by Pablo Averbuj <pablo@averbuj.com>
785 #include <security/pam_appl.h>
787 static int PAM_conv __P((int, const struct pam_message **, struct pam_response **, void *));
789 static int
790 PAM_conv(num_msg, msg, resp, appdata_ptr)
791 int num_msg;
792 const struct pam_message **msg;
793 struct pam_response **resp;
794 void *appdata_ptr;
796 int replies = 0;
797 struct pam_response *reply = NULL;
799 reply = malloc(sizeof(struct pam_response)*num_msg);
800 if (!reply)
801 return PAM_CONV_ERR;
802 #define COPY_STRING(s) (s) ? strdup(s) : NULL
804 for (replies = 0; replies < num_msg; replies++)
806 switch (msg[replies]->msg_style)
808 case PAM_PROMPT_ECHO_OFF:
809 /* wants password */
810 reply[replies].resp_retcode = PAM_SUCCESS;
811 reply[replies].resp = appdata_ptr ? strdup((char *)appdata_ptr) : 0;
812 break;
813 case PAM_TEXT_INFO:
814 /* ignore the informational mesage */
815 /* but first clear out any drek left by malloc */
816 reply[replies].resp = NULL;
817 break;
818 case PAM_PROMPT_ECHO_ON:
819 /* user name given to PAM already */
820 /* fall through */
821 default:
822 /* unknown or PAM_ERROR_MSG */
823 free(reply);
824 return PAM_CONV_ERR;
827 *resp = reply;
828 return PAM_SUCCESS;
831 static struct pam_conv PAM_conversation = {
832 &PAM_conv,
833 NULL
837 #endif
839 /* -- original copyright by Luigi Cannelloni 1985 (luigi@faui70.UUCP) -- */
840 static void
841 screen_builtin_lck()
843 char fullname[100], *cp1, message[100 + 100];
844 #ifdef USE_PAM
845 pam_handle_t *pamh = 0;
846 int pam_error;
847 #else
848 char *pass, mypass[16 + 1], salt[3];
849 #endif
851 #ifndef USE_PAM
852 pass = ppp->pw_passwd;
853 if (pass == 0 || *pass == 0)
855 if ((pass = getpass("Key: ")))
857 strncpy(mypass, pass, sizeof(mypass) - 1);
858 mypass[sizeof(mypass) - 1] = 0;
859 if (*mypass == 0)
860 return;
861 if ((pass = getpass("Again: ")))
863 if (strcmp(mypass, pass))
865 fprintf(stderr, "Passwords don't match.\007\n");
866 sleep(2);
867 return;
871 if (pass == 0)
873 fprintf(stderr, "Getpass error.\007\n");
874 sleep(2);
875 return;
878 salt[0] = 'A' + (int)(time(0) % 26);
879 salt[1] = 'A' + (int)((time(0) >> 6) % 26);
880 salt[2] = 0;
881 pass = crypt(mypass, salt);
882 pass = ppp->pw_passwd = SaveStr(pass);
884 #endif
886 debug("screen_builtin_lck looking in gcos field\n");
887 strncpy(fullname, ppp->pw_gecos, sizeof(fullname) - 9);
888 fullname[sizeof(fullname) - 9] = 0;
890 if ((cp1 = index(fullname, ',')) != NULL)
891 *cp1 = '\0';
892 if ((cp1 = index(fullname, '&')) != NULL)
894 strncpy(cp1, ppp->pw_name, 8);
895 cp1[8] = 0;
896 if (*cp1 >= 'a' && *cp1 <= 'z')
897 *cp1 -= 'a' - 'A';
900 sprintf(message, "Screen used by %s%s<%s> on %s.\nPassword:\007",
901 fullname, fullname[0] ? " " : "", ppp->pw_name, HostName);
903 /* loop here to wait for correct password */
904 for (;;)
906 debug("screen_builtin_lck awaiting password\n");
907 errno = 0;
908 if ((cp1 = getpass(message)) == NULL)
910 AttacherFinit(SIGARG);
911 /* NOTREACHED */
913 #ifdef USE_PAM
914 PAM_conversation.appdata_ptr = cp1;
915 pam_error = pam_start("screen", ppp->pw_name, &PAM_conversation, &pamh);
916 if (pam_error != PAM_SUCCESS)
917 AttacherFinit(SIGARG); /* goodbye */
918 pam_error = pam_authenticate(pamh, 0);
919 pam_end(pamh, pam_error);
920 PAM_conversation.appdata_ptr = 0;
921 if (pam_error == PAM_SUCCESS)
922 break;
923 #else
924 if (!strncmp(crypt(cp1, pass), pass, strlen(pass)))
925 break;
926 #endif
927 debug("screen_builtin_lck: NO!!!!!\n");
928 bzero(cp1, strlen(cp1));
930 bzero(cp1, strlen(cp1));
931 debug("password ok.\n");
934 #endif /* LOCK */
937 void
938 SendCmdMessage(sty, match, av)
939 char *sty;
940 char *match;
941 char **av;
943 int i, s;
944 struct msg m;
945 char *p;
946 int len, n;
948 if (sty == 0)
950 i = FindSocket(&s, (int *)0, (int *)0, match);
951 if (i == 0)
952 Panic(0, "No screen session found.");
953 if (i != 1)
954 Panic(0, "Use -S to specify a session.");
956 else
958 #ifdef NAME_MAX
959 if (strlen(sty) > NAME_MAX)
960 sty[NAME_MAX] = 0;
961 #endif
962 if (strlen(sty) > 2 * MAXSTR - 1)
963 sty[2 * MAXSTR - 1] = 0;
964 sprintf(SockPath + strlen(SockPath), "/%s", sty);
965 if ((s = MakeClientSocket(1)) == -1)
966 exit(1);
968 bzero((char *)&m, sizeof(m));
969 m.type = MSG_COMMAND;
970 if (attach_tty)
972 strncpy(m.m_tty, attach_tty, sizeof(m.m_tty) - 1);
973 m.m_tty[sizeof(m.m_tty) - 1] = 0;
975 p = m.m.command.cmd;
976 n = 0;
977 for (; *av && n < MAXARGS - 1; ++av, ++n)
979 len = strlen(*av) + 1;
980 if (p + len >= m.m.command.cmd + sizeof(m.m.command.cmd) - 1)
981 break;
982 strcpy(p, *av);
983 p += len;
985 *p = 0;
986 m.m.command.nargs = n;
987 strncpy(m.m.attach.auser, LoginName, sizeof(m.m.attach.auser) - 1);
988 m.m.command.auser[sizeof(m.m.command.auser) - 1] = 0;
989 m.protocol_revision = MSG_REVISION;
990 strncpy(m.m.command.preselect, preselect ? preselect : "", sizeof(m.m.command.preselect) - 1);
991 m.m.command.preselect[sizeof(m.m.command.preselect) - 1] = 0;
992 m.m.command.apid = getpid();
993 debug1("SendCommandMsg writing '%s'\n", m.m.command.cmd);
994 if (WriteMessage(s, &m))
995 Msg(errno, "write");
996 close(s);