/** * configの説明を表示する * * @param out 出力先のストリーム */ static void EnmaConfig_usage(FILE *out) { assert(NULL != out); fprintf(out, "Options[with default]:\n"); fprintf(out, " -h\t: show this message\n"); fprintf(out, " -v\t: verbose mode\n"); fprintf(out, " -c filename\t: configuration file on startup\n"); fprintf(out, "\n"); for (const ConfigEntry *p = ConfigEntry_table; NULL != p->config_name; ++p) { fprintf(out, " -o %s\t: %s [%s]\n", p->config_name, p->description, NNSTR(p->default_value)); } fflush(out); }
/** * @attention this function may rewrite yenmacfg */ bool YenmaContext_buildPolicies(YenmaContext *self, YenmaConfig *yenmacfg) { // Resolver DnsResolver_initializer *initializer = DnsResolver_lookupInitializer(yenmacfg->resolver_engine); if (NULL == initializer) { LogError("failed to load resolver module: resolver=%s", PTROR(yenmacfg->resolver_engine, "any")); return false; } // end if self->resolver_pool = ResolverPool_new(initializer, yenmacfg->resolver_conf, yenmacfg->resolver_pool_size, (int) yenmacfg->resolver_timeout, (int) yenmacfg->resolver_retry_count); if (NULL == self->resolver_pool) { LogNoResource(); return false; } // end if // DMARC setup if (yenmacfg->dmarc_verify) { // enable SPF and DKIM if (!yenmacfg->spf_verify) { yenmacfg->spf_verify = true; LogNotice("SPF verification is turned on as a part of DMARC verification"); } // end if if (!yenmacfg->dkim_verify) { yenmacfg->dkim_verify = true; LogNotice("DKIM verification is turned on as a part of DMARC verification"); } // end if // load public suffix list if (NULL == yenmacfg->dmarc_public_suffix_list) { LogError("Public Suffix List must be specified for DMARC verification"); return false; } // end if if (DSTAT_OK != PublicSuffix_build(yenmacfg->dmarc_public_suffix_list, &self->public_suffix)) { LogError("failed to load public suffix list: filename=%s", yenmacfg->dmarc_public_suffix_list); return false; } // end if // check SMTP reject actions self->dmarc_reject_action = YenmaConfig_lookupSmtpRejectActionByKeyword(yenmacfg->dmarc_reject_action); if (0 > self->dmarc_reject_action) { LogError("invalid SMTP action for DMARC reject: action=%s", yenmacfg->dmarc_reject_action); return false; } else if (SMFIS_REJECT == self->dmarc_reject_action && (notstartwith(yenmacfg->dmarc_reject_reply_code, '5') || notstartwith(yenmacfg->dmarc_reject_enhanced_status_code, '5'))) { LogError("invalid SMTP reply code or enhanced status code for DMARC reject action: reply_code=%s, ehanced_status_code=%s", NNSTR(yenmacfg->dmarc_reject_reply_code), NNSTR(yenmacfg->dmarc_reject_enhanced_status_code)); return false; } else if (SMFIS_TEMPFAIL == self->dmarc_reject_action && (notstartwith(yenmacfg->dmarc_reject_reply_code, '4') || notstartwith(yenmacfg->dmarc_reject_enhanced_status_code, '4'))) { LogError("invalid SMTP reply code or enhanced status code for DMARC tempfail action: reply_code=%s, ehanced_status_code=%s", NNSTR(yenmacfg->dmarc_reject_reply_code), NNSTR(yenmacfg->dmarc_reject_enhanced_status_code)); return false; } // end if } // end if if (yenmacfg->dkim_adsp_verify && !yenmacfg->dkim_verify) { yenmacfg->dkim_verify = true; LogNotice("DKIM verification is turned on as a part of DKIM-ADSP verification"); } // end if // building DkimVerificationPolicy if (yenmacfg->dkim_verify) { DkimStatus config_stat = YenmaConfig_buildDkimVerificationPolicy(yenmacfg, &self->dkim_vpolicy); if (DSTAT_OK != config_stat) { return false; } // end if } // end if // building SpfEvalPolicy for SPF (must be after determining authserv-id) if (yenmacfg->spf_verify) { self->spfevalpolicy = YenmaConfig_buildSpfEvalPolicy(yenmacfg); if (NULL == self->spfevalpolicy) { return false; } // end if } // end if // building SpfEvalPolicy for SIDF (must be after determining authserv-id) if (yenmacfg->sidf_verify) { self->sidfevalpolicy = YenmaConfig_buildSidfEvalPolicy(yenmacfg); if (NULL == self->sidfevalpolicy) { return false; } // end if } // end if if (NULL != yenmacfg->service_exclusion_blocks) { self->exclusion_block = YenmaConfig_buildExclusionBlock(yenmacfg->service_exclusion_blocks); if (NULL == self->exclusion_block) { return false; } // end if } // end if return true; } // end function: YenmaContext_buildPolicies
/** * @return DSTAT_OK for success, otherwise status code that indicates error. * @error DSTAT_INFO_ADSP_NOT_EXIST ADSP record have not found * @error DSTAT_PERMFAIL_MULTIPLE_ADSP_RECORD multiple ADSP records are found * @error DSTAT_TMPERR_DNS_ERROR_RESPONSE DNS lookup error (received error response) * @error DSTAT_SYSERR_DNS_LOOKUP_FAILURE DNS lookup error (failed to lookup itself) * @error DSTAT_SYSERR_IMPLERROR obvious implementation error * @error DSTAT_SYSERR_NORESOURCE memory allocation error */ static DkimAdsp * DkimAdsp_query(const DkimPolicyBase *policy, DnsResolver *resolver, const char *domain, DkimStatus *dstat) { assert(NULL != resolver); assert(NULL != domain); // lookup ADSP record DnsTxtResponse *txt_rr = NULL; dns_stat_t txtquery_stat = DnsResolver_lookupTxt(resolver, domain, &txt_rr); switch (txtquery_stat) { case DNS_STAT_NOERROR:; // a TXT RR is found /* * [RFC5617] 4.3. * If the result of this query is a NOERROR response (rcode=0 in * [RFC1035]) with an answer that is a single record that is a valid * ADSP record, use that record, and the algorithm terminates. */ if (0 == DnsTxtResponse_size(txt_rr)) { // no TXT records are found DnsTxtResponse_free(txt_rr); SETDEREF(dstat, DSTAT_INFO_ADSP_NOT_EXIST); break; } else if (1 < DnsTxtResponse_size(txt_rr)) { // multiple TXT records are found DnsTxtResponse_free(txt_rr); SETDEREF(dstat, DSTAT_PERMFAIL_MULTIPLE_ADSP_RECORD); break; } // end if // only one TXT record is found, and now, try to parse as ADSP record DkimStatus build_stat; const char *txtrecord = DnsTxtResponse_data(txt_rr, 0); DkimAdsp *self = DkimAdsp_build(policy, txtrecord, &build_stat); if (NULL != self) { // parsed as a valid ADSP record DnsTxtResponse_free(txt_rr); SETDEREF(dstat, DSTAT_OK); return self; } else if (DSTAT_ISCRITERR(build_stat)) { // propagate system errors as-is DkimLogSysError (policy, "System error has occurred while parsing ADSP record: domain=%s, err=%s, record=%s", domain, DKIM_strerror(build_stat), NNSTR(txtrecord)); SETDEREF(dstat, build_stat); } else if (DSTAT_ISPERMFAIL(build_stat)) { /* * treat syntax errors on ADSP record as DNS NODATA response * * [RFC5617] 4.1. * Records not in compliance with that syntax * or the syntax of individual tags described in Section 4.3 MUST be * ignored (considered equivalent to a NODATA result) for purposes of * ADSP, although they MAY cause the logging of warning messages via an * appropriate system logging mechanism. */ DkimLogDebug(policy, "ADSP record candidate discarded: domain=%s, err=%s, record=%s", domain, DKIM_strerror(build_stat), NNSTR(txtrecord)); SETDEREF(dstat, DSTAT_INFO_ADSP_NOT_EXIST); } else { DkimLogNotice(policy, "DkimAdsp_build failed: domain=%s, err=%s, record=%s", domain, DKIM_strerror(build_stat), NNSTR(txtrecord)); SETDEREF(dstat, DSTAT_INFO_ADSP_NOT_EXIST); } // end if // a TXT RR is not a valid ADSP record DnsTxtResponse_free(txt_rr); break; case DNS_STAT_NXDOMAIN: case DNS_STAT_NODATA: /* * no TXT (and ADSP) records are found * * [RFC5617] 4.3. * If the result of the query is NXDOMAIN or NOERROR with zero * records, there is no ADSP record. If the result of the query * contains more than one record, or a record that is not a valid * ADSP record, the ADSP result is undefined. */ DkimLogDebug(policy, "No ADSP record is found on DNS: domain=%s", domain); SETDEREF(dstat, DSTAT_INFO_ADSP_NOT_EXIST); break; case DNS_STAT_FORMERR: case DNS_STAT_SERVFAIL: case DNS_STAT_NOTIMPL: case DNS_STAT_REFUSED: case DNS_STAT_YXDOMAIN: case DNS_STAT_YXRRSET: case DNS_STAT_NXRRSET: case DNS_STAT_NOTAUTH: case DNS_STAT_NOTZONE: case DNS_STAT_RESERVED11: case DNS_STAT_RESERVED12: case DNS_STAT_RESERVED13: case DNS_STAT_RESERVED14: case DNS_STAT_RESERVED15: /* * [RFC5617] 4.3. * If a query results in a "SERVFAIL" error response (rcode=2 in * [RFC1035]), the algorithm terminates without returning a result; * possible actions include queuing the message or returning an SMTP * error indicating a temporary failure. */ DkimLogInfo(policy, "DNS error on ADSP record look-up: domain=%s, type=txt, err=%s", domain, DnsResolver_getErrorString(resolver)); SETDEREF(dstat, DSTAT_TMPERR_DNS_ERROR_RESPONSE); break; case DNS_STAT_SYSTEM: case DNS_STAT_RESOLVER: case DNS_STAT_RESOLVER_INTERNAL: DkimLogSysError(policy, "error occurred during DNS lookup: domain=%s, type=txt, err=%s", domain, DnsResolver_getErrorString(resolver)); SETDEREF(dstat, DSTAT_SYSERR_DNS_LOOKUP_FAILURE); break; case DNS_STAT_NOMEMORY: DkimLogNoResource(policy); SETDEREF(dstat, DSTAT_SYSERR_NORESOURCE); break; case DNS_STAT_BADREQUEST: default: DkimLogImplError(policy, "DnsResolver_lookupTxt returns unexpected value: value=0x%x, domain=%s, type=txt", txtquery_stat, domain); SETDEREF(dstat, DSTAT_SYSERR_IMPLERROR); break; } // end switch return NULL; } // end function: DkimAdsp_query