+/* imiscd.c - miscellaneous network service -- responder */
+
+#ifndef lint
+static char *rcsid = "$Header: /f/osi/imisc/RCS/imiscd.c,v 7.4 91/02/22 09:26:21 mrose Interim $";
+#endif
+
+/*
+ * $Header: /f/osi/imisc/RCS/imiscd.c,v 7.4 91/02/22 09:26:21 mrose Interim $
+ *
+ *
+ * $Log: imiscd.c,v $
+ * Revision 7.4 91/02/22 09:26:21 mrose
+ * Interim 6.8
+ *
+ * Revision 7.3 90/11/21 11:37:04 mrose
+ * update
+ *
+ * Revision 7.2 90/07/09 14:38:48 mrose
+ * sync
+ *
+ * Revision 7.1 90/07/01 21:04:05 mrose
+ * pepsy
+ *
+ * Revision 7.0 89/11/23 21:57:39 mrose
+ * Release 6.0
+ *
+ */
+
+/*
+ * NOTICE
+ *
+ * Acquisition, use, and distribution of this module and related
+ * materials are subject to the restrictions of a license agreement.
+ * Consult the Preface in the User's Manual for the full terms of
+ * this agreement.
+ *
+ */
+
+
+#include <ctype.h>
+#include <stdio.h>
+#include "IMISC-types.h" /* IMISC type definitions */
+#include "ryresponder.h" /* for generic idempotent responders */
+#include "IMISC-ops.h" /* IMISC operation definitions */
+#include <utmp.h>
+#ifdef SYS5
+#include <sys/times.h>
+#endif
+#include <sys/stat.h>
+
+/* \f DATA */
+
+static char *myservice = "isode miscellany"; /* should be something else */
+
+static int execuid = 1;
+static int execgid = 1;
+
+
+ /* OPERATIONS */
+int op_utcTime (), op_genTime (), op_timeOfDay (), op_users (),
+ op_charGen (), op_pwdGen (), op_exec (), op_tellUser (), op_data ();
+
+static struct dispatch dispatches[] = {
+ "utcTime", operation_IMISC_utcTime, op_utcTime,
+
+ "genTime", operation_IMISC_genTime, op_genTime,
+
+ "timeOfDay", operation_IMISC_timeOfDay, op_timeOfDay,
+
+ "users", operation_IMISC_users, op_users,
+
+ "chargen", operation_IMISC_charGen, op_charGen,
+
+ "pwdGen", operation_IMISC_pwdGen, op_pwdGen,
+
+ "qotd", operation_IMISC_qotd, op_exec,
+
+ "finger", operation_IMISC_finger, op_exec,
+
+ "tellUser", operation_IMISC_tellUser, op_tellUser,
+
+ "ping", operation_IMISC_ping, op_data,
+
+ "sink", operation_IMISC_sink, op_data,
+
+ "echo", operation_IMISC_echo, op_data,
+
+ NULL
+};
+
+
+ /* TYPES */
+struct type_IMISC_IA5List *str2ia5list ();
+
+
+extern int errno;
+
+
+long time ();
+char *ctime ();
+
+/* \f MAIN */
+
+/* ARGSUSED */
+
+main (argc, argv, envp)
+int argc;
+char **argv,
+ **envp;
+{
+ ryresponder (argc, argv, PLocalHostName (), myservice, NULLCP,
+ dispatches, table_IMISC_Operations, NULLIFP, NULLIFP);
+
+ exit (0); /* NOTREACHED */
+}
+
+/* \f OPERATIONS */
+
+/* ARGSUSED */
+
+static int op_utcTime (sd, ryo, rox, in, roi)
+int sd;
+struct RyOperation *ryo;
+struct RoSAPinvoke *rox;
+caddr_t in;
+struct RoSAPindication *roi;
+{
+ long clock;
+ char *cp;
+ register struct tm *tm;
+ struct UTCtime uts;
+ register struct UTCtime *ut = &uts;
+ register struct type_IMISC_UTCResult *ur;
+
+ if (rox -> rox_nolinked == 0) {
+ advise (LLOG_EXCEPTIONS, NULLCP,
+ "RO-INVOKE.INDICATION/%d: %s, unknown linkage %d",
+ sd, ryo -> ryo_name, rox -> rox_linkid);
+ return ureject (sd, ROS_IP_LINKED, rox, roi);
+ }
+ advise (LLOG_NOTICE, NULLCP, "RO-INVOKE.INDICATION/%d: %s",
+ sd, ryo -> ryo_name);
+
+ if (time (&clock) == NOTOK || (tm = gmtime (&clock)) == NULL)
+ return error (sd, error_IMISC_unableToDetermineTime, (caddr_t) NULL,
+ rox, roi);
+
+ tm2ut (tm, ut);
+
+ if ((cp = utct2str (ut)) == NULLCP
+ || (ur = str2qb (cp, strlen (cp), 1)) == NULL)
+ return error (sd, error_IMISC_congested, (caddr_t) NULL, rox, roi);
+
+ if (RyDsResult (sd, rox -> rox_id, (caddr_t) ur, ROS_NOPRIO, roi) == NOTOK)
+ ros_adios (&roi -> roi_preject, "RESULT");
+
+ free_IMISC_UTCResult (ur);
+
+ return OK;
+}
+
+/* \f */
+
+/* ARGSUSED */
+
+static int op_genTime (sd, ryo, rox, in, roi)
+int sd;
+struct RyOperation *ryo;
+struct RoSAPinvoke *rox;
+caddr_t in;
+struct RoSAPindication *roi;
+{
+ long clock;
+ char *cp;
+#if defined(BSD42) || defined (HPUX)
+ struct timeval tvs;
+#endif
+ register struct tm *tm;
+ struct UTCtime uts;
+ register struct UTCtime *ut = &uts;
+ register struct type_IMISC_GenResult *gr;
+
+ if (rox -> rox_nolinked == 0) {
+ advise (LLOG_EXCEPTIONS, NULLCP,
+ "RO-INVOKE.INDICATION/%d: %s, unknown linkage %d",
+ sd, ryo -> ryo_name, rox -> rox_linkid);
+ return ureject (sd, ROS_IP_LINKED, rox, roi);
+ }
+ advise (LLOG_NOTICE, NULLCP, "RO-INVOKE.INDICATION/%d: %s",
+ sd, ryo -> ryo_name);
+
+#if defined(BSD42) || defined (HPUX)
+ if (gettimeofday (&tvs, (struct timezone *) 0) == NOTOK)
+ return error (sd, error_IMISC_unableToDetermineTime, (caddr_t) NULL,
+ rox, roi);
+ clock = tvs.tv_sec;
+#else
+ if (time (&clock) == NOTOK)
+ return error (sd, error_IMISC_unableToDetermineTime, (caddr_t) NULL,
+ rox, roi);
+#endif
+ if ((tm = gmtime (&clock)) == NULL)
+ return error (sd, error_IMISC_unableToDetermineTime, (caddr_t) NULL,
+ rox, roi);
+ tm2ut (tm, ut);
+#ifdef BSD42
+ ut -> ut_flags |= UT_USEC;
+ ut -> ut_usec = tvs.tv_usec;
+#endif
+
+ if ((cp = gent2str (ut)) == NULLCP
+ || (gr = str2qb (cp, strlen (cp), 1)) == NULL)
+ return error (sd, error_IMISC_congested, (caddr_t) NULL, rox, roi);
+
+ if (RyDsResult (sd, rox -> rox_id, (caddr_t) gr, ROS_NOPRIO, roi) == NOTOK)
+ ros_adios (&roi -> roi_preject, "RESULT");
+
+ free_IMISC_GenResult (gr);
+
+ return OK;
+}
+
+/* \f */
+
+/* Return the number of seconds since 00:00 (midnight) 1 January 1900 GMT */
+
+/* ARGSUSED */
+
+static int op_timeOfDay (sd, ryo, rox, in, roi)
+int sd;
+struct RyOperation *ryo;
+struct RoSAPinvoke *rox;
+caddr_t in;
+struct RoSAPindication *roi;
+{
+ long clock;
+ struct type_IMISC_TimeResult trs;
+ register struct type_IMISC_TimeResult *tr = &trs;
+
+ if (rox -> rox_nolinked == 0) {
+ advise (LLOG_EXCEPTIONS, NULLCP,
+ "RO-INVOKE.INDICATION/%d: %s, unknown linkage %d",
+ sd, ryo -> ryo_name, rox -> rox_linkid);
+ return ureject (sd, ROS_IP_LINKED, rox, roi);
+ }
+ advise (LLOG_NOTICE, NULLCP, "RO-INVOKE.INDICATION/%d: %s",
+ sd, ryo -> ryo_name);
+
+ if (time (&clock) == NOTOK)
+ return error (sd, error_IMISC_unableToDetermineTime, (caddr_t) NULL,
+ rox, roi);
+ tr -> parm = clock + 2208988800;
+
+ if (RyDsResult (sd, rox -> rox_id, (caddr_t) tr, ROS_NOPRIO, roi) == NOTOK)
+ ros_adios (&roi -> roi_preject, "RESULT");
+
+ return OK;
+}
+
+/* \f */
+
+#ifdef sun
+#define BSD42
+#undef SYS5
+#endif
+
+#ifdef bsd43_ut_host
+#undef BSD42
+#define SYS5
+#endif
+
+#ifdef BSD42
+#define HMAX (sizeof (ut -> ut_host))
+#endif
+#define LMAX (sizeof (ut -> ut_line))
+#define NMAX (sizeof (ut -> ut_name))
+
+#ifdef SYS5
+struct utmp *getutent ();
+#endif
+
+
+/* ARGSUSED */
+
+static int op_users (sd, ryo, rox, in, roi)
+int sd;
+struct RyOperation *ryo;
+struct RoSAPinvoke *rox;
+caddr_t in;
+struct RoSAPindication *roi;
+{
+#ifndef SYS5
+ int ud;
+#endif
+ register char *dp;
+ char buffer[BUFSIZ];
+ struct utmp uts;
+ register struct utmp *ut = &uts;
+ struct type_IMISC_IA5List *ia5;
+ register struct type_IMISC_IA5List **ia5p;
+
+ if (rox -> rox_nolinked == 0) {
+ advise (LLOG_EXCEPTIONS, NULLCP,
+ "RO-INVOKE.INDICATION/%d: %s, unknown linkage %d",
+ sd, ryo -> ryo_name, rox -> rox_linkid);
+ return ureject (sd, ROS_IP_LINKED, rox, roi);
+ }
+ advise (LLOG_NOTICE, NULLCP, "RO-INVOKE.INDICATION/%d: %s",
+ sd, ryo -> ryo_name);
+
+ ia5 = NULL;
+ ia5p = &ia5;
+
+#ifndef SYS5
+ if ((ud = open ("/etc/utmp", 0)) == NOTOK) {
+ int result;
+
+ (void) sprintf (buffer, "/etc/utmp: %s", sys_errname (errno));
+ if ((*ia5p = str2ia5list (buffer)) == NULL)
+ goto congested;
+ ia5p = &((*ia5p) -> next);
+
+ result = error (sd, error_IMISC_unableToOpenFile, (caddr_t) ia5, rox,
+ roi);
+
+ free_IMISC_IA5List (ia5);
+
+ return result;
+ }
+
+ while (read (ud, (char *) ut, sizeof *ut) == sizeof *ut) {
+ if (ut -> ut_name[0] == NULL)
+ continue;
+ if ((dp = ctime (&ut -> ut_time)) == NULL)
+ goto congested;
+ (void) sprintf (buffer, "%-*.*s %-*.*s %.12s",
+ NMAX, NMAX, ut -> ut_name, LMAX, LMAX, ut -> ut_line, dp + 4);
+#ifdef BSD42
+ if (ut -> ut_host[0])
+ (void) sprintf (buffer + strlen (buffer), "\t(%.*s)",
+ HMAX, ut -> ut_host);
+#endif
+
+ if ((*ia5p = str2ia5list (buffer)) == NULL)
+ goto congested;
+ ia5p = &((*ia5p) -> next);
+ }
+ (void) close (ud);
+#else
+ setutent ();
+ while (ut = getutent ()) {
+ if (ut -> ut_type != USER_PROCESS)
+ continue;
+ if ((dp = ctime (&ut -> ut_time)) == NULL)
+ goto congested;
+ (void) sprintf (buffer, "%-*.*s %-*.*s %.12s",
+ NMAX, NMAX, ut -> ut_name, LMAX, LMAX, ut -> ut_line,
+ dp + 4);
+
+ if ((*ia5p = str2ia5list (buffer)) == NULL)
+ goto congested;
+ ia5p = &((*ia5p) -> next);
+ }
+ endutent ();
+#endif
+
+ if (RyDsResult (sd, rox -> rox_id, (caddr_t) ia5, ROS_NOPRIO, roi)
+ == NOTOK)
+ ros_adios (&roi -> roi_preject, "RESULT");
+ free_IMISC_IA5List (ia5);
+
+ return OK;
+
+congested: ;
+ free_IMISC_IA5List (ia5);
+
+ return error (sd, error_IMISC_congested, (caddr_t) NULL, rox, roi);
+}
+
+
+#ifdef bsd43_ut_host
+#define BSD42
+#undef SYS5
+#endif
+
+/* \f */
+
+#define NBYTES 512
+#define LINSIZ 72
+
+
+/* ARGSUSED */
+
+static int op_charGen (sd, ryo, rox, in, roi)
+int sd;
+struct RyOperation *ryo;
+struct RoSAPinvoke *rox;
+caddr_t in;
+struct RoSAPindication *roi;
+{
+ register int i,
+ j;
+ register char *dp,
+ *de,
+ *rs,
+ *rp,
+ *re;
+ char line[LINSIZ + 1],
+ ring[BUFSIZ];
+ struct type_IMISC_IA5List *ia5;
+ register struct type_IMISC_IA5List **ia5p;
+
+ if (rox -> rox_nolinked == 0) {
+ advise (LLOG_EXCEPTIONS, NULLCP,
+ "RO-INVOKE.INDICATION/%d: %s, unknown linkage %d",
+ sd, ryo -> ryo_name, rox -> rox_linkid);
+ return ureject (sd, ROS_IP_LINKED, rox, roi);
+ }
+ advise (LLOG_NOTICE, NULLCP, "RO-INVOKE.INDICATION/%d: %s",
+ sd, ryo -> ryo_name);
+
+ re = ring;
+ for (i = 0; i < 0x80; i++)
+ if (isprint ((u_char) i))
+ *re++ = i;
+
+ ia5 = NULL;
+ ia5p = &ia5;
+
+ for (rs = ring, i = NBYTES; i > 0; rs++, i -= j) {
+ if (rs >= re)
+ rs = ring;
+ j = i > LINSIZ ? LINSIZ : i;
+ for (de = (dp = line) + j, rp = rs; dp < de; dp++, rp++) {
+ if (rp >= re)
+ rp = ring;
+ *dp = *rp;
+ }
+
+ *dp = NULL;
+ if ((*ia5p = str2ia5list (line)) == NULL)
+ goto congested;
+ ia5p = &((*ia5p) -> next);
+ }
+
+ if (RyDsResult (sd, rox -> rox_id, (caddr_t) ia5, ROS_NOPRIO, roi)
+ == NOTOK)
+ ros_adios (&roi -> roi_preject, "RESULT");
+ free_IMISC_IA5List (ia5);
+
+ return OK;
+
+congested: ;
+ free_IMISC_IA5List (ia5);
+
+ return error (sd, error_IMISC_congested, (caddr_t) NULL, rox, roi);
+}
+
+/* \f */
+
+#define NPASS 6
+
+
+/* ARGSUSED */
+
+static int op_pwdGen (sd, ryo, rox, in, roi)
+int sd;
+struct RyOperation *ryo;
+struct RoSAPinvoke *rox;
+caddr_t in;
+struct RoSAPindication *roi;
+{
+ register int i;
+ char buffer[BUFSIZ];
+ struct type_IMISC_IA5List *ia5;
+ register struct type_IMISC_IA5List **ia5p;
+
+ if (rox -> rox_nolinked == 0) {
+ advise (LLOG_EXCEPTIONS, NULLCP,
+ "RO-INVOKE.INDICATION/%d: %s, unknown linkage %d",
+ sd, ryo -> ryo_name, rox -> rox_linkid);
+ return ureject (sd, ROS_IP_LINKED, rox, roi);
+ }
+ advise (LLOG_NOTICE, NULLCP, "RO-INVOKE.INDICATION/%d: %s",
+ sd, ryo -> ryo_name);
+
+ ia5 = NULL;
+ ia5p = &ia5;
+
+ for (i = NPASS; i > 0; i--) {
+ if (pwdgen (buffer) == NOTOK)
+ goto congested;
+
+ if ((*ia5p = str2ia5list (buffer)) == NULL)
+ goto congested;
+ ia5p = &((*ia5p) -> next);
+ }
+
+ if (RyDsResult (sd, rox -> rox_id, (caddr_t) ia5, ROS_NOPRIO, roi)
+ == NOTOK)
+ ros_adios (&roi -> roi_preject, "RESULT");
+ free_IMISC_IA5List (ia5);
+
+ return OK;
+
+congested: ;
+ free_IMISC_IA5List (ia5);
+
+ return error (sd, error_IMISC_congested, (caddr_t) NULL, rox, roi);
+}
+
+/* \f */
+
+/* Based on an f77 algorithm supplied by Frank Wancho <Wancho@SIMTEL20>,
+ which was based on a basic algorithm by Paul D. Merillat and Arthur A. Key.
+
+ Strings returned are built by alternating vowels and consonants.
+ However, there are "Digraphs", and these are presorted according to
+ END, MIDDLE, and START positions.
+
+ Not going into combinatorial analysis (with 7 characters the "possible"
+ combinations exceed 20 million).
+ */
+
+
+#define TOT 54636577
+
+static struct pair {
+ char *p_form;
+ int p_value;
+} pairs[] = {
+ "cvcvcvce", 0,
+ "vcvcvcvc", 10827189,
+ "cpcpce", 13725209,
+ "dvcpce", 14036249,
+ "vcvcpce", 14327369,
+ "cvcpme", 15296369,
+ "dvcvcvc", 15746954,
+ "cpcvcvc", 16617618,
+ "cvmvcvc", 17547858,
+ "cvcpcvc", 23616474,
+ "cvcvmvc", 24546714,
+ "dpcvce", 30618378,
+ "dvmvce", 30908898,
+ "cpmvce", 32807107,
+ "vmvcvce", 34838173,
+ "vcpcvce", 41163763,
+ "vcvmvce", 42132163,
+ "vmvmvc", 48449078,
+ "vmpcvc", 51995642,
+ "vmvcpc", 52539386,
+ "vcvmpc", 52962661,
+ "vmpme", 53385611,
+ "dvmpc", 53648987,
+ "cpmpc", 53776002,
+ "cvcvcpc", 53912072,
+
+ NULL, TOT
+};
+
+
+static char *Mx;
+static char *Nx = /* XXX */
+ "BBBCBFBKBLBMBNBPBTBVCCCDCFCMCPDBDCDDDFDGDKDLDMDNDPDTDVDWDZFBFCFDFGFKFMFNF\
+PFZGBGDGFGJGMGNGPGTGVKBKDKFKMKNKPKTKVKZLBLCLFLGLMLNLRLVLZMBMCMDMFMGMJMKMLMMMNM\
+RMTMVMZNBNCNFNOSZTBTCTDTFTGTJTKTLTMTNTPTVVCVGVLVPNJNLNPNRPCPDPFPGPKPMPNPVPZRBR\
+CRDRFRGRJRLSBSDSFSGSJSRSV";
+
+static char *Cx = /* consonants */
+ "BCDFGHJKLMNPRSTVWZ";
+
+static char *Vx = /* vowels */
+ "AEIOU";
+
+static char *Dx = /* consonant pairs */
+ "BRCHCLCRDRFLFRGLGRKLKRPHPLPRQUSCSHSKSLSMSNSPSTSWTHTRTW";
+
+static char *Lx = /* end-consonant pairs */
+ "BSCKCSCTDSFSFTGSHSKSLLLDLKLPLSLTMPMSNDNKNNNSNTPPPSPTRKRMRNRPRSSSTSVSWS";
+
+static char *Px = /* vowel pairs */
+ "AIEAEEIEIOOIOOOU";
+
+static char *Ex = /* end-vowels */
+ "EOAY";
+
+static char *Zx = /* end-vowel pairs */
+ "EEOOAYEYOY";
+
+static struct web {
+ char w_key;
+ int w_length;
+ int w_factor;
+ char **w_string;
+ char *w_special;
+} webs[] = {
+ 'm', 189, 2, &Mx, NULL,
+ 'c', 18, 1, &Cx, "HWJ",
+ 'v', 5, 1, &Vx, NULL,
+ 'd', 27, 2, &Dx, NULL,
+ 'l', 35, 2, &Lx, NULL,
+ 'p', 8, 2, &Px, NULL,
+ 'e', 4, 1, &Ex, NULL,
+ 'z', 5, 2, &Zx, NULL,
+
+ NULL, 0, 0, NULL, NULL
+};
+
+/* \f */
+
+#define ifix(f) ((int) ((float) (f) + 0.5))
+#ifndef SYS5
+#define nrand() (((float) (random ()) / (float) 2147483647))
+
+long random ();
+#else
+#define nrand() (((float) (rand ()) / (float) 2147483647))
+
+int rand (), srand ();
+#endif
+#define rng(a,b) if (((i = ifix (a * nrand ()) * b) ? i -= b : i) < 0 \
+ || i >= a * b + (1 - b)) \
+ return NOTOK;
+
+
+static int pwdgen (pw)
+char *pw;
+{
+ register int i,
+ j;
+ register char c,
+ *f,
+ *s;
+ register struct pair *pair;
+ register struct web *web;
+ static int latch = 0;
+
+ if (!latch) {
+ if ((Mx = malloc
+ (((unsigned) (strlen (Dx) + strlen (Lx) + strlen (Nx)))))
+ == NULL)
+ return NOTOK;
+ (void) strcpy (s = Mx, Dx);
+ s += strlen (s);
+ (void) strcpy (s, Lx);
+ s += strlen (s);
+ (void) strcpy (s, Nx);
+ s += strlen (s);
+
+#ifndef SYS5
+ (void) srandom ((int) time ((long *) 0));
+#else
+ (void) srand ((unsigned int) time ((long *) 0));
+#endif
+
+ latch++;
+ }
+
+ rng (TOT, 1.0);
+ for (pair = pairs; pair -> p_form; pair++)
+ if (pair -> p_value < i)
+ f = pair -> p_form;
+ else
+ break;
+
+ do {
+ for (s = pw; c = *f++;) {
+ for (web = webs; web -> w_key != c; web++)
+ if (web -> w_key == c)
+ break;
+ if (!web -> w_key)
+ return NOTOK;
+
+ rng (web -> w_length, web -> w_factor);
+
+ for (j = web -> w_factor; j > 0; j--)
+ *s++ = (*web -> w_string)[i++];
+ if (web -> w_special && *f == NULL) {
+ s--, i--;
+ while (index (web -> w_special, *s))
+ *s = (*web -> w_string)[--i];
+ s++;
+ }
+ }
+
+ *s = NULL;
+ } while (object (pw));
+
+ return OK;
+}
+
+/* \f */
+
+static struct obj {
+ char *o_string;
+ int o_advance;
+} objects[] = {
+ "TRAFLLEHPARCTIHS", 4,
+ "SIPSSATITDOGCUFKUF", 3,
+
+ NULL, 0
+};
+
+
+static int object (pw)
+register char *pw;
+{
+ register int n;
+ register char *f,
+ *s;
+ char buffer[BUFSIZ];
+ register struct obj *o;
+
+ for (f = buffer + strlen (s = pw), *f = NULL; *s; s++)
+ *--f = *s;
+
+ for (o = objects; s = o -> o_string; o++)
+ for (n = o -> o_advance; *s; s += n)
+ if (strncmp (f, s, n) == 0)
+ return NOTOK;
+
+ return OK;
+}
+
+/* \f */
+
+#ifndef FORTUNE
+#define FORTUNE "/usr/games/fortune"
+#endif
+#ifndef RFINGER
+#ifndef SYS5
+#define RFINGER "/usr/ucb/finger"
+#else
+#define RFINGER "/usr/bin/finger"
+#endif
+#endif
+
+
+static int op_exec (sd, ryo, rox, in, roi)
+int sd;
+struct RyOperation *ryo;
+struct RoSAPinvoke *rox;
+caddr_t in;
+struct RoSAPindication *roi;
+{
+ int fd,
+ i,
+ result,
+ vecp,
+ vecq,
+ pd[2];
+ register char *bp,
+ *dp;
+ char buffer[BUFSIZ],
+ data[BUFSIZ],
+ *pgm,
+ *vec[NVEC + 1];
+ struct type_IMISC_IA5List *ia5;
+ register struct type_IMISC_IA5List **ia5p;
+
+ vecp = vecq = 0;
+ if (rox -> rox_nolinked == 0) {
+ advise (LLOG_EXCEPTIONS, NULLCP,
+ "RO-INVOKE.INDICATION/%d: %s, unknown linkage %d",
+ sd, ryo -> ryo_name, rox -> rox_linkid);
+ result = ureject (sd, ROS_IP_LINKED, rox, roi);
+ goto out;
+ }
+ advise (LLOG_NOTICE, NULLCP, "RO-INVOKE.INDICATION/%d: %s",
+ sd, ryo -> ryo_name);
+
+ if (ryo -> ryo_op == operation_IMISC_qotd) {
+ vec[vecp++] = pgm = FORTUNE;
+ vecq = vecp;
+ }
+ else {
+ vec[vecp++] = pgm = RFINGER;
+#ifdef RFOPT1
+ vec[vecp++] = RFOPT1;
+#endif
+#ifdef RFOPT2
+ vec[vecp++] = RFOPT2;
+#endif
+ vecq = vecp;
+ for (ia5 = (struct type_IMISC_IA5List *) in; ia5; ia5 = ia5 -> next)
+ if (vecp >= NVEC
+ || (vec[vecp++] = qb2str (ia5 -> IA5String)) == NULLCP) {
+ result = error (sd, error_IMISC_congested, (caddr_t) NULL, rox,
+ roi);
+ goto out;
+ }
+ }
+ vec[vecp] = NULLCP;
+
+ ia5 = NULL;
+ ia5p = &ia5;
+
+ if (access (pgm, 1) == NOTOK) {
+ result = error_IMISC_unableToAccessFile;
+
+oops: ;
+ free_IMISC_IA5List (ia5);
+ ia5 = NULL;
+ ia5p = &ia5;
+
+ (void) sprintf (buffer, "%s: %s", pgm, sys_errname (errno));
+ if ((*ia5p = str2ia5list (buffer)) == NULL)
+ goto congested;
+ ia5p = &((*ia5p) -> next);
+
+ result = error (sd, result, (caddr_t) ia5, rox, roi);
+
+ free_IMISC_IA5List (ia5);
+
+ goto out;
+ }
+ if (pipe (pd) == NOTOK) {
+ result = error_IMISC_unableToPipe;
+ goto oops;
+ }
+
+ switch (vfork ()) {
+ case NOTOK:
+ (void) close (pd[0]);
+ (void) close (pd[1]);
+ result = error_IMISC_unableToFork;
+ goto oops;
+
+ case OK:
+ if ((fd = open ("/dev/null", 2)) != NOTOK) {
+ if (fd != 0)
+ (void) dup2 (fd, 0), (void) close (fd);
+ }
+ (void) dup2 (pd[1], 1);
+ (void) dup2 (pd[1], 2);
+ (void) close (pd[0]);
+ (void) close (pd[1]);
+ if (execuid != 0) {
+ (void) setgid (execgid);
+ (void) setuid (execuid);
+ }
+ execvp (pgm, vec);
+ _exit (1);
+
+ default:
+ (void) close (pd[1]);
+ for (vecp = vecq; bp = vec[vecp]; vecp++) {
+ free (bp);
+ vec[vecp] = NULL;
+ }
+
+ for (; vecq < vecp; vecq++)
+ if (bp = vec[vecq])
+ free (bp);
+ for (dp = data;;)
+ switch (i = read (pd[0], buffer, sizeof buffer)) {
+ case NOTOK:
+ i = errno;
+ (void) close (pd[0]);
+ errno = i;
+ result = error_IMISC_errorReading;
+ goto oops;
+
+ case OK:
+ (void) close (pd[0]);
+ if (dp != data) {
+ *dp = NULL;
+ if ((*ia5p = str2ia5list (data)) == NULL)
+ goto congested;
+ ia5p = &((*ia5p) -> next);
+ }
+ if (RyDsResult (sd, rox -> rox_id, (caddr_t) ia5,
+ ROS_NOPRIO, roi) == NOTOK)
+ ros_adios (&roi -> roi_preject, "RESULT");
+ free_IMISC_IA5List (ia5);
+ result = OK;
+ goto out;
+
+ default:
+ for (bp = buffer; i > 0; bp++, i--)
+ switch (*bp) {
+ case '\n':
+ *dp = NULL;
+ if ((*ia5p = str2ia5list (data)) == NULL)
+ goto congested;
+ ia5p = &((*ia5p) -> next);
+ dp = data;
+ break;
+
+ case NULL:
+ break;
+
+ default:
+ *dp++ = *bp;
+ break;
+ }
+ continue;
+ }
+ }
+
+congested: ;
+ free_IMISC_IA5List (ia5);
+ result = error (sd, error_IMISC_congested, (caddr_t) NULL, rox, roi);
+
+out: ;
+ for (vecp = vecq; bp = vec[vecp]; vecp++)
+ free (bp);
+
+ return result;
+}
+
+/* \f */
+
+/* ARGSUSED */
+
+static int op_tellUser (sd, ryo, rox, in, roi)
+int sd;
+struct RyOperation *ryo;
+struct RoSAPinvoke *rox;
+caddr_t in;
+struct RoSAPindication *roi;
+{
+#ifndef SYS5
+ int ud;
+#endif
+ int hit,
+ result,
+ vecp;
+ char *bp,
+ *fromuser,
+ *touser,
+ buffer[BUFSIZ],
+ **vec,
+ *vecl[NVEC + 1];
+ struct utmp uts;
+ register struct utmp *ut = &uts;
+ struct type_IMISC_IA5List *ia5;
+
+ vecp = 0;
+ if (rox -> rox_nolinked == 0) {
+ advise (LLOG_EXCEPTIONS, NULLCP,
+ "RO-INVOKE.INDICATION/%d: %s, unknown linkage %d",
+ sd, ryo -> ryo_name, rox -> rox_linkid);
+ result = ureject (sd, ROS_IP_LINKED, rox, roi);
+ goto out;
+ }
+ advise (LLOG_NOTICE, NULLCP, "RO-INVOKE.INDICATION/%d: %s",
+ sd, ryo -> ryo_name);
+
+ for (ia5 = (struct type_IMISC_IA5List *) in; ia5; ia5 = ia5 -> next)
+ if (vecp >= NVEC
+ || (vecl[vecp++] = qb2str (ia5 -> IA5String)) == NULLCP)
+ goto congested;
+ vecl[vecp] = NULLCP;
+
+ if (vecp < 3) {
+ advise (LLOG_EXCEPTIONS, NULLCP,
+ "too few arguments (got %d, wanted at least 3)", vecp);
+ result = ureject (sd, ROS_IP_MISTYPED, rox, roi);
+ goto out;
+ }
+ fromuser = vecl[0];
+ touser = vecl[1];
+ vec = &vecl[2], vecp -= 2;
+
+ hit = 0;
+ result = error_IMISC_userNotLoggedIn;
+#ifndef SYS5
+ if ((ud = open ("/etc/utmp", 0)) == NOTOK) {
+ (void) sprintf (buffer, "/etc/utmp: %s", sys_errname (errno));
+ if ((ia5 = str2ia5list (buffer)) == NULL)
+ goto congested;
+
+ result = error (sd, error_IMISC_unableToOpenFile, (caddr_t) ia5, rox,
+ roi);
+
+ free_IMISC_IA5List (ia5);
+
+ goto out;
+ }
+
+ while (read (ud, (char *) ut, sizeof *ut) == sizeof *ut) {
+ if (ut -> ut_name[0] == NULL)
+ continue;
+ if (strncmp (ut -> ut_name, touser, sizeof ut -> ut_name) == 0)
+ if (do_the_tell (ut, fromuser, vec, vecp) != NOTOK)
+ hit++;
+ else
+ result = error_IMISC_unableToOpenFile;
+ }
+ (void) close (ud);
+#else
+ setutent ();
+ while (ut = getutent ()) {
+ if (ut -> ut_type != USER_PROCESS)
+ continue;
+ if (strncmp (ut -> ut_name, touser, sizeof ut -> ut_name) == 0)
+ if (do_the_tell (ut, fromuser, vec, vecp) != NOTOK)
+ hit++;
+ else
+ result = error_IMISC_unableToOpenFile;
+ }
+ endutent ();
+#endif
+ if (hit == 0) {
+ result = error (sd, result, (caddr_t) NULL, rox, roi);
+ goto out;
+ }
+
+ if (RyDsResult (sd, rox -> rox_id, (caddr_t) NULL, ROS_NOPRIO, roi)
+ == NOTOK)
+ ros_adios (&roi -> roi_preject, "RESULT");
+
+ result = OK;
+ goto out;
+
+congested: ;
+ result = error (sd, error_IMISC_congested, (caddr_t) NULL, rox, roi);
+
+out: ;
+ for (vecp = 0; bp = vecl[vecp]; vecp++)
+ free (bp);
+
+ return result;
+}
+
+/* \f */
+
+static int do_the_tell (ut, from, vec, vecp)
+struct utmp *ut;
+char *from;
+char *vec[];
+int vecp;
+{
+ int i,
+ pid;
+ char *bp,
+ tty[5 + LMAX + 1];
+ struct stat st;
+ FILE *fp;
+
+ (void) strcpy (bp = tty, "/dev/");
+ bp += strlen (bp);
+ (void) strncpy (bp, ut -> ut_line, LMAX);
+ bp += LMAX;
+ *bp = NULL;
+ if (stat (tty, &st) == NOTOK
+ || (st.st_mode & (S_IWRITE >> 3)) != (S_IWRITE >> 3))
+ return NOTOK;
+
+ for (i = 0; i < 5; i++) {
+ switch (pid = fork ()) {
+ case NOTOK:
+ continue;
+
+ case 0:
+ break;
+
+ default:
+ return OK;
+ }
+ break;
+ }
+ if (pid == NOTOK)
+ return NOTOK;
+ if ((fp = fopen (tty, "w")) == NULL)
+ _exit (1);
+ fprintf (fp, "\r\nmessage from %s:\r\n\007", from);
+ for (i = 0, bp = NULL; i < vecp; i++, bp = " ") {
+ if (bp)
+ fputs (bp, fp);
+ fputs (vec[i], fp);
+ }
+ fputs ("\r\n", fp);
+ (void) fclose (fp);
+ _exit (0); /* NOTREACHED */
+}
+
+/* \f */
+
+static int op_data (sd, ryo, rox, in, roi)
+int sd;
+struct RyOperation *ryo;
+struct RoSAPinvoke *rox;
+caddr_t in;
+struct RoSAPindication *roi;
+{
+ if (rox -> rox_nolinked == 0) {
+ advise (LLOG_EXCEPTIONS, NULLCP,
+ "RO-INVOKE.INDICATION/%d: %s, unknown linkage %d",
+ sd, ryo -> ryo_name, rox -> rox_linkid);
+ return ureject (sd, ROS_IP_LINKED, rox, roi);
+ }
+ if (debug)
+ advise (LLOG_DEBUG, NULLCP, "RO-INVOKE.INDICATION/%d: %s",
+ sd, ryo -> ryo_name);
+
+ if (RyDsResult (sd, rox -> rox_id, ryo -> ryo_op == operation_IMISC_echo
+ ? in : (caddr_t) NULL, ROS_NOPRIO, roi) == NOTOK)
+ ros_adios (&roi -> roi_preject, "RESULT");
+
+ return OK;
+}
+
+/* \f ERROR */
+
+static int error (sd, err, param, rox, roi)
+int sd,
+ err;
+caddr_t param;
+struct RoSAPinvoke *rox;
+struct RoSAPindication *roi;
+{
+ if (RyDsError (sd, rox -> rox_id, err, param, ROS_NOPRIO, roi) == NOTOK)
+ ros_adios (&roi -> roi_preject, "ERROR");
+
+ return OK;
+}
+
+/* \f U-REJECT */
+
+static int ureject (sd, reason, rox, roi)
+int sd,
+ reason;
+struct RoSAPinvoke *rox;
+struct RoSAPindication *roi;
+{
+ if (RyDsUReject (sd, rox -> rox_id, reason, ROS_NOPRIO, roi) == NOTOK)
+ ros_adios (&roi -> roi_preject, "U-REJECT");
+
+ return OK;
+}
+
+/* \f TYPES */
+
+struct type_IMISC_IA5List *str2ia5list (s)
+char *s;
+{
+ register struct type_IMISC_IA5List *ia5;
+
+ if ((ia5 = (struct type_IMISC_IA5List *) calloc (1, sizeof *ia5)) == NULL)
+ return NULL;
+
+ if ((ia5 -> IA5String = str2qb (s, strlen (s), 1)) == NULL) {
+ free ((char *) ia5);
+ return NULL;
+ }
+
+ return ia5;
+}