/* Determines if we are the child and if so performs the child logic. Return values: < 0 error 0 parent > 0 child */ static int fake_fork_child (void) { HANDLE section, event; struct fake_fork_info *info; char *name; name = make_section_name (GetCurrentProcessId ()); section = OpenFileMapping (FILE_MAP_WRITE, FALSE, name); xfree (name); /* It seems that Windows 9x and NT set last-error inconsistently when OpenFileMapping() fails; so we assume it failed because the section object does not exist. */ if (!section) return 0; /* We are the parent. */ info = MapViewOfFile (section, FILE_MAP_WRITE, 0, 0, 0); if (!info) { CloseHandle (section); return -1; } event = info->event; info->logfile_changed = false; if (!opt.lfilename) { /* See utils:fork_to_background for explanation. */ FILE *new_log_fp = unique_create (DEFAULT_LOGFILE, false, &opt.lfilename); if (new_log_fp) { info->logfile_changed = true; strncpy (info->lfilename, opt.lfilename, sizeof (info->lfilename)); info->lfilename[sizeof (info->lfilename) - 1] = '\0'; fclose (new_log_fp); } } UnmapViewOfFile (info); CloseHandle (section); /* Inform the parent that we've done our part. */ if (!SetEvent (event)) return -1; CloseHandle (event); return 1; /* We are the child. */ }
char *cmph_change_string(bot_t * bot, char *string, int opt) { unique_t *bu = NULL; cmphx_t **cmphx = NULL; char *str = NULL; char *sep_ptr; if (!string) return NULL; sep_ptr = str_find_sep(string); if (sep_ptr) string = sep_ptr; bu = unique_create(bot, &dl_mod_cmph_unique, UNIQUE_ID_TAG | UNIQUE_ID_CHAN); if (!bu) return NULL; cmphx = (cmphx_t **) & bu->data; switch (opt) { case MOD_CMPH_CLEAR: str = cmph_op_clear(bot, cmphx, NULL); break; case MOD_CMPH_SIZE: str = cmph_op_size(bot, cmphx, NULL); break; case MOD_CMPH_BUILD: str = cmph_op_build(bot, cmphx, string); break; case MOD_CMPH_LIST: break; case MOD_CMPH_FIND: str = cmph_op_find(bot, cmphx, string); break; default: break; } return str; }
char *rant_op_push(bot_t * bot, dlist_t ** dl, char *string) { unique_t *bu = NULL; debug(NULL, "rant_op_push: Entered: dl=%p\n", dl); if (!bot || !string) return NULL; if (!dl) { bu = unique_create(bot, &dl_mod_rant_unique, UNIQUE_ID_TAG | UNIQUE_ID_NICK); if (!bu) return NULL; dl = (dlist_t **) & bu->data; } string = str_unite("%s\n", string); dlist_Dinsert_after(dl, string); return NULL; }
static void redirect_output (void) { char *logfile; logfp = unique_create (DEFAULT_LOGFILE, false, &logfile); if (logfp) { fprintf (stderr, _("\n%s received, redirecting output to %s.\n"), redirect_request_signal_name, quote (logfile)); xfree (logfile); /* Dump the context output to the newly opened log. */ log_dump_context (); } else { /* Eek! Opening the alternate log file has failed. Nothing we can do but disable printing completely. */ fprintf (stderr, _("\n%s received.\n"), redirect_request_signal_name); fprintf (stderr, _("%s: %s; disabling logging.\n"), logfile, strerror (errno)); inhibit_logging = true; } save_context_p = false; }
char *quiz_change_string(bot_t * bot, char *string, int opt) { unique_t *bu = NULL; quiz_active_t **qa = NULL; dlist_t *dl = NULL; char **arg_array = NULL; char *str = NULL; char buf[MAX_BUF_SZ]; char *sep_ptr; debug(bot, "quiz_change_string: Entered\n"); if (!bot || !string) return NULL; sep_ptr = str_find_sep(string); if (sep_ptr) string = sep_ptr; bu = unique_create(bot, &dl_quiz_active_unique, UNIQUE_ID_TAG | UNIQUE_ID_CHAN); if (!bu) return NULL; qa = (quiz_active_t **) & bu->data; if (!qa) { } _memset(buf, 0, sizeof(buf)); if (strlen(string)) { dl = tokenize(bot, string, TOKENIZE_NORMAL | TOKENIZE_EATWHITESPACE, " "); if (!dl) return NULL; arg_array = (char **)dlist_convert_dlist_to_array(dl); if (!arg_array) goto cleanup; capsup(arg_array[0]); } switch (opt) { case QUIZ_OPT_LIST: { str = quiz_op_list(bot); break; } case QUIZ_OPT_INFO: { str = quiz_op_info(bot, *qa); break; } case QUIZ_OPT_CLEAR: { str = quiz_op_clear(bot, *qa); break; } case QUIZ_OPT_CLEAR_WINNERS: { str = quiz_op_clear_winners(bot, *qa); break; } case QUIZ_OPT_WINNERS: { str = quiz_op_winners(bot, *qa); break; } case QUIZ_OPT_SETUP: { str = quiz_op_setup(bot, qa, string); if (str) { module_t *m_ptr = NULL; mod_quiz_info.timer = quiz_timer; m_ptr = module_find_by_name("mod_quiz"); if (m_ptr) { m_ptr->timer = quiz_timer; module_update(m_ptr, "mod_quiz"); } } if (*qa) bu->data = *qa; break; } case QUIZ_OPT_ANSWER: { str = quiz_op_answer(bot, *qa, string); break; } case QUIZ_OPT_GET: { if (!arg_array[1]) return NULL; str = quiz_op_get(bot, arg_array[0], atoi(arg_array[1])); break; } case QUIZ_OPT_DEL: { break; } case QUIZ_OPT_TIMEOUT: { str = quiz_op_timeout(bot, *qa, atoi(arg_array[0])); break; } case QUIZ_OPT_SIZE: { str = quiz_op_size(bot, arg_array[0]); break; } case QUIZ_OPT_MULTI: { str = quiz_op_multi(bot, *qa, arg_array[0]); break; } case QUIZ_OPT_NEWLINES: { str = quiz_op_newlines(bot, *qa, arg_array[0]); break; } case QUIZ_OPT_HIDEKEY: { str = quiz_op_hidekey(bot, *qa, arg_array[1]); break; } default: break; } cleanup: if (dl) tokenize_destroy(bot, &dl); if (arg_array) free(arg_array); if (str) bot->shouldsend = 1; return str; }
/* Loop through all files in metalink structure and retrieve them. Returns RETROK if all files were downloaded. Returns last retrieval error (from retrieve_url) if some files could not be downloaded. */ uerr_t retrieve_from_metalink (const metalink_t* metalink) { metalink_file_t **mfile_ptr; uerr_t last_retr_err = RETROK; /* Store last encountered retrieve error. */ FILE *_output_stream = output_stream; bool _output_stream_regular = output_stream_regular; char *_output_document = opt.output_document; DEBUGP (("Retrieving from Metalink\n")); /* No files to download. */ if (!metalink->files) return RETROK; if (opt.output_document) { /* We cannot support output_document as we need to compute checksum of downloaded file, and to remove it if the checksum is bad. */ logputs (LOG_NOTQUIET, _("-O not supported for metalink download. Ignoring.\n")); } for (mfile_ptr = metalink->files; *mfile_ptr; mfile_ptr++) { metalink_file_t *mfile = *mfile_ptr; metalink_resource_t **mres_ptr; char *filename = NULL; bool hash_ok = false; uerr_t retr_err = METALINK_MISSING_RESOURCE; /* -1 -> file should be rejected 0 -> could not verify 1 -> verified successfully */ char sig_status = 0; output_stream = NULL; DEBUGP (("Processing metalink file %s...\n", quote (mfile->name))); /* Resources are sorted by priority. */ for (mres_ptr = mfile->resources; *mres_ptr; mres_ptr++) { metalink_resource_t *mres = *mres_ptr; metalink_checksum_t **mchksum_ptr, *mchksum; struct iri *iri; struct url *url; int url_err; if (!RES_TYPE_SUPPORTED (mres->type)) { logprintf (LOG_VERBOSE, _("Resource type %s not supported, ignoring...\n"), quote (mres->type)); continue; } retr_err = METALINK_RETR_ERROR; /* If output_stream is not NULL, then we have failed on previous resource and are retrying. Thus, remove the file. */ if (output_stream) { fclose (output_stream); output_stream = NULL; if (unlink (filename)) logprintf (LOG_NOTQUIET, "unlink: %s\n", strerror (errno)); xfree (filename); } /* Parse our resource URL. */ iri = iri_new (); set_uri_encoding (iri, opt.locale, true); url = url_parse (mres->url, &url_err, iri, false); if (!url) { char *error = url_error (mres->url, url_err); logprintf (LOG_NOTQUIET, "%s: %s.\n", mres->url, error); xfree (error); inform_exit_status (URLERROR); iri_free (iri); continue; } else { /* Avoid recursive Metalink from HTTP headers. */ bool _metalink_http = opt.metalink_over_http; /* Assure proper local file name regardless of the URL of particular Metalink resource. To do that we create the local file here and put it as output_stream. We restore the original configuration after we are finished with the file. */ output_stream = unique_create (mfile->name, true, &filename); output_stream_regular = true; /* Store the real file name for displaying in messages. */ opt.output_document = filename; opt.metalink_over_http = false; DEBUGP (("Storing to %s\n", filename)); retr_err = retrieve_url (url, mres->url, NULL, NULL, NULL, NULL, opt.recursive, iri, false); opt.metalink_over_http = _metalink_http; } url_free (url); iri_free (iri); if (retr_err == RETROK) { FILE *local_file; /* Check the digest. */ local_file = fopen (filename, "rb"); if (!local_file) { logprintf (LOG_NOTQUIET, _("Could not open downloaded file.\n")); continue; } for (mchksum_ptr = mfile->checksums; *mchksum_ptr; mchksum_ptr++) { char sha256[SHA256_DIGEST_SIZE]; char sha256_txt[2 * SHA256_DIGEST_SIZE + 1]; mchksum = *mchksum_ptr; /* I have seen both variants... */ if (strcasecmp (mchksum->type, "sha256") && strcasecmp (mchksum->type, "sha-256")) { DEBUGP (("Ignoring unsupported checksum type %s.\n", quote (mchksum->type))); continue; } logprintf (LOG_VERBOSE, _("Computing checksum for %s\n"), quote (mfile->name)); sha256_stream (local_file, sha256); wg_hex_to_string (sha256_txt, sha256, SHA256_DIGEST_SIZE); DEBUGP (("Declared hash: %s\n", mchksum->hash)); DEBUGP (("Computed hash: %s\n", sha256_txt)); if (!strcmp (sha256_txt, mchksum->hash)) { logputs (LOG_VERBOSE, _("Checksum matches.\n")); hash_ok = true; } else { logprintf (LOG_NOTQUIET, _("Checksum mismatch for file %s.\n"), quote (mfile->name)); hash_ok = false; } /* Stop as soon as we checked the supported checksum. */ break; } /* Iterate over available checksums. */ fclose (local_file); local_file = NULL; if (!hash_ok) continue; sig_status = 0; /* Not verified. */ #ifdef HAVE_GPGME /* Check the crypto signature. Note that the signtures from Metalink in XML will not be parsed when using libmetalink version older than 0.1.3. Metalink-over-HTTP is not affected by this problem. */ if (mfile->signature) { metalink_signature_t *msig = mfile->signature; gpgme_error_t gpgerr; gpgme_ctx_t gpgctx; gpgme_data_t gpgsigdata, gpgdata; gpgme_verify_result_t gpgres; gpgme_signature_t gpgsig; gpgme_protocol_t gpgprot = GPGME_PROTOCOL_UNKNOWN; int fd = -1; /* Initialize the library - as name suggests. */ gpgme_check_version (NULL); /* Open data file. */ fd = open (filename, O_RDONLY); if (fd == -1) { logputs (LOG_NOTQUIET, _("Could not open downloaded file for signature " "verification.\n")); goto gpg_skip_verification; } /* Assign file descriptor to GPG data structure. */ gpgerr = gpgme_data_new_from_fd (&gpgdata, fd); if (gpgerr != GPG_ERR_NO_ERROR) { logprintf (LOG_NOTQUIET, "GPGME data_new_from_fd: %s\n", gpgme_strerror (gpgerr)); goto gpg_skip_verification; } /* Prepare new GPGME context. */ gpgerr = gpgme_new (&gpgctx); if (gpgerr != GPG_ERR_NO_ERROR) { logprintf (LOG_NOTQUIET, "GPGME new: %s\n", gpgme_strerror (gpgerr)); gpgme_data_release (gpgdata); goto gpg_skip_verification; } DEBUGP (("Verifying signature %s:\n%s\n", quote (msig->mediatype), msig->signature)); /* Check signature type. */ if (!strcmp (msig->mediatype, "application/pgp-signature")) gpgprot = GPGME_PROTOCOL_OpenPGP; else /* Unsupported signature type. */ { gpgme_release (gpgctx); gpgme_data_release (gpgdata); goto gpg_skip_verification; } gpgerr = gpgme_set_protocol (gpgctx, gpgprot); if (gpgerr != GPG_ERR_NO_ERROR) { logprintf (LOG_NOTQUIET, "GPGME set_protocol: %s\n", gpgme_strerror (gpgerr)); gpgme_release (gpgctx); gpgme_data_release (gpgdata); goto gpg_skip_verification; } /* Load the signature. */ gpgerr = gpgme_data_new_from_mem (&gpgsigdata, msig->signature, strlen (msig->signature), 0); if (gpgerr != GPG_ERR_NO_ERROR) { logprintf (LOG_NOTQUIET, _("GPGME data_new_from_mem: %s\n"), gpgme_strerror (gpgerr)); gpgme_release (gpgctx); gpgme_data_release (gpgdata); goto gpg_skip_verification; } /* Verify the signature. */ gpgerr = gpgme_op_verify (gpgctx, gpgsigdata, gpgdata, NULL); if (gpgerr != GPG_ERR_NO_ERROR) { logprintf (LOG_NOTQUIET, _("GPGME op_verify: %s\n"), gpgme_strerror (gpgerr)); gpgme_data_release (gpgsigdata); gpgme_release (gpgctx); gpgme_data_release (gpgdata); goto gpg_skip_verification; } /* Check the results. */ gpgres = gpgme_op_verify_result (gpgctx); if (!gpgres) { logputs (LOG_NOTQUIET, _("GPGME op_verify_result: NULL\n")); gpgme_data_release (gpgsigdata); gpgme_release (gpgctx); gpgme_data_release (gpgdata); goto gpg_skip_verification; } /* The list is null-terminated. */ for (gpgsig = gpgres->signatures; gpgsig; gpgsig = gpgsig->next) { DEBUGP (("Checking signature %s\n", gpgsig->fpr)); if (gpgsig->summary & (GPGME_SIGSUM_VALID | GPGME_SIGSUM_GREEN)) { logputs (LOG_VERBOSE, _("Signature validation suceeded.\n")); sig_status = 1; break; } if (gpgsig->summary & GPGME_SIGSUM_RED) { logputs (LOG_NOTQUIET, _("Invalid signature. Rejecting resource.\n")); sig_status = -1; break; } if (gpgsig->summary == 0 && (gpgsig->status & 0xFFFF) == GPG_ERR_NO_ERROR) { logputs (LOG_VERBOSE, _("Data matches signature, but signature " "is not trusted.\n")); } if ((gpgsig->status & 0xFFFF) != GPG_ERR_NO_ERROR) { logprintf (LOG_NOTQUIET, "GPGME: %s\n", gpgme_strerror (gpgsig->status & 0xFFFF)); } } gpgme_data_release (gpgsigdata); gpgme_release (gpgctx); gpgme_data_release (gpgdata); gpg_skip_verification: if (fd != -1) close (fd); } /* endif (mfile->signature) */ #endif /* Stop if file was downloaded with success. */ if (sig_status >= 0) break; } /* endif RETR_OK. */ } /* Iterate over resources. */ if (retr_err != RETROK) { logprintf (LOG_VERBOSE, _("Failed to download %s. Skipping resource.\n"), quote (mfile->name)); } else if (!hash_ok) { retr_err = METALINK_CHKSUM_ERROR; logprintf (LOG_NOTQUIET, _("File %s retrieved but checksum does not match. " "\n"), quote (mfile->name)); } #ifdef HAVE_GPGME /* Signature will be only validated if hash check was successful. */ else if (sig_status < 0) { retr_err = METALINK_SIG_ERROR; logprintf (LOG_NOTQUIET, _("File %s retrieved but signature does not match. " "\n"), quote (mfile->name)); } #endif last_retr_err = retr_err == RETROK ? last_retr_err : retr_err; /* Remove the file if error encountered or if option specified. Note: the file has been downloaded using *_loop. Therefore, it is not necessary to keep the file for continuated download. */ if ((retr_err != RETROK || opt.delete_after) && filename != NULL && file_exists_p (filename)) { logprintf (LOG_VERBOSE, _("Removing %s.\n"), quote (filename)); if (unlink (filename)) logprintf (LOG_NOTQUIET, "unlink: %s\n", strerror (errno)); } if (output_stream) { fclose (output_stream); output_stream = NULL; } xfree (filename); } /* Iterate over files. */ /* Restore original values. */ opt.output_document = _output_document; output_stream_regular = _output_stream_regular; output_stream = _output_stream; return last_retr_err; }