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 5 * 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. 10 * 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. 15 * 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 20 * 21 **************************************************************** 22 */ 23 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" 32 33#include <pwd.h> 34 35static int WriteMessage __P((int, struct msg *)); 36static sigret_t AttacherSigInt __P(SIGPROTOARG); 37#if defined(SIGWINCH) && defined(TIOCGWINSZ) 38static sigret_t AttacherWinch __P(SIGPROTOARG); 39#endif 40#ifdef LOCK 41static sigret_t DoLock __P(SIGPROTOARG); 42static void LockTerminal __P((void)); 43static sigret_t LockHup __P(SIGPROTOARG); 44static void screen_builtin_lck __P((void)); 45#endif 46#ifdef DEBUG 47static sigret_t AttacherChld __P(SIGPROTOARG); 48#endif 49#ifdef MULTIUSER 50static sigret_t AttachSigCont __P(SIGPROTOARG); 51#endif 52 53extern int real_uid, real_gid, eff_uid, eff_gid; 54extern char *SockName, *SockMatch, SockPath[]; 55extern struct passwd *ppp; 56extern char *attach_tty, *attach_term, *LoginName, *preselect; 57extern int xflag, dflag, rflag, quietflag, adaptflag; 58extern struct mode attach_Mode; 59extern struct NewWindow nwin_options; 60extern int MasterPid; 61 62#ifdef MULTIUSER 63extern char *multi; 64extern int multiattach, multi_uid, own_uid; 65extern int tty_mode, tty_oldmode; 66# ifndef USE_SETEUID 67static int multipipe[2]; 68# endif 69#endif 70 71 72#ifdef MULTIUSER 73static int ContinuePlease; 74 75static sigret_t 76AttachSigCont SIGDEFARG 77{ 78 debug("SigCont()\n"); 79 ContinuePlease = 1; 80 SIGRETURN; 81} 82#endif 83 84 85/* 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! 90 */ 91 92static int 93WriteMessage(s, m) 94int s; 95struct msg *m; 96{ 97 int r, l = sizeof(*m); 98 99 while(l > 0) 100 { 101 r = write(s, (char *)m + (sizeof(*m) - l), l); 102 if (r == -1 && errno == EINTR) 103 continue; 104 if (r == -1 || r == 0) 105 return -1; 106 l -= r; 107 } 108 return 0; 109} 110 111 112int 113Attach(how) 114int how; 115{ 116 int n, lasts; 117 struct msg m; 118 struct stat st; 119 char *s; 120 121 debug2("Attach: how=%d, tty=%s\n", how, attach_tty); 122#ifdef MULTIUSER 123# ifndef USE_SETEUID 124 while ((how == MSG_ATTACH || how == MSG_CONT) && multiattach) 125 { 126 int ret; 127 128 if (pipe(multipipe)) 129 Panic(errno, "pipe"); 130 if (chmod(attach_tty, 0666)) 131 Panic(errno, "chmod %s", attach_tty); 132 tty_oldmode = tty_mode; 133 eff_uid = -1; /* make UserContext fork */ 134 real_uid = multi_uid; 135 if ((ret = UserContext()) <= 0) 136 { 137 char dummy; 138 eff_uid = 0; 139 real_uid = own_uid; 140 if (ret < 0) 141 Panic(errno, "UserContext"); 142 close(multipipe[1]); 143 read(multipipe[0], &dummy, 1); 144 if (tty_oldmode >= 0) 145 { 146 chmod(attach_tty, tty_oldmode); 147 tty_oldmode = -1; 148 } 149 ret = UserStatus(); 150#ifdef LOCK 151 if (ret == SIG_LOCK) 152 LockTerminal(); 153 else 154#endif 155#ifdef SIGTSTP 156 if (ret == SIG_STOP) 157 kill(getpid(), SIGTSTP); 158 else 159#endif 160 if (ret == SIG_POWER_BYE) 161 { 162 int ppid; 163 setgid(real_gid); 164 setuid(real_uid); 165 if ((ppid = getppid()) > 1) 166 Kill(ppid, SIGHUP); 167 exit(0); 168 } 169 else 170 exit(ret); 171 dflag = 0; 172#ifdef MULTI 173 xflag = 1; 174#endif 175 how = MSG_ATTACH; 176 continue; 177 } 178 close(multipipe[0]); 179 eff_uid = real_uid; 180 break; 181 } 182# else /* USE_SETEUID */ 183 if ((how == MSG_ATTACH || how == MSG_CONT) && multiattach) 184 { 185 real_uid = multi_uid; 186 eff_uid = own_uid; 187 xseteuid(multi_uid); 188 xseteuid(own_uid); 189 if (chmod(attach_tty, 0666)) 190 Panic(errno, "chmod %s", attach_tty); 191 tty_oldmode = tty_mode; 192 } 193# endif /* USE_SETEUID */ 194#endif /* MULTIUSER */ 195 196 bzero((char *) &m, sizeof(m)); 197 m.type = how; 198 m.protocol_revision = MSG_REVISION; 199 strncpy(m.m_tty, attach_tty, sizeof(m.m_tty) - 1); 200 m.m_tty[sizeof(m.m_tty) - 1] = 0; 201 202 if (how == MSG_WINCH) 203 { 204 if ((lasts = MakeClientSocket(0)) >= 0) 205 { 206 WriteMessage(lasts, &m); 207 close(lasts); 208 } 209 return 0; 210 } 211 212 if (how == MSG_CONT) 213 { 214 if ((lasts = MakeClientSocket(0)) < 0) 215 { 216 Panic(0, "Sorry, cannot contact session \"%s\" again.\r\n", 217 SockName); 218 } 219 } 220 else 221 { 222 n = FindSocket(&lasts, (int *)0, (int *)0, SockMatch); 223 switch (n) 224 { 225 case 0: 226 if (rflag && (rflag & 1) == 0) 227 return 0; 228 if (quietflag) 229 eexit(10); 230 Panic(0, SockMatch && *SockMatch ? "There is no screen to be %sed matching %s." : "There is no screen to be %sed.", 231 xflag ? "attach" : 232 dflag ? "detach" : 233 "resum", SockMatch); 234 /* NOTREACHED */ 235 case 1: 236 break; 237 default: 238 if (rflag < 3) 239 { 240 if (quietflag) 241 eexit(10 + n); 242 Panic(0, "Type \"screen [-d] -r [pid.]tty.host\" to resume one of them."); 243 } 244 /* NOTREACHED */ 245 } 246 } 247 /* 248 * Go in UserContext. Advantage is, you can kill your attacher 249 * when things go wrong. Any disadvantages? jw. 250 * Do this before the attach to prevent races! 251 */ 252#ifdef MULTIUSER 253 if (!multiattach) 254#endif 255 setuid(real_uid); 256#if defined(MULTIUSER) && defined(USE_SETEUID) 257 else 258 { 259 /* This call to xsetuid should also set the saved uid */ 260 xseteuid(real_uid); /* multi_uid, allow backend to send signals */ 261 } 262#endif 263 setgid(real_gid); 264 eff_uid = real_uid; 265 eff_gid = real_gid; 266 267 debug2("Attach: uid %d euid %d\n", (int)getuid(), (int)geteuid()); 268 MasterPid = 0; 269 for (s = SockName; *s; s++) 270 { 271 if (*s > '9' || *s < '0') 272 break; 273 MasterPid = 10 * MasterPid + (*s - '0'); 274 } 275 debug1("Attach decided, it is '%s'\n", SockPath); 276 debug1("Attach found MasterPid == %d\n", MasterPid); 277 if (stat(SockPath, &st) == -1) 278 Panic(errno, "stat %s", SockPath); 279 if ((st.st_mode & 0600) != 0600) 280 Panic(0, "Socket is in wrong mode (%03o)", (int)st.st_mode); 281 282 /* 283 * Change: if -x or -r ignore failing -d 284 */ 285 if ((xflag || rflag) && dflag && (st.st_mode & 0700) == 0600) 286 dflag = 0; 287 288 /* 289 * Without -x, the mode must match. 290 * With -x the mode is irrelevant unless -d. 291 */ 292 if ((dflag || !xflag) && (st.st_mode & 0700) != (dflag ? 0700 : 0600)) 293 Panic(0, "That screen is %sdetached.", dflag ? "already " : "not "); 294#ifdef REMOTE_DETACH 295 if (dflag && 296 (how == MSG_ATTACH || how == MSG_DETACH || how == MSG_POW_DETACH)) 297 { 298 m.m.detach.dpid = getpid(); 299 strncpy(m.m.detach.duser, LoginName, sizeof(m.m.detach.duser) - 1); 300 m.m.detach.duser[sizeof(m.m.detach.duser) - 1] = 0; 301# ifdef POW_DETACH 302 if (dflag == 2) 303 m.type = MSG_POW_DETACH; 304 else 305# endif 306 m.type = MSG_DETACH; 307 if (WriteMessage(lasts, &m)) 308 Panic(errno, "WriteMessage"); 309 close(lasts); 310 if (how != MSG_ATTACH) 311 return 0; /* we detached it. jw. */ 312 sleep(1); /* we dont want to overrun our poor backend. jw. */ 313 if ((lasts = MakeClientSocket(0)) == -1) 314 Panic(0, "Cannot contact screen again. Sigh."); 315 m.type = how; 316 } 317#endif 318 ASSERT(how == MSG_ATTACH || how == MSG_CONT); 319 strncpy(m.m.attach.envterm, attach_term, sizeof(m.m.attach.envterm) - 1); 320 m.m.attach.envterm[sizeof(m.m.attach.envterm) - 1] = 0; 321 debug1("attach: sending %d bytes... ", (int)sizeof(m)); 322 323 strncpy(m.m.attach.auser, LoginName, sizeof(m.m.attach.auser) - 1); 324 m.m.attach.auser[sizeof(m.m.attach.auser) - 1] = 0; 325 m.m.attach.esc = DefaultEsc; 326 m.m.attach.meta_esc = DefaultMetaEsc; 327 strncpy(m.m.attach.preselect, preselect ? preselect : "", sizeof(m.m.attach.preselect) - 1); 328 m.m.attach.preselect[sizeof(m.m.attach.preselect) - 1] = 0; 329 m.m.attach.apid = getpid(); 330 m.m.attach.adaptflag = adaptflag; 331 m.m.attach.lines = m.m.attach.columns = 0; 332 if ((s = getenv("LINES"))) 333 m.m.attach.lines = atoi(s); 334 if ((s = getenv("COLUMNS"))) 335 m.m.attach.columns = atoi(s); 336 m.m.attach.encoding = nwin_options.encoding > 0 ? nwin_options.encoding + 1 : 0; 337 338#ifdef MULTIUSER 339 /* setup CONT signal handler to repair the terminal mode */ 340 if (multi && (how == MSG_ATTACH || how == MSG_CONT)) 341 signal(SIGCONT, AttachSigCont); 342#endif 343 344 if (WriteMessage(lasts, &m)) 345 Panic(errno, "WriteMessage"); 346 close(lasts); 347 debug1("Attach(%d): sent\n", m.type); 348#ifdef MULTIUSER 349 if (multi && (how == MSG_ATTACH || how == MSG_CONT)) 350 { 351 while (!ContinuePlease) 352 pause(); /* wait for SIGCONT */ 353 signal(SIGCONT, SIG_DFL); 354 ContinuePlease = 0; 355# ifndef USE_SETEUID 356 close(multipipe[1]); 357# else 358 xseteuid(own_uid); 359 if (tty_oldmode >= 0) 360 if (chmod(attach_tty, tty_oldmode)) 361 Panic(errno, "chmod %s", attach_tty); 362 tty_oldmode = -1; 363 xseteuid(real_uid); 364# endif 365 } 366#endif 367 rflag = 0; 368 return 1; 369} 370 371 372#if defined(DEBUG) || !defined(DO_NOT_POLL_MASTER) 373static int AttacherPanic = 0; 374#endif 375 376#ifdef DEBUG 377static sigret_t 378AttacherChld SIGDEFARG 379{ 380 AttacherPanic = 1; 381 SIGRETURN; 382} 383#endif 384 385static sigret_t 386AttacherSigAlarm SIGDEFARG 387{ 388#ifdef DEBUG 389 static int tick_cnt = 0; 390 if ((tick_cnt = (tick_cnt + 1) % 4) == 0) 391 debug("tick\n"); 392#endif 393 SIGRETURN; 394} 395 396/* 397 * the frontend's Interrupt handler 398 * we forward SIGINT to the poor backend 399 */ 400static sigret_t 401AttacherSigInt SIGDEFARG 402{ 403 signal(SIGINT, AttacherSigInt); 404 Kill(MasterPid, SIGINT); 405 SIGRETURN; 406} 407 408/* 409 * Unfortunatelly this is also the SIGHUP handler, so we have to 410 * check if the backend is already detached. 411 */ 412 413sigret_t 414AttacherFinit SIGDEFARG 415{ 416 struct stat statb; 417 struct msg m; 418 int s; 419 420 debug("AttacherFinit();\n"); 421 signal(SIGHUP, SIG_IGN); 422 /* Check if signal comes from backend */ 423 if (stat(SockPath, &statb) == 0 && (statb.st_mode & 0777) != 0600) 424 { 425 debug("Detaching backend!\n"); 426 bzero((char *) &m, sizeof(m)); 427 strncpy(m.m_tty, attach_tty, sizeof(m.m_tty) - 1); 428 m.m_tty[sizeof(m.m_tty) - 1] = 0; 429 debug1("attach_tty is %s\n", attach_tty); 430 m.m.detach.dpid = getpid(); 431 m.type = MSG_HANGUP; 432 m.protocol_revision = MSG_REVISION; 433 if ((s = MakeClientSocket(0)) >= 0) 434 { 435 WriteMessage(s, &m); 436 close(s); 437 } 438 } 439#ifdef MULTIUSER 440 if (tty_oldmode >= 0) 441 { 442 setuid(own_uid); 443 chmod(attach_tty, tty_oldmode); 444 } 445#endif 446 exit(0); 447 SIGRETURN; 448} 449 450#ifdef POW_DETACH 451static sigret_t 452AttacherFinitBye SIGDEFARG 453{ 454 int ppid; 455 debug("AttacherFintBye()\n"); 456#if defined(MULTIUSER) && !defined(USE_SETEUID) 457 if (multiattach) 458 exit(SIG_POWER_BYE); 459#endif 460 setgid(real_gid); 461#ifdef MULTIUSER 462 setuid(own_uid); 463#else 464 setuid(real_uid); 465#endif 466 /* we don't want to disturb init (even if we were root), eh? jw */ 467 if ((ppid = getppid()) > 1) 468 Kill(ppid, SIGHUP); /* carefully say good bye. jw. */ 469 exit(0); 470 SIGRETURN; 471} 472#endif 473 474#if defined(DEBUG) && defined(SIG_NODEBUG) 475static sigret_t 476AttacherNoDebug SIGDEFARG 477{ 478 debug("AttacherNoDebug()\n"); 479 signal(SIG_NODEBUG, AttacherNoDebug); 480 if (dfp) 481 { 482 debug("debug: closing debug file.\n"); 483 fflush(dfp); 484 fclose(dfp); 485 dfp = NULL; 486 } 487 SIGRETURN; 488} 489#endif /* SIG_NODEBUG */ 490 491static int SuspendPlease; 492 493static sigret_t 494SigStop SIGDEFARG 495{ 496 debug("SigStop()\n"); 497 SuspendPlease = 1; 498 SIGRETURN; 499} 500 501#ifdef LOCK 502static int LockPlease; 503 504static sigret_t 505DoLock SIGDEFARG 506{ 507# ifdef SYSVSIGS 508 signal(SIG_LOCK, DoLock); 509# endif 510 debug("DoLock()\n"); 511 LockPlease = 1; 512 SIGRETURN; 513} 514#endif 515 516#if defined(SIGWINCH) && defined(TIOCGWINSZ) 517static int SigWinchPlease; 518 519static sigret_t 520AttacherWinch SIGDEFARG 521{ 522 debug("AttacherWinch()\n"); 523 SigWinchPlease = 1; 524 SIGRETURN; 525} 526#endif 527 528 529/* 530 * Attacher loop - no return 531 */ 532 533void 534Attacher() 535{ 536 signal(SIGHUP, AttacherFinit); 537 signal(SIG_BYE, AttacherFinit); 538#ifdef POW_DETACH 539 signal(SIG_POWER_BYE, AttacherFinitBye); 540#endif 541#if defined(DEBUG) && defined(SIG_NODEBUG) 542 signal(SIG_NODEBUG, AttacherNoDebug); 543#endif 544#ifdef LOCK 545 signal(SIG_LOCK, DoLock); 546#endif 547 signal(SIGINT, AttacherSigInt); 548#ifdef BSDJOBS 549 signal(SIG_STOP, SigStop); 550#endif 551#if defined(SIGWINCH) && defined(TIOCGWINSZ) 552 signal(SIGWINCH, AttacherWinch); 553#endif 554#ifdef DEBUG 555 signal(SIGCHLD, AttacherChld); 556#endif 557 debug("attacher: going for a nap.\n"); 558 dflag = 0; 559#ifdef MULTI 560 xflag = 1; 561#endif 562 for (;;) 563 { 564#ifndef DO_NOT_POLL_MASTER 565 signal(SIGALRM, AttacherSigAlarm); 566 alarm(15); 567 pause(); 568 alarm(0); 569 if (kill(MasterPid, 0) < 0 && errno != EPERM) 570 { 571 debug1("attacher: Panic! MasterPid %d does not exist.\n", MasterPid); 572 AttacherPanic++; 573 } 574#else 575 pause(); 576#endif 577#if defined(DEBUG) || !defined(DO_NOT_POLL_MASTER) 578 if (AttacherPanic) 579 { 580 fcntl(0, F_SETFL, 0); 581 SetTTY(0, &attach_Mode); 582 printf("\nSuddenly the Dungeon collapses!! - You die...\n"); 583 eexit(1); 584 } 585#endif 586#ifdef BSDJOBS 587 if (SuspendPlease) 588 { 589 SuspendPlease = 0; 590#if defined(MULTIUSER) && !defined(USE_SETEUID) 591 if (multiattach) 592 exit(SIG_STOP); 593#endif 594 signal(SIGTSTP, SIG_DFL); 595 debug("attacher: killing myself SIGTSTP\n"); 596 kill(getpid(), SIGTSTP); 597 debug("attacher: continuing from stop\n"); 598 signal(SIG_STOP, SigStop); 599 (void) Attach(MSG_CONT); 600 } 601#endif 602#ifdef LOCK 603 if (LockPlease) 604 { 605 LockPlease = 0; 606#if defined(MULTIUSER) && !defined(USE_SETEUID) 607 if (multiattach) 608 exit(SIG_LOCK); 609#endif 610 LockTerminal(); 611# ifdef SYSVSIGS 612 signal(SIG_LOCK, DoLock); 613# endif 614 (void) Attach(MSG_CONT); 615 } 616#endif /* LOCK */ 617#if defined(SIGWINCH) && defined(TIOCGWINSZ) 618 if (SigWinchPlease) 619 { 620 SigWinchPlease = 0; 621# ifdef SYSVSIGS 622 signal(SIGWINCH, AttacherWinch); 623# endif 624 (void) Attach(MSG_WINCH); 625 } 626#endif /* SIGWINCH */ 627 } 628} 629 630#ifdef LOCK 631 632/* ADDED by Rainer Pruy 10/15/87 */ 633/* POLISHED by mls. 03/10/91 */ 634 635static char LockEnd[] = "Welcome back to screen !!\n"; 636 637static sigret_t 638LockHup SIGDEFARG 639{ 640 int ppid = getppid(); 641 setgid(real_gid); 642#ifdef MULTIUSER 643 setuid(own_uid); 644#else 645 setuid(real_uid); 646#endif 647 if (ppid > 1) 648 Kill(ppid, SIGHUP); 649 exit(0); 650} 651 652static void 653LockTerminal() 654{ 655 char *prg; 656 int sig, pid; 657 sigret_t (*sigs[NSIG])__P(SIGPROTOARG); 658 659 for (sig = 1; sig < NSIG; sig++) 660 sigs[sig] = signal(sig, sig == SIGCHLD ? SIG_DFL : SIG_IGN); 661 signal(SIGHUP, LockHup); 662 printf("\n"); 663 664 prg = getenv("LOCKPRG"); 665 if (prg && strcmp(prg, "builtin") && !access(prg, X_OK)) 666 { 667 signal(SIGCHLD, SIG_DFL); 668 debug1("lockterminal: '%s' seems executable, execl it!\n", prg); 669 if ((pid = fork()) == 0) 670 { 671 /* Child */ 672 setgid(real_gid); 673#ifdef MULTIUSER 674 setuid(own_uid); 675#else 676 setuid(real_uid); /* this should be done already */ 677#endif 678 closeallfiles(0); /* important: /etc/shadow may be open */ 679 execl(prg, "SCREEN-LOCK", NULL); 680 exit(errno); 681 } 682 if (pid == -1) 683 Msg(errno, "Cannot lock terminal - fork failed"); 684 else 685 { 686#ifdef BSDWAIT 687 union wait wstat; 688#else 689 int wstat; 690#endif 691 int wret; 692 693#ifdef hpux 694 signal(SIGCHLD, SIG_DFL); 695#endif 696 errno = 0; 697 while (((wret = wait(&wstat)) != pid) || 698 ((wret == -1) && (errno == EINTR)) 699 ) 700 errno = 0; 701 702 if (errno) 703 { 704 Msg(errno, "Lock"); 705 sleep(2); 706 } 707 else if (WTERMSIG(wstat) != 0) 708 { 709 fprintf(stderr, "Lock: %s: Killed by signal: %d%s\n", prg, 710 WTERMSIG(wstat), WIFCORESIG(wstat) ? " (Core dumped)" : ""); 711 sleep(2); 712 } 713 else if (WEXITSTATUS(wstat)) 714 { 715 debug2("Lock: %s: return code %d\n", prg, WEXITSTATUS(wstat)); 716 } 717 else 718 printf(LockEnd); 719 } 720 } 721 else 722 { 723 if (prg) 724 { 725 debug1("lockterminal: '%s' seems NOT executable, we use our builtin\n", prg); 726 } 727 else 728 { 729 debug("lockterminal: using buitin.\n"); 730 } 731 screen_builtin_lck(); 732 } 733 /* reset signals */ 734 for (sig = 1; sig < NSIG; sig++) 735 { 736 if (sigs[sig] != (sigret_t(*)__P(SIGPROTOARG)) -1) 737 signal(sig, sigs[sig]); 738 } 739} /* LockTerminal */ 740 741#ifdef USE_PAM 742 743/* 744 * PAM support by Pablo Averbuj <pablo@averbuj.com> 745 */ 746 747#include <security/pam_appl.h> 748 749static int PAM_conv __P((int, const struct pam_message **, struct pam_response **, void *)); 750 751static int 752PAM_conv(num_msg, msg, resp, appdata_ptr) 753int num_msg; 754const struct pam_message **msg; 755struct pam_response **resp; 756void *appdata_ptr; 757{ 758 int replies = 0; 759 struct pam_response *reply = NULL; 760 761 reply = malloc(sizeof(struct pam_response)*num_msg); 762 if (!reply) 763 return PAM_CONV_ERR; 764 #define COPY_STRING(s) (s) ? strdup(s) : NULL 765 766 for (replies = 0; replies < num_msg; replies++) 767 { 768 switch (msg[replies]->msg_style) 769 { 770 case PAM_PROMPT_ECHO_OFF: 771 /* wants password */ 772 reply[replies].resp_retcode = PAM_SUCCESS; 773 reply[replies].resp = appdata_ptr ? strdup((char *)appdata_ptr) : 0; 774 break; 775 case PAM_TEXT_INFO: 776 /* ignore the informational mesage */ 777 /* but first clear out any drek left by malloc */ 778 reply[replies].resp = NULL; 779 break; 780 case PAM_PROMPT_ECHO_ON: 781 /* user name given to PAM already */ 782 /* fall through */ 783 default: 784 /* unknown or PAM_ERROR_MSG */ 785 free(reply); 786 return PAM_CONV_ERR; 787 } 788 } 789 *resp = reply; 790 return PAM_SUCCESS; 791} 792 793static struct pam_conv PAM_conversation = { 794 &PAM_conv, 795 NULL 796}; 797 798 799#endif 800 801/* -- original copyright by Luigi Cannelloni 1985 (luigi@faui70.UUCP) -- */ 802static void 803screen_builtin_lck() 804{ 805 char fullname[100], *cp1, message[100 + 100]; 806#ifdef USE_PAM 807 pam_handle_t *pamh = 0; 808 int pam_error; 809#else 810 char *pass, mypass[16 + 1], salt[3]; 811#endif 812 813#ifndef USE_PAM 814 pass = ppp->pw_passwd; 815 if (pass == 0 || *pass == 0) 816 { 817 if ((pass = getpass("Key: "))) 818 { 819 strncpy(mypass, pass, sizeof(mypass) - 1); 820 mypass[sizeof(mypass) - 1] = 0; 821 if (*mypass == 0) 822 return; 823 if ((pass = getpass("Again: "))) 824 { 825 if (strcmp(mypass, pass)) 826 { 827 fprintf(stderr, "Passwords don't match.\007\n"); 828 sleep(2); 829 return; 830 } 831 } 832 } 833 if (pass == 0) 834 { 835 fprintf(stderr, "Getpass error.\007\n"); 836 sleep(2); 837 return; 838 } 839 840 salt[0] = 'A' + (int)(time(0) % 26); 841 salt[1] = 'A' + (int)((time(0) >> 6) % 26); 842 salt[2] = 0; 843 pass = crypt(mypass, salt); 844 pass = ppp->pw_passwd = SaveStr(pass); 845 } 846#endif 847 848 debug("screen_builtin_lck looking in gcos field\n"); 849 strncpy(fullname, ppp->pw_gecos, sizeof(fullname) - 9); 850 fullname[sizeof(fullname) - 9] = 0; 851 852 if ((cp1 = index(fullname, ',')) != NULL) 853 *cp1 = '\0'; 854 if ((cp1 = index(fullname, '&')) != NULL) 855 { 856 strncpy(cp1, ppp->pw_name, 8); 857 cp1[8] = 0; 858 if (*cp1 >= 'a' && *cp1 <= 'z') 859 *cp1 -= 'a' - 'A'; 860 } 861 862 sprintf(message, "Screen used by %s <%s>.\nPassword:\007", 863 fullname, ppp->pw_name); 864 865 /* loop here to wait for correct password */ 866 for (;;) 867 { 868 debug("screen_builtin_lck awaiting password\n"); 869 errno = 0; 870 if ((cp1 = getpass(message)) == NULL) 871 { 872 AttacherFinit(SIGARG); 873 /* NOTREACHED */ 874 } 875#ifdef USE_PAM 876 PAM_conversation.appdata_ptr = cp1; 877 pam_error = pam_start("screen", ppp->pw_name, &PAM_conversation, &pamh); 878 if (pam_error != PAM_SUCCESS) 879 AttacherFinit(SIGARG); /* goodbye */ 880 pam_error = pam_authenticate(pamh, 0); 881 pam_end(pamh, pam_error); 882 PAM_conversation.appdata_ptr = 0; 883 if (pam_error == PAM_SUCCESS) 884 break; 885#else 886 if (!strncmp(crypt(cp1, pass), pass, strlen(pass))) 887 break; 888#endif 889 debug("screen_builtin_lck: NO!!!!!\n"); 890 bzero(cp1, strlen(cp1)); 891 } 892 bzero(cp1, strlen(cp1)); 893 debug("password ok.\n"); 894} 895 896#endif /* LOCK */ 897 898 899void 900SendCmdMessage(sty, match, av) 901char *sty; 902char *match; 903char **av; 904{ 905 int i, s; 906 struct msg m; 907 char *p; 908 int len, n; 909 910 if (sty == 0) 911 { 912 i = FindSocket(&s, (int *)0, (int *)0, match); 913 if (i == 0) 914 Panic(0, "No screen session found."); 915 if (i != 1) 916 Panic(0, "Use -S to specify a session."); 917 } 918 else 919 { 920#ifdef NAME_MAX 921 if (strlen(sty) > NAME_MAX) 922 sty[NAME_MAX] = 0; 923#endif 924 if (strlen(sty) > 2 * MAXSTR - 1) 925 sty[2 * MAXSTR - 1] = 0; 926 sprintf(SockPath + strlen(SockPath), "/%s", sty); 927 if ((s = MakeClientSocket(1)) == -1) 928 exit(1); 929 } 930 bzero((char *)&m, sizeof(m)); 931 m.type = MSG_COMMAND; 932 if (attach_tty) 933 { 934 strncpy(m.m_tty, attach_tty, sizeof(m.m_tty) - 1); 935 m.m_tty[sizeof(m.m_tty) - 1] = 0; 936 } 937 p = m.m.command.cmd; 938 n = 0; 939 for (; *av && n < MAXARGS - 1; ++av, ++n) 940 { 941 len = strlen(*av) + 1; 942 if (p + len >= m.m.command.cmd + sizeof(m.m.command.cmd) - 1) 943 break; 944 strcpy(p, *av); 945 p += len; 946 } 947 *p = 0; 948 m.m.command.nargs = n; 949 strncpy(m.m.attach.auser, LoginName, sizeof(m.m.attach.auser) - 1); 950 m.m.command.auser[sizeof(m.m.command.auser) - 1] = 0; 951 m.protocol_revision = MSG_REVISION; 952 strncpy(m.m.command.preselect, preselect ? preselect : "", sizeof(m.m.command.preselect) - 1); 953 m.m.command.preselect[sizeof(m.m.command.preselect) - 1] = 0; 954 m.m.command.apid = getpid(); 955 debug1("SendCommandMsg writing '%s'\n", m.m.command.cmd); 956 if (WriteMessage(s, &m)) 957 Msg(errno, "write"); 958 close(s); 959} 960