#include "innbbsconf.h" #include "daemon.h" #include "innbbsd.h" #include #include "bbslib.h" #include "inntobbs.h" #include "nntp.h" #ifdef GETRUSAGE #include #include #endif #ifdef STDC # ifndef ARG # define ARG(x) (x) # else # define ARG(x) () # endif #endif /*< add ... > 200 OK < quit 500 BYE > 300 DBZ Server ... < query > 250 ... > 450 NOT FOUND! */ static int CMDhelp ARG((ClientType*)); static int CMDquit ARG((ClientType*)); static int CMDihave ARG((ClientType*)); static int CMDstat ARG((ClientType*)); static int CMDaddhist ARG((ClientType*)); static int CMDgrephist ARG((ClientType*)); static int CMDmidcheck ARG((ClientType*)); static int CMDshutdown ARG((ClientType*)); static int CMDmode ARG((ClientType*)); static int CMDreload ARG((ClientType*)); static int CMDhismaint ARG((ClientType*)); static int CMDverboselog ARG((ClientType*)); static int CMDlistnodelist ARG((ClientType*)); static int CMDlistnewsfeeds ARG((ClientType*)); #ifdef GETRUSAGE static int CMDgetrusage ARG((ClientType*)); static int CMDmallocmap ARG((ClientType*)); #endif static daemoncmd_t cmds[]= /* cmd-name, cmd-usage, min-argc, max-argc, errorcode, normalcode, cmd-func */ { {"help","help [cmd]",1,2,99,100,CMDhelp}, {"quit","quit",1,0,99,100,CMDquit}, #ifndef DBZSERVER {"ihave","ihave mid",2,2,435,335,CMDihave}, #endif {"stat","stat mid",2,2,223,430,CMDstat}, {"addhist","addhist ",3,3, NNTP_ADDHIST_BAD, NNTP_ADDHIST_OK,CMDaddhist}, {"grephist","grephist ",2,2, NNTP_GREPHIST_BAD, NNTP_GREPHIST_OK, CMDgrephist}, {"midcheck","midcheck [on|off]",1,2, NNTP_MIDCHECK_BAD, NNTP_MIDCHECK_OK, CMDmidcheck}, {"shutdown","shutdown (local)",1,1, NNTP_SHUTDOWN_BAD, NNTP_SHUTDOWN_OK, CMDshutdown}, {"mode","mode (local)",1,1, NNTP_MODE_BAD, NNTP_MODE_OK, CMDmode}, {"listnodelist","listnodelist (local)",1,1, NNTP_MODE_BAD, NNTP_MODE_OK, CMDlistnodelist}, {"listnewsfeeds","listnewsfeeds (local)",1,1, NNTP_MODE_BAD, NNTP_MODE_OK, CMDlistnewsfeeds}, {"reload","reload (local)",1,1, NNTP_RELOAD_BAD, NNTP_RELOAD_OK, CMDreload}, {"hismaint","hismaint (local)",1,1, NNTP_RELOAD_BAD, NNTP_RELOAD_OK, CMDhismaint}, {"verboselog","verboselog [on|off](local)",1,2, NNTP_VERBOSELOG_BAD, NNTP_VERBOSELOG_OK, CMDverboselog}, #ifdef GETRUSAGE {"getrusage","getrusage (local)",1,1, NNTP_MODE_BAD, NNTP_MODE_OK, CMDgetrusage}, #endif #ifdef MALLOCMAP {"mallocmap","mallocmap (local)",1,1, NNTP_MODE_BAD, NNTP_MODE_OK, CMDmallocmap}, #endif {NULL,NULL,0,0,99,100,NULL} }; installinnbbsd() { installdaemon(cmds,100,NULL); } #ifdef OLDLIBINBBSINND testandmkdir(dir) char *dir; { if (!isdir(dir)) { char path[MAXPATHLEN+12]; sprintf(path,"mkdir -p %s",dir); system(path); } } static char splitbuf[2048]; static char joinbuf[1024]; #define MAXTOK 50 static char* Splitptr[MAXTOK]; char **split(line,pat) char *line,*pat; { char *p; int i; for (i=0;iboard,nf2->board)==0) { *ptr[j] = '\0'; continue; } for (n11 = nf1->board, n12 = (char*)strchr(n11,','); n11 && *n11 ; n12 = (char*) strchr(n11,',')) { if (n12) *n12 = '\0'; for (n21 = nf2->board, n22 = (char*)strchr(n21,','); n21 && *n21 ; n22 = (char*) strchr(n21,',')) { if (n22) *n22 = '\0'; if (strcmp(n11,n21)==0) { *n21 = '\t'; } if (n22) { *n22 = ','; n21 = n22 + 1; } else break; } if (n12) { *n12 = ','; n11 = n12 +1; } else break; } } } } return ptr; } char **ssplit(line,pat) char *line,*pat; { char *p; int i; for (i=0;iArgv; fprintf(argv->out,"%d %s\n",argv->dc->usage); return 0; } islocalconnect(client) ClientType *client; { if (strcmp(client->username,"localuser") != 0 || strcmp(client->hostname,"localhost") != 0) return 0; return 1; } static shutdownflag = 0; INNBBSDhalt() { shutdownflag = 1; } int INNBBSDshutdown() { return shutdownflag; } static int CMDshutdown(client) ClientType *client; { argv_t *argv = &client->Argv; buffer_t *in = &client->in; daemoncmd_t *p = argv->dc; if (!islocalconnect(client)) { fprintf(argv->out,"%d shutdown access denied\r\n", p->errorcode); fflush(argv->out); verboselog("Shutdown Put: %d shutdown access denied\n", p->errorcode); return 1; } shutdownflag = 1; fprintf(argv->out,"%d shutdown starting\r\n", p->normalcode); fflush(argv->out); verboselog("Shutdown Put: %d shutdown starting\n", p->normalcode); return 1; } static int CMDmode(client) ClientType *client; { /*char cwdpath[MAXPATHLEN+1];*/ argv_t *argv = &client->Argv; extern ClientType INNBBSD_STAT; buffer_t *in = &client->in; daemoncmd_t *p = argv->dc; time_t uptime, now; int i,j; time_t lasthist; ClientType *client1 = &INNBBSD_STAT; if (!islocalconnect(client)) { fprintf(argv->out,"%d mode access denied\r\n", p->errorcode); fflush(argv->out); verboselog("Mode Put: %d mode access denied\n", p->errorcode); return 1; } fprintf(argv->out,"%d mode\r\n", p->normalcode); fflush(argv->out); verboselog("Mode Put: %d mode\n", p->normalcode); uptime = innbbsdstartup(); time(&now); fprintf(argv->out,"up since %salive %.2f days\r\n", ctime(&uptime), (double)(now - innbbsdstartup())/86400); fprintf(argv->out,"BBSHOME %s\r\n", BBSHOME); fprintf(argv->out,"MYBBSID %s\r\n", MYBBSID); fprintf(argv->out,"ECHOMAIL %s\r\n", ECHOMAIL); fprintf(argv->out,"INNDHOME %s\r\n", INNDHOME); fprintf(argv->out,"HISTORY %s\r\n", HISTORY); fprintf(argv->out,"LOGFILE %s\r\n", LOGFILE); fprintf(argv->out,"INNBBSCONF %s\r\n", INNBBSCONF); fprintf(argv->out,"BBSFEEDS %s\r\n", BBSFEEDS); fprintf(argv->out,"Verbose log: %s\r\n", isverboselog() ?"ON":"OFF"); fprintf(argv->out,"History Expire Days %d\r\n", Expiredays); fprintf(argv->out,"History Expire Time %d:%d\r\n", His_Maint_Hour, His_Maint_Min); lasthist = gethisinfo(); if (lasthist > 0) { time_t keep = lasthist, keep1; time(&now); fprintf(argv->out,"Oldest history entry created: %s",(char*)ctime(&keep)); keep = Expiredays * 86400 * 2 + lasthist; keep1 = keep - now ; fprintf(argv->out,"Next time to maintain history: (%.2f days later) %s",(double)keep1/86400, (char*)ctime(&keep)); } fprintf(argv->out,"PID is %d\r\n", getpid()); fprintf(argv->out,"LOCAL ONLY %d\r\n", LOCALNODELIST); fprintf(argv->out,"NONE NEWSFEEDS %d\r\n", NONENEWSFEEDS); fprintf(argv->out,"Max connections %d\r\n", Maxclient); #ifdef DEBUGCWD getwd(cwdpath); fprintf(argv->out,"Working directory %s\r\n", cwdpath); #endif if (Channel) for (i=0, j=0; i< Maxclient; ++i) { if (Channel[i].fd == -1) continue; if (Channel+i == client) continue; j++; fprintf(argv->out," %d) in->used %d, in->left %d %s@%s\r\n",i, Channel[i].in.used, Channel[i].in.left, Channel[i].username,Channel[i].hostname); } fprintf(argv->out,"Total connections %d\r\n", j); fprintf(argv->out,"Total rec: %d dup: %d fail: %d size: %d, stat rec: %d fail: %d\n", client1->ihavecount, client1->ihaveduplicate, client1->ihavefail, client1->ihavesize, client1->statcount, client1->statfail); fprintf(argv->out,".\r\n"); fflush(argv->out); return 1; } static int CMDlistnodelist(client) ClientType *client; { int nlcount; argv_t *argv = &client->Argv; buffer_t *in = &client->in; daemoncmd_t *p = argv->dc; if (!islocalconnect(client)) { fprintf(argv->out,"%d listnodelist access denied\r\n", p->errorcode); fflush(argv->out); verboselog("Mallocmap Put: %d listnodelist access denied\n", p->errorcode); return 1; } fprintf(argv->out,"%d listnodelist\r\n", p->normalcode); for (nlcount =0; nlcount < NLCOUNT; nlcount++) { nodelist_t *nl = NODELIST+nlcount; fprintf(argv->out,"%2d %s /\\/\\ %s\r\n", nlcount+1, nl->node==NULL?"":nl->node, nl->exclusion==NULL?"":nl->exclusion); fprintf(argv->out," %s:%s:%s\r\n",nl->host==NULL?"":nl->host, nl->protocol==NULL?"":nl->protocol, nl->comments == NULL ? "": nl->comments); } fprintf(argv->out,".\r\n"); fflush(argv->out); verboselog("Listnodelist Put: %d listnodelist complete\n", p->normalcode); return 1; } static int CMDlistnewsfeeds(client) ClientType *client; { argv_t *argv = &client->Argv; buffer_t *in = &client->in; daemoncmd_t *p = argv->dc; int nfcount; if (!islocalconnect(client)) { fprintf(argv->out,"%d listnewsfeeds access denied\r\n", p->errorcode); fflush(argv->out); verboselog("Mallocmap Put: %d listnewsfeeds access denied\n", p->errorcode); return 1; } fprintf(argv->out,"%d listnewsfeeds\r\n", p->normalcode); for (nfcount =0; nfcount < NFCOUNT; nfcount++) { newsfeeds_t *nf = NEWSFEEDS + nfcount; fprintf(argv->out,"%3d %s<=>%s\r\n",nfcount+1, nf->newsgroups, nf->board); fprintf(argv->out," %s\r\n",nf->path==NULL?"(Null)":nf->path); } fprintf(argv->out,".\r\n"); fflush(argv->out); verboselog("Listnewsfeeds Put: %d listnewsfeeds complete\n", p->normalcode); return 1; } #ifdef MALLOCMAP static int CMDmallocmap(client) ClientType *client; { argv_t *argv = &client->Argv; buffer_t *in = &client->in; daemoncmd_t *p = argv->dc; struct rusage ru; int savefd ; if (!islocalconnect(client)) { fprintf(argv->out,"%d mallocmap access denied\r\n", p->errorcode); fflush(argv->out); verboselog("Mallocmap Put: %d mallocmap access denied\n", p->errorcode); return 1; } fprintf(argv->out,"%d mallocmap\r\n", p->normalcode); savefd = dup(1); dup2(client->fd, 1); mallocmap(); dup2(savefd, 1); close(savefd); fprintf(argv->out,".\r\n"); fflush(argv->out); verboselog("Mallocmap Put: %d mallocmap complete\n", p->normalcode); return 1; } #endif #ifdef GETRUSAGE static int CMDgetrusage(client) ClientType *client; { argv_t *argv = &client->Argv; buffer_t *in = &client->in; daemoncmd_t *p = argv->dc; struct rusage ru; if (!islocalconnect(client)) { fprintf(argv->out,"%d getrusage access denied\r\n", p->errorcode); fflush(argv->out); verboselog("Getrusage Put: %d getrusage access denied\n", p->errorcode); return 1; } fprintf(argv->out,"%d getrusage\r\n", p->normalcode); if (getrusage(RUSAGE_SELF,&ru) == 0) { fprintf(argv->out,"user time used: %.6f\r\n",(double)ru.ru_utime.tv_sec + (double)ru.ru_utime.tv_usec/1000000.0); fprintf(argv->out,"system time used: %.6f\r\n",(double)ru.ru_stime.tv_sec + (double)ru.ru_stime.tv_usec/1000000.0); fprintf(argv->out,"maximum resident set size: %lu\r\n",ru.ru_maxrss * getpagesize()); fprintf(argv->out,"integral resident set size: %lu\r\n",ru.ru_idrss * getpagesize()); fprintf(argv->out,"page faults not requiring physical I/O: %d\r\n",ru.ru_minflt); fprintf(argv->out,"page faults requiring physical I/O: %d\r\n",ru.ru_majflt); fprintf(argv->out,"swaps: %d\r\n",ru.ru_nswap); fprintf(argv->out,"block input operations: %d\r\n",ru.ru_inblock); fprintf(argv->out,"block output operations: %d\r\n",ru.ru_oublock); fprintf(argv->out,"messages sent: %d\r\n",ru.ru_msgsnd); fprintf(argv->out,"messages received: %d\r\n",ru.ru_msgrcv); fprintf(argv->out,"signals received: %d\r\n",ru.ru_nsignals); fprintf(argv->out,"voluntary context switches: %d\r\n",ru.ru_nvcsw); fprintf(argv->out,"involuntary context switches: %d\r\n",ru.ru_nivcsw); } fprintf(argv->out,".\r\n"); fflush(argv->out); verboselog("Getrusage Put: %d getrusage complete\n", p->normalcode); return 1; } #endif static int CMDhismaint(client) ClientType *client; { argv_t *argv = &client->Argv; buffer_t *in = &client->in; daemoncmd_t *p = argv->dc; if (!islocalconnect(client)) { fprintf(argv->out,"%d hismaint access denied\r\n", p->errorcode); fflush(argv->out); verboselog("Hismaint Put: %d hismaint access denied\n", p->errorcode); return 1; } verboselog("Hismaint Put: %d hismaint start\n", p->normalcode); HISmaint(); fprintf(argv->out,"%d hismaint complete\r\n", p->normalcode); fflush(argv->out); verboselog("Hismaint Put: %d hismaint complete\n", p->normalcode); return 1; } static int CMDreload(client) ClientType *client; { argv_t *argv = &client->Argv; buffer_t *in = &client->in; daemoncmd_t *p = argv->dc; if (!islocalconnect(client)) { fprintf(argv->out,"%d reload access denied\r\n", p->errorcode); fflush(argv->out); verboselog("Reload Put: %d reload access denied\n", p->errorcode); return 1; } initial_bbs("feed"); fprintf(argv->out,"%d reload complete\r\n", p->normalcode); fflush(argv->out); verboselog("Reload Put: %d reload complete\n", p->normalcode); return 1; } static int CMDverboselog(client) ClientType *client; { argv_t *argv = &client->Argv; buffer_t *in = &client->in; daemoncmd_t *p = argv->dc; if (!islocalconnect(client)) { fprintf(argv->out,"%d verboselog access denied\r\n", p->errorcode); fflush(argv->out); verboselog("Reload Put: %d verboselog access denied\n", p->errorcode); return 1; } if (client->mode == 0) { if (argv->argc > 1) { if (strcasecmp(argv->argv[1],"off")==0) { setverboseoff(); } else { setverboseon(); } } } fprintf(argv->out,"%d verboselog %s\r\n",p->normalcode, isverboselog() ?"ON":"OFF"); fflush(argv->out); verboselog("%d verboselog %s\r\n",p->normalcode, isverboselog()?"ON":"OFF"); } static int CMDmidcheck(client) ClientType *client; { argv_t *argv = &client->Argv; buffer_t *in = &client->in; daemoncmd_t *p = argv->dc; if (client->mode == 0) { if (argv->argc > 1) { if (strcasecmp(argv->argv[1],"off")==0) { client->midcheck = 0; } else { client->midcheck = 1; } } } fprintf(argv->out,"%d mid check %s\r\n",p->normalcode, client->midcheck == 1?"ON":"OFF"); fflush(argv->out); verboselog("%d mid check %s\r\n",p->normalcode, client->midcheck == 1?"ON":"OFF"); } static int CMDgrephist(client) ClientType *client; { argv_t *argv = &client->Argv; buffer_t *in = &client->in; daemoncmd_t *p = argv->dc; if (client->mode == 0) { if (argv->argc > 1) { char *ptr; ptr = (char*)DBfetch(argv->argv[1]); if (ptr != NULL) { fprintf(argv->out,"%d %s OK\r\n", p->normalcode, ptr); fflush(argv->out); verboselog("Addhist Put: %d %s OK\n", p->normalcode, ptr); return 0; } else { fprintf(argv->out,"%d %s not found\r\n", p->errorcode,argv->argv[1]); fflush(argv->out); verboselog("Addhist Put: %d %s not found\n", p->errorcode, argv->argv[1]); return 1; } } } fprintf(argv->out,"%d grephist error\r\n", p->errorcode); fflush(argv->out); verboselog("Addhist Put: %d grephist error\n", p->errorcode); return 1; } static int CMDaddhist(client) ClientType *client; { argv_t *argv = &client->Argv; buffer_t *in = &client->in; daemoncmd_t *p = argv->dc; /* if (strcmp(client->username,"localuser") != 0 || strcmp(client->hostname,"localhost") != 0) { fprintf(argv->out,"%d add hist access denied\r\n", p->errorcode); fflush(argv->out); verboselog("Addhist Put: %d add hist access denied\n", p->errorcode); return 1; } */ if (client->mode == 0) { if (argv->argc > 2) { char *ptr; ptr = (char*)DBfetch(argv->argv[1]); if (ptr == NULL) { if (storeDB(argv->argv[1], argv->argv[2]) < 0) { fprintf(argv->out,"%d add hist store DB error\r\n", p->errorcode); fflush(argv->out); verboselog("Addhist Put: %d add hist store DB error\n", p->errorcode); return 1; } else { fprintf(argv->out,"%d add hist OK\r\n", p->normalcode); fflush(argv->out); verboselog("Addhist Put: %d add hist OK\n", p->normalcode); return 0; } } else { fprintf(argv->out,"%d add hist duplicate error\r\n", p->errorcode); fflush(argv->out); verboselog("Addhist Put: %d add hist duplicate error\n", p->errorcode); return 1; } } } fprintf(argv->out,"%d add hist error\r\n", p->errorcode); fflush(argv->out); verboselog("Addhist Put: %d add hist error\n", p->errorcode); return 1; } static int CMDstat(client) ClientType *client; { argv_t *argv = &client->Argv; char *ptr, *frontptr; buffer_t *in = &client->in; daemoncmd_t *p; if (client->mode == 0) { client->statcount++; if (argv->argc > 1) { if (argv->argv[1][0] != '<') { fprintf(argv->out,"430 No such article\r\n"); fflush(argv->out); verboselog("Stat Put: 430 No such article\n"); client->statfail++; return 0; } ptr = (char*)DBfetch(argv->argv[1]); if (ptr != NULL) { fprintf(argv->out,"223 0 status %s\r\n",argv->argv[1]); fflush(argv->out); client->mode = 0; verboselog("Stat Put: 223 0 status %s\n",argv->argv[1]); return 1; } else { fprintf(argv->out,"430 No such article\r\n"); fflush(argv->out); verboselog("Stat Put: 430 No such article\n"); client->mode = 0; client->statfail++; } } } } #ifndef DBZSERVER static int CMDihave(client) ClientType *client; { argv_t *argv = &client->Argv; char *ptr=NULL, *frontptr; buffer_t *in = &client->in; daemoncmd_t *p; if (client->mode == 0) { client->ihavecount++; if (argv->argc > 1) { if (argv->argv[1][0] != '<') { fprintf(argv->out,"435 Bad Message-ID\r\n"); fflush(argv->out); verboselog("Ihave Put: 435 Bad Message-ID\n"); client->ihavefail++; return 0; } if (client->midcheck == 1) ptr = (char*)DBfetch(argv->argv[1]); if (ptr != NULL && client->midcheck == 1) { fprintf(argv->out,"435 Duplicate\r\n"); fflush(argv->out); client->mode = 0; verboselog("Ihave Put: 435 Duplicate\n"); client->ihaveduplicate++; client->ihavefail++; return 1; } else { fprintf(argv->out,"335\r\n"); fflush(argv->out); client->mode = 1; verboselog("Ihave Put: 335\n"); } } } else { client->mode = 0; readlines(client); if (HEADER[SUBJECT_H] && HEADER[FROM_H] && HEADER[DATE_H] && HEADER[MID_H] && HEADER[NEWSGROUPS_H] ) { char *path1, *path2; int rel ; rel = 0; path1 = (char*)mymalloc(strlen(HEADER[PATH_H]) + 3); path2 = (char*)mymalloc(strlen(MYBBSID) + 3); sprintf(path1, "!%s!",HEADER[PATH_H]); sprintf(path2, "!%s!",MYBBSID); if (HEADER[CONTROL_H]) { bbslog( "Control: %s\n", HEADER[CONTROL_H] ); if (strncasecmp(HEADER[CONTROL_H],"cancel ",7)==0) { rel = cancel_article_front(HEADER[CONTROL_H]+7); } else { rel = receive_control(); } } else if ( (char*)strstr(path1, path2) != NULL) { bbslog( ":Warn: Loop back article: %s!%s\n",MYBBSID,HEADER[PATH_H] ); } else { rel = receive_article(); } free(path1); free(path2); if (rel == -1) { fprintf(argv->out,"400 server side failed\r\n"); fflush(argv->out); verboselog("Ihave Put: 400\n"); clearfdset(client->fd); fclose(client->Argv.in); fclose(client->Argv.out); close(client->fd); client->fd = -1; client->mode = 0; client->ihavefail++; return; } else { fprintf(argv->out,"235\r\n"); verboselog("Ihave Put: 235\n"); } fflush(argv->out); } else if (!HEADER[PATH_H]) { fprintf(argv->out,"437 No Path in \"ihave %s\" header\r\n",HEADER[MID_H]); fflush(argv->out); verboselog("Put: 437 No Path in \"ihave %s\" header\n",HEADER[MID_H]); client->ihavefail++; } else { fprintf(argv->out,"437 No colon-space in \"ihave %s\" header\r\n",HEADER[MID_H]); fflush(argv->out); verboselog("Ihave Put: 437 No colon-space in \"ihave %s\" header\n",HEADER[MID_H]); client->ihavefail++; } #ifdef DEBUG printf("subject is %s\n",HEADER[SUBJECT_H]); printf("from is %s\n",HEADER[FROM_H]); printf("Date is %s\n",HEADER[DATE_H]); printf("Newsgroups is %s\n",HEADER[NEWSGROUPS_H]); printf("mid is %s\n",HEADER[MID_H]); printf("path is %s\n",HEADER[PATH_H]); #endif } fflush(argv->out); return 0; } #endif static int CMDhelp(client) ClientType *client; { argv_t *argv = &client->Argv; daemoncmd_t *p; if (argv->argc>=1) { fprintf(argv->out,"%d Available Commands\r\n",argv->dc->normalcode); for (p=cmds;p->name !=NULL;p++) { fprintf(argv->out," %s\r\n",p->usage); } fprintf(argv->out,"Report problems to %s\r\n",ADMINUSER); } fputs(".\r\n",argv->out); fflush(argv->out); client->mode = 0; return 0; } static int CMDquit(client) ClientType *client; { argv_t *argv = &client->Argv; fprintf(argv->out,"205 quit\r\n"); fflush(argv->out); verboselog("Quit Put: 205 quit\n"); clearfdset(client->fd); fclose(client->Argv.in); fclose(client->Argv.out); close(client->fd); client->fd = -1; client->mode = 0; channeldestroy(client); /*exit(0);*/ }