#include #include "innbbsconf.h" #include "daemon.h" #include "bbslib.h" #include "config.h" #include "externs.h" #include #include #include #include "bbs.h" #define DEBUG #undef DEBUG #ifndef MAXCLIENT #define MAXCLIENT 500 #endif #ifndef ChannelSize #define ChannelSize 4096 #endif #ifndef ReadSize #define ReadSize 1024 #endif #ifndef DefaultINNBBSPort #define DefaultINNBBSPort "7777" #endif #ifndef HIS_MAINT #define HIS_MAINT #define HIS_MAINT_HOUR 5 #define HIS_MAINT_MIN 30 #endif int Maxclient = MAXCLIENT; ClientType *Channel = NULL; ClientType INNBBSD_STAT; int Max_Art_Size = MAX_ART_SIZE; int inetdstart = 0; int Junkhistory = 0; char *REMOTEUSERNAME, *REMOTEHOSTNAME; static fd_set rfd, wfd, efd, orfd, owfd, oefd; int channelreader(ClientType *); void clearfdset(fd) int fd; { FD_CLR(fd, &rfd); } static void channelcreate(client) ClientType *client; { buffer_t *in, *out; in = &client->in; out = &client->out; if (in->data != NULL) free(in->data); in->data = (char *)mymalloc(ChannelSize); in->left = ChannelSize; in->used = 0; if (out->data != NULL) free(out->data); out->data = (char *)mymalloc(ChannelSize); out->used = 0; out->left = ChannelSize; client->ihavecount = 0; client->ihaveduplicate = 0; client->ihavefail = 0; client->ihavesize = 0; client->statcount = 0; client->statfail = 0; client->begin = time(NULL); } void channeldestroy(client) ClientType *client; { if (client->in.data != NULL) { free(client->in.data); client->in.data = NULL; } if (client->out.data != NULL) { free(client->out.data); client->out.data = NULL; } #if !defined(PowerBBS) && !defined(DBZSERVER) if (client->ihavecount > 0 || client->statcount > 0) { bbslog("%s@%s rec: %d dup: %d fail: %d size: %d, stat rec: %d fail: %d, time sec: %d\n", client->username, client->hostname, client->ihavecount, client->ihaveduplicate, client->ihavefail, client->ihavesize, client->statcount, client->statfail, time(NULL) - client->begin); INNBBSD_STAT.ihavecount += client->ihavecount; INNBBSD_STAT.ihaveduplicate += client->ihaveduplicate; INNBBSD_STAT.ihavefail += client->ihavefail; INNBBSD_STAT.ihavesize += client->ihavesize; INNBBSD_STAT.statcount += client->statcount; INNBBSD_STAT.statfail += client->statfail; } #endif } void inndchannel(port, path) char *port, *path; { time_t tvec; int i; int bbsinnd; int localbbsinnd; struct timeval tout; ClientType *client = (ClientType *) mymalloc(sizeof(ClientType) * Maxclient); int localdaemonready = 0; Channel = client; bbsinnd = pmain(port); if (bbsinnd < 0) { perror("pmain, existing"); docompletehalt(0); return; } FD_ZERO(&rfd); FD_ZERO(&wfd); FD_ZERO(&efd); localbbsinnd = p_unix_main(path); if (localbbsinnd < 0) { perror("local pmain, existing"); /* * Kaede if (!inetdstart) fprintf(stderr, "if no other innbbsd * running, try to remove %s\n",path); */ close(bbsinnd); return; } else { FD_SET(localbbsinnd, &rfd); localdaemonready = 1; } FD_SET(bbsinnd, &rfd); tvec = time((time_t *) 0); for (i = 0; i < Maxclient; ++i) { client[i].fd = -1; client[i].access = 0; client[i].buffer[0] = '\0'; client[i].mode = 0; client[i].in.left = 0; client[i].in.used = 0; client[i].in.data = NULL; client[i].out.left = 0; client[i].out.used = 0; client[i].out.data = NULL; client[i].midcheck = 1; } for (;;) { int nsel, i; /* * When to maintain history files. */ time_t now; static int maint = 0; struct tm *local; if (INNBBSDshutdown()) { HISclose(); bbslog(" Shutdown Complete \n"); docompletehalt(0); exit(0); } time(&now); local = localtime(&now); if (local != NULL & local->tm_hour == His_Maint_Hour && local->tm_min >= His_Maint_Min) { if (!maint) { bbslog(":Maint: start (%d:%d).\n", local->tm_hour, local->tm_min); HISmaint(); time(&now); local = localtime(&now); if (local != NULL) bbslog(":Maint: end (%d:%d).\n", local->tm_hour, local->tm_min); maint = 1; } } else { maint = 0; } /* * */ /* * in order to maintain history, timeout every 60 seconds in case no * connections */ tout.tv_sec = 60; tout.tv_usec = 0; orfd = rfd; if ((nsel = select(FD_SETSIZE, &orfd, NULL, NULL, &tout)) < 0) { continue; } if (localdaemonready && FD_ISSET(localbbsinnd, &orfd)) { int ns; ns = tryaccept(localbbsinnd); if (ns < 0) continue; for (i = 0; i < Maxclient; ++i) { if (client[i].fd == -1) break; } if (i == Maxclient) { static char msg[] = "502 no free descriptors\r\n"; printf("%s", msg); write(ns, msg, sizeof(msg)); close(ns); continue; } client[i].fd = ns; client[i].buffer[0] = '\0'; client[i].mode = 0; client[i].midcheck = 1; channelcreate(&client[i]); FD_SET(ns, &rfd); /* FD_SET(ns,&wfd); */ { strncpy(client[i].username, "localuser", 20); strncpy(client[i].hostname, "localhost", 128); client[i].Argv.in = fdopen(ns, "r"); client[i].Argv.out = fdopen(ns, "w"); #if !defined(PowerBBS) && !defined(DBZSERVER) bbslog("connected from (%s@%s).\n", client[i].username, client[i].hostname); #endif #ifdef INNBBSDEBUG printf("connected from (%s@%s).\n", client[i].username, client[i].hostname); #endif #ifdef DBZSERVER fprintf(client[i].Argv.out, "200 %s InterNetNews DBZSERVER server %s (%s@%s).\r\n", MYBBSID, VERSION, client[i].username, client[i].hostname); #else fprintf(client[i].Argv.out, "200 %s InterNetNews INNBBSD server %s (%s@%s).\r\n", MYBBSID, VERSION, client[i].username, client[i].hostname); #endif fflush(client[i].Argv.out); verboselog("UNIX Connect from %s@%s\n", client[i].username, client[i].hostname); } } if (FD_ISSET(bbsinnd, &orfd)) { int ns = tryaccept(bbsinnd), length; struct sockaddr_in there; char *name; struct hostent *hp; if (ns < 0) continue; for (i = 0; i < Maxclient; ++i) { if (client[i].fd == -1) break; } if (i == Maxclient) { static char msg[] = "502 no free descriptors\r\n"; printf("%s", msg); write(ns, msg, sizeof(msg)); close(ns); continue; } client[i].fd = ns; client[i].buffer[0] = '\0'; client[i].mode = 0; client[i].midcheck = 1; channelcreate(&client[i]); FD_SET(ns, &rfd); /* FD_SET(ns,&wfd); */ length = sizeof(there); if (getpeername(ns, (struct sockaddr *) & there, &length) >= 0) { name = (char *)my_rfc931_name(ns, (struct sockaddr_in *)&there); strncpy(client[i].username, name, 20); hp = (struct hostent *) gethostbyaddr((char *)&there.sin_addr, sizeof(struct in_addr), there.sin_family); if (hp) strncpy(client[i].hostname, hp->h_name, 128); else strncpy(client[i].hostname, (char *)inet_ntoa(there.sin_addr), 128); client[i].Argv.in = fdopen(ns, "r"); client[i].Argv.out = fdopen(ns, "w"); if ((char *)search_nodelist(client[i].hostname, client[i].username) == NULL) { bbslog(":Err: invalid connection (%s@%s).\n", client[i].username, client[i].hostname); fprintf(client[i].Argv.out, "502 You are not in my access file. (%s@%s)\r\n", client[i].username, client[i].hostname); fflush(client[i].Argv.out); fclose(client[i].Argv.in); fclose(client[i].Argv.out); close(client[i].fd); FD_CLR(client[i].fd, &rfd); client[i].fd = -1; continue; } bbslog("connected from (%s@%s).\n", client[i].username, client[i].hostname); #ifdef INNBBSDEBUG printf("connected from (%s@%s).\n", client[i].username, client[i].hostname); #endif #ifdef DBZSERVER fprintf(client[i].Argv.out, "200 %s InterNetNews DBZSERVER server %s (%s@%s).\r\n", MYBBSID, VERSION, client[i].username, client[i].hostname); #else fprintf(client[i].Argv.out, "200 %s InterNetNews INNBBSD server %s (%s@%s).\r\n", MYBBSID, VERSION, client[i].username, client[i].hostname); #endif fflush(client[i].Argv.out); verboselog("INET Connect from %s@%s\n", client[i].username, client[i].hostname); } else { } } for (i = 0; i < Maxclient; ++i) { int fd = client[i].fd; if (fd < 0) { continue; } if (FD_ISSET(fd, &orfd)) { int nr; #ifdef DEBUG printf("before read i %d in.used %d in.left %d\n", i, client[i].in.used, client[i].in.left); #endif nr = channelreader(client + i); #ifdef DEBUG printf("after read i %d in.used %d in.left %d\n", i, client[i].in.used, client[i].in.left); #endif /* int nr=read(fd,client[i].buffer,1024); */ if (nr <= 0) { FD_CLR(fd, &rfd); fclose(client[i].Argv.in); fclose(client[i].Argv.out); close(fd); client[i].fd = -1; channeldestroy(client + i); continue; } #ifdef DEBUG printf("nr %d %.*s", nr, nr, client[i].buffer); #endif if (client[i].access == 0) { continue; } } } } } void commandparse(client) ClientType *client; { char *ptr, *lastend; argv_t *Argv = &client->Argv; int (*Main) (); char *buffer = client->in.data; buffer_t *in = &client->in; int dataused; int dataleft; #ifdef DEBUG printf("%s %s buffer %s", client->username, client->hostname, buffer); #endif ptr = (char *)strchr(in->data + in->used, '\n'); if (client->mode == 0) { if (ptr == NULL) { in->used += in->lastread; in->left -= in->lastread; return; } else { dataused = ptr - (in->data + in->used) + 1; dataleft = in->lastread - dataused; lastend = ptr + 1; } } else { if (in->used >= 5) { ptr = (char *)strstr(in->data + in->used - 5, "\r\n.\r\n"); } else if (strncmp(in->data, ".\r\n", 3) == 0) { ptr = in->data; } else { ptr = (char *)strstr(in->data + in->used, "\r\n.\r\n"); } if (ptr == NULL) { in->used += in->lastread; in->left -= in->lastread; return; } else { ptr[2] = '\0'; if (strncmp(in->data, ".\r\n", 3) == 0) dataused = 3; else dataused = ptr - (in->data + in->used) + 5; dataleft = in->lastread - dataused; lastend = ptr + 5; verboselog("Get: %s@%s end of data . size %d\n", client->username, client->hostname, in->used + dataused); client->ihavesize += in->used + dataused; } } if (client->mode == 0) { struct Daemoncmd *dp; Argv->argc = 0, Argv->argv = NULL, Argv->inputline = buffer; if (ptr != NULL) *ptr = '\0'; verboselog("Get: %s\n", Argv->inputline); Argv->argc = argify(in->data + in->used, &Argv->argv); if (ptr != NULL) *ptr = '\n'; dp = (struct Daemoncmd *) searchcmd(Argv->argv[0]); Argv->dc = dp; if (Argv->dc) { #ifdef DEBUG printf("enter command %s\n", Argv->argv[0]); #endif if (Argv->argc < dp->argc) { fprintf(Argv->out, "%d Usage: %s\r\n", dp->errorcode, dp->usage); fflush(Argv->out); verboselog("Put: %d Usage: %s\n", dp->errorcode, dp->usage); } else if (dp->argno != 0 && Argv->argc > dp->argno) { fprintf(Argv->out, "%d Usage: %s\r\n", dp->errorcode, dp->usage); fflush(Argv->out); verboselog("Put: %d Usage: %s\n", dp->errorcode, dp->usage); } else { Main = Argv->dc->main; if (Main) { fflush(stdout); (*Main) (client); } } } else { fprintf(Argv->out, "500 Syntax error or bad command\r\n"); fflush(Argv->out); verboselog("Put: 500 Syntax error or bad command\r\n"); } deargify(&Argv->argv); } else { if (Argv->dc) { #ifdef DEBUG printf("enter data mode\n"); #endif Main = Argv->dc->main; if (Main) { fflush(stdout); (*Main) (client); } } } if (client->mode == 0) { if (dataleft > 0) { strncpy(in->data, lastend, dataleft); #ifdef INNBBSDEBUG printf("***** try to copy %x %x %d bytes\n", in->data, lastend, dataleft); #endif } else { dataleft = 0; } in->left += in->used - dataleft; in->used = dataleft; } } int channelreader(client) ClientType *client; { int len; char *ptr; buffer_t *in = &client->in; if (in->left < ReadSize + 3) { int need = in->used + in->left + ReadSize + 3; need += need / 5; in->data = (char *)myrealloc(in->data, need); in->left = need - in->used; verboselog("channelreader realloc %d\n", need); } len = read(client->fd, in->data + in->used, ReadSize); if (len <= 0) return len; in->data[len + in->used] = '\0'; in->lastread = len; #ifdef DEBUG printf("after read lastread %d\n", in->lastread); printf("len %d client %d\n", len, strlen(in->data + in->used)); #endif REMOTEHOSTNAME = client->hostname; REMOTEUSERNAME = client->username; if (client->mode == 0) { if ((ptr = (char *)strchr(in->data, '\n')) != NULL) { if (in->data[0] != '\r') commandparse(client); } } else { commandparse(client); } return len; } void do_command() { } void dopipesig(s) int s; { printf("catch sigpipe\n"); signal(SIGPIPE, dopipesig); } int standaloneinit(port) char *port; { int ndescriptors; FILE *pf; char pidfile[24]; ndescriptors = getdtablesize(); #ifndef NOFORK if (!inetdstart) if (fork()) exit(0); #endif sprintf(pidfile, "/tmp/innbbsd-%s.pid", port); /* * Kaede if (!inetdstart) fprintf(stderr, "PID file is in %s\n", * pidfile); */ { int s; for (s = 3; s < ndescriptors; s++) (void)close(s); } pf = fopen(pidfile, "w"); if (pf != NULL) { fprintf(pf, "%d\n", getpid()); fclose(pf); } return 0; } extern char *optarg; extern int opterr, optind; void innbbsusage(name) char *name; { fprintf(stderr, "Usage: %s [options] [port [path]]\n", name); fprintf(stderr, " -v (verbose log)\n"); fprintf(stderr, " -h|? (help)\n"); fprintf(stderr, " -n (not to use in core dbz)\n"); fprintf(stderr, " -i (start from inetd with wait option)\n"); fprintf(stderr, " -c connections (maximum number of connections accepted)\n"); fprintf(stderr, " default=%d\n", Maxclient); fprintf(stderr, " -j (keep history of junk article, default=none)\n"); } #ifdef DEBUGNGSPLIT main() { char **ngptr; char buf[1024]; gets(buf); ngptr = (char **)BNGsplit(buf); printf("line %s\n", buf); while (*ngptr != NULL) { printf("%s\n", *ngptr); ngptr++; } } #endif static time_t INNBBSDstartup; int innbbsdstartup(void) { return INNBBSDstartup; } int main(argc, argv) int argc; char **argv; { char *port, *path; int c, errflag = 0; extern INNBBSDhalt(); /* * woju */ setgid(BBSGID); setuid(BBSUID); chdir(BBSHOME); attach_SHM(); resolve_boards(); port = DefaultINNBBSPort; path = LOCALDAEMON; Junkhistory = 0; time(&INNBBSDstartup); openlog("innbbsd", LOG_PID | LOG_ODELAY, LOG_DAEMON); while ((c = getopt(argc, argv, "c:f:s:vhidn?j")) != -1) switch (c) { case 'j': Junkhistory = 1; break; case 'v': verboseon("innbbsd.log"); break; case 'n': hisincore(0); break; case 'c': Maxclient = atoi(optarg); if (Maxclient < 0) Maxclient = 0; break; case 'i':{ struct sockaddr_in there; int len = sizeof(there); int rel; if ((rel = getsockname(0, (struct sockaddr *) & there, &len)) < 0) { fprintf(stdout, "You must run -i from inetd with inetd.conf line: \n"); fprintf(stdout, "service-port stream tcp wait bbs " BBSHOME "/innd/innbbsd innbbsd -i port\n"); fflush(stdout); exit(5); } inetdstart = 1; startfrominetd(1); } break; case 'd': dbzdebug(1); break; case 's': Max_Art_Size = atol(optarg); if (Max_Art_Size < 0) Max_Art_Size = 0; break; case 'h': case '?': default: errflag++; } if (errflag > 0) { innbbsusage(argv[0]); return (1); } if (argc - optind >= 1) { port = argv[optind]; } if (argc - optind >= 2) { path = argv[optind + 1]; } standaloneinit(port); initial_bbs("feed"); /* * Kaede if (!inetdstart) fprintf(stderr, "Try to listen in port %s and * path %s\n", port, path); */ HISmaint(); HISsetup(); installinnbbsd(); sethaltfunction(INNBBSDhalt); signal(SIGPIPE, dopipesig); inndchannel(port, path); HISclose(); return 0; }