/** Log all allocations. */ void log_mem_check(void) { MEM *chk; if (!options.mem_check) return; do_rawlog(LT_TRACE, "MEMCHECK dump starts"); for (chk = memcheck_head->links[0]; chk; chk = chk->links[0]) { do_rawlog(LT_TRACE, "%s : %d", chk->ref_name, chk->ref_count); } do_rawlog(LT_TRACE, "MEMCHECK dump ends"); }
/** Add new help command. This function is * the basis for the help_command directive in mush.cnf. It creates * a new help entry for the hash table, builds a help index, * and adds the new command to the command table. * \param command_name name of help command to add. * \param filename name of the help file to use for this command. * \param admin if 1, this command reads admin topics, rather than standard. */ void add_help_file(const char *command_name, const char *filename, int admin) { help_file *h; if (help_init == 0) init_help_files(); if (!command_name || !filename || !*command_name || !*filename) return; /* If there's already an entry for it, complain */ h = hashfind(strupper(command_name), &help_files); if (h) { do_rawlog(LT_ERR, "Duplicate help_command %s ignored.", command_name); return; } h = mush_malloc(sizeof *h, "help_file.entry"); h->command = mush_strdup(strupper(command_name), "help_file.command"); h->file = mush_strdup(filename, "help_file.filename"); h->entries = 0; h->indx = NULL; h->admin = admin; help_build_index(h, h->admin); if (!h->indx) { mush_free(h->command, "help_file.command"); mush_free(h->file, "help_file.filename"); mush_free(h, "help_file.entry"); return; } (void) command_add(h->command, CMD_T_ANY | CMD_T_NOPARSE, NULL, 0, NULL, cmd_helpcmd); hashadd(h->command, h, &help_files); }
/** Validates a timezone name to see if it fits the right format. * \param name The name of the time zone. * \return true or false */ bool is_valid_tzname(const char *name) { static pcre *re = NULL; static pcre_extra *extra = NULL; int len; int ovec[15]; if (!re) { int erroffset; const char *errptr; re = pcre_compile("^[A-Z][\\w+-]+(?:/[A-Z][\\w+-]+)?$", 0, &errptr, &erroffset, tables); if (!re) { do_rawlog(LT_ERR, "tz: Unable to compile timezone name validation RE: %s", errptr); return 0; } extra = pcre_study(re, pcre_study_flags, &errptr); } len = strlen(name); return pcre_exec(re, extra, name, len, 0, 0, ovec, 15) > 0; }
/** Convert a time string to a struct tm using getdate(). * Formats for the time string are taken from the file referenced in * the DATEMSK environment variable. * \param str a time string. * \param ttm pointer to a struct tm to fill. * \retval 1 success. * \retval 0 failure. */ int do_convtime_gd(const char *str, struct tm *ttm) { /* converts time string to a struct tm. Returns 1 on success, 0 on fail. * Formats of the time string are taken from the file listed in the * DATEMSK env variable */ struct tm *tc; tc = getdate(str); if (tc == NULL) { #ifdef NEVER if (getdate_err <= 7) do_rawlog(LT_ERR, "getdate returned error code %d for %s", getdate_err, str); #endif return 0; } memcpy(ttm, tc, sizeof(struct tm)); ttm->tm_isdst = -1; return 1; }
static void shift_bufferq(BUFFERQ *bq, int space_needed) { char *p = bq->buffer; int size, jump; int skipped = 0; while ((space_needed > 0) && (p < bq->buffer_end)) { /* First 4 bytes is the size of the first string, not including \0 */ memcpy(&size, p, sizeof(size)); /* Jump to the start of the next string */ jump = size + BUFFERQLINEOVERHEAD + 1; p += jump; space_needed -= jump; skipped++; } if ((p != bq->buffer_end) && (space_needed > 0)) { /* Not good. We couldn't get the space we needed even after we * emptied the buffer. This should never happen, but if it does, * we'll just log a fault and do nothing. */ do_rawlog(LT_ERR, "Unable to get enough buffer queue space"); return; } /* Shift everything here and after up to the front * At this point, p may be pointing at the very end of the buffer, * in which case, we just move it to the front with no shifting. */ if (p < bq->buffer_end) memmove(bq->buffer, p, bq->buffer_end - p); bq->buffer_end -= (p - bq->buffer); bq->num_buffered -= skipped; }
static DH * get_dh1024(void) { static unsigned char dh1024_p[] = { 0xB6, 0xBC, 0x30, 0x5B, 0xB4, 0xE5, 0x96, 0x62, 0x3F, 0x85, 0x5B, 0x1F, 0x88, 0xD1, 0x12, 0xE1, 0x1D, 0x27, 0x69, 0x63, 0xAD, 0xB3, 0x4D, 0x23, 0xB8, 0x4B, 0x1A, 0x90, 0xA6, 0x89, 0xD8, 0x5D, 0xFA, 0xF5, 0x8F, 0xFF, 0xFF, 0xF4, 0x54, 0x3B, 0xCD, 0x5C, 0xAA, 0x79, 0x8B, 0x14, 0xBB, 0x84, 0xAC, 0xEE, 0x94, 0x47, 0x76, 0xEC, 0x46, 0x75, 0x26, 0x48, 0x8C, 0x06, 0x55, 0x27, 0x7F, 0xC0, 0xF1, 0xE8, 0x1F, 0xD2, 0xE4, 0x55, 0xAE, 0x78, 0x11, 0x6E, 0xF1, 0x3B, 0xCD, 0x55, 0xE8, 0x17, 0xE9, 0x15, 0x7B, 0x05, 0x91, 0x28, 0x9D, 0xD3, 0x40, 0x2E, 0x34, 0x03, 0x04, 0x2B, 0x2D, 0xC5, 0x5C, 0x67, 0xC5, 0xF4, 0x28, 0x8E, 0x16, 0xAC, 0xDD, 0x68, 0x43, 0x66, 0x51, 0xC1, 0x6F, 0x54, 0xB9, 0x22, 0xD8, 0x1A, 0x39, 0x6B, 0x0A, 0xC1, 0x20, 0x5A, 0x9D, 0x31, 0x30, 0xE4, 0x0B, 0xC3, }; static unsigned char dh1024_g[] = { 0x02, }; DH *dh; if ((dh = DH_new()) == NULL) return NULL; if (dh->p) { BN_free(dh->p); dh->p = NULL; } if (dh->g) { BN_free(dh->g); dh->g = NULL; } dh->p = BN_bin2bn(dh1024_p, sizeof(dh1024_p), NULL); if (!dh->p) { do_rawlog(LT_ERR, "Error in BN_bin2bn 1"); DH_free(dh); return NULL; } dh->g = BN_bin2bn(dh1024_g, sizeof(dh1024_g), NULL); if (!dh->g) { do_rawlog(LT_ERR, "Error in BN_bin2bn 2"); DH_free(dh); return NULL; } return dh; }
void cu5_pennpy_initialize(void) { FILE *main_py_fp; assert(cu5_pennpy_main == NULL); do_rawlog(LT_ERR, T("PennPy: Initializing")); /* Initialize Python without installing signal handlers. */ Py_InitializeEx(0); /* Borrow a reference to __main__. */ if (!(cu5_pennpy_main = PyImport_AddModule("__main__"))) { /* This shouldn't happen, but you never know. */ mush_panic(T("PennPy: Can't get reference to __main__")); } cu5_pennpy_main_dict = PyModule_GetDict(cu5_pennpy_main); /* Initialize __pennmush__ internal module. */ if (!cu5_pennpy_initialize_module()) { /* Can't initialize module. */ mush_panic(T("PennPy: Can't initialize __pennmush__ module")); } /* Execute game/python/main.py. */ if (!(main_py_fp = fopen(MAIN_PY, "r"))) { /* Can't run main.py. */ do_rawlog(LT_ERR, T("PennPy: Can't open %s"), MAIN_PY); return; } if (PyRun_SimpleFile(main_py_fp, MAIN_PY) != 0) { /* Something wrong with main.py. */ do_rawlog(LT_ERR, T("PennPy: Failed to execute %s"), MAIN_PY); fclose(main_py_fp); return; } fclose(main_py_fp); /* Ready. */ cu5_pennpy_enabled = 1; }
/** Rebuild a help file index. * \verbatim * This command implements @readcache. * \endverbatim * \param player the enactor. */ void help_reindex(dbref player) { help_file *curr; for (curr = hash_firstentry(&help_files); curr; curr = hash_nextentry(&help_files)) { if (curr->indx) { mush_free(curr->indx, "help_index"); curr->indx = NULL; curr->entries = 0; } help_build_index(curr, curr->admin); } if (player != NOTHING) { notify(player, T("Help files reindexed.")); do_rawlog(LT_WIZ, "Help files reindexed by %s(#%d)", Name(player), player); } else do_rawlog(LT_WIZ, "Help files reindexed."); }
int CheckDatabase(const char *path, FILETIME * modified, long *filesize) { HANDLE filscan; WIN32_FIND_DATA fildata; SYSTEMTIME st; static const char *const months[] = { ">!<", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; FILE *f; size_t bytes; filscan = FindFirstFile(path, &fildata); if (filscan == INVALID_HANDLE_VALUE) { do_rawlog(LT_ERR, "File \"%s\" not found.", path); return FALSE; } *modified = fildata.ftLastWriteTime; *filesize = fildata.nFileSizeLow; FindClose(filscan); FileTimeToSystemTime(&fildata.ftLastWriteTime, &st); if (st.wMonth < 1 || st.wMonth > 12) st.wMonth = 0; do_rawlog(LT_ERR, "File \"%s\" found, size %ld %s, modified on %02d %s %04d %02d:%02d:%02d", path, fildata.nFileSizeLow, fildata.nFileSizeLow == 1 ? "byte" : "bytes", st.wDay, months[st.wMonth], st.wYear, st.wHour, st.wMinute, st.wSecond); if (fildata.nFileSizeHigh == 0 && fildata.nFileSizeLow < 80) { do_rawlog(LT_ERR, "File is too small to be a MUSH database."); return FALSE; } /* check file for validity */ f = fopen(path, "rb"); if (!f) { do_rawlog(LT_ERR, "Unable to open file %s", path); return FALSE; } if (fseek(f, -80, SEEK_END) != 0) { do_rawlog(LT_ERR, "Unable to check file %s", path); fclose(f); return FALSE; } bytes = fread(buff, 1, 80, f); fclose(f); if (bytes != 80) { do_rawlog(LT_ERR, "Unable to read last part of file %s", path); return FALSE; } if (strstr(buff, "***END OF DUMP***") == 0) { do_rawlog(LT_ERR, "Database not terminated correctly, file %s", path); return FALSE; } return TRUE; } /* end of CheckDatabase */
void cu5_pennpy_finalize(void) { assert(cu5_pennpy_main != NULL); cu5_pennpy_enabled = 0; do_rawlog(LT_ERR, T("PennPy: Finalizing")); /* Clean up (some) Python interpreter resources. Not exhaustive. */ Py_Finalize(); }
/** Remove an allocation check. * \param ref type of allocation to remove. * \param filename file del_check was called from * \param line linenumber in filename where del_check was called */ void del_check(const char *ref, const char *filename, int line) { MEM *chk; if (!options.mem_check) return; chk = lookup_check(ref); if (chk) { chk->ref_count -= 1; if (chk->ref_count < 0) do_rawlog(LT_TRACE, "ERROR: Deleting a check with a negative count: %s (At %s:%d)", ref, filename, line); } else { do_rawlog(LT_TRACE, "ERROR: Deleting a non-existant check: %s (At %s:%d)", ref, filename, line); } }
/* Unload one Module */ int module_close(struct module_entry_t *m) { int ret; ret = m->unload(m); /* first run requierd unload code */ if(!ret) return 0; /* next unload the modules for real */ ret = lt_dlclose(m->handle); if(ret != 0) { do_rawlog(LT_ERR, "Could not unload module: %s/%d | %s", __FILE__, __LINE__, lt_dlerror()); return 0; } if(!module_entry_del(m)) { do_rawlog(LT_ERR, "Could not unload module: %s/%d ", __FILE__, __LINE__); return 0; } return 1; }
/* Load Module name */ int module_open(char *path, char *name) { char file[BUFFER_LEN]; int (*module_loader)(struct module_entry_t *); struct module_entry_t *module; void *handle; memset(file, '\0', BUFFER_LEN); snprintf(file, BUFFER_LEN, "%s/%s", path, name); handle = lt_dlopen(file); if(!handle) { do_rawlog(LT_ERR, "Error Loading Module: %s | %s ", file, lt_dlerror()); return 0; } /* Some OSes may need symbols to be prefixed with _.. Will need to look into autoconfig code for this */ module_loader = MODULE_FUNCRET(handle, "module_load"); if(!module_loader) { do_rawlog(LT_ERR, "Error Loading Module: Could not call module_load | %s", file); return 0; } /* Add the module to the linked list */ module = module_entry_add(name); if(module == NULL) { return 0; } module->handle = handle; module->load = module_loader; module->unload = MODULE_FUNCRET(handle, "module_unload"); /* Grab info and version from module & put it in */ /* Success.. Call the module */ return module_loader(module); }
/** Resize a hash table. * \param htab pointer to hashtable. * \param primesize new size. * \param seed_index Index of first hash seed to use */ static bool hash_resize(HASHTAB *htab, int newsize, int hashseed_offset) { struct hash_bucket *oldarr; int oldsize, oldoffset, i; /* Massive overkill here */ if (resize_calls > 150) { do_rawlog(LT_ERR, "Ooops. Too many attempts to resize a hash table."); return false; } /* If all possible hash function combos have been exhausted, grow the array */ if (hashseed_offset == first_offset) { int newersize = next_prime_after(floor(newsize * 1.15)); first_offset = -1; return hash_resize(htab, newersize, hashseed_offset); } resize_calls += 1; /* Save the old data we need */ oldsize = htab->hashsize; oldoffset = htab->hashseed_offset; oldarr = htab->buckets; htab->buckets = mush_calloc(newsize, sizeof(struct hash_bucket), "hash.buckets"); htab->hashsize = newsize; htab->hashseed_offset = hashseed_offset; for (i = 0; i < oldsize; i++) { if (oldarr[i].key) { if (!hash_insert(htab, oldarr[i].key, oldarr[i].keylen, oldarr[i].data)) { /* Couldn't fit an element in. Try with different hash functions. */ mush_free(htab->buckets, "hash.buckets"); htab->buckets = oldarr; htab->hashsize = oldsize; htab->hashseed_offset = oldoffset; if (first_offset == -1) first_offset = hashseed_offset; return hash_resize(htab, newsize, (hashseed_offset + 1) % NHASH_MOD); } } } mush_free(oldarr, "hash.buckets"); return true; }
/** Check a player's password against a given string. * * First checks new-style formatted password strings * If that doesn't match, tries old-style SHA0 password * strings, and upgrades the stored password. * If that doesn't match, tries really-old-style crypt(3) * password strings, and upgrades the stored password. * If that doesn't work, you lose. * * \param player dbref of player. * \param password plaintext password string to check. * \retval 1 password matches (or player has no password). * \retval 0 password fails to match. */ bool password_check(dbref player, const char *password) { ATTR *a; char *saved; /* read the password and compare it */ if (!(a = atr_get_noparent(player, pword_attr))) return 1; /* No password attribute */ saved = strdup(atr_value(a)); if (!saved) return 0; if (!password_comp(saved, password)) { /* Nope. Try SHA0. */ char *passwd = mush_crypt_sha0(password); if (strcmp(saved, passwd) != 0) { /* Not SHA0 either. Try old-school crypt(); */ #ifdef HAVE_CRYPT if (strcmp(crypt(password, "XX"), saved) != 0) { /* Nope */ #endif /* HAVE_CRYPT */ /* See if it's a MUX password */ if (!check_mux_password(saved, password)) { /* As long as it's not obviously encrypted, check for a * plaintext password. */ if (strlen(password) < 4 || *password == '$' || (password[0] == 'X' && password[1] == 'X') || strcmp(saved, password)) { free(saved); return 0; } } #ifdef HAVE_CRYPT } #endif } /* Something worked. Change password to SHS-encrypted */ do_rawlog(LT_CONN, "Updating password format for player #%d", player); (void) atr_add(player, pword_attr, password_hash(password, NULL), GOD, 0); } /* Success! */ free(saved); return 1; }
void kill_ssl_slave(void) { if (ssl_slave_pid > 0) { WAIT_TYPE my_stat; do_rawlog(LT_ERR, "Terminating ssl_slave pid %d", ssl_slave_pid); block_a_signal(SIGCHLD); kill(ssl_slave_pid, SIGTERM); mush_wait(ssl_slave_pid, &my_stat, 0); unblock_a_signal(SIGCHLD); close(ssl_slave_ctl_fd); ssl_slave_pid = -1; ssl_slave_state = SSL_SLAVE_DOWN; } }
static ATTR * attr_alias_read(PENNFILE *f, char *alias) { char *tmp; ATTR *a; db_read_this_labeled_string(f, "name", &tmp); a = aname_find_exact(tmp); if (!a) { /* Oops */ do_rawlog(LT_ERR, "Alias of non-existant attribute '%s' in db.", tmp); (void) getstring_noalloc(f); return NULL; } db_read_this_labeled_string(f, "alias", &tmp); strcpy(alias, tmp); return a; }
/** Kill the info_slave process, typically at shutdown. */ void kill_info_slave(void) { WAIT_TYPE my_stat; if (info_slave_state != INFO_SLAVE_DOWN) { if (info_slave_pid > 0) { do_rawlog(LT_ERR, "Terminating info_slave pid %d", info_slave_pid); block_a_signal(SIGCHLD); closesocket(info_slave); kill(info_slave_pid, SIGTERM); mush_wait(info_slave_pid, &my_stat, 0); info_slave_pid = -1; unblock_a_signal(SIGCHLD); } info_slave_state = INFO_SLAVE_DOWN; } }
static void cu5_pennpy_exception(char *buff, char **bp) { const char *ex_name; PyObject *ex_type; /* * Report exception. We don't return specifics; if you need them, * handle that in the Python code and return a string. */ ex_name = "PYTHON"; /* catch-all exception "name" */ ex_type = PyErr_Occurred(); if (PyExceptionClass_Check(ex_type)) { /* Exception type is a valid exception class. */ ex_name = PyExceptionClass_Name(ex_type); if (ex_name) { /* Exception class has a name. */ char *ex_short_name = strrchr(ex_name, '.'); if (ex_short_name) { /* blah.blah.ExceptionName */ ex_name = ex_short_name + 1; } } else { /* Shouldn't happen, but extra cautious. */ } } else { /* * This must be an old-style string exception, but those are * deprecated and now too rare for us to bother identifying. */ } safe_format(buff, bp, T("#-1 %s EXCEPTION"), ex_name); /* Dump the stack to stderr and clear the error indicator. */ do_rawlog(LT_ERR, "PennPy: Python exception:"); PyErr_Print(); }
/** Add new help command. This function is * the basis for the help_command directive in mush.cnf. It creates * a new help entry for the hash table, builds a help index, * and adds the new command to the command table. * \param command_name name of help command to add. * \param filename name of the help file to use for this command. * \param admin if 1, this command reads admin topics, rather than standard. */ void add_help_file(const char *command_name, const char *filename, int admin) { help_file *h; char newfilename[256] = "\0"; /* Must use a buffer for MacOS file path conversion */ strncpy(newfilename, filename, 256); if (help_init == 0) init_help_files(); if (!command_name || !filename || !*command_name || !*newfilename) return; /* If there's already an entry for it, complain */ h = hashfind(strupper(command_name), &help_files); if (h) { do_rawlog(LT_ERR, T("Duplicate help_command %s ignored."), command_name); return; } h = mush_malloc(sizeof *h, "help_file.entry"); h->command = mush_strdup(strupper(command_name), "help_file.command"); h->file = mush_strdup(newfilename, "help_file.filename"); h->entries = 0; h->indx = NULL; h->admin = admin; help_build_index(h, h->admin); if (!h->indx) { mush_free(h->command, "help_file.command"); mush_free(h->file, "help_file.filename"); mush_free(h, "help_file.entry"); return; } (void) command_add(h->command, CMD_T_ANY | CMD_T_NOPARSE, NULL, cmd_helpcmd, NULL); hashadd(h->command, h, &help_files); }
/** Kill the info_slave process, typically at shutdown. */ void kill_info_slave(void) { WAIT_TYPE my_stat; if (info_slave_state != INFO_SLAVE_DOWN) { if (info_slave_pid > 0) { do_rawlog(LT_ERR, "Terminating info_slave pid %d", info_slave_pid); block_a_signal(SIGCHLD); closesocket(info_slave); kill(info_slave_pid, 15); /* Have to wait long enough for the info_slave to actually die. This will hopefully be enough time. */ usleep(100); mush_wait(info_slave_pid, &my_stat, WNOHANG); info_slave_pid = -1; unblock_a_signal(SIGCHLD); } info_slave_state = INFO_SLAVE_DOWN; } }
/** Parse a time zone description file. */ struct tzinfo * read_tzfile(const char *tzname) { char tzfile[BUFFER_LEN]; int fd; struct tzinfo *tz; if (!is_valid_tzname(tzname)) return NULL; snprintf(tzfile, BUFFER_LEN, "%s/%s", TZDIR, tzname); if ((fd = open(tzfile, O_RDONLY)) < 0) { if (errno != ENOENT) do_rawlog(LT_ERR, "tz: Unable to open %s: %s\n", tzfile, strerror(errno)); return NULL; } tz = do_read_tzfile(fd, tzfile, 4); close(fd); return tz; }
void cu5_pennpy_timer(void) { PyObject *result; if (!cu5_pennpy_enabled || !cu5_pennpy_timer_hook) { /* No timer hook available. */ return; } /* Call timer hook. */ result = PyObject_CallObject(cu5_pennpy_timer_hook, NULL); if (!result) { do_rawlog(LT_ERR, "PennPy: Timer hook threw exception"); PyErr_Print(); /* Disable timer hook. Annoying, so don't throw exceptions. */ cu5_pennpy_set_timer(NULL); return; } /* Discard result. */ Py_DECREF(result); }
/** Migrate some number of chunks. * The requested amount is only a guideline; the actual amount * migrated will be more or less due to always migrating all the * attributes, locks, and mail on any given object together. * \param amount the suggested number of attributes to migrate. */ static void migrate_stuff(int amount) { static int start_obj = 0; static chunk_reference_t **refs = NULL; static int refs_size = 0; int end_obj; int actual; ATTR *aptr; lock_list *lptr; MAIL *mp; if (db_top == 0) return; end_obj = start_obj; actual = 0; do { for (aptr = List(end_obj); aptr; aptr = AL_NEXT(aptr)) if (aptr->data != NULL_CHUNK_REFERENCE) actual++; for (lptr = Locks(end_obj); lptr; lptr = L_NEXT(lptr)) if (L_KEY(lptr) != NULL_CHUNK_REFERENCE) actual++; if (IsPlayer(end_obj)) { for (mp = find_exact_starting_point(end_obj); mp; mp = mp->next) if (mp->msgid != NULL_CHUNK_REFERENCE) actual++; } end_obj = (end_obj + 1) % db_top; } while (actual < amount && end_obj != start_obj); if (actual == 0) return; if (!refs || actual > refs_size) { if (refs) mush_free(refs, "migration reference array"); refs = mush_calloc(actual, sizeof(chunk_reference_t *), "migration reference array"); refs_size = actual; if (!refs) mush_panic("Could not allocate migration reference array"); } #ifdef DEBUG_MIGRATE do_rawlog(LT_TRACE, "Migrate asked %d, actual objects #%d to #%d for %d", amount, start_obj, (end_obj + db_top - 1) % db_top, actual); #endif actual = 0; do { for (aptr = List(start_obj); aptr; aptr = AL_NEXT(aptr)) if (aptr->data != NULL_CHUNK_REFERENCE) { refs[actual] = &(aptr->data); actual++; } for (lptr = Locks(start_obj); lptr; lptr = L_NEXT(lptr)) if (L_KEY(lptr) != NULL_CHUNK_REFERENCE) { refs[actual] = &(lptr->key); actual++; } if (IsPlayer(start_obj)) { for (mp = find_exact_starting_point(start_obj); mp; mp = mp->next) if (mp->msgid != NULL_CHUNK_REFERENCE) { refs[actual] = &(mp->msgid); actual++; } } start_obj = (start_obj + 1) % db_top; } while (start_obj != end_obj); chunk_migration(actual, refs); }
static struct tzinfo * do_read_tzfile(int fd, const char *tzfile, int time_size) { struct tzinfo *tz = NULL; int size, n; bool has_64bit_times = 0; int isstdcnt, isgmtcnt; { char magic[5] = { '\0' }; if (read(fd, magic, 4) != 4) { do_rawlog(LT_ERR, "tz: Unable to read header from %s: %s.\n", tzfile, strerror(errno)); goto error; } if (memcmp(magic, TZMAGIC, 4) != 0) { do_rawlog(LT_ERR, "tz: %s is not a valid tzfile. Wrong magic number.\n", tzfile); goto error; } } { char version[16]; if (read(fd, version, 16) != 16) { do_rawlog(LT_ERR, "tz: Unable to read chunk from %s: %s\n", tzfile, strerror(errno)); goto error; } /* There's a second copy of the data using 64 bit times, following the chunk with 32 bit times. */ if (version[0] == '2') has_64bit_times = 1; } tz = mush_malloc(sizeof *tz, "timezone"); memset(tz, 0, sizeof *tz); { int32_t counts[6]; READ_CHUNK(counts, sizeof counts); isgmtcnt = decode32(counts[0]); isstdcnt = decode32(counts[1]); tz->leapcnt = decode32(counts[2]); tz->timecnt = decode32(counts[3]); tz->typecnt = decode32(counts[4]); tz->charcnt = decode32(counts[5]); } /* Use 64-bit time_t version on such systems. */ if (has_64bit_times && sizeof(time_t) == 8 && time_size == 4) { off_t skip = 44; /* Header and sizes */ skip += tz->timecnt * 5; skip += tz->typecnt * 6; skip += tz->charcnt; skip += tz->leapcnt * (4 + time_size); skip += isgmtcnt + isstdcnt; if (lseek(fd, skip, SEEK_SET) < 0) { do_rawlog(LT_ERR, "tz: Unable to seek to second section of %s: %s\n", tzfile, strerror(errno)); goto error; } mush_free(tz, "timezone"); return do_read_tzfile(fd, tzfile, 8); } #define READ_TRANSITIONS(type, decode) \ do { \ type *buf; \ \ size = tz->timecnt * time_size; \ buf = malloc(size); \ READ_CHUNKF(buf, size); \ \ tz->transitions = calloc(tz->timecnt, sizeof(time_t)); \ for (n = 0; n < tz->timecnt; n += 1) \ tz->transitions[n] = (time_t) decode(buf[n]); \ \ free(buf); \ } while (0) if (time_size == 4) { READ_TRANSITIONS(int32_t, decode32); } else { READ_TRANSITIONS(int64_t, decode64); } tz->offset_indexes = malloc(tz->timecnt); READ_CHUNK(tz->offset_indexes, tz->timecnt); { uint8_t *buf; int m, size = tz->typecnt * 6; buf = malloc(size); READ_CHUNKF(buf, size); tz->offsets = calloc(tz->typecnt, sizeof(struct ttinfo)); for (n = 0, m = 0; n < tz->typecnt; n += 1, m += 6) { int32_t gmtoff; memcpy(&gmtoff, &buf[m], 4); tz->offsets[n].tt_gmtoff = decode32(gmtoff); tz->offsets[n].tt_isdst = buf[m + 4]; tz->offsets[n].tt_abbrind = buf[m + 5]; tz->offsets[n].tt_std = tz->offsets[n].tt_utc = 0; } free(buf); } tz->abbrevs = malloc(tz->charcnt); READ_CHUNK(tz->abbrevs, tz->charcnt); #define READ_LEAPSECS(type, decode) \ do { \ type *buf; \ int m, size = tz->leapcnt * (4 + time_size); \ \ buf = malloc(size); \ READ_CHUNKF(buf, size); \ \ tz->leapsecs = calloc(tz->leapcnt, sizeof(struct ttleapsecs)); \ \ for (n = 0, m = 0; n < tz->leapcnt; n += 1, m += (4 + time_size)) { \ type when; \ int32_t secs; \ \ memcpy(&when, buf, time_size); \ memcpy(&secs, buf + time_size, 4); \ tz->leapsecs[n].tt_when = (time_t) decode(when); \ tz->leapsecs[n].tt_secs = decode32(secs); \ } \ free(buf); \ } while (0) if (tz->leapcnt) { if (time_size == 4) READ_LEAPSECS(int32_t, decode32); else READ_LEAPSECS(int64_t, decode64); } { uint8_t *buf; int n; buf = malloc(isstdcnt); READ_CHUNKF(buf, isstdcnt); for (n = 0; n < isstdcnt; n += 1) tz->offsets[n].tt_std = buf[n]; free(buf); buf = malloc(isgmtcnt); READ_CHUNKF(buf, isgmtcnt); for (n = 0; n < isgmtcnt; n += 1) tz->offsets[n].tt_utc = buf[n]; free(buf); } return tz; error: if (tz) free_tzinfo(tz); return NULL; }
bool make_info_slave(void) { int socks[2]; pid_t child; int n; if (info_slave_state != INFO_SLAVE_DOWN) { if (info_slave_pid > 0) kill_info_slave(); info_slave_state = INFO_SLAVE_DOWN; } if (startup_attempts == 0) time(&startup_window); startup_attempts += 1; if (startup_attempts > MAX_ATTEMPTS) { time_t now; time(&now); if (difftime(now, startup_window) <= 60.0) { /* Too many failed attempts to start info_slave in 1 minute */ do_rawlog(LT_ERR, "Disabling info_slave due to too many errors."); info_slave_halted = true; return false; } else { /* Reset counter */ startup_window = now; startup_attempts = 0; } } #ifndef AF_LOCAL /* Use Posix.1g names. */ #define AF_LOCAL AF_UNIX #endif #ifdef HAVE_SOCKETPAIR if (socketpair(AF_LOCAL, SOCK_DGRAM, 0, socks) < 0) { penn_perror("creating slave datagram socketpair"); return false; } if (socks[0] >= maxd) maxd = socks[0] + 1; if (socks[1] >= maxd) maxd = socks[1] + 1; #endif child = fork(); if (child < 0) { penn_perror("forking info slave"); #ifdef HAVE_SOCKETPAIR closesocket(socks[0]); closesocket(socks[1]); #endif return false; } else if (child > 0) { info_slave_state = INFO_SLAVE_READY; info_slave_pid = child; #ifdef HAVE_SOCKETPAIR info_slave = socks[0]; closesocket(socks[1]); do_rawlog(LT_ERR, "Spawning info slave, communicating using socketpair, pid %d.", child); #endif make_nonblocking(info_slave); } else { int errfd = fileno(stderr); int dupfd; /* Close unneeded fds and sockets: Everything but stderr and the socket used to talk to the mush */ for (n = 0; n < maxd; n++) { if (n == errfd) continue; #ifdef HAVE_SOCKETPAIR if (n == socks[1]) continue; #endif close(n); } /* Reuse stdin and stdout for talking to the slave */ dupfd = dup2(socks[1], 0); if (dupfd < 0) { penn_perror("dup2() of stdin in info_slave"); exit(1); } dupfd = dup2(socks[1], 1); if (dupfd < 0) { penn_perror("dup2() of stdout in info_slave"); exit(1); } close(socks[1]); execl("./info_slave", "info_slave", "for", MUDNAME, (char *) NULL); penn_perror("execing info slave"); exit(1); } if (info_slave >= maxd) maxd = info_slave + 1; lower_priority_by(info_slave_pid, 4); for (n = 0; n < maxd; n++) if (FD_ISSET(n, &info_pending)) query_info_slave(n); return true; }
/** Create a new SSL slave. * \param port The port to listen on for SSL connections. * \return 0 on success, -1 on failure */ int make_ssl_slave(void) { int fds[2]; if (ssl_slave_state != SSL_SLAVE_DOWN) { do_rawlog(LT_ERR, "Attempt to start ssl slave when a copy is already running."); return -1; } if (ssl_slave_halted) { do_rawlog(LT_ERR, "Attempt to start disabled ssl slave."); return -1; } if (startup_attempts == 0) time(&startup_window); startup_attempts += 1; if (startup_attempts > MAX_ATTEMPTS) { time_t now; time(&now); if (difftime(now, startup_window) <= 60.0) { do_rawlog(LT_ERR, "Disabling ssl_slave due to too many errors."); ssl_slave_halted = true; return -1; } else { /* Reset counter */ startup_window = now; startup_attempts = 0; } } if (pipe(fds) < 0) { do_rawlog(LT_ERR, "Unable to create pipe to speak to ssl_slave: %s", strerror(errno)); return -1; } if (fds[0] >= maxd) maxd = fds[0] + 1; if (fds[1] >= maxd) maxd = fds[1] + 1; if ((ssl_slave_pid = fork()) == 0) { /* Set up and exec ssl_slave */ int n, errfd = -1, connfd = -1; struct log_stream *lg; /* Close all open files but LT_CONN and LT_ERR, and assign them as stdout and stderr, respectively. */ /* If called on startup, maxd is 0 but log files and such have been opened. Use a reasonable max descriptor. If called because ssl_slave went down, maxd will be set properly already. */ if (!maxd) maxd = 20; lg = lookup_log(LT_ERR); if (lg) errfd = fileno(lg->fp); lg = lookup_log(LT_CONN); if (lg) connfd = fileno(lg->fp); dup2(fds[0], 0); /* stdin */ dup2(connfd, 1); /* stdout */ dup2(errfd, 2); /* stderr */ for (n = 3; n < maxd; n++) close(n); execl("./ssl_slave", "ssl_slave", "for", MUDNAME, NULL); penn_perror("execing ssl slave"); return EXIT_FAILURE; } else if (ssl_slave_pid < 0) { do_rawlog(LT_ERR, "Failure to fork ssl_slave: %s", strerror(errno)); return -1; } else { struct ssl_slave_config cf; ssl_slave_ctl_fd = fds[1]; close(fds[0]); /* Set up arguments to the slave */ memset(&cf, 0, sizeof cf); strcpy(cf.socket_file, options.socket_file); strcpy(cf.ssl_ip_addr, SSL_IP_ADDR); cf.normal_port = options.port; cf.ssl_port = options.ssl_port; strcpy(cf.private_key_file, options.ssl_private_key_file); strcpy(cf.ca_file, options.ssl_ca_file); cf.require_client_cert = options.ssl_require_client_cert; cf.keepalive_timeout = options.keepalive_timeout; if (write(ssl_slave_ctl_fd, &cf, sizeof cf) < 0) { do_rawlog(LT_ERR, "Unable to send ssl_slave config options: %s", strerror(errno)); return -1; } ssl_slave_state = SSL_SLAVE_RUNNING; do_rawlog(LT_ERR, "Spawning ssl_slave, communicating over %s, pid %d.", options.socket_file, ssl_slave_pid); return 0; } return -1; }
static void help_build_index(help_file *h, int restricted) { long bigpos, pos = 0; bool in_topic; int i, lineno, ntopics; size_t n; char *s, *topic; char the_topic[TOPIC_NAME_LEN + 1]; char line[LINE_SIZE + 1]; FILE *rfp; tlist *cur; /* Quietly ignore null values for the file */ if (!h || !h->file) return; if ((rfp = fopen(h->file, FOPEN_READ)) == NULL) { do_rawlog(LT_ERR, "Can't open %s for reading: %s", h->file, strerror(errno)); return; } if (restricted) do_rawlog(LT_WIZ, "Indexing file %s (admin topics)", h->file); else do_rawlog(LT_WIZ, "Indexing file %s", h->file); topics = NULL; num_topics = 0; top_topics = 0; bigpos = 0L; lineno = 0; ntopics = 0; in_topic = 0; #ifdef HAVE_POSIX_FADVISE posix_fadvise(fileno(rfp), 0, 0, POSIX_FADV_SEQUENTIAL); #endif while (fgets(line, LINE_SIZE, rfp) != NULL) { ++lineno; if (ntopics == 0) { /* Looking for the first topic, but we'll ignore blank lines */ if (!line[0]) { /* Someone's feeding us /dev/null? */ do_rawlog(LT_ERR, "Malformed help file %s doesn't start with &", h->file); fclose(rfp); return; } if (isspace(line[0])) continue; if (line[0] != '&') { do_rawlog(LT_ERR, "Malformed help file %s doesn't start with &", h->file); fclose(rfp); return; } } n = strlen(line); if (line[n - 1] != '\n') { do_rawlog(LT_ERR, "Line %d of %s: line too long", lineno, h->file); } if (line[0] == '&') { ++ntopics; if (!in_topic) { /* Finish up last entry */ if (ntopics > 1) { write_topic(pos); } in_topic = true; } /* parse out the topic */ /* Get the beginning of the topic string */ for (topic = &line[1]; (*topic == ' ' || *topic == '\t') && *topic != '\0'; topic++) ; /* Get the topic */ strcpy(the_topic, ""); for (i = -1, s = topic; *s != '\n' && *s != '\0'; s++) { if (i >= TOPIC_NAME_LEN - 1) break; if (*s != ' ' || the_topic[i] != ' ') the_topic[++i] = *s; } if ((restricted && the_topic[0] == '&') || (!restricted && the_topic[0] != '&')) { the_topic[++i] = '\0'; cur = (tlist *) malloc(sizeof(tlist)); strcpy(cur->topic, the_topic); cur->next = top; top = cur; } } else { if (in_topic) { pos = bigpos; } in_topic = false; } bigpos = ftell(rfp); } /* Handle last topic */ write_topic(pos); if (topics) qsort(topics, num_topics, sizeof(help_indx), topic_cmp); h->entries = num_topics; h->indx = topics; add_check("help_index"); fclose(rfp); do_rawlog(LT_WIZ, "%d topics indexed.", num_topics); return; }
static void do_new_spitfile(dbref player, char *arg1, help_file *help_dat) { help_indx *entry = NULL; FILE *fp; char *p, line[LINE_SIZE + 1]; char the_topic[LINE_SIZE + 2]; int default_topic = 0; size_t n; if (*arg1 == '\0') { default_topic = 1; arg1 = (char *) help_dat->command; } else if (*arg1 == '&') { notify(player, T("Help topics don't start with '&'.")); return; } if (strlen(arg1) > LINE_SIZE) *(arg1 + LINE_SIZE) = '\0'; if (help_dat->admin) { sprintf(the_topic, "&%s", arg1); } else strcpy(the_topic, arg1); if (!help_dat->indx || help_dat->entries == 0) { notify(player, T("Sorry, that command is temporarily unvailable.")); do_rawlog(LT_ERR, "No index for %s.", help_dat->command); return; } entry = help_find_entry(help_dat, the_topic); if (!entry && default_topic) entry = help_find_entry(help_dat, (help_dat->admin ? "&help" : "help")); if (!entry) { notify_format(player, T("No entry for '%s'."), arg1); return; } if ((fp = fopen(help_dat->file, FOPEN_READ)) == NULL) { notify(player, T("Sorry, that function is temporarily unavailable.")); do_log(LT_ERR, 0, 0, "Can't open text file %s for reading", help_dat->file); return; } if (fseek(fp, entry->pos, 0) < 0L) { notify(player, T("Sorry, that function is temporarily unavailable.")); do_rawlog(LT_ERR, "Seek error in file %s", help_dat->file); return; } strcpy(the_topic, strupper(entry->topic + (*entry->topic == '&'))); /* ANSI topics */ notify_format(player, "%s%s%s", ANSI_HILITE, the_topic, ANSI_END); if (SUPPORT_PUEBLO) notify_noenter(player, open_tag("SAMP")); for (n = 0; n < BUFFER_LEN; n++) { if (fgets(line, LINE_SIZE, fp) == NULL) break; if (line[0] == '&') break; if (line[0] == '\n') { notify(player, " "); } else { for (p = line; *p != '\0'; p++) if (*p == '\n') *p = '\0'; notify(player, line); } } if (SUPPORT_PUEBLO) notify(player, close_tag("SAMP")); fclose(fp); if (n >= BUFFER_LEN) notify_format(player, T("%s output truncated."), help_dat->command); }
/** Read the access.cnf file. * Initialize the access rules linked list and read in the access.cnf file. * \return true if successful, false if not */ bool read_access_file(void) { FILE *fp; char buf[BUFFER_LEN]; char *p; uint32_t can, cant; int retval; dbref who; char *comment; const char *errptr = NULL; if (access_top) { /* We're reloading the file, so we've got to delete any current * entries */ free_access_list(); } access_top = NULL; /* Be sure we have a file descriptor */ release_fd(); fp = fopen(ACCESS_FILE, FOPEN_READ); if (!fp) { do_rawlog(LT_ERR, "Access file %s not found.", ACCESS_FILE); retval = 0; } else { do_rawlog(LT_ERR, "Reading %s", ACCESS_FILE); while (fgets(buf, BUFFER_LEN, fp)) { /* Strip end of line if it's \r\n or \n */ if ((p = strchr(buf, '\r'))) *p = '\0'; else if ((p = strchr(buf, '\n'))) *p = '\0'; /* Find beginning of line; ignore blank lines */ p = buf; if (*p && isspace((unsigned char) *p)) p++; if (*p && *p != '#') { can = cant = 0; comment = NULL; /* Is this the @sitelock entry? */ if (!strncasecmp(p, "@sitelock", 9)) { if (!add_access_node("@sitelock", AMBIGUOUS, ACS_SITELOCK, 0, "", &errptr)) do_log(LT_ERR, GOD, GOD, "Failed to add sitelock node: %s", errptr); } else { if ((comment = strchr(p, '#'))) { *comment++ = '\0'; while (*comment && isspace((unsigned char) *comment)) comment++; } /* Move past the host name */ while (*p && !isspace((unsigned char) *p)) p++; if (*p) *p++ = '\0'; if (!parse_access_options(p, &who, &can, &cant, NOTHING)) /* Nothing listed, so assume we can't do anything! */ cant = ACS_DEFAULT; if (!add_access_node(buf, who, can, cant, comment, &errptr)) do_log(LT_ERR, GOD, GOD, "Failed to add access node: %s", errptr); } } } retval = 1; fclose(fp); } reserve_fd(); return retval; }