ag@cbmvax.commodore.com (Keith Gabryelski) (10/17/90)
The included source code includes advise.c # a user program to interact with # the advise device and module. advisedev.c # the advise device driver. # (requests to attach to a users terminal # are done through this device) advisemod.c # the advise module. # (this module is pushed onto the advisee's # tty stream so advisedev may attach to # it.) advisemod.h # useful header file. COPYING Makefile # Other files. Pax, Keith Ps, This will only work under System V Release 4.0 streams ttys. With little effort it could be made to work under other streams tty subsystems. No amount of effort (save re-thinking and re-implimenting) will make this thing work on non-streams based ttys. #! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create the files: # COPYING # Makefile # advise.c # advise.man # advisedev.c # advisemod.c # advisemod.h # This archive created: Tue Oct 16 19:15:42 1990 export PATH; PATH=/bin:$PATH if test -f 'COPYING' then echo shar: will not over-write existing file "'COPYING'" else cat << \SHAR_EOF > 'COPYING' Advise GENERAL PUBLIC LICENSE (Clarified 11 Feb 1988) Copyright (C) 1988 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license, but changing it is not allowed. You can also use this wording to make the terms for other programs. The license agreements of most software companies keep you at the mercy of those companies. By contrast, our general public license is intended to give everyone the right to share Advise. To make sure that you get the rights we want you to have, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. Hence this license agreement. Specifically, we want to make sure that you have the right to give away copies of Advise, that you receive source code or else can get it if you want it, that you can change Advise or use pieces of it in new free programs, and that you know you can do these things. To make sure that everyone has such rights, we have to forbid you to deprive anyone else of these rights. For example, if you distribute copies of Advise, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must tell them their rights. Also, for our own protection, we must make certain that everyone finds out that there is no warranty for Advise. If Advise is modified by someone else and passed on, we want its recipients to know that what they have is not what we distributed, so that any problems introduced by others will not reflect on our reputation. Therefore we (Richard Stallman and the Free Software Foundation, Inc.) make the following terms which say what you must do to be allowed to distribute or change Advise. COPYING POLICIES 1. You may copy and distribute verbatim copies of Advise source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy a valid copyright notice "Copyright (C) 1988 Free Software Foundation, Inc." (or with whatever year is appropriate); keep intact the notices on all files that refer to this License Agreement and to the absence of any warranty; and give any other recipients of the Advise program a copy of this License Agreement along with the program. You may charge a distribution fee for the physical act of transferring a copy. 2. You may modify your copy or copies of Advise or any portion of it, and copy and distribute such modifications under the terms of Paragraph 1 above, provided that you also do the following: a) cause the modified files to carry prominent notices stating that you changed the files and the date of any change; and b) cause the whole of any work that you distribute or publish, that in whole or in part contains or is a derivative of Advise or any part thereof, to be licensed at no charge to all third parties on terms identical to those contained in this License Agreement (except that you may choose to grant more extensive warranty protection to some or all third parties, at your option). c) You may charge a distribution fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. Mere aggregation of another unrelated program with this program (or its derivative) on a volume of a storage or distribution medium does not bring the other program under the scope of these terms. 3. You may copy and distribute Advise (or a portion or derivative of it, under Paragraph 2) in object code or executable form under the terms of Paragraphs 1 and 2 above provided that you also do one of the following: a) accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Paragraphs 1 and 2 above; or, b) accompany it with a written offer, valid for at least three years, to give any third party free (except for a nominal shipping charge) a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Paragraphs 1 and 2 above; or, c) accompany it with the information you received as to where the corresponding source code may be obtained. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form alone.) For an executable file, complete source code means all the source code for all modules it contains; but, as a special exception, it need not include source code for modules which are standard libraries that accompany the operating system on which the executable file runs. 4. You may not copy, sublicense, distribute or transfer Advise except as expressly provided under this License Agreement. Any attempt otherwise to copy, sublicense, distribute or transfer Advise is void and your rights to use the program under this License agreement shall be automatically terminated. However, parties who have received computer software programs from you with this License Agreement will not have their licenses terminated so long as such parties remain in full compliance. 5. If you wish to incorporate parts of Advise into other free programs whose distribution conditions are different, write to the Free Software Foundation at 675 Mass Ave, Cambridge, MA 02139. We have not yet worked out a simple rule that can be stated here, but we will often permit this. We will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software. Your comments and suggestions about our licensing policies and our software are welcome! Please contact the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, or call (617) 876-3296. NO WARRANTY BECAUSE ADVISE IS LICENSED FREE OF CHARGE, WE PROVIDE ABSOLUTELY NO WARRANTY, TO THE EXTENT PERMITTED BY APPLICABLE STATE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING, FREE SOFTWARE FOUNDATION, INC, RICHARD M. STALLMAN AND/OR OTHER PARTIES PROVIDE ADVISE "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF ADVISE IS WITH YOU. SHOULD ADVISE PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW WILL RICHARD M. STALLMAN, THE FREE SOFTWARE FOUNDATION, INC., AND/OR ANY OTHER PARTY WHO MAY MODIFY AND REDISTRIBUTE GNU SEND AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY LOST PROFITS, LOST MONIES, OR OTHER SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS) GNU SEND, EVEN IF YOU HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES, OR FOR ANY CLAIM BY ANY OTHER PARTY. SHAR_EOF fi # end of overwriting check if test -f 'Makefile' then echo shar: will not over-write existing file "'Makefile'" else cat << \SHAR_EOF > 'Makefile' # Copyright (C) 1990 Keith Gabryelski (ag@amix.commodore.com) # # This file is part of advise. # # advise is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY. No author or distributor # accepts responsibility to anyone for the consequences of using it # or for whether it serves any particular purpose or works at all, # unless he says so in writing. Refer to the advise General Public # License for full details. # # Everyone is granted permission to copy, modify and redistribute # advise, but only under the conditions described in the # advise General Public License. A copy of this license is # supposed to have been given to you along with advise so you # can know your rights and responsibilities. It should be in a # file named COPYING. Among other things, the copyright notice # and this notice must be preserved on all copies. */ # # Author: Keith Gabryelski (ag@amix.commodore.com) # CC=gcc CFLAGS=-O all: advise advise.o: advisemod.h SHAR_EOF fi # end of overwriting check if test -f 'advise.c' then echo shar: will not over-write existing file "'advise.c'" else cat << \SHAR_EOF > 'advise.c' /* Copyright (C) 1990 Keith Gabryelski (ag@amix.commodore.com) This file is part of advise. advise is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY. No author or distributor accepts responsibility to anyone for the consequences of using it or for whether it serves any particular purpose or works at all, unless he says so in writing. Refer to the advise General Public License for full details. Everyone is granted permission to copy, modify and redistribute advise, but only under the conditions described in the advise General Public License. A copy of this license is supposed to have been given to you along with advise so you can know your rights and responsibilities. It should be in a file named COPYING. Among other things, the copyright notice and this notice must be preserved on all copies. */ /* ** Author: Keith Gabryelski (ag@amix.commodore.com) */ #include <sys/types.h> #include <sys/stat.h> #include <signal.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <stropts.h> #include <poll.h> #include <sys/stream.h> #include <errno.h> #include <utmp.h> #include <pwd.h> #include <termios.h> #include <string.h> #include <ctype.h> #include "advisemod.h" extern char *optarg; #define max(a,b) ((a)>(b)?(a):(b)) static struct module_list { char *name; /* name of module */ struct module_list *next; /* next module to be pushed */ } advise_module_list = { "advise", NULL, }; static void usage(void), advise(char *); static char *strchar(char); static struct module_list *list_modules(int, char *); static int allow_deny_p, allow_deny; static int allow_advise_p, allow_advise; static int error_flag; static int secret, spy; static int meta_character = '~'; static char *progname; static char *module = "ldterm"; int main(int argc, char **argv) { int c, error = 0; struct termios termios; struct module_list *modules; progname = *argv; while((c = getopt(argc, argv, "ADM:Sadm:s?")) != EOF) { switch(c) { case 's': spy++; break; case 'S': if (!getuid()) secret++; break; case 'a': allow_deny_p++; allow_deny=ADVISE_ALLOW; allow_advise_p++; allow_advise++; break; case 'd': allow_advise_p++; allow_advise=0; break; case 'A': allow_deny_p++; allow_deny=ADVISE_ALLOW; break; case 'D': allow_deny_p++; allow_deny=ADVISE_DENY; break; case 'm': meta_character = optarg[0]; break; case 'M': module = optarg; break; case '?': error_flag++; break; } if (error_flag) { usage(); } } if (allow_advise_p) { int status = ioctl(0, ADVISE_STATUS, &status); if (allow_advise && status) { int advise_module_pushed = 0; /* Push advise module on stream */ (void) ioctl(0, TCGETS, &termios); modules = list_modules(0, module); advise_module_list.next = modules; for (modules = &advise_module_list; modules != NULL; modules = modules->next) { if (!strcmp(modules->name, "advise")) { if (advise_module_pushed) continue; advise_module_pushed = 1; } if (ioctl(0, I_PUSH, modules->name)) { (void) fprintf(stderr, "%s: Couldn't I_PUSH: %s (%s).\n", progname, modules->name, strerror(errno)); error++; } } (void) ioctl(0, TCSETS, &termios); } if (!allow_advise && !status) { (void) ioctl(0, TCGETS, &termios); modules = list_modules(0, "advise"); while (modules != NULL) { if (strcmp(modules->name, "advise")) { if (ioctl(0, I_PUSH, modules->name)) { (void) fprintf(stderr, "%s: Couldn't I_PUSH: %s (%s).\n", progname, modules->name, strerror(errno)); error++; } } modules = modules->next; } (void) ioctl(0, TCSETS, &termios); } if (!allow_deny_p) return error ? 1 : 0; } if (allow_deny_p) { if (ioctl(0, allow_deny, 0)) { if (errno == EINVAL) { (void) fprintf(stderr, "%s: module \"advise\" not in stream.\n", progname); } else { (void) fprintf(stderr, "%s: Couldn't set advisory mode (%s).\n", progname, strerror(errno)); } return 1; } return 0; } /* All switches have been handled */ argc -= optind; argv += optind; if (argc > 1) { usage(); } if (argc == 0) { int status; /* ** Status of advise. */ if (ioctl(0, ADVISE_STATUS, &status)) { printf("Module \"advise\" not pushed on stream.\n"); } else { printf("Advise access %s\n", status ? "allowed" : "denied"); } return 0; } advise(*argv); return 0; } void usage() { (void) fprintf(stderr, "usage: %s [-ADad?] [-M module] | [-Ss] [-m char] [ device | username ]\n", progname); exit(1); } static void advise(char *who) { int ret, fd, metad=0; char buf[1024], *device, *devname, *login_name, *tty_name; struct pollfd pfds[2]; struct termios termios, oldtermios; struct stat stbuf; struct utmp *ut, uts; char username[sizeof(ut->ut_name) + 1]; username[0] = '\0'; if (*who == '/') /* full path name */ device = who; else { /* Either this is /dev/ + who OR a username */ setutent(); while ((ut = getutent()) != NULL) { if (!strncmp(who, ut->ut_name, sizeof(ut->ut_name))) { device = (char *)malloc(sizeof("/dev/") + sizeof(ut->ut_name)); if (device == NULL) { (void) fprintf(stderr, "%s: malloc failed (Out of Memory)\n", progname); exit(1); } strcpy(device, "/dev/"); strncat(device, ut->ut_name, sizeof(ut->ut_name)); device[sizeof("/dev/")+sizeof(ut->ut_name)] = '\0'; strncpy(username, ut->ut_name, sizeof(ut->ut_name)); username[sizeof(ut->ut_name)] = '\0'; break; } } if (ut == NULL) /* Is /dev/ + who */ { device = (char *)malloc(sizeof("/dev/") + strlen(who)); if (device == NULL) { (void) fprintf(stderr, "%s: malloc failed (Out of Memory)\n", progname); exit(1); } strcpy(device, "/dev/"); strcat(device, who); } endutent(); } devname = device + sizeof("/dev/") - 1; if (username[0] == '\0') { setutent(); strncpy(uts.ut_line, devname, sizeof(uts.ut_line)); if ((ut = getutline(&uts)) != NULL) { strncpy(username, ut->ut_name, sizeof(ut->ut_name)); username[sizeof(ut->ut_name)] = '\0'; } else { strcpy(username, "unknown"); } endutent(); } if (stat(device, &stbuf) < 0) { if (errno == ENOENT) { (void) fprintf(stderr, "%s: no advisee device: %s\n", progname, device); } else { (void) fprintf(stderr, "%s: Couldn't stat() advisee device: %s (%s)\n", progname, device, strerror(errno)); } exit(1); } if ((fd = open("/dev/advise", O_RDWR)) < 0) { (void) fprintf(stderr, "%s: Couldn't open advisory device: /dev/advise (%s)\n", progname, strerror(errno)); exit(1); } if (ioctl(fd, ADVISE_SETADVISEE, stbuf.st_rdev)) { if (errno == EUNATCH) { (void) fprintf(stderr, "%s: module \"advise\" not in place for %s\n", progname, device); } else if (errno == EACCES) { (void) fprintf(stderr, "%s: permission denied.\n", progname); } else { (void) fprintf(stderr, "%s: Couldn't set advisee: %s (%lu, %lu) (%s)\n", progname, device, ((stbuf.st_rdev >> 16) &0xFFFF), (stbuf.st_rdev&0xFFFF), strerror(errno)); } exit(1); } if (!secret) { char *str; struct passwd *pt; if ((login_name = getlogin()) == NULL) { pt = getpwuid(getuid()); if (pt == NULL || pt->pw_name == NULL) { login_name = "somebody"; } else { login_name = pt->pw_name; } } if ((tty_name = ttyname(2)) != NULL) { if (!strncmp(tty_name, "/dev/", sizeof("/dev/")-1)) tty_name += sizeof("/dev/")-1; } else tty_name = "somewhere"; str = malloc(strlen(login_name) + strlen(tty_name) + sizeof("[: advising :]\n\r") + strlen(username) + strlen(devname)); if (str) { struct advise_message m; struct strbuf ctl, data; m.type = ADVISE_READDATA; ctl.len = sizeof(m); ctl.buf = (void *)&m; sprintf(str, "[%s:%s %s %s:%s]\n\r", login_name, tty_name, spy ? "spying" : "advising", username, devname); data.len = strlen(str); data.buf = str; (void) putmsg(fd, &ctl, &data, 0); free(str); } } if (!spy) { (void) ioctl(0, TCGETS, &termios); oldtermios = termios; termios.c_cc[VMIN] = 1; termios.c_cc[VTIME] = 0; termios.c_lflag &= ~(ISIG|ICANON|ECHO); (void) ioctl(0, TCSETS, &termios); } pfds[0].fd = fd; pfds[0].events = POLLIN; pfds[1].fd = 0; pfds[1].events = POLLIN; for (;;) { if (poll(pfds, 2, INFTIM) < 0) continue; if ((pfds[0].revents&POLLIN) != 0) /* data from advisee ready */ { if ((ret = read(fd, buf, sizeof(buf))) > 0) write(1, buf, ret); } if ((pfds[1].revents&POLLIN) != 0) /* data from advisor ready */ { if ((ret = read(0, buf, sizeof(buf))) > 0) { if (!spy) { register int i; register char *p = buf, *pp=buf; for (i=0; i < ret; ++i, p++) { if (metad) { if (metad == 2) { meta_character = *p; printf("The meta character is now: %s\n", strchar(meta_character)); pp++; metad = 0; continue; } switch (*p) { case '=': metad=2; pp++; break; case '?': { char *escstr = strchar(meta_character); printf("Help for meta character <%s>:\n", escstr); printf("%s?\t-- This help message.\n", escstr); printf("%s~\t-- Send a single meta character.\n", escstr); printf("%s.\t-- Disconnect advise session.\n", escstr); printf("%s=C\t-- Change meta character to C.\n", escstr); printf("%s^Z\t-- Suspend advise session.\n", escstr); pp++; metad=0; break; } case '.': { if (!secret) { char *str; str = malloc(strlen(login_name) + strlen(tty_name) + sizeof("[/ disconnecting from :]\n") + strlen(username) + strlen(devname)); if (str) { struct advise_message m; struct strbuf ctl, data; m.type = ADVISE_READDATA; ctl.len = sizeof(m); ctl.buf = (void *)&m; sprintf(str, "[%s/%s disconnecting from %s:%s]\n\r", login_name, tty_name, username, devname); data.len = strlen(str); data.buf = str; (void) putmsg(fd, &ctl, &data, 0); free(str); } } close(fd); (void) ioctl(0, TCSETS, &oldtermios); exit(0); } case CTRL('Z'): { (void) ioctl(0, TCSETS, &oldtermios); (void) signal(SIGTSTP, SIG_DFL); (void) kill(0, SIGTSTP); (void) ioctl(0, TCSETS, &termios); metad=0; break; } default: metad=0; break; } } else { if (*p == meta_character) { int d = p - pp; metad=1; if (d) write(fd, pp, d); pp += d + 1; i += d; } } } if (p - pp) { struct advise_message m; struct strbuf ctl, data; m.type = ADVISE_DATA; ctl.len = sizeof(m); ctl.buf = (void *)&m; data.len = p - pp; data.buf = p; (void) putmsg(fd, &ctl, &data, 0); } } } } } } static struct module_list * list_modules(int fd, char *push_below) { char lookbuf[max(FMNAMESZ+1,256)]; struct module_list *mp, *mpp; mp = NULL; while (ioctl(fd, I_LOOK, lookbuf) == 0) { if (ioctl(fd, I_POP, 0)) { (void) fprintf(stderr, "%s: Couldn't I_POP: %s (%s).\n", progname, lookbuf, strerror(errno)); return mp; } if ((mpp = malloc(sizeof(struct module_list))) == NULL || (mpp->name = malloc(strlen(lookbuf) + 1)) == NULL) { (void) fprintf(stderr, "%s: Couldn't malloc (out of memory).\n", progname); return mp; } mpp->next = mp; mp = mpp; strcpy(mp->name, lookbuf); if (!strcmp(push_below, lookbuf)) break; } return mp; } static char * strchar(char character) { static char retbuf[4]; char *p = retbuf; int capit = 0; if (!isascii(character)) { *p++ = '~'; capit = 1; character = toascii(character); } if (iscntrl(character)) { *p++ = '^'; capit = 1; character += '@'; } if (capit) *p++ = toupper(character); else *p++ = character; *p = '\0'; return retbuf; } SHAR_EOF fi # end of overwriting check if test -f 'advise.man' then echo shar: will not over-write existing file "'advise.man'" else cat << \SHAR_EOF > 'advise.man' .TH advise 1 .SH NAME advise \- Attach to another user. .SH SYNOPSIS .B advise [-ADad?] [-M module] | [-Ss] [-m char] [ device | username ] .SH DESCRIPTION .B Advise attaches a user (the advisor) to another user's (the advisee) terminal in such a way the the advisor can type for the advisee and view what the advisee's terminal is displaying. .PP The advisee would typically type ``advise -a'' to allow advise attaches; the advisor would then type ``advise username'' which would connect the advisors terminal the the advisee's. .PP All characters the advisor types are sent to the advisee's terminal as if the advisee typed them save the meta character. .PP The default meta character is tilde (~). The advisor uses the meta character to disconnect or suspend the advise session. The meta commands that are available to the advisor are: .PP .RS .TP ~? Meta character help message. .TP ~~ Send the meta character to the advisee's terminal. .TP ~. Disconnect advise session. .TP ~=C Change the meta character to C. .TP ~^Z Suspend this advise session. .RE .PP In Advise mode the advisor uses ``~.'' to disconnect the advise session (Note: the advisor should use ``~~'' to send one tilde to the advisee's terminal). .PP In ``spy mode'' the advisor should use an interrupt is use to disconnect the advise session. .PP ``advise -d'' can be used by the advisee to disconnect the advise session. .SH OPTIONS .TP -A Allow advise attaches to this terminal. .TP -D Disallow advise attaches to this terminal. .TP -M module Name of module to place advise module under. .TP -S When attaching to another user, don't send the attach message. (available to the super user, only). .TP -a Push advise module on standard input stream and allow advise attaches. .TP -d Push advise module on standard input stream and disallow advise attaches. .TP -m char Change the meta character to ``char''. The default meta character is tilde (~). .TP -s Spy mode only (ie, input from the advisor is not passed to the advisee). .TP device The name of the tty device to advise. .TP username The name of the user to advise. .SH AUTHOR .RS .PP Keith M. Gabryelski (ag@amix.commodore.com) .RE SHAR_EOF fi # end of overwriting check if test -f 'advisedev.c' then echo shar: will not over-write existing file "'advisedev.c'" else cat << \SHAR_EOF > 'advisedev.c' /* Copyright (C) 1990 Keith Gabryelski (ag@amix.commodore.com) This file is part of advise. advise is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY. No author or distributor accepts responsibility to anyone for the consequences of using it or for whether it serves any particular purpose or works at all, unless he says so in writing. Refer to the advise General Public License for full details. Everyone is granted permission to copy, modify and redistribute advise, but only under the conditions described in the advise General Public License. A copy of this license is supposed to have been given to you along with advise so you can know your rights and responsibilities. It should be in a file named COPYING. Among other things, the copyright notice and this notice must be preserved on all copies. */ /* ** Author: Keith Gabryelski (ag@amix.commodore.com) */ #include <sys/types.h> #include <sys/param.h> #include <sys/sysmacros.h> #include <sys/signal.h> #include <sys/file.h> #include <sys/user.h> #include <sys/proc.h> #include <sys/termios.h> #include <sys/ttold.h> #include <sys/cmn_err.h> #include <sys/stream.h> #include <sys/stropts.h> #include <sys/errno.h> #include <sys/debug.h> #include "advisemod.h" #include <sys/inline.h> int adviseopen(), adviseclose(), adviserput(), advisewput(); void advisesrvioc(); static struct module_info advisemiinfo = { 0, "advise", 0, INFPSZ, 2048, 128, }; static struct qinit adviserinit = { adviserput, NULL, adviseopen, adviseclose, NULL, &advisemiinfo, }; static struct module_info advisemoinfo = { 42, "advise", 0, INFPSZ, 300, 200, }; static struct qinit advisewinit = { advisewput, NULL, adviseopen, adviseclose, NULL, &advisemoinfo, }; struct streamtab adviseinfo = { &adviserinit, &advisewinit, NULL, NULL, }; extern struct advise_state advise_table; /*ARGSUSED*/ static int adviseopen(q, devp, flag, sflag, credp) register queue_t *q; dev_t *devp; int flag, sflag; cred_t *credp; { register mblk_t *bp; struct advise_queue_list *ql; struct advise_state *sp; int i; if (sflag == MODOPEN) return EINVAL; for (i=1; i < L_MAXMIN; ++i) { sp = &advise_table; while (sp->next != NULL) { ql = sp->next->q_list; while (ql != NULL) { if (ql->minord == i) break; ql = ql->next; } if (ql != NULL) break; sp = sp->next; } if (sp->next == NULL) break; } if (i == L_MAXMIN) { return ENOMEM; /* no more resources */ } *devp = makedevice(getmajor(*devp), i); if ((bp = allocb((int)sizeof(struct advise_queue_list), BPRI_MED)) == NULL) { return ENOMEM; } bp->b_wptr += sizeof(struct advise_queue_list); ql = (struct advise_queue_list *)bp->b_rptr; ql->savbp = bp; ql->next = NULL; ql->q = q; ql->state = NULL; ql->minord = i; q->q_ptr = (caddr_t)ql; WR(q)->q_ptr = (caddr_t)ql; return 0; } static adviseclose(q) register queue_t *q; { struct advise_state *llist = &advise_table; struct advise_queue_list *qp = (struct advise_queue_list *)q->q_ptr; struct advise_queue_list *ql, *qlp; /* Remove us from the advisor's list */ if (qp->state != NULL) { while (llist != NULL && llist->next != qp->state) llist = llist->next; if (llist != NULL) { ql = llist->next->q_list; if (ql->q == q) { llist->next->q_list = ql->next; } else { while (ql->next != NULL && ql->next->q != q) ql = ql->next; if (ql->next != NULL) { ql->next = ql->next->next; } } } } qp->state = NULL; freeb(qp->savbp); q->q_ptr = NULL; } static int adviserput(q, bp) struct queue *q; mblk_t *bp; { putnext(q, bp); } static int advisewput(q, bp) struct queue *q; mblk_t *bp; { struct advise_queue_list *qp = (struct advise_queue_list *)q->q_ptr; struct advise_state *sp = qp->state; switch (bp->b_datap->db_type) { case M_PROTO: { struct advise_message *ms = (struct advise_message *)bp->b_rptr; mblk_t *bp2 = unlinkb(bp); if (bp2) { if (sp != NULL && sp->q != NULL) { if (ms->type == ADVISE_READDATA) { putnext(WR(sp->q), bp2); } else { putnext(sp->q, bp2); } } else freemsg(bp2); } freemsg(bp); break; } case M_DATA: /* ** Write data to advisee. */ if (sp != NULL && sp->q != NULL) putnext(sp->q, bp); else freemsg(bp); break; case M_IOCTL: case M_IOCDATA: advisesrvioc(q, bp); break; default: freemsg(bp); break; } } static void advisesrvioc(q, mp) queue_t *q; mblk_t *mp; { mblk_t *mp1; struct iocblk *iocbp = (struct iocblk *)mp->b_rptr; struct advise_queue_list *qp=(struct advise_queue_list *)q->q_ptr; int s; if (mp->b_datap->db_type == M_IOCDATA) { /* For copyin/copyout failures, just free message. */ if (((struct copyresp *)mp->b_rptr)->cp_rval) { freemsg(mp); return; } if (!((struct copyresp *)mp->b_rptr)->cp_private) { mp->b_datap->db_type = M_IOCACK; freemsg(unlinkb(mp)); iocbp->ioc_count = 0; iocbp->ioc_rval = 0; iocbp->ioc_error = 0; putnext(RD(q), mp); return; } } switch (iocbp->ioc_cmd) { case ADVISE_SETADVISEE: { register dev_t p; struct advise_queue_list *qlp; struct advise_state *llist; if (qp->state != NULL) /* already advising someone */ { iocbp->ioc_error = EBUSY; mp->b_datap->db_type = M_IOCNAK; iocbp->ioc_count = 0; putnext(RD(q), mp); break; } if (!mp->b_cont) { iocbp->ioc_error = EINVAL; mp->b_datap->db_type = M_IOCNAK; iocbp->ioc_count = 0; putnext(RD(q), mp); break; } p = *(dev_t *)mp->b_cont->b_rptr; s = spladvise(); llist = advise_table.next; while (llist != NULL && llist->dev != p) { llist = llist->next; } if (llist == NULL) { splx(s); iocbp->ioc_error = EUNATCH; mp->b_datap->db_type = M_IOCNAK; iocbp->ioc_count = 0; putnext(RD(q), mp); break; } if ((llist->status & ALLOW_ADVICE) == 0 && (!suser(u.u_cred))) { splx(s); iocbp->ioc_error = EACCES; mp->b_datap->db_type = M_IOCNAK; iocbp->ioc_count = 0; putnext(RD(q), mp); break; } /* ** Add ourself to the list of advisors for this advisee. */ if (llist->q_list == NULL) { qlp = llist->q_list = qp; } else { qlp = llist->q_list; while (qlp->next != NULL) qlp = qlp->next; qlp->next = qp; qlp = qp; } qlp->state = llist; splx(s); mp->b_datap->db_type = M_IOCACK; mp1 = unlinkb(mp); if (mp1) freeb(mp1); iocbp->ioc_count = 0; putnext(RD(q), mp); break; } default: /* Unrecognized ioctl command */ if (canput(RD(q)->q_next)) { mp->b_datap->db_type = M_IOCNAK; putnext(RD(q), mp); } else putbq(q, mp); break; } } SHAR_EOF fi # end of overwriting check if test -f 'advisemod.c' then echo shar: will not over-write existing file "'advisemod.c'" else cat << \SHAR_EOF > 'advisemod.c' /* Copyright (C) 1990 Keith Gabryelski (ag@amix.commodore.com) This file is part of advise. advise is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY. No author or distributor accepts responsibility to anyone for the consequences of using it or for whether it serves any particular purpose or works at all, unless he says so in writing. Refer to the advise General Public License for full details. Everyone is granted permission to copy, modify and redistribute advise, but only under the conditions described in the advise General Public License. A copy of this license is supposed to have been given to you along with advise so you can know your rights and responsibilities. It should be in a file named COPYING. Among other things, the copyright notice and this notice must be preserved on all copies. */ /* ** Author: Keith Gabryelski (ag@amix.commodore.com) */ #include <sys/types.h> #include <sys/param.h> #include <sys/signal.h> #include <sys/file.h> #include <sys/user.h> #include <sys/proc.h> #include <sys/termios.h> #include <sys/ttold.h> #include <sys/cmn_err.h> #include <sys/stream.h> #include <sys/stropts.h> #include <sys/errno.h> #include <sys/debug.h> #include "advisemod.h" #include <sys/inline.h> int advisemopen(), advisemclose(), advisemrput(), advisemwput(); static struct module_info advisemiinfo = { 0, "advisemod", 0, INFPSZ, 2048, 128, }; static struct qinit adviserinit = { advisemrput, NULL, advisemopen, advisemclose, NULL, &advisemiinfo, }; static struct module_info advisemoinfo = { 42, "advisemod", 0, INFPSZ, 300, 200, }; static struct qinit advisewinit = { advisemwput, NULL, advisemopen, advisemclose, NULL, &advisemoinfo, }; struct streamtab advisemodinfo = { &adviserinit, &advisewinit, NULL, NULL, }; struct advise_state advise_table; /*ARGSUSED*/ static int advisemopen(q, devp, flag, sflag, credp) register queue_t *q; dev_t *devp; int flag, sflag; cred_t *credp; { register struct advise_state *sp; register mblk_t *bp; struct advise_state *llist = &advise_table; if (sflag != MODOPEN) return EINVAL; if ((bp = allocb((int)sizeof(struct advise_state), BPRI_MED)) == NULL) { return ENOMEM; } bp->b_wptr += sizeof(struct advise_state); sp = (struct advise_state *)bp->b_rptr; sp->savbp = bp; sp->dev = *devp; sp->status = 0; /* Deny access by default */ sp->next = NULL; sp->q_list = NULL; sp->q = q; while (llist->next != NULL) { if (llist->next->dev == *devp) { /* ** We are already pushed on this stream. */ freeb(bp); sp = llist->next; break; } llist = llist->next; } llist->next = sp; q->q_ptr = (caddr_t)sp; WR(q)->q_ptr = (caddr_t)sp; return 0; } static advisemclose(q) register queue_t *q; { register struct advise_state *sp = (struct advise_state *)q->q_ptr; struct advise_state *llist = &advise_table; struct advise_queue_list *qp = sp->q_list; sp->status = 0; /* unlink us from the state table */ while (llist->next != sp) llist = llist->next; llist->next = llist->next->next; while (sp->next != NULL) { /* tell each advisor that we're shutting down */ flushq(sp->q, FLUSHDATA); putctl(sp->q->q_next, M_HANGUP); sp = sp->next; } freeb(sp->savbp); q->q_ptr = NULL; } static advisemrput(q, mp) register queue_t *q; register mblk_t *mp; { putnext(q, mp); } static advisemwput(q, mp) register queue_t *q; register mblk_t *mp; { struct advise_state *sp = (struct advise_state *)q->q_ptr; register struct advise_queue_list *qp; int s; switch (mp->b_datap->db_type) { case M_DATA: /* ** Write data to advisors. */ s = spladvise(); for (qp = sp->q_list; qp != NULL; qp = qp->next) { mblk_t *mp1 = copymsg(mp); if (mp1 != NULL) putnext(qp->q, mp1); } splx(s); break; case M_IOCTL: case M_IOCDATA: if (advisemsrvioc(q, mp)) /* handled? */ return; break; } putnext(q, mp); } static int advisemsrvioc(q, mp) queue_t *q; mblk_t *mp; { mblk_t *mp1; struct iocblk *iocbp = (struct iocblk *)mp->b_rptr; struct advise_state *sp = (struct advise_state *)q->q_ptr; if (mp->b_datap->db_type == M_IOCDATA) { struct copyresp *csp = (struct copyresp *)mp->b_rptr; switch(csp->cp_cmd) { case ADVISE_STATUS: case ADVISE_ALLOW: case ADVISE_DENY: /* For copyin/copyout failures, just free message. */ if (csp->cp_rval) freemsg(mp); else if (!csp->cp_private) { mp->b_datap->db_type = M_IOCACK; freemsg(unlinkb(mp)); iocbp->ioc_count = 0; iocbp->ioc_rval = 0; iocbp->ioc_error = 0; putnext(RD(q), mp); } return 1; } } switch (iocbp->ioc_cmd) { case ADVISE_STATUS: { int *status; caddr_t arg = *(caddr_t *)mp->b_cont->b_rptr; freemsg(mp->b_cont); mp->b_cont = allocb(sizeof(int), BPRI_MED); if (!mp->b_cont) { mp->b_datap->db_type = M_IOCNAK; freemsg(unlinkb(mp)); iocbp->ioc_count = 0; iocbp->ioc_rval = 0; iocbp->ioc_error = ENOMEM; putnext(RD(q), mp); return 1; } status = (int *)mp->b_cont->b_rptr; mp->b_cont->b_wptr += sizeof(int); *status = sp->status; if (mp->b_datap->db_type == M_IOCTL && iocbp->ioc_count == TRANSPARENT) { struct copyreq *creq = (struct copyreq *)mp->b_rptr; mp->b_datap->db_type = M_COPYOUT; creq->cq_addr = arg; mp->b_wptr = mp->b_rptr + sizeof *creq; mp->b_cont->b_wptr = mp->b_cont->b_rptr + sizeof(int); creq->cq_size = sizeof(int); creq->cq_flag = 0; creq->cq_private = (mblk_t *)NULL; putnext(RD(q), mp); return 1; } } break; case ADVISE_ALLOW: sp->status |= ALLOW_ADVICE; mp->b_datap->db_type = M_IOCACK; mp1 = unlinkb(mp); if (mp1) freeb(mp1); iocbp->ioc_count = 0; putnext(RD(q), mp); break; case ADVISE_DENY: sp->status &= ~(ALLOW_ADVICE); mp->b_datap->db_type = M_IOCACK; mp1 = unlinkb(mp); if (mp1) freeb(mp1); iocbp->ioc_count = 0; putnext(RD(q), mp); break; default: return 0; } return 1; } SHAR_EOF fi # end of overwriting check if test -f 'advisemod.h' then echo shar: will not over-write existing file "'advisemod.h'" else cat << \SHAR_EOF > 'advisemod.h' /* Copyright (C) 1990 Keith Gabryelski (ag@amix.commodore.com) This file is part of advise. advise is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY. No author or distributor accepts responsibility to anyone for the consequences of using it or for whether it serves any particular purpose or works at all, unless he says so in writing. Refer to the advise General Public License for full details. Everyone is granted permission to copy, modify and redistribute advise, but only under the conditions described in the advise General Public License. A copy of this license is supposed to have been given to you along with advise so you can know your rights and responsibilities. It should be in a file named COPYING. Among other things, the copyright notice and this notice must be preserved on all copies. */ /* ** Author: Keith Gabryelski (ag@amix.commodore.com) */ struct advise_queue_list { mblk_t *savbp; /* ptr to this mblk for freeb()ing */ queue_t *q; /* advisor's queue */ int minord; /* minor device for this advisor */ struct advise_state *state; /* ptr back to advise_state struct */ struct advise_queue_list *next; /* ptr to next advisor */ }; struct advise_state { mblk_t *savbp; /* ptr to this mblk for freeb()ing */ int status; /* current status */ dev_t dev; /* our device */ queue_t *q; /* queue for advisor writing */ struct advise_queue_list *q_list;/* list of spies */ struct advise_state *next; /* next in advise_table */ }; #define ALLOW_ADVICE (0x01) struct advise_message { int type; /* What type of data is this? */ }; #define ADVISE_DATA (0x00) #define ADVISE_READDATA (0x01) #define ADVISE ('z'<<16) #define ADVISE_SETADVISEE (ADVISE|0x01) #define ADVISE_ALLOW (ADVISE|0x02) #define ADVISE_DENY (ADVISE|0x03) #define ADVISE_STATUS (ADVISE|0x04) #define spladvise spltty SHAR_EOF fi # end of overwriting check # End of shell archive exit 0