/* Copyright (C) 1991, Marcus J. Ranum. All rights reserved. */ /* configure all options BEFORE including system stuff. */ #include "config.h" #include "mud.h" #include "xact.h" #include "sbuf.h" typedef void (*sighandler_t) (int); #ifndef FD_SET #define NBBY 8 #define NFDBITS (sizeof(long) * NBBY) #define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS))) #define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS))) #define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS))) #define FD_ZERO(p) bzero((char *)(p), sizeof(*(p))) #endif /* #define XMITBSD_DEBUG */ /* don't bother being too big - this is a TCP */ #define XMBUFSIZ 1024 /* default timeout for I/O or connections */ #define DEFAULT_TIMEOUT 2 /* mud database entry */ typedef struct mudent { int flg; char *name; char *plyport; char *host; char *symhost; char *rempw; char *locpw; struct sockaddr_in addr; int timot; struct mudent *next; } Mudent; /* buffered connection */ typedef struct { SOCKET fd; char ibuf[XMBUFSIZ]; char *ibp; int ibc; char obuf[XMBUFSIZ]; char *obp; Mudent *curmp; } Cnxt; int xc_write (char *, ...); static Mudent *getmudent(char *mud); static Mudent *isknownmud(char *mud); static Mudent *mud_list; static Cnxt xbuf; static Mudent *lastmud = (Mudent *) 0; /* Look up the remote MUD and set the context up right */ int set_remmud (char *nam) { Mudent *mp; if ((mp = getmudent (nam)) == (Mudent *) 0) return (1); lastmud = xbuf.curmp = mp; return (0); } int xc_open (char *mud) { Mudent *mp; #ifdef WIN32 unsigned long flags = 1; #endif if ((mp = getmudent (mud)) == (Mudent *) 0) { log_printf ("unknown mud ", mud, "\n", (char *) 0); return (-1); } if ((xbuf.fd = socket (AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) { perror ("socket"); return (-1); } #ifdef WIN32 ioctlsocket (xbuf.fd, FIONBIO, &flags); #else fcntl (xbuf.fd, F_SETFL, FNDELAY); #endif /* this may EWOULDBLOCK, which is OK */ if (connect (xbuf.fd, (struct sockaddr *) &(mp->addr), sizeof (struct sockaddr_in)) == SOCKET_ERROR) { fd_set msk; sighandler_t sigsaved; struct timeval timo; #ifdef EINPROGRESS if (GETERROR != EWOULDBLOCK && GETERROR != EINPROGRESS) { #else if (GETERROR != EWOULDBLOCK) { #endif shutdown (xbuf.fd, 2); closesocket (xbuf.fd); #ifdef XMITBSD_DEBUG perror ("connect"); #endif log_printf ("connection to ", mud, " failed ", (char *) -1, "\n", (char *) 0); return (-1); } FD_ZERO (&msk); FD_SET (xbuf.fd, &msk); timo.tv_usec = 0; timo.tv_sec = mp->timot; if (select (xbuf.fd + 1, 0, &msk, 0, &timo) != 1) { shutdown (xbuf.fd, 2); closesocket (xbuf.fd); #ifdef XMITBSD_DEBUG perror ("connect failed (timeout?)"); #endif log_printf ("connection to ", mud, " timeout ", (char *) -1, "\n", (char *) 0); return (-1); } /* Probe the fd to see if the connect() worked */ #ifndef WIN32 sigsaved = signal (SIGPIPE, SIG_IGN); #endif if (write (xbuf.fd, "", 0) < 0) { #ifndef WIN32 signal (SIGPIPE, sigsaved); #endif return (-1); } #ifndef WIN32 signal (SIGPIPE, sigsaved); #endif } #ifdef XMITBSD_DEBUG (void) printf ("<<<connected>>>\n"); #endif log_printf ("connection to ", mud, "\n", (char *) 0); xbuf.ibp = xbuf.ibuf; xbuf.ibc = 0; xbuf.obp = xbuf.obuf; *xbuf.ibp = *xbuf.obp = '\0'; lastmud = xbuf.curmp = mp; return (0); } int xc_initfd (SOCKET fd) { #ifdef WIN32 unsigned long flags = 1; #endif xbuf.fd = fd; xbuf.ibp = xbuf.ibuf; xbuf.ibc = 0; xbuf.obp = xbuf.obuf; *xbuf.ibp = *xbuf.obp = '\0'; #ifdef WIN32 ioctlsocket (xbuf.fd, FIONBIO, &flags); #else fcntl (xbuf.fd, F_SETFL, FNDELAY); #endif return (0); } /* Send out an OIF Level 2 greet string to the current mud */ int xmit_greet () { /* Firewall. This should NEVER happen. */ if (xbuf.curmp == (Mudent *) 0) return (-1); if (xc_write ("UnterMUD ", mud_getname (), " ", version, " ", (xbuf.curmp)->locpw, "\n", (char *) 0)) return (-1); if (xc_flush ()) return (-1); return (0); } /* Return 0 if pwd is OK */ int check_rempwd (char *pwd) { /* NEVER happen. */ if (xbuf.curmp == (Mudent *) 0) return (1); return (strcmp (pwd, (xbuf.curmp)->rempw)); } /* These grub data out of the LAST Mud contacted. */ char *xc_getips () { if (lastmud == (Mudent *) 0) return (""); return (inet_ntoa (lastmud->addr.sin_addr)); } char *xc_getmudname () { if (lastmud == (Mudent *) 0) { return (""); } return (lastmud->name); } char *xc_gethostname () { if (lastmud == (Mudent *) 0) return (""); return (lastmud->symhost); } char *xc_getport () { if (lastmud == (Mudent *) 0) return (""); return (lastmud->plyport); } static Mudent *getmudent (char *mud) { Mudent *mp = mud_list; while (mp != (Mudent *) 0) { if (!strcmp (mud, mp->name)) return (mp); mp = mp->next; } return ((Mudent *) 0); } /* define a MUD entry. One semi-sensible thing done here is to pre-resolve the addresses and just stash those. this way we shouldn't have to hit our resolver a whole lot once the MUD is up, if at all. also accept "dot" notation. */ int xmit_def_mudent (char *name, char *host, char *symhost, char *rempw, char *locpw, char *port, char *plyport, char *timot) { Mudent *np; #ifndef NO_HUGE_RESOLVER_CODE struct hostent *hp; #endif struct sockaddr_in tmpa; char *p; p = host; while (*p != '\0' && (*p == '.' || isdigit (*p))) p++; if (*p != '\0') { #ifndef NO_HUGE_RESOLVER_CODE if ((hp = gethostbyname (host)) == (struct hostent *) 0) { log_printf ("unknown host ", host, "\n", (char *) 0); return (1); } (void) bcopy (hp->h_addr, (char *) &tmpa.sin_addr, hp->h_length); #else log_printf ("must use 'dot' notation to define host ", host, "\n", (char *) 0); return (1); #endif } else { #ifdef WIN32 unsigned long f; #else struct in_addr f; #endif #ifdef WIN32 if ((f = inet_addr (host)) == INADDR_NONE) return 1; #else if (inet_aton (host, &f) == 0) return 1; #endif bcopy ((char *) &f, (char *) &tmpa.sin_addr, sizeof (f)); } if ((np = (Mudent *) malloc (sizeof (Mudent))) == (Mudent *) 0) { log_printf ("cannot allocate remote mud map\n", (char *) 0); return (1); } bcopy ((char *) &tmpa.sin_addr, &(np->addr.sin_addr), sizeof (tmpa.sin_addr)); np->addr.sin_port = htons (atoi (port)); np->addr.sin_family = AF_INET; if (timot != (char *) 0) np->timot = atoi (timot); else np->timot = DEFAULT_TIMEOUT; np->name = (char *) malloc ((unsigned) (strlen (name) + 1)); np->rempw = (char *) malloc ((unsigned) (strlen (rempw) + 1)); np->locpw = (char *) malloc ((unsigned) (strlen (locpw) + 1)); np->plyport = (char *) malloc ((unsigned) (strlen (plyport) + 1)); np->host = (char *) malloc ((unsigned) (strlen (host) + 1)); np->symhost = (char *) malloc ((unsigned) (strlen (symhost) + 1)); if (np->name == (char *) 0 || np->rempw == (char *) 0 || np->locpw == (char *) 0 || np->plyport == (char *) 0 || np->host == (char *) 0 || np->symhost == (char *) 0) { log_printf ("cannot allocate remote mud data. owie.\n", (char *) 0); return (1); } (void) strcpy (np->name, name); (void) strcpy (np->rempw, rempw); (void) strcpy (np->locpw, locpw); (void) strcpy (np->plyport, plyport); (void) strcpy (np->host, host); (void) strcpy (np->symhost, symhost); np->flg = 0; /* link on */ np->next = mud_list; mud_list = np; return (0); } void xc_close () { shutdown (xbuf.fd, 2); closesocket (xbuf.fd); xbuf.fd = -1; xbuf.curmp = (Mudent *) 0; log_printf ("hang up connection\n", (char *) 0); #ifdef XMITBSD_DEBUG (void) printf ("<<<dis-connected>>>\n"); #endif } int xc_sbread (Sbuf * sb) { if (xbuf.fd == -1 || sb == (Sbuf *) 0) return (0); sbuf_reset (sb); while (1) { /* buffer empty ? fill. */ if (xbuf.ibc <= 0) { fd_set msk; struct timeval timo; FD_ZERO (&msk); FD_SET (xbuf.fd, &msk); timo.tv_usec = 0; if (xbuf.curmp != (Mudent *) 0) timo.tv_sec = xbuf.curmp->timot; else timo.tv_sec = DEFAULT_TIMEOUT; if (select (xbuf.fd + 1, &msk, 0, 0, &timo) != 1) { log_printf ("timeout\n", (char *) 0); return (0); } xbuf.ibc = recv (xbuf.fd, xbuf.ibuf, sizeof (xbuf.ibuf), 0); if (xbuf.ibc <= 0) return (0); xbuf.ibp = xbuf.ibuf; } /* end of line? */ if (*xbuf.ibp == '\n') { sbuf_put ('\0', sb); xbuf.ibp++; xbuf.ibc--; return (1); } /* put. */ sbuf_put (*xbuf.ibp, sb); xbuf.ibp++; xbuf.ibc--; } } int xc_flush () { fd_set msk; struct timeval timo; int twrt; FD_ZERO (&msk); FD_SET (xbuf.fd, &msk); timo.tv_usec = 0; if (xbuf.curmp != (Mudent *) 0) timo.tv_sec = xbuf.curmp->timot; else timo.tv_sec = DEFAULT_TIMEOUT; if (select (xbuf.fd + 1, 0, &msk, 0, &timo) != 1) { log_printf ("write timeout\n", (char *) 0); return (1); } twrt = xbuf.obp - xbuf.obuf; if (send (xbuf.fd, xbuf.obuf, twrt, 0) != twrt) return (1); xbuf.obp = xbuf.obuf; return (0); } /* VARARGS */ int xc_write (char *first, ...) { char *s = first; va_list ap; va_start (ap, first); do { while (*s) { if ((xbuf.obp - xbuf.obuf) >= (int) sizeof (xbuf.obuf)) if (xc_flush ()) return (1); *xbuf.obp++ = *s++; } } while (s = va_arg (ap, char *)); va_end (ap); return (0); } /* Maintain a list of MUD-names we've heard about. */ static Mudent *known_muds = 0; static int restrict_known = 0; /* Don't restrict to just known MUDs. */ static Mudent *isknownmud (char *mud) { Mudent *temp, *pos; temp = getmudent (mud); if (temp != NULL) return temp; pos = known_muds; while (pos != NULL) { if (!strcmp (pos->name, mud)) return pos; pos = pos->next; } return (Mudent *) 0; } int xmit_def_knownmud (char *mud) { Mudent *mp; restrict_known = 1; mp = isknownmud (mud); if (mp != 0) return 0; mp = (Mudent *) malloc (sizeof (Mudent)); if (mp == 0) { log_printf ("couldn't alloc memory for knownmud mudent\n", (char *) 0); return 1; } mp->name = (char *) malloc ((unsigned) (strlen (mud) + 1)); if (mp->name == 0) { free (mp); log_printf ("couldn't alloc memory for knownmud name\n", (char *) 0); return 1; } strcpy (mp->name, mud); mp->next = known_muds; known_muds = mp; return 0; } /* A given MUD name is okay if: - we don't have MUD security enabled (we have specified no defknownmuds) - it's a MUD we connect to - it's a MUD listed in a _mudconfig defknownmud or - it's us. */ int xmit_okay_remote (char *name) { if (!restrict_known) return 1; if (isknownmud (name) != 0) return 1; if (!strcmp (name, mud_getname ())) return 1; return 0; }