rsalz@bbn.com (Rich Salz) (10/10/90)
Submitted-by: Dan Bernstein <brnstnd@kramden.acf.nyu.edu> Posting-number: Volume 23, Issue 34 Archive-name: pty/part04 #! /bin/sh # This is a shell archive. Remove anything before this line, then feed it # into a shell via "sh file" or similar. To overwrite existing files, # type "sh file -c". # The tool that generated this appeared in the comp.sources.unix newsgroup; # send mail to comp-sources-unix@uunet.uu.net if you want that tool. # Contents: COPYRIGHT QUESTIONS TESTS patch/Makefile patch/README # sig.c slave.c texts.c util/biff.c util/sesslist.c util/sessuser.1 # util/sessuser.c util/sessutil.c util/write.c util/xsessutil.c # Wrapped by rsalz@litchi.bbn.com on Wed Oct 10 10:11:39 1990 PATH=/bin:/usr/bin:/usr/ucb ; export PATH echo If this archive is complete, you will see the following message: echo ' "shar: End of archive 4 (of 6)."' if test -f 'COPYRIGHT' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'COPYRIGHT'\" else echo shar: Extracting \"'COPYRIGHT'\" \(2129 characters\) sed "s/^X//" >'COPYRIGHT' <<'END_OF_FILE' Xpty version 3.001, August 21, 1990. XCopyright (c) 1990, Daniel J. Bernstein. XAll rights reserved. X XI want this program to be distributed freely in original form. X XOnce you've received a legal copy of this program, you can use it. XForever. Nobody can take that right away from you. You can make changes Xand backup copies for your use (or, if you're an organization, for the Xuse of everyone in the organization). You can distribute patches (though Xnot patched versions). You'd have all these rights even if I didn't tell Xyou about them. X XCopyright law gives an author the exclusive right to copy and distribute his Xworks. So that you don't have to worry about these legalities, I grant you the Xright to make and distribute exact and complete copies of this program. X XOn the other hand, I don't want this program sold without my permission. XUnless I give you permission, you may not charge for copies. You may charge for Xdistribution---but only if you first warn the recipient that the code is free, Xand tell him where you got it from. X XI don't want this program distributed without my name on it. I also don't Xwant lots of different versions running around, so unless I give you permission Xyou can't send out a modified version. It's perfectly all right to send other Xpeople a description of how to make your changes (i.e., a patch), because then Xeach recipient knows firsthand what patches he's installed, and I won't go Xchasing ghosts. (An author has no right to control patches in any case.) X XIf you run an archive site: When you receive a patch supposedly from me, do you Xapply it to the original package and repackage it? I encourage you to change Xyour policy, if for no other reason than to give recipients a fallback in case Xof buggy patches. If you're really set on this, how about including the patches Xas separate, unapplied PATCHnn files inside the package? That's fine by me. X XIf you have questions about this program or about this notice, or if you Xwould like additional rights beyond those granted above, or if you have Xa patch that you don't mind sharing, please contact me on the Internet Xat brnstnd@acf10.nyu.edu. END_OF_FILE if test 2129 -ne `wc -c <'COPYRIGHT'`; then echo shar: \"'COPYRIGHT'\" unpacked with wrong size! fi # end of 'COPYRIGHT' fi if test -f 'QUESTIONS' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'QUESTIONS'\" else echo shar: Extracting \"'QUESTIONS'\" \(4202 characters\) sed "s/^X//" >'QUESTIONS' <<'END_OF_FILE' XI selected the questions below from articles posted to the USENET Xnewsgroup comp.unix.questions. All the questions are reasonably easy to Xanswer with pty and not too easy to answer with other widely available Xtools. So I hope this file is useful, and I hope other software authors Xadopt the QUESTIONS idea. X XOrganization: question, one-sentence answer, further details of Xanswer, why the question normally poses a problem, and why the answer Xgiven solves the problem. X X X1. How to redirect telnet's input? X XRun pty telnet instead of telnet. Caveat: telnet stupidly flushes its Xinput at connect time, so be careful not to flood it; instead do Xsomething like % (sleep 5;echo help;echo quit) | pty telnet whatever 25. X(Try it!) The five-second pause should be enough. For a more Xsophisticated (and reliable) technique, see #4 below. X XThe problem here is that telnet wants to take its input from a terminal. XMost other interactive applications (e.g., editors) feel the same way Xabout stdin, stdout, and stderr. pty solves this by setting input, Xoutput, and error all to the pseudo-terminal. X X X2. How to redirect su's input? X Xpty su < input, of course. (I certainly don't recommend putting your Xpassword in plaintext to be fed to su, but it can be done!) Note that Xsome su's flush their input; solve this as in #1 above or #4 below. X XThe problem is that su opens /dev/tty for its input. Many other programs Xuse /dev/tty explicitly for input and output; how do you redirect them? Xpty solves this because a program under a pseudo-terminal refers to that Xterminal when it opens /dev/tty. X X X3. How to make sed 's/foo/bar/g' | more work? X Xpty -0 sed 's/foo/bar/g' | more. You can abbreviate pty -0 as condom. X XThe problem is that sed uses stdio. stdio checks whether its output is a Xterminal; if not, it buffers a block of data inside the program. To see Xthis in action, try the original % sed 's/foo/bar/g' | more; unless you Xtype a lot of input, sed will keep buffering its output, so you'll never Xsee anything. X Xpty solves the stdio buffer problem because a program under stdio does Xhave a terminal (the pseudo-terminal) as output. So stdio buffers only a Xline at a time. X X X4. How to start a program, respond to its prompts, give the correct X replies, and catch the output? X XOn a machine with named pipes created by mknod foo p: X X #!/bin/sh X # Generic reader-writer. X (umask 077;mknod input p;mknod output p) X pty -0 program args < input | pty -0 tee record > output & X exec 4>input 5<output X # Now read prompts from <&5 and write replies to >&4. X # A transcript is kept in record. X XAnother solution is to create two (unnamed) pipes, then stick pty Xbetween them as above. This requires C code but is more portable. X XThe problems here are just the problems in #1-#3 above. X X X5. How to fool rn into processing KILL files in the background? X Xpty -T rn &. This does have one deficiency: control characters like ^C, X^Z, and so on affect pty rather than rn. (That's what -T does.) This Xdoesn't matter for rn, but pty -T vi verylongfile definitely doesn't Xwork the right way. To pass control characters through, start with X X % pty -s sh -c 'sessname;disconnect;pty vi verylongfile' X X(pty -s can be abbreviated as sess.) Then watch the vi process with ps Xor by typing pty -sT reconnect xx, watching, then pressing ^C, where xx Xis the session name (pty extension). When you want to reconnect and pass Xcontrol characters to vi, type % pty -s reconnect xx. From that point Xit'll feel just like a normal vi. X XThe problem is that rn---like all character-based interactive Xapplications---wants to change the tty mode to read one character at a Xtime instead of one line at a time. The tty driver doesn't let it do Xthis in the background. pty -T rn solves this because rn is really in Xthe foreground under the pty. X X X6. How to get terminal speed from shell script? X X"`pty stty speed`", assuming fd 0 or fd 2 is the tty. X XThe problem is that a straight `stty speed` pipes stty's output away Xfrom your terminal and back into your shell. Many versions of stty Xassume that their output points to the terminal, so they blow up. pty Xsolves this because it copies information from the real terminal to the Xpseudo-terminal. END_OF_FILE if test 4202 -ne `wc -c <'QUESTIONS'`; then echo shar: \"'QUESTIONS'\" unpacked with wrong size! fi # end of 'QUESTIONS' fi if test -f 'TESTS' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'TESTS'\" else echo shar: Extracting \"'TESTS'\" \(3657 characters\) sed "s/^X//" >'TESTS' <<'END_OF_FILE' X#!/bin/sh X# This is a shell script. Feed it to sh. Xecho ' XHi, and welcome to the pty test script. X XAs in installation, I'\''m not actually going to do anything. XI'\''ll just guide you through a few (non-comprehensive) tests. X XRemember: Like all software, pty comes without warranty, to the extent Xpermitted by applicable law. Use it at your own risk. X' X Xecho '----- Press return to continue. ' | tr -d '\012'; read contline X Xecho ' XFirst, just try % pty vi. You shouldn'\''t be able to tell the Xdifference between this and a normal vi; stopping and restarting should Xwork perfectly, as should normal typing. X' X Xecho '----- Press return to continue. ' | tr -d '\012'; read contline X Xecho ' XNext, try % pty -0 tr \! \? | pty vi. This should work just like the Xlast vi, with the following differences: 1. Stopping will require two X^Zs, because csh idiotically doesn'\''t think a pipeline has stopped Xwhen just its second component stops. 2. Exiting will require an extra Xline to feed through tr, so that it gets a broken pipe; this is more Xsensible than #1. 3. All exclamation points will be turned into question Xmarks. This has obvious applications. :w /dev/null helps to escape. X' X Xecho '----- Press return to continue. ' | tr -d '\012'; read contline X Xecho ' XContinuing along the lines of how to stick annoying programs into a Xpipe, try % pty -0 sed '\''s/foo/bar/g'\'' | more. (Remember that sed outputs Xeach line only after it receives the next.) Try the same thing without Xpty. X XNote that pty -0 can be abbreviated as condom. X' X Xecho '----- Press return to continue. ' | tr -d '\012'; read contline X Xecho ' XNext, try using the replacement script program. % script. Type various Xcommands; try logging on to another terminal and using talk; observe Xthat you'\''re listed in /etc/utmp. Try the clones of tty, mesg, biff, Xu, wall, who, lock. (Try them under a non-pty session too.) X' X Xecho '----- Press return to continue. ' | tr -d '\012'; read contline X Xecho ' XMuch of the fun of pty is in disconnecting and reconnecting sessions. XIf you'\''re ambitious, try % sess sh. ^Z will get you out and back in. XTry sessname without an argument; try it with an argument. Try sesslist. XFinally, try $ disconnect, and go on to the next part of this script. X' X Xecho '----- Press return to continue. ' | tr -d '\012'; read contline X Xecho ' XAlthough it looks like your sh session has finished, it'\''s actually Xsitting in limbo, waiting for you to reconnect. You can still see it Xunder who, sesslist, or ps. Now try % sess reconnect q7 or whatever the Xextension of the disconnected session is; you should be right back in. X XYou can try the same thing by actually hanging up your connection, then Xlogging in again and reconnecting. X' X Xecho '----- Press return to continue. ' | tr -d '\012'; read contline X Xecho ' XFor one final trick, X% sess sh X$ PS1=FOO.; disconnect X% sess sh X$ sesslist X... X$ PS1=BAR.; reconnect q7; disconnect XFOO.reconnect p4; disconnect XBAR.reconnect q7; disconnect XFOO.echo Neat, flipping right back and forth! X' X Xecho '----- Press return to continue. ' | tr -d '\012'; read contline X Xecho ' XThat'\''s it! Make sure the manual pages and programs are easily Xaccessible. To repeat a note from INSTALL: X XIf you make it through installation and testing and get pty running, Xplease send a note to the author, Dan Bernstein, on the Internet Xat brnstnd@nyu.edu. Let him know your computer model, OS version, and Xwhat changes you had to make. If you have any trouble, please also get Xin touch with the author. If you have a different kind of system with Xpseudo-terminal support that could use a pty port, the author would Xlove to hear about it. X XThanks! X' END_OF_FILE if test 3657 -ne `wc -c <'TESTS'`; then echo shar: \"'TESTS'\" unpacked with wrong size! fi # end of 'TESTS' fi if test -f 'patch/Makefile' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'patch/Makefile'\" else echo shar: Extracting \"'patch/Makefile'\" \(2813 characters\) sed "s/^X//" >'patch/Makefile' <<'END_OF_FILE' Xtpat: tpat1 X Xtpat1: igntt X echo '1. Get the new telnetd from ucbarpa.berkeley.edu:' 1>&2 X echo 'This command will retrieve telnet.90.06.28.tar.Z.' 1>&2 X echo 'To execute it, just press return.' 1>&2 X echo 'To continue, just make tpat2 > /dev/null.' 1>&2 X ./igntt tiocsti 'ftp -n 128.32.130.11 < TELNET.FTP' X Xtpat2: igntt X echo '2. Unpack telnetd:' 1>&2 X echo 'This is self-explanatory. You may want tar xvf to see a file list.' 1>&2 X echo 'To continue, just make tpat3 > /dev/null.' 1>&2 X if test -f telnet.90.06.28.tar.Z ;\ X then ./igntt tiocsti 'uncompress < telnet.90.06.28.tar.Z | tar xf -' ;\ X else echo 'Aack! telnet.90.06.28.tar.Z doesn'\''t exist!' ;\ X fi X Xtpat3: igntt X echo '3. Apply these patches, and check that they'\''re safe:' 1>&2 X echo 'If all goes well, you should see a flood of successful patch output.' 1>&2 X echo 'The unifdefs are to check the safety of the patches;' 1>&2 X echo 'as you will see, the patches do nothing with USEPTY undefined.' 1>&2 X echo 'To continue, just make tpat4 > /dev/null.' 1>&2 X if test -d telnet.90.06.28 ;\ X then ./igntt tiocsti 'cd telnet.90.06.28/telnetd; ' \ X 'patch < ../../telnetd.90.06.28.patch; ' \ X 'unifdef -UUSEPTY sys_term.c | cmp - sys_term.c.orig; ' \ X 'unifdef -UUSEPTY telnetd.c | cmp - telnetd.c.orig; ' \ X 'unifdef -UUSEPTY pathnames.h | cmp - pathnames.h.orig; ' \ X 'cd ../..' ;\ X fi X Xtpat4: igntt X echo '4. Check the pty pathname and fix it if necessary:' 1>&2 X echo 'Since there is no standard like /inst for where programs go,' 1>&2 X echo 'you had better make sure telnetd's pathnames.h is correct.' 1>&2 X echo 'To continue, just make tpat5 > /dev/null.' 1>&2 X ./igntt tiocsti 'grep PATH_PTY telnet.90.06.28/telnetd/pathnames.h' X Xtpat5: igntt X echo '5. Add sock.o and sock.h symlinks:' 1>&2 X echo 'This is self-explanatory.' 1>&2 X echo 'To continue, just make tpat6 > /dev/null.' 1>&2 X ./igntt tiocsti 'ln -s ../../../sock.{h,o} telnet.90.06.28/telnetd' X Xtpat6: igntt X echo '6. Preparing for compile: Edit Makefile and Makefile.generic.' 1>&2 X echo 'You must at least add -DUSEPTY to CFLAGS and sock.o to OBJS' 1>&2 X echo 'in Makefile.generic.' 1>&2 X echo 'telnetd isn'\''t too high on the portability scale, so you' 1>&2 X echo 'may have to make quite a few more changes.' 1>&2 X echo 'Anyway, make tpat7 > /dev/null to continue.' 1>&2 X ./igntt tiocsti 'vi telnet.90.06.28/telnetd/Makefile.generic' X Xtpat7: igntt X echo '7. Compile!' 1>&2 X echo 'As explained in the telnetd source documentation, you have' 1>&2 X echo 'to provide the machine name to make. Under SunOS 4.0.3,' 1>&2 X echo 'you can just press return here.' 1>&2 X echo 'When and if this succeeds, go to step 8 of README.' 1>&2 X ./igntt tiocsti '( cd telnet.90.06.28/telnetd; (date;make sun4.0) >>&Makelog ) &' X Xigntt: igntt.c X cc -o igntt igntt.c END_OF_FILE if test 2813 -ne `wc -c <'patch/Makefile'`; then echo shar: \"'patch/Makefile'\" unpacked with wrong size! fi # end of 'patch/Makefile' fi if test -f 'patch/README' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'patch/README'\" else echo shar: Extracting \"'patch/README'\" \(4777 characters\) sed "s/^X//" >'patch/README' <<'END_OF_FILE' XAt the moment, the only thing here is telnetd.90.06.28.patch. It's Xpublic domain. X Xtelnetd.90.06.28.patch is a safe patch to the telnetd source in Xtelnet.90.06.28 on ucbarpa.berkeley.edu (128.32.130.11). ``Safe'' means Xthat every file compiles exactly the same if USEPTY is not defined; Xyou can apply the patch without any worry of messing up your source. X XWhat follows is an outline of how to apply the patch and enable it. A Xpatched telnetd uses pty to manage sessions, so that users can easily Xdisconnect and reconnect login sessions. You *must* have compiled file Xdescriptor passing into pty for this to work; telnetd needs to get the Xpseudo-terminal descriptors from pty. Given fd passing, though, the Xpatched telnetd gives you the *full* efficiency of the unpatched Xversion, even for reconnected sessions! X X XHere's what to do. If you have the tiocsti utility installed, try X``make > /dev/null'' in this directory; or just read through these Xinstructions. The usual warning: Like all software, this comes with Xall warranties disclaimed, to the extent permitted by applicable law. X X X1. Get the new telnetd: X X % ftp -n 128.32.130.11 < TELNET.FTP X X2. Unpack it: X X % uncompress < telnet.90.06.28.tar.Z | tar xf - X X3. Apply these patches, and check that they're safe: X X % cd telnet.90.06.28/telnetd X % patch < ../../telnetd.90.06.28.patch X % unifdef -UUSEPTY sys_term.c | cmp - sys_term.c.orig X % unifdef -UUSEPTY telnetd.c | cmp - telnetd.c.orig X % unifdef -UUSEPTY pathnames.h | cmp - pathnames.h.orig X % cd ../.. X X4. Check the pty pathname and fix it if necessary: X X % grep PATH_PTY telnet.90.06.28/telnetd/pathnames.h X X5. Add sock.o and sock.h symlinks: X X % ( cd telnet.90.06.28/telnetd; ln -s ../../../sock.{o,h} . ) X X6. When you want to compile the patched version: Add sock.o to OBJS X and -DUSEPTY to CCOPTS in Makefile.generic. Change whatever else X necessary to get telnetd to compile. X X7. Compile! On a Sun 4 under SunOS 4.0.3, for example, you just X ``make sun4.0'' in the telnetd directory. X X8. If you actually survive telnetd's incompatibilities and get it to X compile, keep reading. X X XThe reason this telnetd is so big is that it supports Linemode, a bold Xattempt to cut the Internet load from all the fast typists in the world Xby a third or even a half. X XIf you're bored, compile the telnet client as well. X X XAnyway, the telnetd you just compiled supports pty. You probably don't Xwant to replace your original telnetd, because if something goes wrong Xthen you need to log in again. Also, your telnetd may have special Xfeatures for your machine. Instead, take the gradual upgrade path: Put Xtelnetd into /usr/local/telnetd.pty, add a new ``tpt'' port to X/etc/services, and add this line to /etc/inetd.conf: X Xtpt stream tcp nowait root /usr/local/telnetd.pty telnetd X X(On older machines, ``root'' wouldn't be there; imitate the telnet line Xto figure out the right format. If you have the better interface of Xattachport, use it instead.) kill -HUP the inetd process so that it will Xreread inetd.conf. X X XNow try connecting to the tpt port rather than 23 (instead of telnet X, Xdo telnet X tpt). You should end up talking to the new telnetd, a clean Xlogin, and (best of all) a pty session. (The most common problem: Lines Xdon't appear until after you press return. This means that your old Xtelnet doesn't support Linemode; type ``^]mo ch'' to fix it. Also send Xcomplaints about the incompatibilities to dab@cray.com.) If the Xconnection hangs for more than a second or produces weird results, Xyou're probably out of luck; pty's author would appreciate hearing about Xyour experiences. X XIf all goes well (whew!) you can log in normally, just as if you're Xconnected to the old telnetd. Once you're in a shell, try using the pty Xutilities, as if you were under sess. You should find that the commands Xfail unless you're root, because that session was started by root rather Xthan you. (This points out a failure in the telnetd-login-utmp model.) XTo gain control of the session, type ``sessuser'' and pray. If nothing Xgoes wrong, you can then disconnect the session, set up a reconnect to Xanother one, use sessname and sesslist, etc. Yahoo! Tell your users! XReplace your old telnetd with the new one! Add sessuser to the default X.cshrc! And please send a note to brnstnd@nyu.edu about your success. X X XNote that many popular versions of login use an annoying heuristic to Xsave a few microseconds in updating /etc/utmp. The result is, first, Xthat there's a race condition that can break down /etc/utmp on heavily Xloaded machines; and second, that login and pty have different views of X/etc/utmp. For this reason, pty is invoked with -xR to search for ptys Xin order. You may even want to make -xR default (by setting flagxrandom Xto 0 in pty's globals.c). Sigh. END_OF_FILE if test 4777 -ne `wc -c <'patch/README'`; then echo shar: \"'patch/README'\" unpacked with wrong size! fi # end of 'patch/README' fi if test -f 'sig.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'sig.c'\" else echo shar: Extracting \"'sig.c'\" \(4549 characters\) sed "s/^X//" >'sig.c' <<'END_OF_FILE' X/* Copyright 1990, Daniel J. Bernstein. All rights reserved. */ X X#include "config.h" X#include <sys/time.h> X#include "sig.h" X X/* This is a stripped-down signal library, with automatic critical */ X/* sections around every signal handler. As long as no signal handler */ X/* has to pause waiting for another signal, this works beautifully */ X/* and prevents all races. */ X Xstatic int queued[SIGNUM]; Xstatic int quo[SIGNUM]; Xstatic sig_syshandler orig[SIGNUM]; Xstatic sig_handler handler[SIGNUM]; X Xstatic sig_syshandler signalv(s,h) Xregister sig_num s; Xregister sig_syshandler h; X{ X return signal(s,h); X} X Xstatic int crit = 0; X Xstatic void handle(i) Xregister sig_num i; X{ X if (crit) X queued[i] = 1; X else X { X register int q; X register sig_num j; X X crit = 1; (void) handler[i](i); queued[i] = 0; crit = 0; X do for (j = q = 0;j < SIGNUM;j++) if (queued[j]) X { X crit = q = 1; X if (j != i) (void) handler[j](j); X queued[j] = 0; crit = 0; X } X while (q); X } X} X X/* To see why handle() works: First, crit can be considered a local Xvariable, because handle() is the only routine that modifies it, and Xhandle() always leaves crit the same. Second, crit is 1 while any Xhandler is called, and then any simultaneous handle()s will simply Xqueue. Hence handlers are mutually exclusive. Third, when handle() is Xcalled with crit == 0, it can only exit after going through an entire j Xloop with no queued[]s true. Fourth, if all queued[]s are false through Xthat j loop, then crit is not set by handle() during that loop. Finally, Xif crit is 0, handle() will exit with no queued signals: this is true by Xinduction from the previous observations. */ X X X/* There is unfortunately no guarantee that a signal handler as */ X/* passed to signal() will receive its signal number as its first */ X/* argument. We do make that guarantee. */ X X#define HAN(s,h) SIGRET_TYPE h() { handle(s); } X XHAN(0,han0); HAN(1,han1); HAN(2,han2); HAN(3,han3); XHAN(4,han4); HAN(5,han5); HAN(6,han6); HAN(7,han7); XHAN(8,han8); HAN(9,han9); HAN(10,han10); HAN(11,han11); XHAN(12,han12); HAN(13,han13); HAN(14,han14); HAN(15,han15); XHAN(16,han16); HAN(17,han17); HAN(18,han18); HAN(19,han19); XHAN(20,han20); HAN(21,han21); HAN(22,han22); HAN(23,han23); XHAN(24,han24); HAN(25,han25); HAN(26,han26); HAN(27,han27); XHAN(28,han28); HAN(29,han29); HAN(30,han30); HAN(31,han31); X Xstatic sig_syshandler han[32] = X { han0 ,han1 ,han2 ,han3 ,han4 ,han5 ,han6 ,han7 , X han8 ,han9 ,han10,han11,han12,han13,han14,han15, X han16,han17,han18,han19,han20,han21,han22,han23, X han24,han25,han26,han27,han28,han29,han30,han31 X } ; X X#define QUE(s,h) SIGRET_TYPE h() { quo[s] = 1; } X XQUE(0,que0); QUE(1,que1); QUE(2,que2); QUE(3,que3); XQUE(4,que4); QUE(5,que5); QUE(6,que6); QUE(7,que7); XQUE(8,que8); QUE(9,que9); QUE(10,que10); QUE(11,que11); XQUE(12,que12); QUE(13,que13); QUE(14,que14); QUE(15,que15); XQUE(16,que16); QUE(17,que17); QUE(18,que18); QUE(19,que19); XQUE(20,que20); QUE(21,que21); QUE(22,que22); QUE(23,que23); XQUE(24,que24); QUE(25,que25); QUE(26,que26); QUE(27,que27); XQUE(28,que28); QUE(29,que29); QUE(30,que30); QUE(31,que31); X Xstatic sig_syshandler que[32] = X { que0 ,que1 ,que2 ,que3 ,que4 ,que5 ,que6 ,que7 , X que8 ,que9 ,que10,que11,que12,que13,que14,que15, X que16,que17,que18,que19,que20,que21,que22,que23, X que24,que25,que26,que27,que28,que29,que30,que31 X } ; X X Xvoid sig_init() X{ X sig_num i; X X for (i = 0;i < SIGNUM;i++) X quo[i] = 0; X for (i = 0;i < SIGNUM;i++) X orig[i] = signalv(i,que[i]); X} X Xvoid sig_restore() X{ X sig_num i; X X for (i = 0;i < SIGNUM;i++) X (void) signalv(i,orig[i]); X} X Xvoid sig_handle(s) Xsig_num s; X{ X if (quo[s]) X han[s](); X (void) signalv(s,han[s]); X quo[s] = 0; X} X Xvoid sig_ignore(s) Xsig_num s; X{ X (void) signalv(s,SIG_IGN); X} X Xvoid sig_default(s) Xsig_num s; X{ X (void) signalv(s,SIG_DFL); X} X Xvoid sig_sethandler(s,h) Xsig_num s; Xsig_handler h; X{ X handler[s] = h; X} X X#ifdef SIGINTERRUPT Xvoid sig_interrupt() X{ X register sig_num s; X X for (s = 0;s < SIGNUM;s++) X (void) siginterrupt(s,1); X} X#endif X Xvoid sig_startring() X{ X struct itimerval it; X X it.it_value.tv_sec = it.it_interval.tv_sec = 0; X it.it_value.tv_usec = it.it_interval.tv_usec = 10000; X (void) setitimer(ITIMER_REAL,&it,(struct itimerval *) 0); X} X Xvoid sig_stopring() X{ X struct itimerval it; X X it.it_value.tv_sec = it.it_interval.tv_sec = 0; X it.it_value.tv_usec = it.it_interval.tv_usec = 0; X (void) setitimer(ITIMER_REAL,&it,(struct itimerval *) 0); X} X X/*ARGSUSED*/ Xvoid nothing(i) Xsig_num i; X{ X ; /* that's right, absolutely nothing. */ X} END_OF_FILE if test 4549 -ne `wc -c <'sig.c'`; then echo shar: \"'sig.c'\" unpacked with wrong size! fi # end of 'sig.c' fi if test -f 'slave.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'slave.c'\" else echo shar: Extracting \"'slave.c'\" \(2687 characters\) sed "s/^X//" >'slave.c' <<'END_OF_FILE' X/* Copyright 1990, Daniel J. Bernstein. All rights reserved. */ X X#include "file.h" X#include "config.h" X#include "pty.h" X#include "tty.h" X#include "err.h" X#include "sig.h" X#include "slave.h" X#include "logs.h" X Xvoid slave(fnsty,arg) Xchar *fnsty; Xchar **arg; X{ X sig_ignore(SIGTTOU); X sig_ignore(SIGTTIN); X X if (fdtty > -1) X { X (void) tty_dissoc(fdtty); /* must succeed */ X (void) close(fdtty); X } X if (fdre > -1) X (void) close(fdre); X (void) close(fdin); X (void) close(fdout); X (void) close(fdmty); X (void) close(fdsty); X (void) close(0); X (void) close(1); X if (flagsameerr < 2) X (void) close(2); X if (flagsameerr < 1) X { X (void) close(3); X for (fdout = getdtablesize();fdout > 3;fdout--) X (void) close(fdout); X } X X if (open(fnsty,O_RDONLY) != 0) X fatalerrp(1,"pty: fatal: cannot reopen pty for input",errno); X if (open(fnsty,O_WRONLY) != 1) X fatalerrp(1,"pty: fatal: cannot reopen pty for output",errno); X if (flagsameerr < 2) X if (open(fnsty,(flagxerrwo ? O_WRONLY : O_RDWR)) != 2) X fatalerrp(1,"pty: fatal: cannot reopen pty for stderr",errno); X if (flagsameerr < 1) X if (open("/dev/tty",O_RDWR) != 3) X fatalerrp(1,"pty: fatal: cannot reopen pty for /dev/tty",errno); X X if ((fdtty = open("/dev/tty",O_RDWR)) == -1) X fatalerrp(1,"pty: fatal: cannot reopen pty for temporary /dev/tty",errno); X X if (setpgrp(0,getpid()) == -1) X fatalerr(1,"pty: fatal: cannot set process group\n"); X if (tty_setpgrp(fdtty,getpid()) == -1) X fatalerrp(1,"pty: fatal: cannot set pty process group",errno); X if (tty_setmodes(fdtty,&tmopty) == -1) X fatalerr(1,"pty: fatal: cannot set pty modes\n"); X if (flagxexcl) X if (tty_setexcl(fdtty) == -1) X fatalerr(1,"pty: fatal: cannot set exclusive use on pty\n"); X X (void) fchmod(0,USEDPTYMODE); X X if (flagxchown) X (void) fchown(0,uid,PTYGROUP); X X (void) close(fdtty); X X date = now(); /* could use original date instead */ X X if (flagxutmp) X { X if (flagverbose) X warnerr2("%s","pty: writing utmp entry\n"); X if (utmp(fnsty + PTYUTMP_OFFSET,username,PTYUTMP_HOST,date) == -1) X warnerr2("pty: warning: cannot write %s utmp entry\n",fnsty); X } X X if (flagxwtmp) X { X if (flagverbose) X warnerr2("%s","pty: writing wtmp entry\n"); X if (wtmp(fnsty + PTYWTMP_OFFSET,username,PTYWTMP_HOST,date) == -1) X warnerr2("pty: warning: cannot write %s wtmp entry\n",fnsty); X } X X if (setreuid(uid,uid) == -1) X /* We absolutely refuse to exec while setuid. */ X fatalerrp(1,"pty: fatal: cannot setreuid",errno); X X sig_restore(); X if (flagverbose) X warnerr2("pty: executing program %s\n",arg[0]); X (void) execvp(arg[0],arg); X fatalerr2p(1,"pty: fatal: cannot execute %s",arg[0],errno); X /*NOTREACHED*/ X} END_OF_FILE if test 2687 -ne `wc -c <'slave.c'`; then echo shar: \"'slave.c'\" unpacked with wrong size! fi # end of 'slave.c' fi if test -f 'texts.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'texts.c'\" else echo shar: Extracting \"'texts.c'\" \(3819 characters\) sed "s/^X//" >'texts.c' <<'END_OF_FILE' X/* Copyright 1990, Daniel J. Bernstein. All rights reserved. */ X X#include "config.h" X#include "texts.h" X Xchar *ptyauthor[] = { X"pty was written by Daniel J. Bernstein." , X"Internet address: brnstnd@acf10.nyu.edu." , X0 } ; X Xchar *ptyversion[] = { X"pty version 3.001, August 21, 1990." , X"Copyright (c) 1990, Daniel J. Bernstein." , X"All rights reserved." , X0 } ; X Xchar *ptycopyright[] = { X"pty version 3.001, August 21, 1990." , X"Copyright (c) 1990, Daniel J. Bernstein." , X"All rights reserved." , X"" , X"I want this program to be distributed freely in original form." , X"" , X"Once you've received a legal copy of this program, you can use it." , X"Forever. Nobody can take that right away from you. You can make changes" , X"and backup copies for your use (or, if you're an organization, for the" , X"use of everyone in the organization). You can distribute patches (though" , X"not patched versions). You'd have all these rights even if I didn't tell" , X"you about them." , X"" , X"I do grant you further rights, as detailed in the source package. Don't" , X"worry about them unless you're planning to distribute further copies." , X"" , X"If you have questions about this program or about this notice, or if you" , X"would like additional rights beyond those granted above, or if you have" , X"a patch that you don't mind sharing, please contact me on the Internet" , X"at brnstnd@acf10.nyu.edu." , X0 } ; X Xchar *ptywarranty[] = { X"Daniel J. Bernstein disclaims all warranties to the extent permitted" , X"by applicable law. He is not and shall not be liable for any damages" , X"arising from the use of this program. This disclaimer shall be governed" , X"by the laws of the state of New York." , X"" , X"In other words, use this program at your own risk." , X"" , X"If you have questions about this program or about this disclaimer of" , X"warranty, please feel free to contact me at brnstnd@acf10.nyu.edu on" , X"the Internet." , X0 } ; X Xchar *ptyusage[] = { X"Usage: pty [ -qQve3EdDjJsStT0FACHUVW ] [ -fn ] [ -p[cCdDeEnNrRsS0] ]" , X" [ -x[cCeEnNoOrRsSuUwWxX ] program [ arg ... ]" , X"Help: pty -H" , X0 } ; X Xchar *ptyhelp[] = { X"pty runs a program under a pseudo-terminal session." , X"pty -ACHUVW: print authorship notice, copyright notice, this notice," , X" short usage summary, version number, disclaimer of warranty" , X"pty [-qQve3EdDjJsStT0F] [-fn] [-p[cCdDeEnNrRsS0]] [-x[cCeEnNoOrRsSuUwWxX]]" , X" program [arg...]: run program under a pseudo-terminal" , X"Options processed l to r. Capitals turn things off. Here + means default." , X"-q: quiet (nothing on stderr) -e: leave fds 2 & 3 0=eSTp0 p0=pcrEN" , X"+Q: normal level of verbosity -3: leave fd 3 only d=dJT D=Djt d=>T" , X"-v: complain about everything +E: 2 & 3 both->pty s=sxu S=SxU s=>E" , X"-d: we are detached +j: job control +t: change orig tty to char mode" , X"+D: we have ctrl tty -J: ignore stops -T: leave orig tty alone" , X"-s: session (allow disconnect & reconnect) -fn: pass pty fds up fd n" , X"+S: no session: disconnect will send HUP +F: no -f" , X"-p[cCdDeEnNrRsS]: set pty modes; defaults taken from original tty if -D" , X" c: cbreak, character mode +n: change return to newline +e: echo" , X" +d: new line discipline r: raw, no keyboard signals +s: screen, crt" , X"-x[cCeEnNoOrRsSuUwWxX]: security/experimental/extended, may be restricted" , X" c: change pty owner e: pty's stderr write-only x: set TIOCEXCL" , X" +s: setuid, safer +n: check if anyone has pty open u: use /etc/utmp" , X" +r: pick random pty o: skip if anyone has pty open w: use /etc/wtmp" , X"If you have questions about or suggestions for pty, please feel free" , X"to contact the author, Daniel J. Bernstein, at brnstnd@acf10.nyu.edu" , X"on the Internet." , X0 } ; X/* I still can't believe ptyhelp fits. :-) */ END_OF_FILE if test 3819 -ne `wc -c <'texts.c'`; then echo shar: \"'texts.c'\" unpacked with wrong size! fi # end of 'texts.c' fi if test -f 'util/biff.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'util/biff.c'\" else echo shar: Extracting \"'util/biff.c'\" \(1038 characters\) sed "s/^X//" >'util/biff.c' <<'END_OF_FILE' X/* Public domain. */ X X#include <sys/types.h> X#include <sys/stat.h> X#include <stdio.h> X#include "sessutil.h" Xextern unsigned short getuid(); X X#define FOO (void) fstat(0,&st); \ Xif (which) (void) fchmod(0,(int) (st.st_mode | 0100)); \ Xelse (void) fchmod(0,(int) (st.st_mode & ~0100)); X Xmain(argc,argv) Xint argc; Xchar *argv[]; X{ X struct stat st; X struct pty_session ps; X int uid; X int which; X X uid = getuid(); X X if (argc == 1) X { X (void) setreuid(uid,uid); X (void) fstat(0,&st); X if (st.st_mode & 0100) X (void) printf("is y\n"); X else X (void) printf("is n\n"); X } X else X { X switch(argv[1][0]) X { X case 'y': which = 1; break; X case 'n': which = 0; break; X default: (void) fprintf(stderr,"usage: biff [y] [n]\n"); exit(1); X } X if (pty_get_sess(0,uid,&ps) == -1) X { X (void) setreuid(uid,uid); X FOO X } X else X if (ps.uid != uid) X (void) fprintf(stderr,"not your session\n"); X else X { X FOO X (void) setreuid(uid,uid); X FOO X } X } X (void) exit(0); X} END_OF_FILE if test 1038 -ne `wc -c <'util/biff.c'`; then echo shar: \"'util/biff.c'\" unpacked with wrong size! fi # end of 'util/biff.c' fi if test -f 'util/sesslist.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'util/sesslist.c'\" else echo shar: Extracting \"'util/sesslist.c'\" \(2102 characters\) sed "s/^X//" >'util/sesslist.c' <<'END_OF_FILE' X/* Public domain. */ X X#include <sys/types.h> X#include <sys/file.h> X#ifdef BSD X#include <limits.h> X#endif X#include <sys/dir.h> X#include <stdio.h> X#include "sessutil.h" Xextern unsigned short getuid(); X Xmain() X{ X int uid; X DIR *dirp; X struct direct *dp; X int fd; X int intbuf[100]; X char *buf = (char *) intbuf; X int r; X X uid = getuid(); X X if (pty_sessdir(uid) == -1) X { X (void) fputs("sesslist: fatal: cannot change to session directory\n",stderr); X (void) exit(1); X } X dirp = opendir("."); X while (dp = readdir(dirp)) X { X if (!strncmp(dp->d_name,"re.",3)) X (void) printf("session %s disconnected\n",dp->d_name + 3); X else if (!strncmp(dp->d_name,"sess.",5)) X { X if ((fd = open(dp->d_name,O_RDONLY)) == -1) X (void) fprintf(stderr, X "sesslist: warning: cannot open %s\n",dp->d_name); X else X { X r = read(fd,buf,99); /* anything up to sizeof(intbuf) - 1 */ X if (r < 4 * sizeof(int)) X (void) fprintf(stderr, X "sesslist: warning: cannot read %s\n",dp->d_name); X else if (r == 4 * sizeof(int)) X (void) printf("session %s sigler %d master %d slave %d\n", X dp->d_name + 5,intbuf[1],intbuf[2],intbuf[3]); X else X { X buf[r] = '\0'; X (void) printf("session %s sigler %d master %d slave %d: %s\n", X dp->d_name + 5,intbuf[1],intbuf[2],intbuf[3], X buf + 4 * sizeof(int)); X } X (void) close(fd); X } X } X else if (!strncmp(dp->d_name,"sig.",4)) X { X if ((fd = open(dp->d_name,O_RDONLY)) == -1) X (void) fprintf(stderr, X "sesslist: warning: cannot open %s\n",dp->d_name); X else X { X r = read(fd,buf,99); X if (r < 9) X (void) fprintf(stderr, X "sesslist: warning: cannot read %s\n",dp->d_name); X else X { X buf[r] = '\0'; X (void) printf("session %s will drop into session %s\n", X dp->d_name + 4,buf + 8); X } X (void) close(fd); X } X } X else if (!strncmp(dp->d_name,".",1)) X ; X else if (!strncmp(dp->d_name,"..",2)) X ; X else X (void) fprintf(stderr, X "sesslist: warning: unknown file type %s\n",dp->d_name); X } X (void) exit(0); X} END_OF_FILE if test 2102 -ne `wc -c <'util/sesslist.c'`; then echo shar: \"'util/sesslist.c'\" unpacked with wrong size! fi # end of 'util/sesslist.c' fi if test -f 'util/sessuser.1' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'util/sessuser.1'\" else echo shar: Extracting \"'util/sessuser.1'\" \(2006 characters\) sed "s/^X//" >'util/sessuser.1' <<'END_OF_FILE' X.TH sessuser 1 X.SH NAME Xsessuser \- rectify ownership of current pty session X.SH SYNOPSIS X.B sessuser X.SH DESCRIPTION X.I sessuser Xtransfers ownership of the current pty session Xto the user who owns the actual pseudo-terminal file. X.PP X.I sessuser Xis useful in adapting X.I pty Xto old, inconsistent models of logging in. XAn incoming user should be forced to type Xa correct password before the login process Xeven touches a terminal; Xhe should be given a tty Xonly after his identity is established. XInstead, Xusers are given terminals X(as root) Xfirst. XWhen Xthese obsolete programs are modified Xto let X.I pty Xallocate a pseudo-terminal, Xtheir order of operations is still the same, Xand X.I pty Xstill thinks the session is owned by root. XHowever, Xthe login program Xdoes change the ownership of the Xpseudo-terminal file to the user. X.I sessuser Xcommunicates this change to Xthe X.I pty Xmanager, Xso that X.I sesslist, X.I sessname, X.I sesskill, X.I disconnect, Xand X.I reconnect Xwill work. X.PP X.I xsessuser Xis just like X.I sessuser Xbut applies to sessions started with X.B\-xS. XIt should never be needed, but it is Xprovided for consistency. X.SH DIAGNOSTICS X.TP X.I cannot find session XThe standard input to X.I sessuser Xis not a session owned by Xthe effective uid of X.I sessuser. X.TP X.I cannot stat tty XThis cannot happen. X.TP X.I you don't own tty XYou don't own the pseudo-terminal file. X.TP X.I not child of session slave XThe parent to X.I sessuser Xis not the head process in the session. X.TP X.I cannot find your username XYou're not listed in X/etc/passwd. X.TP X.I cannot open /etc/utmp XSelf-explanatory. X.TP X.I cannot set session X.I sessuser Xis unable to record the Xchange in session ownership. X.TP X.I cannot communicate new user X.I sessuser Xis unable to communicate with Xthe pseudo-terminal Xmanager. X.SH RESTRICTIONS X.I sessuser Xrequires that the session be Xlisted in X/etc/utmp. XIf it is not, Xor if it is not listed under Xthe correct username, X.I sessuser Xwill exit silently Xwith exit code 1. X.SH "SEE ALSO" Xpty(1), Xsess(1) END_OF_FILE if test 2006 -ne `wc -c <'util/sessuser.1'`; then echo shar: \"'util/sessuser.1'\" unpacked with wrong size! fi # end of 'util/sessuser.1' fi if test -f 'util/sessuser.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'util/sessuser.c'\" else echo shar: Extracting \"'util/sessuser.c'\" \(1872 characters\) sed "s/^X//" >'util/sessuser.c' <<'END_OF_FILE' X/* Public domain. */ X X#include <sys/types.h> X#include <sys/stat.h> X#include <stdio.h> X#include <utmp.h> X#include <pwd.h> X#include <signal.h> X#include <strings.h> X#include "sessutil.h" Xextern unsigned short getuid(); Xextern unsigned short geteuid(); X#define PTYUTMP_FILE "/etc/utmp" X Xmain() X{ X struct pty_session ps; X int uid; X int euid; X register FILE *fi; X struct utmp ut; X struct stat st; X struct passwd *pw; X char *username; X X uid = getuid(); X euid = geteuid(); X X if (pty_get_sess(0,euid,&ps) == -1) /* i.e., as root */ X { X (void) fputs("sessuser: fatal: cannot find session\n",stderr); X (void) exit(1); X } X if (fstat(0,&st) == -1) X { X (void) fputs("sessuser: fatal: cannot stat tty\n",stderr); X (void) exit(1); X } X if (st.st_uid != uid) X { X (void) fputs("sessuser: fatal: you don't own tty\n",stderr); X (void) exit(1); X } X if (ps.slavepid != getppid()) X { X (void) fputs("sessuser: fatal: not child of session slave\n",stderr); X (void) exit(1); X } X if (!(pw = getpwuid(uid))) X { X (void) fputs("sessuser: fatal: cannot find your username\n",stderr); X (void) exit(1); X } X username = pw->pw_name; X if (!(fi = fopen(PTYUTMP_FILE,"r"))) X { X (void) perror("sessuser: fatal: cannot open /etc/utmp"); X (void) exit(1); X } X else X while (fread((char *) &ut,sizeof(ut),1,fi)) X if ((ut.ut_line[3] == ps.ext1) && (ut.ut_line[4] == ps.ext2) X &&(ut.ut_line[5] == '\0')) X if (!strncmp(ut.ut_name,username,8)) X { X ps.uid = uid; X if (pty_set_sess(0,uid,&ps) == -1) X { X (void) fputs("sessuser: fatal: cannot set session\n",stderr); X (void) exit(1); X } X if (kill(ps.masterpid,SIGUSR2) == -1) X { X (void) fputs("sessuser: fatal: cannot communicate new user\n",stderr); X (void) exit(1); X } X (void) fchown(0,euid,-1); X (void) exit(0); X } X else X (void) exit(1); X (void) exit(1); X} END_OF_FILE if test 1872 -ne `wc -c <'util/sessuser.c'`; then echo shar: \"'util/sessuser.c'\" unpacked with wrong size! fi # end of 'util/sessuser.c' fi if test -f 'util/sessutil.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'util/sessutil.c'\" else echo shar: Extracting \"'util/sessutil.c'\" \(3786 characters\) sed "s/^X//" >'util/sessutil.c' <<'END_OF_FILE' X/* Public domain. */ X X#include "sessutil.h" X#include <sys/types.h> X#include <sys/stat.h> X#include <sys/file.h> X#ifdef BSD X#include <limits.h> X#endif X#include <stdio.h> Xextern char *ttyname(); Xextern long lseek(); X X/* Will have to change ttyn indices if DEVSTY changes. */ X Xint pty_sessdir(uid) Xint uid; X{ X char foo[50]; X X (void) sprintf(foo,"/usr/etc/pty/%d",uid); X return chdir(foo); X} X Xint pty_get_sess(fd,uid,ps) Xint fd; Xint uid; Xstruct pty_session *ps; X{ X char *ttyn; X X if (ttyn = ttyname(fd)) X return pty_get_sessbyext(ttyn[8],ttyn[9],uid,ps); X return -1; X} X Xint pty_get_sessbyext(ext1,ext2,uid,ps) Xchar ext1; Xchar ext2; Xint uid; Xstruct pty_session *ps; X{ X char foo[50]; X int fdsess; X X ps->ext1 = ext1; X ps->ext2 = ext2; X (void) sprintf(foo,"/usr/etc/pty/%d/sess.%c%c",uid,ps->ext1,ps->ext2); X if ((fdsess = open(foo,O_RDONLY)) != -1) X { X if ((read(fdsess,(char *) &ps->uid,sizeof(int)) == sizeof(int)) X &&(read(fdsess,(char *) &ps->siglerpid,sizeof(int)) == sizeof(int)) X &&(read(fdsess,(char *) &ps->masterpid,sizeof(int)) == sizeof(int)) X &&(read(fdsess,(char *) &ps->slavepid,sizeof(int)) == sizeof(int))) X { X (void) close(fdsess); X return 0; X } X (void) close(fdsess); X } X return -1; X} X Xint pty_set_sess(fd,uid,ps) Xint fd; Xint uid; Xstruct pty_session *ps; X{ X char *ttyn; X char foo[50]; X int fdsess; X X if (ttyn = ttyname(fd)) X { X ps->ext1 = ttyn[8]; X ps->ext2 = ttyn[9]; X (void) sprintf(foo,"/usr/etc/pty/%d/sess.%c%c",uid,ps->ext1,ps->ext2); X if ((fdsess = open(foo,O_WRONLY)) != -1) X { X if ((write(fdsess,(char *) &ps->uid,sizeof(int)) == sizeof(int)) X &&(write(fdsess,(char *) &ps->siglerpid,sizeof(int)) == sizeof(int)) X &&(write(fdsess,(char *) &ps->masterpid,sizeof(int)) == sizeof(int)) X &&(write(fdsess,(char *) &ps->slavepid,sizeof(int)) == sizeof(int))) X { X (void) close(fdsess); X return 0; X } X (void) close(fdsess); X } X } X return -1; X} X Xint pty_get_sessname(fd,uid,buf,len) Xint fd; Xint uid; Xchar *buf; Xint len; X{ X char *ttyn; X char foo[50]; X int fdsess; X int r; X X if (ttyn = ttyname(fd)) X { X (void) sprintf(foo,"/usr/etc/pty/%d/sess.%c%c",uid,ttyn[8],ttyn[9]); X if ((fdsess = open(foo,O_RDONLY)) != -1) X { X if (lseek(fdsess,(long) (4 * sizeof(int)),0) != (long) -1) X if ((r = read(fdsess,buf,len - 1)) > 0) X { /* could make that != -1. This way, default session is unnamed. */ X buf[r] = '\0'; X (void) close(fdsess); X return 0; X } X (void) close(fdsess); X } X } X return -1; X} X Xint pty_set_sessname(fd,uid,buf,len) Xint fd; Xint uid; Xchar *buf; Xint len; X{ X char *ttyn; X char foo[50]; X int fdsess; X X if (ttyn = ttyname(fd)) X { X (void) sprintf(foo,"/usr/etc/pty/%d/sess.%c%c",uid,ttyn[8],ttyn[9]); X if ((fdsess = open(foo,O_WRONLY)) != -1) X { X if (lseek(fdsess,(long) (4 * sizeof(int)),0) != (long) -1) X if (write(fdsess,buf,len) != -1) X { X (void) close(fdsess); X return 0; X } X (void) close(fdsess); X } X } X return -1; X} X Xint pty_get_rebyext(ext1,ext2,uid) Xchar ext1; Xchar ext2; Xint uid; X{ X char foo[50]; X struct stat st; X X (void) sprintf(foo,"/usr/etc/pty/%d/re.%c%c",uid,ext1,ext2); X return stat(foo,&st); X} X Xint pty_set_sig(ext1,ext2,uid,ps) Xchar ext1; Xchar ext2; Xint uid; Xstruct pty_session *ps; X{ X char foo[50]; X int fdsig; X X (void) sprintf(foo,"/usr/etc/pty/%d/sig.%c%c",uid,ps->ext1,ps->ext2); X if ((fdsig = open(foo,O_WRONLY | O_CREAT | O_TRUNC,0600)) != -1) X { X (void) sprintf(foo,"/dev/tty%c%c",ext1,ext2); X if (write(fdsig,foo,11) == 11) X { X (void) close(fdsig); X return 0; X } X (void) close(fdsig); X } X return -1; X} X Xint pty_unset_sig(uid,ps) Xint uid; Xstruct pty_session *ps; X{ X char foo[50]; X X (void) sprintf(foo,"/usr/etc/pty/%d/sig.%c%c",uid,ps->ext1,ps->ext2); X return unlink(foo); X} END_OF_FILE if test 3786 -ne `wc -c <'util/sessutil.c'`; then echo shar: \"'util/sessutil.c'\" unpacked with wrong size! fi # end of 'util/sessutil.c' fi if test -f 'util/write.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'util/write.c'\" else echo shar: Extracting \"'util/write.c'\" \(2728 characters\) sed "s/^X//" >'util/write.c' <<'END_OF_FILE' X/* Public domain. */ X X#include <sys/types.h> X#include <sys/timeb.h> X#include <sys/stat.h> X#include <sys/file.h> X#ifdef BSD X#include <limits.h> X#endif X#include <stdio.h> X#include <strings.h> X#include <utmp.h> X#include <pwd.h> X#include <time.h> X#include <ctype.h> Xextern unsigned short getuid(); Xextern char *ttyname(); Xextern long time(); X#define PTYUTMP_FILE "/etc/utmp" X Xmain(argc,argv) Xint argc; Xchar *argv[]; X{ X register FILE *fi; X struct utmp ut; X char line[9]; X int lines = 0; X char fntty[30]; X int fd; X struct stat st; X char buf[500]; X int offset; X char *username; X struct passwd *pw; X char hostname[64]; X char *ttyn; X long t; X struct tm *tm; X char *s; X X if (argc < 2) X { X (void) fprintf(stderr,"Usage: write user [ttyname]\n"); X (void) exit(1); X } X X if (!(pw = getpwuid((int) getuid()))) X { X (void) fprintf(stderr,"write: who are you?\n"); X (void) exit(1); X } X username = pw->pw_name; X X (void) gethostname(hostname,sizeof(hostname)); X X if (!(ttyn = ttyname(2))) X { X (void) fprintf(stderr,"write: Can't find your tty\n"); X (void) exit(1); X } X X t = time((long *) 0); X tm = localtime(&t); X X if (fi = fopen(PTYUTMP_FILE,"r")) X while (fread((char *) &ut,sizeof(ut),1,fi)) X if (!strncmp(ut.ut_name,argv[1],8)) X if ((argc == 2) || (!strncmp(ut.ut_line,argv[2],8))) X if (!lines) X { X (void) strncpy(line,ut.ut_line,8); X line[8] = '\0'; X lines = 1; X } X else X lines++; X if (!lines) X { X if (argc == 2) X (void) fprintf(stderr,"write: %s not logged in\n",argv[1]); X else X (void) fprintf(stderr,"write: %s not logged in on tty %s\n", X argv[1],argv[2]); X (void) exit(1); X } X if (lines > 1) X (void) fprintf(stderr, X "write: %s logged in more than once ... writing to %s\n", X argv[1],line); X X (void) sprintf(fntty,"/dev/%s",line); X if ((fd = open(fntty,O_WRONLY)) == -1) X { X (void) fprintf(stderr,"write: Permission denied\n"); X (void) exit(1); X } X X (void) sprintf(buf,"\nMessage from %s@%s on %s at %d:%02d ...\n", X username,hostname,ttyn + 5,tm->tm_hour,tm->tm_min); X (void) write(fd,buf,strlen(buf)); X X (void) sprintf(buf,"%s: ",username); X offset = strlen(buf); X X while (fgets(buf + offset,sizeof(buf) - offset,stdin)) X { X (void) fstat(fd,&st); X if (!(st.st_mode & 0020)) X { X (void) fprintf(stderr,"write: Permission denied\n"); X (void) exit(1); X } X for (s = buf;*s;s++) X if (((!isascii(*s) || !isprint(*s))) && (*s != '\n')) X *s = '^'; X (void) write(fd,buf,strlen(buf)); X (void) sleep(1); X } X X t = time((long *) 0); X tm = localtime(&t); X (void) sprintf(buf,"End of message from %s@%s on %s at %d:%02d\n", X username,hostname,ttyn + 5,tm->tm_hour,tm->tm_min); X (void) write(fd,buf,strlen(buf)); X X (void) exit(0); X} END_OF_FILE echo shar: 1 control character may be missing from \"'util/write.c'\" if test 2728 -ne `wc -c <'util/write.c'`; then echo shar: \"'util/write.c'\" unpacked with wrong size! fi # end of 'util/write.c' fi if test -f 'util/xsessutil.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'util/xsessutil.c'\" else echo shar: Extracting \"'util/xsessutil.c'\" \(4232 characters\) sed "s/^X//" >'util/xsessutil.c' <<'END_OF_FILE' X/* Public domain. */ X X#include "sessutil.h" X#include <sys/types.h> X#include <sys/stat.h> X#include <sys/file.h> X#ifdef BSD X#include <limits.h> X#endif X#include <stdio.h> Xextern char *ttyname(); Xextern long lseek(); Xextern char *getenv(); X X/* Will have to change ttyn indices if DEVSTY changes. */ X Xint pty_sessdir(uid) Xint uid; X{ X char foo[50]; X char *ho; X X if (!(ho = getenv("HOME"))) X return -1; X (void) sprintf(foo,"%s/.pty/%d",ho,uid); X return chdir(foo); X} X Xint pty_get_sess(fd,uid,ps) Xint fd; Xint uid; Xstruct pty_session *ps; X{ X char *ttyn; X X if (ttyn = ttyname(fd)) X return pty_get_sessbyext(ttyn[8],ttyn[9],uid,ps); X return -1; X} X Xint pty_get_sessbyext(ext1,ext2,uid,ps) Xchar ext1; Xchar ext2; Xint uid; Xstruct pty_session *ps; X{ X char foo[50]; X int fdsess; X char *ho; X X if (!(ho = getenv("HOME"))) X return -1; X X ps->ext1 = ext1; X ps->ext2 = ext2; X (void) sprintf(foo,"%s/.pty/%d/sess.%c%c",ho,uid,ps->ext1,ps->ext2); X if ((fdsess = open(foo,O_RDONLY)) != -1) X { X if ((read(fdsess,(char *) &ps->uid,sizeof(int)) == sizeof(int)) X &&(read(fdsess,(char *) &ps->siglerpid,sizeof(int)) == sizeof(int)) X &&(read(fdsess,(char *) &ps->masterpid,sizeof(int)) == sizeof(int)) X &&(read(fdsess,(char *) &ps->slavepid,sizeof(int)) == sizeof(int))) X { X (void) close(fdsess); X return 0; X } X (void) close(fdsess); X } X return -1; X} X Xint pty_set_sess(fd,uid,ps) Xint fd; Xint uid; Xstruct pty_session *ps; X{ X char *ttyn; X char foo[50]; X int fdsess; X char *ho; X X if (!(ho = getenv("HOME"))) X return -1; X X if (ttyn = ttyname(fd)) X { X ps->ext1 = ttyn[8]; X ps->ext2 = ttyn[9]; X (void) sprintf(foo,"%s/.pty/%d/sess.%c%c",ho,uid,ps->ext1,ps->ext2); X if ((fdsess = open(foo,O_WRONLY)) != -1) X { X if ((write(fdsess,(char *) &ps->uid,sizeof(int)) == sizeof(int)) X &&(write(fdsess,(char *) &ps->siglerpid,sizeof(int)) == sizeof(int)) X &&(write(fdsess,(char *) &ps->masterpid,sizeof(int)) == sizeof(int)) X &&(write(fdsess,(char *) &ps->slavepid,sizeof(int)) == sizeof(int))) X { X (void) close(fdsess); X return 0; X } X (void) close(fdsess); X } X } X return -1; X} X Xint pty_get_sessname(fd,uid,buf,len) Xint fd; Xint uid; Xchar *buf; Xint len; X{ X char *ttyn; X char foo[50]; X int fdsess; X int r; X char *ho; X X if (!(ho = getenv("HOME"))) X return -1; X X if (ttyn = ttyname(fd)) X { X (void) sprintf(foo,"%s/.pty/%d/sess.%c%c",ho,uid,ttyn[8],ttyn[9]); X if ((fdsess = open(foo,O_RDONLY)) != -1) X { X if (lseek(fdsess,(long) (4 * sizeof(int)),0) != (long) -1) X if ((r = read(fdsess,buf,len - 1)) > 0) X { /* could make that != -1. This way, default session is unnamed. */ X buf[r] = '\0'; X (void) close(fdsess); X return 0; X } X (void) close(fdsess); X } X } X return -1; X} X Xint pty_set_sessname(fd,uid,buf,len) Xint fd; Xint uid; Xchar *buf; Xint len; X{ X char *ttyn; X char foo[50]; X int fdsess; X char *ho; X X if (!(ho = getenv("HOME"))) X return -1; X X if (ttyn = ttyname(fd)) X { X (void) sprintf(foo,"%s/.pty/%d/sess.%c%c",ho,uid,ttyn[8],ttyn[9]); X if ((fdsess = open(foo,O_WRONLY)) != -1) X { X if (lseek(fdsess,(long) (4 * sizeof(int)),0) != (long) -1) X if (write(fdsess,buf,len) != -1) X { X (void) close(fdsess); X return 0; X } X (void) close(fdsess); X } X } X return -1; X} X Xint pty_get_rebyext(ext1,ext2,uid) Xchar ext1; Xchar ext2; Xint uid; X{ X char foo[50]; X struct stat st; X char *ho; X X if (!(ho = getenv("HOME"))) X return -1; X X (void) sprintf(foo,"%s/.pty/%d/re.%c%c",ho,uid,ext1,ext2); X return stat(foo,&st); X} X Xint pty_set_sig(ext1,ext2,uid,ps) Xchar ext1; Xchar ext2; Xint uid; Xstruct pty_session *ps; X{ X char foo[50]; X int fdsig; X char *ho; X X if (!(ho = getenv("HOME"))) X return -1; X X (void) sprintf(foo,"%s/.pty/%d/sig.%c%c",ho,uid,ps->ext1,ps->ext2); X if ((fdsig = open(foo,O_WRONLY | O_CREAT | O_TRUNC,0600)) != -1) X { X (void) sprintf(foo,"/dev/tty%c%c",ext1,ext2); X if (write(fdsig,foo,11) == 11) X { X (void) close(fdsig); X return 0; X } X (void) close(fdsig); X } X return -1; X} X Xint pty_unset_sig(uid,ps) Xint uid; Xstruct pty_session *ps; X{ X char foo[50]; X char *ho; X X if (!(ho = getenv("HOME"))) X return -1; X X (void) sprintf(foo,"%s/.pty/%d/sig.%c%c",ho,uid,ps->ext1,ps->ext2); X return unlink(foo); X} END_OF_FILE if test 4232 -ne `wc -c <'util/xsessutil.c'`; then echo shar: \"'util/xsessutil.c'\" unpacked with wrong size! fi # end of 'util/xsessutil.c' fi echo shar: End of archive 4 \(of 6\). cp /dev/null ark4isdone MISSING="" for I in 1 2 3 4 5 6 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked all 6 archives. rm -f ark[1-9]isdone else echo You still must unpack the following archives: echo " " ${MISSING} fi exit 0 exit 0 # Just in case... -- Please send comp.sources.unix-related mail to rsalz@uunet.uu.net. Use a domain-based address or give alternate paths, or you may lose out.