Require password, when applicable, for remote detach
[screen-lua.git] / src / attacher.c
blobfe3956efc02285a9d702d20c6e435271462f9781
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_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 there is no password for the session, or the user enters the correct
321 * password, then we get a SIGCONT. Otherwise we get a SIG_BYE */
322 signal(SIGCONT, AttachSigCont);
323 if (WriteMessage(lasts, &m))
324 Panic(errno, "WriteMessage");
325 close(lasts);
326 while (!ContinuePlease)
327 pause(); /* wait for SIGCONT */
328 signal(SIGCONT, SIG_DFL);
329 ContinuePlease = 0;
330 if (how != MSG_ATTACH)
331 return 0; /* we detached it. jw. */
332 sleep(1); /* we dont want to overrun our poor backend. jw. */
333 if ((lasts = MakeClientSocket(0)) == -1)
334 Panic(0, "Cannot contact screen again. Sigh.");
335 m.type = how;
337 #endif
338 ASSERT(how == MSG_ATTACH || how == MSG_CONT);
339 strncpy(m.m.attach.envterm, attach_term, sizeof(m.m.attach.envterm) - 1);
340 m.m.attach.envterm[sizeof(m.m.attach.envterm) - 1] = 0;
341 debug1("attach: sending %d bytes... ", (int)sizeof(m));
343 strncpy(m.m.attach.auser, LoginName, sizeof(m.m.attach.auser) - 1);
344 m.m.attach.auser[sizeof(m.m.attach.auser) - 1] = 0;
345 m.m.attach.esc = DefaultEsc;
346 m.m.attach.meta_esc = DefaultMetaEsc;
347 strncpy(m.m.attach.preselect, preselect ? preselect : "", sizeof(m.m.attach.preselect) - 1);
348 m.m.attach.preselect[sizeof(m.m.attach.preselect) - 1] = 0;
349 m.m.attach.apid = getpid();
350 m.m.attach.adaptflag = adaptflag;
351 m.m.attach.lines = m.m.attach.columns = 0;
352 if ((s = getenv("LINES")))
353 m.m.attach.lines = atoi(s);
354 if ((s = getenv("COLUMNS")))
355 m.m.attach.columns = atoi(s);
356 m.m.attach.encoding = nwin_options.encoding > 0 ? nwin_options.encoding + 1 : 0;
358 #ifdef REMOTE_DETACH
359 #ifdef POW_DETACH
360 if (dflag == 2)
361 m.m.attach.detachfirst = MSG_POW_DETACH;
362 else
363 #endif
364 if (dflag)
365 m.m.attach.detachfirst = MSG_DETACH;
366 else
367 #endif
368 m.m.attach.detachfirst = MSG_ATTACH;
370 #ifdef MULTIUSER
371 /* setup CONT signal handler to repair the terminal mode */
372 if (multi && (how == MSG_ATTACH || how == MSG_CONT))
373 signal(SIGCONT, AttachSigCont);
374 #endif
376 if (WriteMessage(lasts, &m))
377 Panic(errno, "WriteMessage");
378 close(lasts);
379 debug1("Attach(%d): sent\n", m.type);
380 #ifdef MULTIUSER
381 if (multi && (how == MSG_ATTACH || how == MSG_CONT))
383 while (!ContinuePlease)
384 pause(); /* wait for SIGCONT */
385 signal(SIGCONT, SIG_DFL);
386 ContinuePlease = 0;
387 # ifndef USE_SETEUID
388 close(multipipe[1]);
389 # else
390 xseteuid(own_uid);
391 if (tty_oldmode >= 0)
392 if (chmod(attach_tty, tty_oldmode))
393 Panic(errno, "chmod %s", attach_tty);
394 tty_oldmode = -1;
395 xseteuid(real_uid);
396 # endif
398 #endif
399 rflag = 0;
400 return 1;
404 #if defined(DEBUG) || !defined(DO_NOT_POLL_MASTER)
405 static int AttacherPanic = 0;
406 #endif
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 #ifndef DO_NOT_POLL_MASTER
597 signal(SIGALRM, AttacherSigAlarm);
598 alarm(15);
599 pause();
600 alarm(0);
601 if (kill(MasterPid, 0) < 0 && errno != EPERM)
603 debug1("attacher: Panic! MasterPid %d does not exist.\n", MasterPid);
604 AttacherPanic++;
606 #else
607 pause();
608 #endif
609 #if defined(DEBUG) || !defined(DO_NOT_POLL_MASTER)
610 if (AttacherPanic)
612 fcntl(0, F_SETFL, 0);
613 SetTTY(0, &attach_Mode);
614 printf("\nSuddenly the Dungeon collapses!! - You die...\n");
615 eexit(1);
617 #endif
618 #ifdef BSDJOBS
619 if (SuspendPlease)
621 SuspendPlease = 0;
622 #if defined(MULTIUSER) && !defined(USE_SETEUID)
623 if (multiattach)
624 exit(SIG_STOP);
625 #endif
626 signal(SIGTSTP, SIG_DFL);
627 debug("attacher: killing myself SIGTSTP\n");
628 kill(getpid(), SIGTSTP);
629 debug("attacher: continuing from stop\n");
630 signal(SIG_STOP, SigStop);
631 (void) Attach(MSG_CONT);
633 #endif
634 #ifdef LOCK
635 if (LockPlease)
637 LockPlease = 0;
638 #if defined(MULTIUSER) && !defined(USE_SETEUID)
639 if (multiattach)
640 exit(SIG_LOCK);
641 #endif
642 LockTerminal();
643 # ifdef SYSVSIGS
644 signal(SIG_LOCK, DoLock);
645 # endif
646 (void) Attach(MSG_CONT);
648 #endif /* LOCK */
649 #if defined(SIGWINCH) && defined(TIOCGWINSZ)
650 if (SigWinchPlease)
652 SigWinchPlease = 0;
653 # ifdef SYSVSIGS
654 signal(SIGWINCH, AttacherWinch);
655 # endif
656 (void) Attach(MSG_WINCH);
658 #endif /* SIGWINCH */
662 #ifdef LOCK
664 /* ADDED by Rainer Pruy 10/15/87 */
665 /* POLISHED by mls. 03/10/91 */
667 static char LockEnd[] = "Welcome back to screen !!\n";
669 static sigret_t
670 LockHup SIGDEFARG
672 int ppid = getppid();
673 setgid(real_gid);
674 #ifdef MULTIUSER
675 setuid(own_uid);
676 #else
677 setuid(real_uid);
678 #endif
679 if (ppid > 1)
680 Kill(ppid, SIGHUP);
681 exit(0);
684 static void
685 LockTerminal()
687 char *prg;
688 int sig, pid;
689 sigret_t (*sigs[NSIG])__P(SIGPROTOARG);
691 for (sig = 1; sig < NSIG; sig++)
692 sigs[sig] = signal(sig, sig == SIGCHLD ? SIG_DFL : SIG_IGN);
693 signal(SIGHUP, LockHup);
694 printf("\n");
696 prg = getenv("LOCKPRG");
697 if (prg && strcmp(prg, "builtin") && !access(prg, X_OK))
699 signal(SIGCHLD, SIG_DFL);
700 debug1("lockterminal: '%s' seems executable, execl it!\n", prg);
701 if ((pid = fork()) == 0)
703 /* Child */
704 setgid(real_gid);
705 #ifdef MULTIUSER
706 setuid(own_uid);
707 #else
708 setuid(real_uid); /* this should be done already */
709 #endif
710 closeallfiles(0); /* important: /etc/shadow may be open */
711 execl(prg, "SCREEN-LOCK", NULL);
712 exit(errno);
714 if (pid == -1)
715 Msg(errno, "Cannot lock terminal - fork failed");
716 else
718 #ifdef BSDWAIT
719 union wait wstat;
720 #else
721 int wstat;
722 #endif
723 int wret;
725 #ifdef hpux
726 signal(SIGCHLD, SIG_DFL);
727 #endif
728 errno = 0;
729 while (((wret = wait(&wstat)) != pid) ||
730 ((wret == -1) && (errno == EINTR))
732 errno = 0;
734 if (errno)
736 Msg(errno, "Lock");
737 sleep(2);
739 else if (WTERMSIG(wstat) != 0)
741 fprintf(stderr, "Lock: %s: Killed by signal: %d%s\n", prg,
742 WTERMSIG(wstat), WIFCORESIG(wstat) ? " (Core dumped)" : "");
743 sleep(2);
745 else if (WEXITSTATUS(wstat))
747 debug2("Lock: %s: return code %d\n", prg, WEXITSTATUS(wstat));
749 else
750 printf(LockEnd);
753 else
755 if (prg)
757 debug1("lockterminal: '%s' seems NOT executable, we use our builtin\n", prg);
759 else
761 debug("lockterminal: using buitin.\n");
763 screen_builtin_lck();
765 /* reset signals */
766 for (sig = 1; sig < NSIG; sig++)
768 if (sigs[sig] != (sigret_t(*)__P(SIGPROTOARG)) -1)
769 signal(sig, sigs[sig]);
771 } /* LockTerminal */
773 #ifdef USE_PAM
776 * PAM support by Pablo Averbuj <pablo@averbuj.com>
779 #include <security/pam_appl.h>
781 static int PAM_conv __P((int, const struct pam_message **, struct pam_response **, void *));
783 static int
784 PAM_conv(num_msg, msg, resp, appdata_ptr)
785 int num_msg;
786 const struct pam_message **msg;
787 struct pam_response **resp;
788 void *appdata_ptr;
790 int replies = 0;
791 struct pam_response *reply = NULL;
793 reply = malloc(sizeof(struct pam_response)*num_msg);
794 if (!reply)
795 return PAM_CONV_ERR;
796 #define COPY_STRING(s) (s) ? strdup(s) : NULL
798 for (replies = 0; replies < num_msg; replies++)
800 switch (msg[replies]->msg_style)
802 case PAM_PROMPT_ECHO_OFF:
803 /* wants password */
804 reply[replies].resp_retcode = PAM_SUCCESS;
805 reply[replies].resp = appdata_ptr ? strdup((char *)appdata_ptr) : 0;
806 break;
807 case PAM_TEXT_INFO:
808 /* ignore the informational mesage */
809 /* but first clear out any drek left by malloc */
810 reply[replies].resp = NULL;
811 break;
812 case PAM_PROMPT_ECHO_ON:
813 /* user name given to PAM already */
814 /* fall through */
815 default:
816 /* unknown or PAM_ERROR_MSG */
817 free(reply);
818 return PAM_CONV_ERR;
821 *resp = reply;
822 return PAM_SUCCESS;
825 static struct pam_conv PAM_conversation = {
826 &PAM_conv,
827 NULL
831 #endif
833 /* -- original copyright by Luigi Cannelloni 1985 (luigi@faui70.UUCP) -- */
834 static void
835 screen_builtin_lck()
837 char fullname[100], *cp1, message[100 + 100];
838 #ifdef USE_PAM
839 pam_handle_t *pamh = 0;
840 int pam_error;
841 #else
842 char *pass, mypass[16 + 1], salt[3];
843 #endif
845 #ifndef USE_PAM
846 pass = ppp->pw_passwd;
847 if (pass == 0 || *pass == 0)
849 if ((pass = getpass("Key: ")))
851 strncpy(mypass, pass, sizeof(mypass) - 1);
852 mypass[sizeof(mypass) - 1] = 0;
853 if (*mypass == 0)
854 return;
855 if ((pass = getpass("Again: ")))
857 if (strcmp(mypass, pass))
859 fprintf(stderr, "Passwords don't match.\007\n");
860 sleep(2);
861 return;
865 if (pass == 0)
867 fprintf(stderr, "Getpass error.\007\n");
868 sleep(2);
869 return;
872 salt[0] = 'A' + (int)(time(0) % 26);
873 salt[1] = 'A' + (int)((time(0) >> 6) % 26);
874 salt[2] = 0;
875 pass = crypt(mypass, salt);
876 pass = ppp->pw_passwd = SaveStr(pass);
878 #endif
880 debug("screen_builtin_lck looking in gcos field\n");
881 strncpy(fullname, ppp->pw_gecos, sizeof(fullname) - 9);
882 fullname[sizeof(fullname) - 9] = 0;
884 if ((cp1 = index(fullname, ',')) != NULL)
885 *cp1 = '\0';
886 if ((cp1 = index(fullname, '&')) != NULL)
888 strncpy(cp1, ppp->pw_name, 8);
889 cp1[8] = 0;
890 if (*cp1 >= 'a' && *cp1 <= 'z')
891 *cp1 -= 'a' - 'A';
894 sprintf(message, "Screen used by %s%s<%s>.\nPassword:\007",
895 fullname, fullname[0] ? " " : "", ppp->pw_name);
897 /* loop here to wait for correct password */
898 for (;;)
900 debug("screen_builtin_lck awaiting password\n");
901 errno = 0;
902 if ((cp1 = getpass(message)) == NULL)
904 AttacherFinit(SIGARG);
905 /* NOTREACHED */
907 #ifdef USE_PAM
908 PAM_conversation.appdata_ptr = cp1;
909 pam_error = pam_start("screen", ppp->pw_name, &PAM_conversation, &pamh);
910 if (pam_error != PAM_SUCCESS)
911 AttacherFinit(SIGARG); /* goodbye */
912 pam_error = pam_authenticate(pamh, 0);
913 pam_end(pamh, pam_error);
914 PAM_conversation.appdata_ptr = 0;
915 if (pam_error == PAM_SUCCESS)
916 break;
917 #else
918 if (!strncmp(crypt(cp1, pass), pass, strlen(pass)))
919 break;
920 #endif
921 debug("screen_builtin_lck: NO!!!!!\n");
922 bzero(cp1, strlen(cp1));
924 bzero(cp1, strlen(cp1));
925 debug("password ok.\n");
928 #endif /* LOCK */
931 void
932 SendCmdMessage(sty, match, av)
933 char *sty;
934 char *match;
935 char **av;
937 int i, s;
938 struct msg m;
939 char *p;
940 int len, n;
942 if (sty == 0)
944 i = FindSocket(&s, (int *)0, (int *)0, match);
945 if (i == 0)
946 Panic(0, "No screen session found.");
947 if (i != 1)
948 Panic(0, "Use -S to specify a session.");
950 else
952 #ifdef NAME_MAX
953 if (strlen(sty) > NAME_MAX)
954 sty[NAME_MAX] = 0;
955 #endif
956 if (strlen(sty) > 2 * MAXSTR - 1)
957 sty[2 * MAXSTR - 1] = 0;
958 sprintf(SockPath + strlen(SockPath), "/%s", sty);
959 if ((s = MakeClientSocket(1)) == -1)
960 exit(1);
962 bzero((char *)&m, sizeof(m));
963 m.type = MSG_COMMAND;
964 if (attach_tty)
966 strncpy(m.m_tty, attach_tty, sizeof(m.m_tty) - 1);
967 m.m_tty[sizeof(m.m_tty) - 1] = 0;
969 p = m.m.command.cmd;
970 n = 0;
971 for (; *av && n < MAXARGS - 1; ++av, ++n)
973 len = strlen(*av) + 1;
974 if (p + len >= m.m.command.cmd + sizeof(m.m.command.cmd) - 1)
975 break;
976 strcpy(p, *av);
977 p += len;
979 *p = 0;
980 m.m.command.nargs = n;
981 strncpy(m.m.attach.auser, LoginName, sizeof(m.m.attach.auser) - 1);
982 m.m.command.auser[sizeof(m.m.command.auser) - 1] = 0;
983 m.protocol_revision = MSG_REVISION;
984 strncpy(m.m.command.preselect, preselect ? preselect : "", sizeof(m.m.command.preselect) - 1);
985 m.m.command.preselect[sizeof(m.m.command.preselect) - 1] = 0;
986 m.m.command.apid = getpid();
987 debug1("SendCommandMsg writing '%s'\n", m.m.command.cmd);
988 if (WriteMessage(s, &m))
989 Msg(errno, "write");
990 close(s);