Fix compiling when multiuser mode is disabled.
[screen-lua.git] / src / attacher.c
blobdfe111ba3924f364213a159598edb09c9fd2ae5a
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 #if defined(DEBUG) || !defined(DO_NOT_POLL_MASTER)
407 static int AttacherPanic = 0;
408 #endif
410 #ifdef DEBUG
411 static sigret_t
412 AttacherChld SIGDEFARG
414 AttacherPanic = 1;
415 SIGRETURN;
417 #endif
419 static sigret_t
420 AttacherSigAlarm SIGDEFARG
422 #ifdef DEBUG
423 static int tick_cnt = 0;
424 if ((tick_cnt = (tick_cnt + 1) % 4) == 0)
425 debug("tick\n");
426 #endif
427 SIGRETURN;
431 * the frontend's Interrupt handler
432 * we forward SIGINT to the poor backend
434 static sigret_t
435 AttacherSigInt SIGDEFARG
437 signal(SIGINT, AttacherSigInt);
438 Kill(MasterPid, SIGINT);
439 SIGRETURN;
443 * Unfortunatelly this is also the SIGHUP handler, so we have to
444 * check if the backend is already detached.
447 sigret_t
448 AttacherFinit SIGDEFARG
450 struct stat statb;
451 struct msg m;
452 int s;
454 debug("AttacherFinit();\n");
455 signal(SIGHUP, SIG_IGN);
456 /* Check if signal comes from backend */
457 if (stat(SockPath, &statb) == 0 && (statb.st_mode & 0777) != 0600)
459 debug("Detaching backend!\n");
460 bzero((char *) &m, sizeof(m));
461 strncpy(m.m_tty, attach_tty, sizeof(m.m_tty) - 1);
462 m.m_tty[sizeof(m.m_tty) - 1] = 0;
463 debug1("attach_tty is %s\n", attach_tty);
464 m.m.detach.dpid = getpid();
465 m.type = MSG_HANGUP;
466 m.protocol_revision = MSG_REVISION;
467 if ((s = MakeClientSocket(0)) >= 0)
469 WriteMessage(s, &m);
470 close(s);
473 #ifdef MULTIUSER
474 if (tty_oldmode >= 0)
476 setuid(own_uid);
477 chmod(attach_tty, tty_oldmode);
479 #endif
480 exit(0);
481 SIGRETURN;
484 #ifdef POW_DETACH
485 static sigret_t
486 AttacherFinitBye SIGDEFARG
488 int ppid;
489 debug("AttacherFintBye()\n");
490 #if defined(MULTIUSER) && !defined(USE_SETEUID)
491 if (multiattach)
492 exit(SIG_POWER_BYE);
493 #endif
494 setgid(real_gid);
495 #ifdef MULTIUSER
496 setuid(own_uid);
497 #else
498 setuid(real_uid);
499 #endif
500 /* we don't want to disturb init (even if we were root), eh? jw */
501 if ((ppid = getppid()) > 1)
502 Kill(ppid, SIGHUP); /* carefully say good bye. jw. */
503 exit(0);
504 SIGRETURN;
506 #endif
508 #if defined(DEBUG) && defined(SIG_NODEBUG)
509 static sigret_t
510 AttacherNoDebug SIGDEFARG
512 debug("AttacherNoDebug()\n");
513 signal(SIG_NODEBUG, AttacherNoDebug);
514 if (dfp)
516 debug("debug: closing debug file.\n");
517 fflush(dfp);
518 fclose(dfp);
519 dfp = NULL;
521 SIGRETURN;
523 #endif /* SIG_NODEBUG */
525 static int SuspendPlease;
527 static sigret_t
528 SigStop SIGDEFARG
530 debug("SigStop()\n");
531 SuspendPlease = 1;
532 SIGRETURN;
535 #ifdef LOCK
536 static int LockPlease;
538 static sigret_t
539 DoLock SIGDEFARG
541 # ifdef SYSVSIGS
542 signal(SIG_LOCK, DoLock);
543 # endif
544 debug("DoLock()\n");
545 LockPlease = 1;
546 SIGRETURN;
548 #endif
550 #if defined(SIGWINCH) && defined(TIOCGWINSZ)
551 static int SigWinchPlease;
553 static sigret_t
554 AttacherWinch SIGDEFARG
556 debug("AttacherWinch()\n");
557 SigWinchPlease = 1;
558 SIGRETURN;
560 #endif
564 * Attacher loop - no return
567 void
568 Attacher()
570 signal(SIGHUP, AttacherFinit);
571 signal(SIG_BYE, AttacherFinit);
572 #ifdef POW_DETACH
573 signal(SIG_POWER_BYE, AttacherFinitBye);
574 #endif
575 #if defined(DEBUG) && defined(SIG_NODEBUG)
576 signal(SIG_NODEBUG, AttacherNoDebug);
577 #endif
578 #ifdef LOCK
579 signal(SIG_LOCK, DoLock);
580 #endif
581 signal(SIGINT, AttacherSigInt);
582 #ifdef BSDJOBS
583 signal(SIG_STOP, SigStop);
584 #endif
585 #if defined(SIGWINCH) && defined(TIOCGWINSZ)
586 signal(SIGWINCH, AttacherWinch);
587 #endif
588 #ifdef DEBUG
589 signal(SIGCHLD, AttacherChld);
590 #endif
591 debug("attacher: going for a nap.\n");
592 dflag = 0;
593 #ifdef MULTI
594 xflag = 1;
595 #endif
596 for (;;)
598 #ifndef DO_NOT_POLL_MASTER
599 signal(SIGALRM, AttacherSigAlarm);
600 alarm(15);
601 pause();
602 alarm(0);
603 if (kill(MasterPid, 0) < 0 && errno != EPERM)
605 debug1("attacher: Panic! MasterPid %d does not exist.\n", MasterPid);
606 AttacherPanic++;
608 #else
609 pause();
610 #endif
611 #if defined(DEBUG) || !defined(DO_NOT_POLL_MASTER)
612 if (AttacherPanic)
614 fcntl(0, F_SETFL, 0);
615 SetTTY(0, &attach_Mode);
616 printf("\nSuddenly the Dungeon collapses!! - You die...\n");
617 eexit(1);
619 #endif
620 #ifdef BSDJOBS
621 if (SuspendPlease)
623 SuspendPlease = 0;
624 #if defined(MULTIUSER) && !defined(USE_SETEUID)
625 if (multiattach)
626 exit(SIG_STOP);
627 #endif
628 signal(SIGTSTP, SIG_DFL);
629 debug("attacher: killing myself SIGTSTP\n");
630 kill(getpid(), SIGTSTP);
631 debug("attacher: continuing from stop\n");
632 signal(SIG_STOP, SigStop);
633 (void) Attach(MSG_CONT);
635 #endif
636 #ifdef LOCK
637 if (LockPlease)
639 LockPlease = 0;
640 #if defined(MULTIUSER) && !defined(USE_SETEUID)
641 if (multiattach)
642 exit(SIG_LOCK);
643 #endif
644 LockTerminal();
645 # ifdef SYSVSIGS
646 signal(SIG_LOCK, DoLock);
647 # endif
648 (void) Attach(MSG_CONT);
650 #endif /* LOCK */
651 #if defined(SIGWINCH) && defined(TIOCGWINSZ)
652 if (SigWinchPlease)
654 SigWinchPlease = 0;
655 # ifdef SYSVSIGS
656 signal(SIGWINCH, AttacherWinch);
657 # endif
658 (void) Attach(MSG_WINCH);
660 #endif /* SIGWINCH */
664 #ifdef LOCK
666 /* ADDED by Rainer Pruy 10/15/87 */
667 /* POLISHED by mls. 03/10/91 */
669 static char LockEnd[] = "Welcome back to screen !!\n";
671 static sigret_t
672 LockHup SIGDEFARG
674 int ppid = getppid();
675 setgid(real_gid);
676 #ifdef MULTIUSER
677 setuid(own_uid);
678 #else
679 setuid(real_uid);
680 #endif
681 if (ppid > 1)
682 Kill(ppid, SIGHUP);
683 exit(0);
686 static void
687 LockTerminal()
689 char *prg;
690 int sig, pid;
691 sigret_t (*sigs[NSIG])__P(SIGPROTOARG);
693 for (sig = 1; sig < NSIG; sig++)
694 sigs[sig] = signal(sig, sig == SIGCHLD ? SIG_DFL : SIG_IGN);
695 signal(SIGHUP, LockHup);
696 printf("\n");
698 prg = getenv("LOCKPRG");
699 if (prg && strcmp(prg, "builtin") && !access(prg, X_OK))
701 signal(SIGCHLD, SIG_DFL);
702 debug1("lockterminal: '%s' seems executable, execl it!\n", prg);
703 if ((pid = fork()) == 0)
705 /* Child */
706 setgid(real_gid);
707 #ifdef MULTIUSER
708 setuid(own_uid);
709 #else
710 setuid(real_uid); /* this should be done already */
711 #endif
712 closeallfiles(0); /* important: /etc/shadow may be open */
713 execl(prg, "SCREEN-LOCK", NULL);
714 exit(errno);
716 if (pid == -1)
717 Msg(errno, "Cannot lock terminal - fork failed");
718 else
720 #ifdef BSDWAIT
721 union wait wstat;
722 #else
723 int wstat;
724 #endif
725 int wret;
727 #ifdef hpux
728 signal(SIGCHLD, SIG_DFL);
729 #endif
730 errno = 0;
731 while (((wret = wait(&wstat)) != pid) ||
732 ((wret == -1) && (errno == EINTR))
734 errno = 0;
736 if (errno)
738 Msg(errno, "Lock");
739 sleep(2);
741 else if (WTERMSIG(wstat) != 0)
743 fprintf(stderr, "Lock: %s: Killed by signal: %d%s\n", prg,
744 WTERMSIG(wstat), WIFCORESIG(wstat) ? " (Core dumped)" : "");
745 sleep(2);
747 else if (WEXITSTATUS(wstat))
749 debug2("Lock: %s: return code %d\n", prg, WEXITSTATUS(wstat));
751 else
752 printf(LockEnd);
755 else
757 if (prg)
759 debug1("lockterminal: '%s' seems NOT executable, we use our builtin\n", prg);
761 else
763 debug("lockterminal: using buitin.\n");
765 screen_builtin_lck();
767 /* reset signals */
768 for (sig = 1; sig < NSIG; sig++)
770 if (sigs[sig] != (sigret_t(*)__P(SIGPROTOARG)) -1)
771 signal(sig, sigs[sig]);
773 } /* LockTerminal */
775 #ifdef USE_PAM
778 * PAM support by Pablo Averbuj <pablo@averbuj.com>
781 #include <security/pam_appl.h>
783 static int PAM_conv __P((int, const struct pam_message **, struct pam_response **, void *));
785 static int
786 PAM_conv(num_msg, msg, resp, appdata_ptr)
787 int num_msg;
788 const struct pam_message **msg;
789 struct pam_response **resp;
790 void *appdata_ptr;
792 int replies = 0;
793 struct pam_response *reply = NULL;
795 reply = malloc(sizeof(struct pam_response)*num_msg);
796 if (!reply)
797 return PAM_CONV_ERR;
798 #define COPY_STRING(s) (s) ? strdup(s) : NULL
800 for (replies = 0; replies < num_msg; replies++)
802 switch (msg[replies]->msg_style)
804 case PAM_PROMPT_ECHO_OFF:
805 /* wants password */
806 reply[replies].resp_retcode = PAM_SUCCESS;
807 reply[replies].resp = appdata_ptr ? strdup((char *)appdata_ptr) : 0;
808 break;
809 case PAM_TEXT_INFO:
810 /* ignore the informational mesage */
811 /* but first clear out any drek left by malloc */
812 reply[replies].resp = NULL;
813 break;
814 case PAM_PROMPT_ECHO_ON:
815 /* user name given to PAM already */
816 /* fall through */
817 default:
818 /* unknown or PAM_ERROR_MSG */
819 free(reply);
820 return PAM_CONV_ERR;
823 *resp = reply;
824 return PAM_SUCCESS;
827 static struct pam_conv PAM_conversation = {
828 &PAM_conv,
829 NULL
833 #endif
835 /* -- original copyright by Luigi Cannelloni 1985 (luigi@faui70.UUCP) -- */
836 static void
837 screen_builtin_lck()
839 char fullname[100], *cp1, message[100 + 100];
840 #ifdef USE_PAM
841 pam_handle_t *pamh = 0;
842 int pam_error;
843 #else
844 char *pass, mypass[16 + 1], salt[3];
845 #endif
847 #ifndef USE_PAM
848 pass = ppp->pw_passwd;
849 if (pass == 0 || *pass == 0)
851 if ((pass = getpass("Key: ")))
853 strncpy(mypass, pass, sizeof(mypass) - 1);
854 mypass[sizeof(mypass) - 1] = 0;
855 if (*mypass == 0)
856 return;
857 if ((pass = getpass("Again: ")))
859 if (strcmp(mypass, pass))
861 fprintf(stderr, "Passwords don't match.\007\n");
862 sleep(2);
863 return;
867 if (pass == 0)
869 fprintf(stderr, "Getpass error.\007\n");
870 sleep(2);
871 return;
874 salt[0] = 'A' + (int)(time(0) % 26);
875 salt[1] = 'A' + (int)((time(0) >> 6) % 26);
876 salt[2] = 0;
877 pass = crypt(mypass, salt);
878 pass = ppp->pw_passwd = SaveStr(pass);
880 #endif
882 debug("screen_builtin_lck looking in gcos field\n");
883 strncpy(fullname, ppp->pw_gecos, sizeof(fullname) - 9);
884 fullname[sizeof(fullname) - 9] = 0;
886 if ((cp1 = index(fullname, ',')) != NULL)
887 *cp1 = '\0';
888 if ((cp1 = index(fullname, '&')) != NULL)
890 strncpy(cp1, ppp->pw_name, 8);
891 cp1[8] = 0;
892 if (*cp1 >= 'a' && *cp1 <= 'z')
893 *cp1 -= 'a' - 'A';
896 sprintf(message, "Screen used by %s%s<%s> on %s.\nPassword:\007",
897 fullname, fullname[0] ? " " : "", ppp->pw_name, HostName);
899 /* loop here to wait for correct password */
900 for (;;)
902 debug("screen_builtin_lck awaiting password\n");
903 errno = 0;
904 if ((cp1 = getpass(message)) == NULL)
906 AttacherFinit(SIGARG);
907 /* NOTREACHED */
909 #ifdef USE_PAM
910 PAM_conversation.appdata_ptr = cp1;
911 pam_error = pam_start("screen", ppp->pw_name, &PAM_conversation, &pamh);
912 if (pam_error != PAM_SUCCESS)
913 AttacherFinit(SIGARG); /* goodbye */
914 pam_error = pam_authenticate(pamh, 0);
915 pam_end(pamh, pam_error);
916 PAM_conversation.appdata_ptr = 0;
917 if (pam_error == PAM_SUCCESS)
918 break;
919 #else
920 if (!strncmp(crypt(cp1, pass), pass, strlen(pass)))
921 break;
922 #endif
923 debug("screen_builtin_lck: NO!!!!!\n");
924 bzero(cp1, strlen(cp1));
926 bzero(cp1, strlen(cp1));
927 debug("password ok.\n");
930 #endif /* LOCK */
933 void
934 SendCmdMessage(sty, match, av)
935 char *sty;
936 char *match;
937 char **av;
939 int i, s;
940 struct msg m;
941 char *p;
942 int len, n;
944 if (sty == 0)
946 i = FindSocket(&s, (int *)0, (int *)0, match);
947 if (i == 0)
948 Panic(0, "No screen session found.");
949 if (i != 1)
950 Panic(0, "Use -S to specify a session.");
952 else
954 #ifdef NAME_MAX
955 if (strlen(sty) > NAME_MAX)
956 sty[NAME_MAX] = 0;
957 #endif
958 if (strlen(sty) > 2 * MAXSTR - 1)
959 sty[2 * MAXSTR - 1] = 0;
960 sprintf(SockPath + strlen(SockPath), "/%s", sty);
961 if ((s = MakeClientSocket(1)) == -1)
962 exit(1);
964 bzero((char *)&m, sizeof(m));
965 m.type = MSG_COMMAND;
966 if (attach_tty)
968 strncpy(m.m_tty, attach_tty, sizeof(m.m_tty) - 1);
969 m.m_tty[sizeof(m.m_tty) - 1] = 0;
971 p = m.m.command.cmd;
972 n = 0;
973 for (; *av && n < MAXARGS - 1; ++av, ++n)
975 len = strlen(*av) + 1;
976 if (p + len >= m.m.command.cmd + sizeof(m.m.command.cmd) - 1)
977 break;
978 strcpy(p, *av);
979 p += len;
981 *p = 0;
982 m.m.command.nargs = n;
983 strncpy(m.m.attach.auser, LoginName, sizeof(m.m.attach.auser) - 1);
984 m.m.command.auser[sizeof(m.m.command.auser) - 1] = 0;
985 m.protocol_revision = MSG_REVISION;
986 strncpy(m.m.command.preselect, preselect ? preselect : "", sizeof(m.m.command.preselect) - 1);
987 m.m.command.preselect[sizeof(m.m.command.preselect) - 1] = 0;
988 m.m.command.apid = getpid();
989 debug1("SendCommandMsg writing '%s'\n", m.m.command.cmd);
990 if (WriteMessage(s, &m))
991 Msg(errno, "write");
992 close(s);