/* This source code is protected under the GNU General Public License (GPL), found at http://www.gnu.org/licenses/gpl.html */ #include #include #include "s-pluginapi.h" #define RL 32 // This plugin will hold 32 records of <{REG} {PUID} "IP Address"> static uint32 pwr(uint16 base, uint8 exp); typedef struct { uint32 rSeed; uint32 pSeed; uint32 ipMin; uint32 ipMax; } HostMgr, *HostMgrPtr; static uint8 RegHash[] = { 4, //A 5, //B 6, //C 7, //D 0, //E 1, //F 2, //G 3, //H 12, //I 0, //J 0, //K 0, //L 8, //M 9, //N 10, //O 11 //P }; static uint8 VldChrs[] = { '{', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'M', 'N', 'O', 'P', 'Z', '}', ' ', '\t', '\"', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '*', '.', 0 }; static char *config; static uint8 nbrRecs; static HostMgr Recs[RL]; AnyType initializeServerPlugin(PluginID pluginID, int argc, char *argv[]) { setPluginUserInfoSize(pluginID, sizeof(char)); if (argc > 1) { config = argv[1]; } FormattedLogMessage(NULL, "HostManager©", "v2.0 (Limit: %d) (2004-2005) by Paul Taylor (Janus) ", RL); scheduleTimerEvent(pluginID, 0, 0); return (AnyType) pluginID; } void noteUserCreation(ServerState *state, AnyType pluginDat, ServerUserRec *user) { *((char *)getPluginUserInfo((PluginID) pluginDat, user)) = 0; } /* If you ask why I didn't code the user verification system into the ClientMsg function, here's why. Verifying this way allows all other plugin security, including the server itself to verify a user's information that has been sent is valid. Other issues I got into just grew tiresome and boring. There's nothing wrong with the way I did this here *wink* // Janus */ void noteUserRoomEntry(ServerState *state, AnyType pluginDat, ServerUserRec *user, ServerRoomRec *room) { char *Checked = (char *)getPluginUserInfo((PluginID) pluginDat, user); if (!(*Checked) && user->loggedOn) { (*Checked)++; uint16 i; uint32 ipAdr = htonl(user->feIPAddr); /* Show me da SEED! // Janus */ uint32 pSeed = user->puidCRC ^ user->puidCtr; uint32 rSeed = user->crc ^ user->counter ^ 0x9602C9BFL; for (i = 0; i < nbrRecs; i++) { if (rSeed == Recs[i].rSeed && (!Recs[i].pSeed || pSeed == Recs[i].pSeed) && ipAdr >= Recs[i].ipMin && ipAdr <= Recs[i].ipMax) { (*Checked)++; /* Sets wiz/god (op/admin) flags to 3, OR forces these bits to TRUE // Janus */ user->flags |= 3; /* Since the client doesn't always use null bytes at the end of a username, also considering strings are considered terminated by a null character, we force the user's name to end with a null byte (if it's length is less than 31)! // Janus */ Checked = user->user.name; if (*Checked < 31) { user->user.name[*Checked + 1] = 0; } /* Lets leave a special note that indeed, an Admin was here. // Janus */ FormattedLogMessage(user, "HostManager©", "(Reigstered Host Admin)"); sendMsgUserStatus(toUser(user), user, user->flags, ""); /* Alert the staff that it's just a friend, not an intruder. // Janus */ WizGlobalMessage("Attention on deck! %0.31s has come aboard!", ++Checked); UserMessage(user, "Welcome Host Admin %0.31s!", Checked); break; } } } } void noteUserDeletion(ServerState *state, AnyType pluginDat, ServerUserRec *user) { char *Checked = (char *)getPluginUserInfo((PluginID) pluginDat, user); if (*Checked > 1) { /* Since the client doesn't always use null bytes at the end of a username, also considering strings are considered terminated by a null character, we force the user's name to end with a null byte (if it's length is less than 31)! // Janus */ Checked = user->user.name; if (*Checked < 31) { user->user.name[*Checked + 1] = 0; } WizGlobalMessage("%0.31s has left the building!", ++Checked); } } void handleTimerEvent(ServerState *state, AnyType pluginDat, AnyType timerDat) { uint8 e, m; // Error-Checking/Mode // Janus uint8 i, j, k; // Accumulators // Janus uint8 iBfr[64]; // Line Read Buffer // Janus char *lBfr, *Ptr; nbrRecs = 0; FILE *STDIN = fopen(config, "r"); /* Required, incase permissions are wrong, trying to read from a file that's permissioned off would crash our server! // Janus */ if (STDIN != NULL) { ReadErr: while (!feof(STDIN) && nbrRecs < RL) { m = 0; lBfr = iBfr; fgets(iBfr, 63, STDIN); Recs[nbrRecs].rSeed = 0; Recs[nbrRecs].pSeed = 0; Recs[nbrRecs].ipMin = 0; Recs[nbrRecs].ipMax = 0; while (*lBfr) { if (*lBfr == '#') { goto ReadErr; } e = 0; for (i = 0; i < strlen(VldChrs); i++) { if (*lBfr == VldChrs[i]) { e = 1; break; } } if (e == 0) { goto ReadErr; } switch (m) { case 0: case 2: /* This section resets the previous input record entry for the r/p SEEDs. // Janus */ if (*lBfr == '{') { m++; j = 0; } break; case 1: case 3: /* This section builds the r/p SEED from the Hash in the bless file. // Janus */ if (*lBfr == '}') { m++; break; } if (*lBfr == 'Z') { if (*(lBfr - 1) == '{' && m > 2) { ++lBfr; } else { goto ReadErr; } } if (*lBfr >= 'A' && *lBfr <= 'P' && j < 9) { k = RegHash[*lBfr - 'A']; // 'A' = 65 // Janus if (m < 2) { Recs[nbrRecs].rSeed += (k * pwr(13, j++)); } else { Recs[nbrRecs].pSeed += (k * pwr(13, j++)); } } else { goto ReadErr; } break; case 4: /* This section resets the previous input record entry for the ipMin/ipMax. // Janus */ if (*lBfr == '\"') { m++; j = 4; Ptr = lBfr + 1; } break; case 5: /* This section builds the ipMin/ipMax ranges [(#/*).(#/*).(#/*).(#/*)]. // Janus */ if (!j) { goto ReadErr; } if (*lBfr == '.' || *lBfr == '\"') { /* This part may not be neccessary since atoi() only converts integers. // Janus */ if (*lBfr == '.') { *lBfr = 0; } if (*Ptr == '*') { if (Ptr == (lBfr - 1)) { /* Since this is a range, only increase the upper value. // Janus */ Recs[nbrRecs].ipMax += (255 * pwr(256, --j)); } else { /* Somebody didn't use the range (*) character properly. // Janus */ goto ReadErr; } } else { /* Since this is a range, this builds up both the upper/lower values. // Janus */ k = atoi(Ptr); Recs[nbrRecs].ipMin += (k * pwr(256, --j)); Recs[nbrRecs].ipMax += (k * pwr(256, j)); } Ptr = lBfr + 1; } if (*lBfr == '\"') { /* All security/format checks passed, we're clear to try another round/line of the file! // Janus */ ++nbrRecs; goto ReadErr; } break; } ++lBfr; } } fclose(STDIN); } /* Reloads the hostmgr.bless file every 2.5 minutes (150 seconds) = 1 Swatch Time Beat (Swiss Time) // Janus */ scheduleTimerEvent((PluginID) pluginDat, 0, 150); } /* I know has a pow() function, but our server didn't like using pow(), so, I rigged up my own! // Janus */ static uint32 pwr(uint16 base, uint8 exp) { uint32 i = 1; while (exp--) { i *= base; } return i; } /* I would like to thank OpenText for not butting into palace development projects in the works, even if Phalanx does suck. I would like to thank my crew, past and present from MPP/PEG, Aephix, Aephix Core, Gemini Project, and now ThePalaceHost! Specifically Darryl, Richard, Patrick, and Scott. You guys are the best and you've always been there in spirit. I didn't make the initial plugin SDK so I'm not going to open source that, but if you can find a copy, I wish you the best of luck, might have to switch the linker to -shared instead of -Xlinker. Aight! PEACE! // Janus PS To Joe (owner of PalaceBox), unlike you, I enjoy sharing knowledge. */