00001
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046 #include "services.h"
00047 #include "hash.h"
00048 #include "nickserv.h"
00049 #include "memoserv.h"
00050 #include "infoserv.h"
00051 #include "sipc.h"
00052 #include "db.h"
00053 #include "mass.h"
00054 #include "log.h"
00055
00056 #include <getopt.h>
00057
00058 #ifdef USE_SQL
00059 extern PGconn *dbConn;
00060 #endif
00061
00062 extern int ipcPort;
00063 extern int svcOptFork;
00064
00065
00066
00067
00068 extern char myname[255];
00069 extern char mypass[33];
00070
00071
00072
00073
00074 extern char hostname[255];
00075 extern int port;
00076
00077
00078
00079
00080 extern int server;
00081
00082
00083
00084
00085
00086 extern Service services[NUMSERVS];
00087 extern database db;
00088
00090 extern SLogfile *operlog, *nicklog, *chanlog;
00091
00093 extern FILE *corelog;
00094
00096 extern u_long totalusers;
00097
00099 extern u_long mostusers, mostnicks, mostchans, mostmemos;
00100
00102 extern unsigned long top_akill_stamp;
00103
00105 extern long startup, firstup;
00106
00108 extern char *OperServ, *NickServ, *ChanServ, *MemoServ, *InfoServ, *GameServ;
00109
00111 extern char coreBuffer[IRCBUF];
00112
00114 extern u_int AccessLimit, OpLimit, AkickLimit, ChanLimit, NickLimit;
00115
00117 extern time_t CTime;
00118
00120 extern time_t nextNsync, nextCsync, nextMsync;
00121
00122 static int lockfile(char *);
00123 time_t updateCloneAlerts(time_t);
00124
00126 IpcType servicesIpc;
00127
00128 int runAsRootOverride = 0;
00129
00131 void ServicesProgramHelp()
00132 {
00133 printf("Usage: services [OPTION] ...\n");
00134 printf("SorceryNet Services server\n");
00135 printf("Information:\n");
00136 printf(" -h, --help Show this information\n");
00137 printf(" -v, --version Print version information\n");
00138 printf(" -f, --fork Run as a daemon, fork into background\n");
00139 printf(" -F, --nofork Stay in foreground\n");
00140 printf(" -i, --ipc=[PORT] Enable services IPC using PORT\n");
00141 printf(" -I, --noipc Disable services IPC\n");
00142 printf("\nReport bugs to services-bugs@sorcery.net\n");
00143 return;
00144 }
00145
00147 int main(int argc, char *argv[])
00148 {
00149 char buffer[4097];
00150 fd_set readme, writeme, xceptme;
00151 FILE *fp, *pidf;
00152 struct timeval tv;
00153 int cc;
00154 time_t next_alert_update = 0;
00155 #ifdef USE_SQL
00156 int PQsockfd;
00157 #endif
00158 #ifndef NORLIMIT
00159 struct rlimit corelim;
00160 #endif
00161
00162 #ifndef DEBUG
00163 #ifdef FORK_EM
00164 int pid;
00165 #endif
00166 #endif
00167
00168 static struct option servOpts[] =
00169 {
00170
00171 { "help", 0, 0, 0 },
00172 { "version", 0, 0, 1 },
00173 { "fork", 0, 0, 2 },
00174 { "nofork", 0, 0, 3 },
00175 { "ipc", 2, 0, 4 },
00176 { "noipc", 0, 0, 5 },
00177 { 0, 0, 0, 0 },
00178 };
00179
00180 int lastOpt;
00181 char ch;
00182
00183 ipcPort = 0;
00184
00185
00186 while ( optind < argc )
00187 {
00188 static const char *libUf = ( "\n"
00189 "Copyr. 1996-2001 Chip Norkus, Max Byrd, Greg Poma, Michael Graff\n"
00190 " James Hess, Dafydd James\n"
00191 "All Rights Reserved.\n\n"
00192 "This product includes software developed by Chip Norkus, Max Byrd,\n"
00193 "Greg Poma, Michael Graff, James Hess, Dafydd James, the University\n"
00194 "of California, Berkeley and its contributors.\n\n"
00195 "THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND\n"
00196 "ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n"
00197 "IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n"
00198 "ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE\n"
00199 "FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n"
00200 "DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\n"
00201 "OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\n"
00202 "HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n"
00203 "LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n"
00204 "OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n"
00205 "SUCH DAMAGE.\n"
00206 );
00207
00208 ch = getopt_long(argc, argv, "RhvfFi:I", servOpts, &lastOpt);
00209
00210 if (ch == '?' || ch == ':')
00211 exit(2);
00212
00213 if (ch == -1) {
00214 printf("%s: invalid option -- %s\n", PACKAGE, argv[optind]);
00215 exit(2);
00216 }
00217
00218 switch(ch)
00219 {
00220 case 'h':
00221 case 0:
00222 ServicesProgramHelp();
00223 exit(0);
00224 break;
00225
00226 case 'v':
00227 case 1:
00228 printf("%s\n", (PACKAGE "-" VERSION));
00229 fprintf(stdout, "%s\n", libUf);
00230 exit(0);
00231 break;
00232
00233 case 'f':
00234 case 2:
00235 svcOptFork = 1;
00236 break;
00237
00238 case 'F':
00239 case 3:
00240 svcOptFork = 0;
00241 break;
00242
00243 case 'R':
00244 runAsRootOverride = 1;
00245 break;
00246
00247 case 'i':
00248 case 4:
00249 if (optarg == NULL)
00250 ipcPort = 3030;
00251 else if (isdigit(*optarg))
00252 ipcPort = atoi(optarg);
00253
00254 if (ipcPort <= 1024 || ipcPort >= SHRT_MAX) {
00255 printf("services: Invalid port number.\n"
00256 "Must be between 1025 and %d.\n",
00257 SHRT_MAX);
00258 exit(2);
00259 }
00260 break;
00261
00262 case 'I':
00263 case 5:
00264 ipcPort = -1;
00265 break;
00266
00267 default:
00268 printf("HUH?\n");
00269 exit(100);
00270 }
00271 }
00272
00273
00274
00275 if (geteuid() == 0 && runAsRootOverride == 0) {
00276 fprintf(stderr, "ERROR: %s should not be run as root.\n", argv[0]);
00277 exit(1);
00278 }
00279
00280
00281 CTime = time(NULL);
00282
00283
00284
00285
00286 dlogInit();
00287
00288 dlogEntry("Starting...");
00289
00290
00291
00292
00293
00294 pidf = fopen("services.pid", "r");
00295 if (pidf != NULL) {
00296 fprintf(stderr,
00297 "Error, services.pid already exists. If services isn't\n"
00298 "actually running, delete the .pid file and run me again.\n"
00299 "If it is running, don't load me again.\n");
00300 fclose(pidf);
00301 return 1;
00302 }
00303
00304 #ifdef DEBUG
00305 printf("Using %s for sending mail from stdin\n", SENDMAIL);
00306 #endif
00307 #ifndef NORLIMIT
00308 corelim.rlim_cur = corelim.rlim_max = RLIM_INFINITY;
00309 if (setrlimit(RLIMIT_CORE, &corelim))
00310 fprintf(stderr, "Cannot unlimit core! -> %i", errno);
00311 #endif
00312
00313 umask(077);
00314 setenv("TZ", "GMT", 1);
00315 tzset();
00316 dlogEntry("Locking files");
00317
00318 if (lockfile("chanserv/chanserv.db")) {
00319 printf("Exiting...\n");
00320 sshutdown(-1);
00321 }
00322
00323 if (lockfile("nickserv/nickserv.db")) {
00324 printf("Exiting...\n");
00325 sshutdown(-1);
00326 }
00327
00328 if (lockfile("memoserv/memoserv.db")) {
00329 printf("Exiting...\n");
00330 sshutdown(-1);
00331 }
00332
00333
00334
00335
00336 dlogEntry("Opening logs");
00337 operlog = new SLogfile("operserv/operserv.log", "operserv/operserv-w");
00338 nicklog = new SLogfile("nickserv/nickserv.log", "nickserv/nickserv-w");
00339 chanlog = new SLogfile("chanserv/chanserv.log", "chanserv/chanserv-w");
00340 corelog = fopen("core.log", "a");
00341
00342 if (!operlog || !nicklog || !chanlog || !corelog) {
00343 if (corelog)
00344 dlogEntry("Unable to open logfile(s)");
00345 fprintf(stderr, "Unable to open: %s%s%s%s.\n",
00346 operlog ? "" : " operlog",
00347 nicklog ? "" : " nicklog",
00348 chanlog ? "" : " chanlog", corelog ? "" : " corelog");
00349 sshutdown(0);
00350 }
00351
00352 dlogEntry("Reading nickname data");
00353 readNickData();
00354
00355 dlogEntry("Reading channel data");
00356 readChanData();
00357
00358 dlogEntry("Reading article data");
00359 readInfoData();
00360
00361 dlogEntry("Reading trigger data");
00362 readTriggerData();
00363
00364 dlogEntry("Reading config");
00365 readConf();
00366
00367 #ifndef DEBUG
00368 #ifdef FORK_EM
00369 if (svcOptFork)
00370 {
00371 dlogEntry("Forked");
00372
00373 pid = fork();
00374
00375 if (pid) {
00376 pidf = fopen("services.pid", "w");
00377 if (pidf != NULL) {
00378 fprintf(pidf, "%d", pid);
00379 fclose(pidf);
00380 return 0;
00381 }
00382 else
00383 {
00384 perror("fopen(services.pid)");
00385 exit(5);
00386 }
00387 }
00388 }
00389 else
00390 {
00391 pid = getpid();
00392 pidf = fopen("services.pid", "w");
00393
00394 if (pidf != NULL) {
00395 fprintf(pidf, "%d", pid);
00396 fclose(pidf);
00397 }
00398 else {
00399 perror("fopen(services.pid)");
00400 exit(5);
00401 }
00402 return 0;
00403 }
00404 #endif
00405 #endif
00406
00407 if (chdir(CFGPATH) == -1)
00408 fprintf(stderr, "Cannot chdir(%s)\n", CFGPATH);
00409
00410 #ifdef DEBUG
00411 printf
00412 ("\n\n\nMyName:%s MyPass:%s\nConnectHost:%s ConnectPort:%i\n",
00413 myname, mypass, hostname, port);
00414 #endif
00415
00416 dlogEntry("Connecting to server %s, port %d", hostname, port);
00417
00418 #ifdef USE_SQL
00419 if (dbConn != NULL)
00420 PQfinish(dbConn);
00421 dbConn = PQconnectdb(""
00422 #ifdef SQL_HOST
00423 " host=" SQL_HOST
00424 #endif
00425 #ifdef SQL_HOSTADDR
00426 " hostaddr=" SQL_HOSTADDR
00427 #endif
00428 #ifdef SQL_PORT
00429 " port=" SQL_PORT
00430 #endif
00431 " dbname=" SQL_DB
00432 " user=" SQL_USER " password=" SQL_PASS "");
00433 if (!dbConn) {
00434 fprintf(stderr,
00435 "Error allocating memory for database connection.\n");
00436 sshutdown(-1);
00437 }
00438 if (PQstatus(dbConn) != CONNECTION_OK) {
00439 fprintf(stderr, "Error connecting to the database.\n");
00440 sshutdown(-1);
00441 }
00442 PQsetnonblocking(dbConn, TRUE);
00443 #endif
00444
00445 if (ipcPort == -1 || servicesIpc.start(ipcPort) < 0) {
00446 if (ipcPort > 0)
00447 printf("Could not startup ipc!\n");
00448 else
00449 printf("Ipc not enabled.\n");
00450 }
00451
00452 srand48(time(NULL));
00453 srandom(time(NULL));
00454
00455 if ((server = ConnectToServer(hostname, port)) < 0) {
00456 printf
00457 ("Could not connect to server!, exiting now.\nSocket # is: %i\n",
00458 server);
00459 exit(0);
00460 }
00461
00462 dlogEntry("Logging in");
00463 sSend("PASS %s", mypass);
00464 sSend("SERVER %s 1 :Services Impenetrable Fortress ;)", myname);
00465 addUser(services[0].name, services[0].uname, services[0].host,
00466 services[0].rname, services[0].mode);
00467 addUser(services[1].name, services[1].uname, services[1].host,
00468 services[1].rname, services[1].mode);
00469 addUser(services[2].name, services[2].uname, services[2].host,
00470 services[2].rname, services[2].mode);
00471 addUser(services[3].name, services[3].uname, services[3].host,
00472 services[3].rname, services[3].mode);
00473 addUser(services[4].name, services[4].uname, services[4].host,
00474 services[4].rname, services[4].mode);
00475 addUser(services[5].name, services[5].uname, services[5].host,
00476 services[5].rname, services[5].mode);
00477 addUser(services[6].name, services[6].uname, services[6].host,
00478 services[6].rname, services[5].mode);
00479
00480 dlogEntry("Reading services total files");
00481 fp = fopen("services.totals", "r");
00482
00483 if (fp != NULL) {
00484 mostusers = mostnicks = mostchans = mostmemos = 0;
00485 firstup = 0;
00486
00487 if (sfgets(buffer, 256, fp))
00488 mostusers = atoi(buffer);
00489
00490 if (sfgets(buffer, 256, fp))
00491 mostnicks = atoi(buffer);
00492
00493 if (sfgets(buffer, 256, fp))
00494 mostchans = atoi(buffer);
00495
00496 if (sfgets(buffer, 256, fp))
00497 mostmemos = atoi(buffer);
00498
00499 if (sfgets(buffer, 10, fp))
00500 firstup = atol(buffer);
00501
00502 if (sfgets(buffer, 10, fp))
00503 top_akill_stamp = atol(buffer);
00504
00505 fclose(fp);
00506 }
00507
00508 totalusers = 0;
00509
00510 startup = time(NULL);
00511 dlogEntry("Operational at", startup);
00512
00513 #if 1
00514 signal(SIGPIPE, handler);
00515 signal(SIGSEGV, handler);
00516 signal(SIGTERM, handler);
00517 #endif
00518
00519 signal(SIGALRM, SIG_IGN);
00520 signal(SIGHUP, SIG_IGN);
00521
00522 signal(SIGINT, handler);
00523
00524 OperServ = services[0].name;
00525 NickServ = services[1].name;
00526 ChanServ = services[2].name;
00527 MemoServ = services[3].name;
00528 InfoServ = services[4].name;
00529 GameServ = services[5].name;
00530 MassServ = services[6].name;
00531
00532
00533
00534 timer(90, timed_akill_queue, NULL);
00535 timer(20, timed_advert_maint, NULL);
00536
00537 while (1) {
00538 tv.tv_sec = 1;
00539 tv.tv_usec = 0;
00540
00541 FD_ZERO(&readme);
00542 FD_ZERO(&writeme);
00543 FD_ZERO(&xceptme);
00544 FD_SET(server, &readme);
00545 #ifdef USE_SQL
00546 if (dbConn) {
00547 PQsockfd = PQsocket(dbConn);
00548 PQflush(dbConn);
00549 FD_SET(PQsockfd, &readme);
00550 FD_SET(PQsockfd, &xceptme);
00551 }
00552 #endif
00553 memset(buffer, 0, sizeof(buffer));
00554
00555
00556 servicesIpc.fdFillSet(readme);
00557 servicesIpc.fdFillSet(writeme);
00558 servicesIpc.fdFillSet(xceptme);
00559
00560
00561
00562
00563
00564 #ifdef USE_SQL
00565 cc =
00566 select(MAX(1+servicesIpc.getTopfd(), MAX(server, PQsockfd) + 1), &readme, &writeme, &xceptme,
00567 &tv);
00568 #else
00569 cc = select(MAX(1+servicesIpc.getTopfd(), server + 1), &readme, &writeme, &xceptme, &tv);
00570 #endif
00571
00572
00573
00574
00575 if (cc < 0) {
00576 dlogEntry("Error on select(): %s", strerror(errno));
00577 sshutdown(0);
00578 }
00579
00580
00581
00582
00583 if (cc == 0) {
00584 timeralarm();
00585 continue;
00586 }
00587
00588 if (next_alert_update < CTime)
00589 next_alert_update = updateCloneAlerts(CTime);
00590
00591 servicesIpc.pollAndHandle(readme, writeme, xceptme);
00592
00593 #ifdef USE_SQL
00594 if (dbConn) {
00595 if (FD_ISSET(PQsockfd, &xceptme)
00596 || FD_ISSET(PQsockfd, &readme)) {
00597 switch (PQstatus(dbConn)) {
00598 default:
00599 break;
00600 case CONNECTION_BAD:
00601 logDump(corelog,
00602 "DB connection went bad, attempting to reset...");
00603 sSend
00604 ("GLOBOPS :DB connection went bad, attempting to reset...");
00605 PQreset(dbConn);
00606 if (PQstatus(dbConn) != CONNECTION_OK) {
00607 logDump(corelog,
00608 "Unable to re-establish db connection, dying.");
00609 sSend
00610 ("GLOBOPS :Unable to re-establish db connection, dying.");
00611 sshutdown(-1);
00612 }
00613 break;
00614 }
00615 }
00616
00617 if (FD_ISSET(PQsockfd, &readme)) {
00618 PGresult *res;
00619
00620 PQconsumeInput(dbConn);
00621 if (!PQisBusy(dbConn)) {
00622 }
00623 while ((res = PQgetResult(dbConn))) {
00624 PQclear(res);
00625 }
00626 }
00627 }
00628 #endif
00629
00630
00631
00632
00633 if (FD_ISSET(server, &readme)) {
00634 cc = net_read(server, buffer, sizeof(buffer) - 1);
00635
00636
00637
00638
00639
00640 if (cc < 0 || cc == 0) {
00641 dlogEntry("Closing server connection due to error: %s",
00642 (cc ==
00643 0 ? "Connection closed" : strerror(errno)));
00644
00645 sshutdown(0);
00646 }
00647 }
00648
00649 breakLine(buffer);
00650 }
00651
00652
00653 return 0;
00654 }
00655
00664 static int lockfile(char *fname)
00665 {
00666 int fd;
00667 int i;
00668
00669 fd = open(fname, O_RDONLY);
00670 if (fd < 0) {
00671 printf("Cannot open %s\n", fname);
00672 return -1;
00673 }
00674
00675 i = flock(fd, LOCK_EX | LOCK_NB);
00676 if (i != 0) {
00677 printf("Cannot lock file %s\n", fname);
00678 return -1;
00679 }
00680
00681 return 0;
00682 }
00683
00684
00685
00686