/* Create the pipe used to awaken and terminate the helper processes * must be called with the counter mutex */ static u_char ready_helpers(void *logp) { int fds[2]; if (helper.pipe_write >= 0 && helper.pipe_read >= 0) return 1; terminate_helpers(); /* give the helper child processes an FD that will go dead * if the parent dies or otherwise closes the other end */ dcc_clean_stdio(); if (0 > pipe(fds)) { thr_error_msg(logp, "DNSBL parent helper pipe(): %s", ERROR_STR()); terminate_helpers(); return 0; } helper.pipe_read = fds[0]; helper.pipe_write = fds[1]; if (0 > fcntl(helper.pipe_write, F_SETFD, FD_CLOEXEC)) { thr_error_msg(logp, "DNSBL helper fcntl(FD_CLOEXEC): %s", ERROR_STR()); terminate_helpers(); return 0; } return 1; }
/* open the helper socket used by helper processes to receive requests * must be called with the counter mutex */ static u_char open_helper_soc(DCC_CLNT_CTXT *ctxt, void *logp) { socklen_t soc_len; static int rcvbuf = 32*1024; static u_char rcvbuf_set; char sustr[DCC_SU2STR_SIZE]; DCC_EMSG emsg; rcvbuf_set = 0; /* We want to create a new socket with the same choice of * IPv4 or IPv6 as the DCC client context's socket. To do that, * try to ensure that the context's socket is healthy. */ dcc_ctxts_lock(); if (!dcc_clnt_rdy(emsg, ctxt, DCC_CLNT_FG_BAD_SRVR_OK | DCC_CLNT_FG_NO_MEASURE_RTTS | DCC_CLNT_FG_NO_FAIL) || !dcc_info_unlock(emsg)) thr_trace_msg(logp, "DNSBL helper: %s", emsg); dcc_ctxts_unlock(); dcc_mk_loop_su(&helper.su, ctxt->soc[0].loc.sa.sa_family, 0); dcc_clean_stdio(); if (!udp_create(emsg, &helper.soc, &helper.su, 0)) { thr_error_msg(logp, "DNSBL helper bind(%s): %s", dcc_su2str(sustr, sizeof(sustr), &helper.su), emsg); terminate_helpers(); return 0; } soc_len = sizeof(helper.su); if (0 > getsockname(helper.soc, &helper.su.sa, &soc_len)) { thr_error_msg(logp, "DNSBL helper getsockname(%d, %s): %s", helper.soc, dcc_su2str(sustr, sizeof(sustr), &helper.su), ERROR_STR()); terminate_helpers(); return 0; } for (;;) { if (!setsockopt(helper.soc, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(rcvbuf))) break; if (rcvbuf_set || rcvbuf <= 4096) { thr_error_msg(logp, "DNSBL setsockopt(%s,SO_RCVBUF=%d): %s", dcc_su2str(sustr, sizeof(sustr), &helper.su), rcvbuf, ERROR_STR()); break; } rcvbuf -= 4096; } rcvbuf_set = 1; return 1; }
static void init_ge2d() { ge2d_fd = open("/dev/ge2d", O_RDWR); if (ge2d_fd < 0) { ERROR_STR("Can't open /dev/ge2d\n"); } memclient_fd = open("/dev/memclient", O_RDWR); if (memclient_fd < 0) { ERROR_STR("Can't open /dev/memclient\n"); } }
/* this is needed only on systems without coherent mmap()/read()/write() */ static void sync_white(WF *wf) { if (wf->wtbl && 0 > MSYNC(wf->wtbl, wf->wtbl_size, MS_SYNC)) dcc_error_msg("msync(%s): %s", wf->ht_nm, ERROR_STR()); }
static u_char close_white_ht(DCC_EMSG emsg, WF *wf) { u_char result = 1; if (wf->ht_fd < 0) return result; wf->closed = 1; unmap_white_ht(wf); #ifdef DCC_WIN32 /* unlock the file before closing it to keep Win95 happy */ if (!dcc_unlock_fd(emsg, wf->ht_fd, DCC_LOCK_ALL_FILE, "whitelist ", wf->ht_nm)) result = 0; #endif if (0 > close(wf->ht_fd)) { dcc_pemsg(EX_IOERR, emsg, "close(%s): %s", wf->ht_nm, ERROR_STR()); result = 0; } wf->ht_fd = -1; memset(&wf->ht_sb, 0, sizeof(wf->ht_sb)); #ifndef DCC_WIN32 wf->ht_sb.st_dev = -1; wf->ht_sb.st_ino = -1; #endif return result; }
int read_db(DCC_EMSG emsg, void *buf, u_int buf_len, int fd, off_t pos, const char *file_nm) { int i; if (-1 == lseek(fd, pos, SEEK_SET)) { dcc_pemsg(EX_IOERR, emsg, "lseek(%s, 0): %s", DB_NM2PATH_ERR(file_nm), ERROR_STR()); return -1; } i = read(fd, buf, buf_len); if (i >= 0) return i; dcc_pemsg(EX_IOERR, emsg, "read(%s): %s", DB_NM2PATH_ERR(file_nm), ERROR_STR()); return -1; }
static void unmap_white_ht(WF *wf) { if (!wf->wtbl) return; sync_white(wf); #ifdef DCC_WIN32 dcc_win32_unmap(&wf->ht_map, wf->wtbl, wf->ht_nm); #else if (0 > munmap((void *)wf->wtbl, wf->wtbl_size)) dcc_error_msg("munmap(%s,%d): %s", wf->ht_nm, wf->wtbl_size, ERROR_STR()); #endif wf->wtbl = 0; }
int /* 0=ok -1=failed */ unlink_white_ht(DCC_EMSG emsg, WF *wf, time_t now) /* 0=our own new file */ { int result; /* mark it bad if it is a brand new hash table */ if (!now && wf->wtbl && !(wf->wf_flags & WF_RO)) wf->wtbl->hdr.ascii_mtime = 0; #ifdef DCC_WIN32 /* racy but you cannot unlink an open file on WIN32 */ close_white_ht(0, wf); #endif result = -1; if (!(wf->wf_flags & WF_RO)) { if (0 <= unlink(wf->ht_nm) || errno == ENOENT) { result = 0; #ifndef DCC_WIN32 } else if ((errno == EACCES || errno == EPERM) && dcc_get_priv_home(wf->ht_nm)) { if (0 <= unlink(wf->ht_nm)) result = 0; dcc_rel_priv(); #endif } if (result < 0) dcc_pemsg(EX_IOERR, emsg,"unlink(%s): %s", wf->ht_nm, ERROR_STR()); } /* If we failed to unlink the old hash table, * remember in core that things are broken but do not touch the file * in case it is a link to /etc/passwd or something else dangerous */ if (result < 0 && now) wf->broken = now + WHITE_BROKEN_DELAY; #ifndef DCC_WIN32 close_white_ht(0, wf); #endif return result; }
static u_char /* 1=done, 0=failed */ map_white_ht(DCC_EMSG emsg, WF *wf, WHITE_INX entries) { size_t size; #ifndef DCC_WIN32 void *p; #endif unmap_white_ht(wf); if (entries > MAX_WHITE_ENTRIES) { dcc_pemsg(EX_IOERR, emsg, "%s should not contain %d entries", wf->ht_nm, entries); return 0; } size = ENTRIES2SIZE(entries); #ifdef DCC_WIN32 if (!wf->wtbl) { wf->wtbl = dcc_win32_map(emsg, &wf->ht_map, wf->ht_nm, wf->ht_fd, size); if (!wf->wtbl) return 0; } #else p = mmap(0, size, (wf->wf_flags & WF_RO) ? PROT_READ : (PROT_READ|PROT_WRITE), MAP_SHARED, wf->ht_fd, 0); if (p == MAP_FAILED) { dcc_pemsg(EX_IOERR, emsg, "mmap(%s,%d): %s", wf->ht_nm, (int)size, ERROR_STR()); return 0; } wf->wtbl = p; #endif wf->wtbl_size = size; wf->wtbl_entries = entries; wf->wtbl_fgs = wf->wtbl->hdr.fgs; wf->wtbl_sws = wf->wtbl->hdr.sws; return 1; }
int main(int argc, char **argv) { const char *to = 0; u_char print_version = 0; u_char first; DCC_PATH tmp; WHITE_INX inx, inx2; const char *nm; DCC_SUM sum; struct stat ht_sb, ascii_sb, inc_sb; char tgts_buf[20]; char range_buf[INET6_ADDRSTRLEN+1+INET6_ADDRSTRLEN+1]; int col; u_char heading; DCC_TGTS tgts; WHITE_LISTING listing; DCC_CK_TYPES type; int i; dcc_syslog_init(0, argv[0], 0); dcc_clnt_debug = 99; wf_init(&cmn_wf, WF_WLIST | WF_EITHER); while ((i = getopt(argc, argv, "VPQqh:t:")) != EOF) { switch (i) { case 'V': dcc_version_print(); print_version = 1; break; case 'P': /* parse or rebuild hash table */ cmn_wf.wf_flags &= ~WF_WLIST_RO; cmn_wf.wf_flags |= WF_WLIST_RW; break; case 'Q': /* query; don't rebuild hash table */ cmn_wf.wf_flags &= ~WF_WLIST_RW; cmn_wf.wf_flags |= WF_WLIST_RO; break; case 'q': quiet = 1; break; case 'h': homedir = optarg; break; case 't': to = optarg; break; default: usage(); } } argc -= optind; argv += optind; if (argc == 0) { if (print_version) exit(EX_OK); usage(); } if (!dcc_cdhome(0, homedir, 1) && homedir) dcc_cdhome(0, homedir = 0, 1); first = 1; while ((nm = *argv++) != 0) { if (first) { first = 0; } else { printf("\n\n--------------------------------\n"); } if (cmn_wf.wf_flags & WF_WLIST_RO) cmn_wf.wf_flags |= WF_RO; else cmn_wf.wf_flags &= ~WF_RO; if (!dcc_new_white_nm(dcc_emsg, &cmn_wf, nm)) { dcc_error_msg("%s", dcc_emsg); exit(EX_DATAERR); } printf("%s\n", dcc_fnm2abs_msg(tmp, cmn_wf.ascii_nm)); /* try to force re-parsing */ if (cmn_wf.wf_flags & WF_WLIST_RW) { if (!new_ht_nm(dcc_emsg, &cmn_wf, 0) || 0 > unlink_white_ht(dcc_emsg, &cmn_wf, time(0))) { dcc_error_msg("-P failed to force re-parsing;" " %s", dcc_emsg); exit(EX_DATAERR); } if (!dcc_new_white_nm(dcc_emsg, &cmn_wf, nm)) { dcc_error_msg("%s", dcc_emsg); exit(EX_DATAERR); } } switch (wf_rdy(dcc_emsg, &cmn_wf, &cmn_tmp_wf)) { case WHITE_OK: break; case WHITE_NOFILE: dcc_error_msg("does %s exist?", nm); exit(EX_DATAERR); break; case WHITE_CONTINUE: dcc_error_msg("%s", dcc_emsg); break; case WHITE_SILENT: case WHITE_COMPLAIN: dcc_error_msg("%s", dcc_emsg); exit(EX_DATAERR); break; } printf("%s\n", cmn_wf.wtbl->magic); if (to) { str2ck(&sum, 0, 0, to); printf("%s\n%8s %s\t", to, type2str_err(DCC_CK_ENV_TO, 0, 0, 0), ck2str_err(DCC_CK_ENV_TO, &sum, 0)); if (WHITE_OK != wf_sum(dcc_emsg, &cmn_wf, DCC_CK_ENV_TO, &sum, &tgts, &listing)) { dcc_error_msg("%s", dcc_emsg); } if (listing == WHITE_UNLISTED) { printf("unlisted\n"); } else { printf("%s\n", tgts2str(tgts_buf, sizeof(tgts_buf), tgts, 0)); } continue; } printf(" %s whitelist %d entries\n", (cmn_wf.wtbl_fgs & WHITE_FG_PER_USER) ? "per-user" : "global", cmn_wf.wtbl->hdr.entries); if (0 > fstat(cmn_wf.ht_fd, &ht_sb)) { dcc_error_msg("stat(%s): %s", cmn_wf.ht_nm, ERROR_STR()); exit(EX_DATAERR); } if (0 > stat(cmn_wf.ascii_nm, &ascii_sb)) { dcc_error_msg("stat(%s): %s", cmn_wf.ascii_nm, ERROR_STR()); } else if (ht_sb.st_mtime < ascii_sb.st_mtime) { printf(" %s is older than %s\n", cmn_wf.ht_nm, cmn_wf.ascii_nm); } if (cmn_wf.wtbl->hdr.ascii_mtime == 0) { printf(" %s broken\n", cmn_wf.ht_nm); } else if (cmn_wf.wtbl->hdr.ascii_mtime != ascii_sb.st_mtime) { printf(" %s has timestamp %s\n" "\tfor %s which has mtime %s\n", cmn_wf.ht_nm, ts2buf(cmn_wf.wtbl->hdr.ascii_mtime), cmn_wf.ascii_nm, ts2buf(ascii_sb.st_mtime)); } if (cmn_wf.wtbl->hdr.broken != 0) printf(" %s broken until %s\n", cmn_wf.ht_nm, ts2buf(cmn_wf.wtbl->hdr.broken)); if (cmn_wf.wtbl->hdr.reparse != 0) printf(" re-parse %s for errors after %s\n", cmn_wf.ascii_nm, ts2buf(cmn_wf.wtbl->hdr.reparse)); if (cmn_wf.wtbl->hdr.fgs & WHITE_FG_HOSTNAMES) { printf(" resolve host names after %s\n", ts2buf(ht_sb.st_mtime + DCC_WHITECLNT_RESOLVE)); } else if (!(cmn_wf.wtbl->hdr.fgs & WHITE_FG_PER_USER)) { printf(" contains no host names\n"); } for (i = 0; i < DIM(cmn_wf.wtbl->hdr.white_incs); ++i) { if (cmn_wf.wtbl->hdr.white_incs[i].nm[0] == '\0') break; if (!i) printf(" includes\n"); printf(" %s\n", dcc_fnm2abs_msg(tmp, cmn_wf.wtbl ->hdr.white_incs[ i].nm)); if (0 > stat(cmn_wf.wtbl->hdr.white_incs[i].nm, &inc_sb)) { dcc_error_msg("stat(%s): %s", cmn_wf.ascii_nm, ERROR_STR()); } else if (ht_sb.st_mtime < inc_sb.st_mtime) { printf(" %s is older than %s" " and needs rebuilding\n", cmn_wf.ht_nm, dcc_path2fnm(cmn_wf.wtbl->hdr.white_incs[i ].nm)); } } if (cmn_wf.wtbl_sws & WHITE_SW_DCC_ON) printf(" option DCC-on\n"); if (cmn_wf.wtbl_sws & WHITE_SW_DCC_OFF) printf(" option DCC-off\n"); if (cmn_wf.wtbl_sws & WHITE_SW_REP_ON) printf(" option dcc-rep-on\n"); if (cmn_wf.wtbl_sws & WHITE_SW_REP_OFF) printf(" option dcc-rep-off\n"); if (cmn_wf.wtbl_sws & WHITE_SW_GREY_ON) printf(" option greylist-on\n"); if (cmn_wf.wtbl_sws & WHITE_SW_GREY_OFF) printf(" option greylist-off\n"); if (cmn_wf.wtbl_sws & WHITE_SW_GREY_SPAM_ON) printf(" option greylist-ignore-spam-on\n"); if (cmn_wf.wtbl_sws & WHITE_SW_GREY_SPAM_OFF) printf(" option greylist-ignore-spam-off\n"); if (cmn_wf.wtbl_sws & WHITE_SW_LOG_ALL) printf(" option log-all\n"); if (cmn_wf.wtbl_sws & WHITE_SW_LOG_NORMAL) printf(" option log-normal\n"); if (cmn_wf.wtbl_sws & WHITE_SW_LOG_D) printf(" option log-subdirectory-day\n"); if (cmn_wf.wtbl_sws & WHITE_SW_LOG_H) printf(" option log-subdirectory-hour\n"); if (cmn_wf.wtbl_sws & WHITE_SW_LOG_M) printf(" option log-subdirectory-minute\n"); if (cmn_wf.wtbl_sws & WHITE_SW_GREY_LOG_ON) printf(" option greylist-log-on\n"); if (cmn_wf.wtbl_sws & WHITE_SW_GREY_LOG_OFF) printf(" option greylist-log-off\n"); if (cmn_wf.wtbl_sws & WHITE_SW_MTA_FIRST) printf(" option MTA-first\n"); if (cmn_wf.wtbl_sws & WHITE_SW_MTA_LAST) printf(" option MTA-last\n"); for (i = 0; i < NUM_DNSBL_GROUPS; ++i) { if (cmn_wf.wtbl_sws & WHITE_SW_DNSBL_ON(i)) printf(" option DNSBL%d-on\n", i+1); if (cmn_wf.wtbl_sws & WHITE_SW_DNSBL_OFF(i)) printf(" option DNSBL%d-off\n", i+1); } if (cmn_wf.wtbl_sws & WHITE_SW_DISCARD_OK) printf(" option forced-discard-ok\n"); if (cmn_wf.wtbl_sws & WHITE_SW_DISCARD_NO) printf(" option no-forced-discard\n"); if (cmn_wf.wtbl_sws & WHITE_SW_TRAP_NOT) printf(" option "DCC_XHDR_TRAP_NOT"\n"); if (cmn_wf.wtbl_sws & WHITE_SW_TRAP_DIS) printf(" option "DCC_XHDR_TRAP_DIS"\n"); if (cmn_wf.wtbl_sws & WHITE_SW_TRAP_REJ) printf(" option "DCC_XHDR_TRAP_REJ"\n"); for (type = DCC_CK_TYPE_FIRST; type <= DCC_CK_TYPE_LAST; ++type) { tgts = cmn_wf.wtbl->hdr.tholds_rej.t[type]; if (tgts == THOLD_UNSET) continue; printf(" option threshold %s,%s\n", type2str_err(type, 0, 0, 0), thold2str(tgts_buf, sizeof(tgts_buf), type, tgts)); } printf("\n file checksum %s\n", ck2str_err(0, &cmn_wf.wtbl->hdr.ck_sum, 0)); if (quiet) continue; /* display ranges of IP addresses */ heading = 0; for (i = 0; i < cmn_wf.wtbl->hdr.ranges.len; ++i) { WHITE_IP_RANGE *r; if (!heading) { heading = 1; fputs("\n IP address blocks\n", stdout); } r = &cmn_wf.wtbl->hdr.ranges.rs[i]; printf("%6s %s\n", tgts2str(tgts_buf, sizeof(tgts_buf), r->tgts, 0), range2str(range_buf, sizeof(range_buf), &r->range)); } if (heading) putchar('\n'); /* first the hash table */ fputs("\n hash table\n", stdout); col = 0; for (inx = 0; inx < DIM(cmn_wf.wtbl->bins); ++inx) { if (!cmn_wf.wtbl->bins[inx] && col == 0 && inx != 0) { inx2 = inx; while (inx2 < DIM(cmn_wf.wtbl->bins) && !cmn_wf.wtbl->bins[inx2]) ++inx2; i = inx2 - inx; i -= i % 4; if (i != 0) { printf(" ...\n"); inx += i; } } printf("%4d:", inx); if (cmn_wf.wtbl->bins[inx]) { printf("%-4d", cmn_wf.wtbl->bins[inx]); } else { printf(" "); } col = (col + 1) % 4; putchar(col == 0 ? '\n' : '\t'); } /* then the entries */ printf("\n\n%4s->%-4s %12s %6s\n", "slot", "next", "type", "count"); for (inx = 0; inx < cmn_wf.wtbl_entries; ++inx) { WHITE_ENTRY *e = &cmn_wf.wtbl->tbl[inx]; if (e->type == DCC_CK_INVALID) continue; printf("%4d->%-4d %12s %6s %s\n", inx, e->fwd, type2str_err(e->type, 0, 0, 0), tgts2str(tgts_buf, sizeof(tgts_buf), e->tgts, 0), ck2str_err(e->type, &e->sum, 0)); } } exit(EX_OK); }
/* (re)load the client-ID and password database * -1=failed to find target, 0=sick file, 1=ok, 2=file unchanged */ int load_ids(DCC_EMSG emsg, DCC_CLNT_ID tgt_id, /* DCC_ID_ANON or needed ID */ const ID_TBL **tgt_tbl, u_char force, u_char debug) { DCC_PATH tmp; DCC_FNM_LNO_BUF fnm_buf; ID_TBL t, *tp, **tpp, **bin; FILE *f; int lno, passwords; u_char found_it; int result; char buf[sizeof(ID_TBL)*2+1]; const char *bufp, *passbuf; char id_buf[30]; struct stat sb; char *p, *p1; if (!id_tbl_blocks) { id_make_blocks(debug); id_tbl_expand_hash(debug); } if (tgt_tbl) *tgt_tbl = 0; if (!set_ids_path(emsg, 0)) return -1; if (!force) { if (!dcc_ck_private(emsg, &sb, ids_path, -1)) { ids_mtime = 0; return -1; } if (ids_mtime == sb.st_mtime) return 2; } f = fopen(ids_path, "r"); if (!f) { dcc_pemsg(EX_NOINPUT, emsg, "fopen(%s): %s", dcc_fnm2abs_msg(tmp, ids_path), ERROR_STR()); return -1; } /* the file contains passwords, so refuse to use it if anyone else * can read it */ if (!dcc_ck_private(emsg, &sb, ids_path, fileno(f))) { fclose(f); ids_mtime = 0; return -1; } /* empty the table by making all entries into placeholders */ memset(&t, 0, sizeof(t)); for (tpp = &id_tbl_hash[0]; tpp < &id_tbl_hash[id_tbl_bins]; ++tpp) { for (tp = *tpp; tp; tp = tp->hfwd) { t.hfwd = tp->hfwd; t.hbak = tp->hbak; t.id = tp->id; *tp = t; } } ids_mtime = sb.st_mtime; passwords = 0; lno = 0; result = 1; found_it = (tgt_id == DCC_ID_ANON); for (;;) { /* read and parse a line contain a client-ID and key(s) */ bufp = fgets(buf, sizeof(buf), f); if (!bufp) { if (ferror(f) && result > 0) { dcc_pemsg(EX_IOERR, emsg, "fgets(%s): %s", dcc_fnm2abs_msg(tmp, ids_path), ERROR_STR()); result = 0; } break; } ++lno; /* Ignore blank lines and lines starting with '#'. * Note that '#' flags a comment only at the start of * the line to avoid dealing with the escaping hassles * of allowing '#' in passwords. */ bufp += strspn(bufp, DCC_WHITESPACE); if (*bufp == '\0' || *bufp == '#') continue; memset(&t, 0, sizeof(t)); t.delay_inflate = DCC_ANON_INFLATE_OFF; /* Each substantive line has the form: * ID[,trace][,rpt-ok][,delay=ms[*inflate]] passwd1 passwd2 * ID,delay=forever * * Placeholders have the from * ID * or for servers on masters * ID,simple|ignore|rogue|commerical * * Both passwords are always accepted. They are intended * to be the previous and current or the current and * next to allow the password to be changed at both the * client and the server without loss of service. */ passbuf = dcc_parse_word(emsg, id_buf, sizeof(id_buf), bufp, "ID", ids_path, lno); if (!passbuf) { result = 0; /* line too long */ continue; } /* stop parsing the line if the server-ID is bad */ p = strchr(id_buf, ','); if (p) *p++ = '\0'; t.id = dcc_get_id(emsg, id_buf, ids_path, lno); if (t.id == DCC_ID_INVALID) { result = 0; continue; } if (t.id == DCC_ID_ANON) { dcc_pemsg(EX_DATAERR, emsg, "invalid ID \"%s\"%s", id_buf, dcc_fnm_lno(&fnm_buf, ids_path, lno)); result = 0; continue; } /* parse the options */ for (; p; p = p1) { p1 = strchr(p, ','); if (p1) *p1++ = '\0'; if (!strcasecmp(p, "trace")) { if (!client_server(emsg, 0, t.id, p, lno)) { result = 0; } else { t.flags |= ID_FLG_TRACE; } continue; } if (!strcasecmp(p, "rpt-ok") || !strcasecmp(p, "rpt_ok")) { if (!client_server(emsg, 0, t.id, p, lno)) { result = 0; } else { t.flags |= ID_FLG_RPT_OK; } continue; } if (!CLITCMP(p, "delay=")) { if (!client_server(emsg, 0, t.id, p, lno)) { result = 0; } else if (!parse_dccd_delay(emsg, &t.delay_us, &t.delay_inflate, p+LITZ("delay="), ids_path, lno)) { result = 0; } else { t.flags |= ID_FLG_DELAY_SET; } continue; } if (!strcasecmp(p, DCC_XHDR_ID_SIMPLE)) { if (!client_server(emsg, 1, t.id, p, lno)) { result = 0; } else { } continue; } if (!strcasecmp(p, DCC_XHDR_ID_IGNORE)) { if (!client_server(emsg, 1, t.id, p, lno)) { result = 0; } continue; } if (!strcasecmp(p, DCC_XHDR_ID_ROGUE)) { if (!client_server(emsg, 1, t.id, p, lno)) { result = 0; } continue; } if (!strcasecmp(p, DCC_XHDR_ID_REP_OK)) { if (!client_server(emsg, 1, t.id, p, lno)) { result = 0; } continue; } dcc_pemsg(EX_DATAERR, emsg, "invalid option \"%s\"%s", p, dcc_fnm_lno(&fnm_buf, ids_path, lno)); result = 0; } if (*passbuf != '\0') { passbuf = parse_passwd(emsg, t.cur_passwd, passbuf, "current password", ids_path, lno); if (!passbuf) { result = 0; /* line too long */ continue; } passbuf = parse_passwd(emsg, t.next_passwd, passbuf, "next password", ids_path, lno); if (!passbuf) { result = 0; /* line too long */ continue; } if (*passbuf != '\0') { dcc_pemsg(EX_DATAERR, emsg, "invalid next password%s", dcc_fnm_lno(&fnm_buf, ids_path, lno)); result = 0; continue; } } /* put the entry into the hash table if not already present */ bin = &ID_HASH_ENTRY(t.id); tp = *bin; for (;;) { if (tp == 0) { tp = add_id_tbl(t.id, &bin, debug); break; } else if (tp->id == t.id) { break; } tp = tp->hfwd; } /* If the ID is already present, the file is bad unless * the previous or current line is only a placeholder * showing that the ID exists. * Merge from the old entry to the new entry. */ if (!(t.flags & ID_FLG_DELAY_SET)) { t.delay_us = tp->delay_us; t.delay_inflate = tp->delay_inflate; if (tp->flags & ID_FLG_DELAY_SET) t.flags |= ID_FLG_DELAY_SET; } else if ((tp->flags & ID_FLG_DELAY_SET) && (t.delay_us != tp->delay_us || t.delay_inflate != tp->delay_inflate)) { dcc_pemsg(EX_DATAERR, emsg, "conflicting delays for ID %d%s", t.id, dcc_fnm_lno(&fnm_buf, ids_path, lno)); result = 0; continue; } if (t.cur_passwd[0] == '\0') { memcpy(t.cur_passwd, tp->cur_passwd, sizeof(t.cur_passwd)); memcpy(t.next_passwd, tp->next_passwd, sizeof(t.next_passwd)); } else { if (tp->cur_passwd[0] != '\0' && (memcmp(t.cur_passwd, tp->cur_passwd, sizeof(t.cur_passwd)) || memcmp(t.next_passwd, tp->next_passwd, sizeof(t.next_passwd)))) { dcc_pemsg(EX_DATAERR, emsg, "conflicting passwords for ID %d%s", t.id, dcc_fnm_lno(&fnm_buf, ids_path, lno)); result = 0; continue; } ++passwords; /* remember the target */ if (t.id == tgt_id) { found_it = 1; if (tgt_tbl) *tgt_tbl = tp; } } t.flags |= (tp->flags & (ID_FLG_TRACE | ID_FLG_RPT_OK)); t.hfwd = tp->hfwd; t.hbak = tp->hbak; *tp = t; } fclose(f); if (!passwords) { if (result > 0) dcc_pemsg(EX_DATAERR, emsg, "%s contains no passwords", dcc_fnm2abs_msg(tmp, ids_path)); result = -1; } if (!found_it) { if (result > 0) dcc_pemsg(EX_DATAERR, emsg, "%s does not contain the password for ID %d", dcc_fnm2abs_msg(tmp, ids_path), tgt_id); result = -1; } id_probes = 0; id_searches = 0; return result; }
static void maliCopy(PixmapPtr pDstPixmap, int srcX, int srcY, int dstX, int dstY, int width, int height) { PrivPixmap *srcPrivPixmap = (PrivPixmap *)exaGetPixmapDriverPrivate(SrcPixmap); PrivPixmap *dstPrivPixmap = (PrivPixmap *)exaGetPixmapDriverPrivate(pDstPixmap); IGNORE(pDstPixmap); IGNORE(srcX); IGNORE(srcY); IGNORE(dstX); IGNORE(dstY); IGNORE(width); IGNORE(height); //ERROR_STR("%s: pDstPixmap=%p srcX=%d srcY=%d dstX=%d dstY=%d width=%d height=%d\n", // __FUNCTION__, pDstPixmap, srcX, srcY, dstX, dstY, width, height); ScreenPtr pScreen = SrcPixmap->drawable.pScreen; ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; MaliPtr fPtr = MALIPTR(pScrn); struct fb_var_screeninfo var_info; int ret = ioctl(fPtr->fb_lcd_fd, FBIOGET_VSCREENINFO, &var_info); if (ret < 0) { ERROR_STR("FBIOGET_VSCREENINFO failed.\n"); } unsigned char revX = 0; unsigned char revY = 0; if (dstY > srcY) { revY = 1; } if (dstX > srcX) { revX = 1; } //if (srcPrivPixmap->frameBufferNumber != 0) //{ // srcY += (var_info.yres * srcPrivPixmap->frameBufferNumber); //} //if (dstPrivPixmap->frameBufferNumber != 0) //{ // dstY += (var_info.yres * dstPrivPixmap->frameBufferNumber); //} ump_secure_id srcID = ump_secure_id_get(srcPrivPixmap->mem_info->handle); memclient_attach_dmabuf_param_t srcParam; srcParam.handle = srcID; ret = ioctl(memclient_fd, MEMCLIENT_ATTACH_UMP, &srcParam); if (ret < 0) { ERROR_STR("srcParam MEMCLIENT_ATTACH_UMP failed.\n"); } ump_secure_id dstID = ump_secure_id_get(dstPrivPixmap->mem_info->handle); memclient_attach_dmabuf_param_t dstParam; dstParam.handle = dstID; ret = ioctl(memclient_fd, MEMCLIENT_ATTACH_UMP, &dstParam); if (ret < 0) { ERROR_STR("dstParam MEMCLIENT_ATTACH_UMP failed.\n"); } // Configure GE2D struct config_para_ex_s configex; memset(&configex, 0x00, sizeof(configex)); configex.src_para.mem_type = CANVAS_ALLOC; //CANVAS_OSD0 configex.src_para.left = 0; configex.src_para.top = 0; configex.src_para.width = var_info.xres; configex.src_para.height = var_info.yres; configex.src_para.x_rev = revX; configex.src_para.y_rev = revY; configex.src_planes[0].addr = srcParam.physical_address; configex.src_planes[0].w = configex.src_para.width; configex.src_planes[0].h = configex.src_para.height; configex.src_para.format = GE2D_FORMAT_S32_ARGB; // GE2D_FORMAT_S32_BGRA; // GE2D_FMT_S32_RGBA; configex.src2_para.mem_type = CANVAS_TYPE_INVALID; configex.dst_para.mem_type = CANVAS_ALLOC; // CANVAS_OSD0; configex.dst_para.left = 0; configex.dst_para.top = 0; configex.dst_para.width = configex.src_para.width; configex.dst_para.height = configex.src_para.height; configex.dst_para.x_rev = configex.src_para.x_rev; configex.dst_para.y_rev = configex.src_para.y_rev; configex.dst_planes[0].addr = dstParam.physical_address; configex.dst_planes[0].w = configex.dst_para.width; configex.dst_planes[0].h = configex.dst_para.height; configex.dst_para.format = GE2D_FORMAT_S32_ARGB; ret = ioctl(ge2d_fd, GE2D_CONFIG_EX, &configex); if (ret < 0) { ERROR_STR("GE2D_CONFIG_EX failed.\n"); } // Perform the blit operation struct ge2d_para_s blitRect; memset(&blitRect, 0, sizeof(blitRect)); blitRect.src1_rect.x = srcX; blitRect.src1_rect.y = srcY; blitRect.src1_rect.w = width; blitRect.src1_rect.h = height; blitRect.dst_rect.x = dstX; blitRect.dst_rect.y = dstY; if (revY) // && height > 1 { blitRect.src1_rect.y -= 1; } ret = ioctl(ge2d_fd, GE2D_BLIT, &blitRect); if (ret < 0) { ERROR_STR("GE2D_BLIT failed.\n"); } ret = ioctl(memclient_fd, MEMCLIENT_RELEASE_UMP, dstID); if (ret < 0) { ERROR_STR("dstID MEMCLIENT_RELEASE_UMP failed.\n"); } ret = ioctl(memclient_fd, MEMCLIENT_RELEASE_UMP, srcID); if (ret < 0) { ERROR_STR("srcID MEMCLIENT_RELEASE_UMP failed.\n"); } }
/* ask a helper process to do some filtering */ u_char /* 1=got an answer */ ask_helper(DCC_CLNT_CTXT *ctxt, void *logp, time_t avail_us, /* spend at most this much time */ HELPER_REQ_HDR *req, /* request sent to helper */ int req_len, HELPER_RESP_HDR *resp, /* put answer here */ int resp_len) { DCC_EMSG emsg; DCC_SOCKU send_su; socklen_t su_len; DCC_SOCKU recv_su; char sustr[DCC_SU2STR_SIZE]; char sustr2[DCC_SU2STR_SIZE]; u_char counted; u_int gen; struct timeval now; time_t us; DCC_POLLFD pollfd; int i; emsg[0] = '\0'; /* We will use the client context socket to talk to the helper, * so ensure that it is open */ if (!helper_soc_open(emsg, ctxt)) { thr_trace_msg(logp, "DNSBL reopen %s", emsg); return 0; } /* keep the lock until we have sent our request and wake-up call * to ensure that some other thread does not shut down all of * the helpers. */ helper_lock(); gettimeofday(&now, 0); /* If it has been a long time since we used a helper, then the last * of them might be about to die of boredom. Fix that race by * restarting all of them. * Most dying helpers should be reaped by the totals timer thread. */ if (helper.idle_helpers > 0 && DCC_IS_TIME(now.tv_sec, helper.idle_restart, HELPER_IDLE_RESTART)) { reap_helpers(1); if (helper.idle_helpers > 0) terminate_helpers(); gettimeofday(&now, 0); } /* Restart all helpers if the current helper socket is the wrong * family. This should happen only when the DCC client library * has chosen a new server */ if (helper.soc != INVALID_SOCKET && ctxt->soc[0].loc.sa.sa_family != AF_UNSPEC && helper.su.sa.sa_family != ctxt->soc[0].loc.sa.sa_family) { terminate_helpers(); gettimeofday(&now, 0); } helper.idle_restart = now.tv_sec + HELPER_IDLE_RESTART; if (helper.idle_helpers - helper.slow_helpers > 0) { /* avoid taking the last idle helper because there are * usually fewer truly idle helpers than we think because * we don't always wait for them to finish */ if (helper.idle_helpers > 2 || helper.total_helpers >= helper.max_helpers || !new_helper(ctxt, logp, req->id)) --helper.idle_helpers; counted = 1; } else if (helper.total_helpers >= helper.max_helpers) { if (helper.debug > 0) thr_trace_msg(logp, "%s DNSBL %d idle, %d slow, and" " %d total DNSBL helpers", req->id, helper.idle_helpers, helper.slow_helpers, helper.total_helpers); counted = 0; } else { if (!new_helper(ctxt, logp, req->id)) { helper_unlock(); return 0; } counted = 1; } /* The resolution of the BIND timeout limits is seconds, so even on * systems where the timeout limits work, the helper might delay * a second or two. To keep the count of idle helpers as accurate * as possible, always wait at least 1 second for an answer * and 2 seconds for an answer to reach the parent. */ req->avail_us = avail_us; avail_us += DCC_US; req->start = now; req->magic = HELPER_MAGIC_REQ; req->version = HELPER_VERSION; req->sn = ++helper.sn; gen = helper.gen; /* snapshot the address in case another thread restarts the helpers */ send_su = helper.su; /* If the client context socket is connected but not to the helper * socket, * then either disconnect it or connect to the helper's socket */ if (ctxt->soc[0].rem.sa.sa_family != AF_UNSPEC && !DCC_SU_EQ(&ctxt->soc[0].rem, &send_su) && !helper_soc_connect(emsg, ctxt, &send_su)) { thr_trace_msg(logp, "DNSBL soc_connect(): %s", emsg); help_finish(gen, 0, counted, 1); helper_unlock(); return 0; } if (ctxt->soc[0].rem.sa.sa_family == AF_UNSPEC) { i = sendto(ctxt->soc[0].s, req, req_len, 0, &send_su.sa, DCC_SU_LEN(&send_su)); } else { i = send(ctxt->soc[0].s, req, req_len, 0); } if (i != req_len) { if (i < 0) thr_trace_msg(logp, "%s DNSBL sendto(%s): %s", req->id, dcc_su2str(sustr, sizeof(sustr), &send_su), ERROR_STR()); else thr_trace_msg(logp, "%s DNSBL sendto(%s)=%d", req->id, dcc_su2str(sustr, sizeof(sustr), &send_su), i); help_finish(gen, 0, counted, 1); helper_unlock(); return 0; } /* awaken a helper */ i = write(helper.pipe_write, "x", 1); if (i != 1) { if (i < 0) thr_trace_msg(logp, "%s DNSBL write(pipe_write=%d): %s", req->id, helper.pipe_write, ERROR_STR()); else thr_trace_msg(logp, "%s DNSBL write(pipe_write)=%d", req->id, i); help_finish(gen, 0, counted, 1); helper_unlock(); return 0; } helper_unlock(); for (;;) { us = avail_us - tv_diff2us(&now, &req->start); if (us < 0) us = 0; pollfd.fd = ctxt->soc[0].s; i = select_poll(emsg, &pollfd, 1, 1, us); if (i < 0) { thr_error_msg(logp, "%s DNSBL %s", req->id, emsg); help_finish(gen, 0, counted, 0); return 0; } gettimeofday(&now, 0); if (i == 0) { if (helper.debug) thr_trace_msg(logp, "%s DNSBL no helper answer after" " %1.f sec", req->id, tv_diff2us(&now, &req->start) / (DCC_US*1.0)); helper_lock(); if (helper.slow_helpers<=helper.total_helpers/MAX_SLOW) ++helper.slow_helpers; help_finish(gen, 0, counted, 1); helper_unlock(); return 0; } su_len = sizeof(recv_su); i = recvfrom(ctxt->soc[0].s, resp, resp_len, 0, &recv_su.sa, &su_len); /* because we are using UDP, we might get stray packets */ if (i != resp_len) { if (i < 0) { thr_trace_msg(logp, "%s DNSBL recvfrom(): %s", req->id, ERROR_STR()); if (DCC_BLOCK_ERROR()) continue; help_finish(gen, 0, counted, 0); return 0; } if (helper.debug > 1) thr_trace_msg(logp, "%s DNSBL recvfrom(%s)=%d", req->id, dcc_su2str(sustr, sizeof(sustr), &recv_su), i); continue; } if (!DCC_SUnP_EQ(&send_su, &recv_su)) { if (helper.debug != 0) thr_trace_msg(logp, "%s DNSBL recvfrom(%s)" " instead of %s", req->id, dcc_su2str(sustr, sizeof(sustr), &recv_su), dcc_su2str(sustr2, sizeof(sustr2), &send_su)); continue; } if (resp->magic != HELPER_MAGIC_RESP || resp->version != HELPER_VERSION || resp->sn != req->sn) { if (helper.debug >1 ) thr_trace_msg(logp, "%s DNSBL recvfrom(%s)" " magic=%#08x sn=%d", req->id, dcc_su2str(sustr, sizeof(sustr), &recv_su), resp->magic, resp->sn); continue; } if (helper.debug > 4) thr_trace_msg(logp,"%s DNSBL answer from %s", req->id, dcc_su2str(sustr, sizeof(sustr), &recv_su)); help_finish(gen, 1, counted, 0); return 1; } }
/* Start a new helper process. * The counter mutex must be locked */ static u_char new_helper(DCC_CLNT_CTXT *ctxt, void *logp, const char *id) { pid_t pid; char arg_buf[sizeof("set:")+sizeof(HELPER_PAT)+9+9+9]; char trace_buf[200]; char *bufp; DCC_SOCKET s; int pid_inx, buf_len, i, j; /* open the pipes and sockets if necessary */ if (helper.soc == INVALID_SOCKET) { if (!ready_helpers(logp)) return 0; if (!open_helper_soc(ctxt, logp)) return 0; } reap_helpers(1); for (pid_inx = 0; ; ++pid_inx) { if (pid_inx >= helper.max_helpers) dcc_logbad(EX_SOFTWARE, "no free DNSBL pids[] entry"); if (helper.pids[pid_inx] == 0) break; } fflush(stdout); fflush(stderr); pid = fork(); if (pid < 0) { thr_error_msg(logp, "%s DNSBL helper fork(): %s", id, ERROR_STR()); return 0; } if (pid != 0) { /* this is the parent */ helper.pids[pid_inx] = pid; ++helper.total_helpers; return 1; } dcc_rel_priv(); /* no fun or games */ dcc_clean_stdio(); /* reset FD_CLOEXEC without affecting parent */ s = helper.soc; if (s != INVALID_SOCKET) { s = dup(s); if (s == INVALID_SOCKET) { thr_error_msg(logp, "%s DNSBL soc dup(%d): %s", id, helper.soc, ERROR_STR()); return 0; } } snprintf(arg_buf, sizeof(arg_buf), "set:"HELPER_PAT, s, helper.pipe_read, helper.total_helpers); helper_save_arg("-B", arg_buf); helper.argv[0] = dnsbl_progpath; buf_len = sizeof(trace_buf); bufp = trace_buf; for (i = 0; i < helper.argc && buf_len > 2; ++i) { j = snprintf(bufp, buf_len, "%s ", helper.argv[i]); buf_len -= j; bufp += j; } if (helper.debug >= 4) dcc_trace_msg("DNSBL helper exec %s", trace_buf); execv(helper.argv[0], (char * const *)helper.argv); /* This process should continue at helper_child() */ dcc_logbad(EX_UNAVAILABLE, "execv(%s): %s", trace_buf, ERROR_STR()); return 0; }
/* helper processes start here via fork()/exec() in the parent */ void DCC_NORET helper_child(DCC_SOCKET s, int fd, int total_helpers) { sigset_t sigs; socklen_t soc_len; DNSBL_REQ req; int req_len; DNSBL_RESP resp; DCC_SOCKU req_su; socklen_t su_len; struct timeval now; u_char wake_buf; int secs, i; /* this process inherits via exec() by dccm or dccifd odd signal * blocking from some pthreads implementations including FreeBSD 5.* */ signal(SIGHUP, SIG_IGN); signal(SIGINT, SIG_IGN); signal(SIGTERM, SIG_IGN); sigemptyset(&sigs); sigaddset(&sigs, SIGALRM); sigprocmask(SIG_UNBLOCK, &sigs, 0); helper_init(0); if (have_helpers) dcc_logbad(EX_SOFTWARE, "no threads for DNSBL helpers"); helper.total_helpers = total_helpers; helper.pipe_read = fd; helper.soc = s; soc_len = sizeof(helper.su); if (0 > getsockname(helper.soc, &helper.su.sa, &soc_len)) dcc_logbad(EX_IOERR, "DNSBL helper getsockname(%d): %s", helper.soc, ERROR_STR()); if (helper.debug > 1) dcc_trace_msg("DNSBL helper process starting on %s", dcc_su2str_err(&helper.su)); for (;;) { /* Use read() and SIGALRM to watch for a wake-up byte * from the parent, the parent ending and closing the pipe, * or enough idle time to require our retirement. This * tactic awakens a single child for each wake-up call * from the parent. Using select() or poll() on the main * socket awakens a thundering herd of children */ secs = HELPER_IDLE_STOP_SECS+1; if (helper.total_helpers > 0) secs /= helper.total_helpers+1; if (secs < 5) secs = 5; signal(SIGALRM, helper_alarm); #ifdef HAVE_SIGINTERRUPT siginterrupt(SIGALRM, 1); #endif helper_alarm_hit = 0; alarm(secs); for (;;) { su_len = sizeof(req_su); req_len = recvfrom(helper.soc, &req, ISZ(req), 0, &req_su.sa, &su_len); /* sleep until awakened if no work is ready */ if (req_len <= 0) { if (req_len == 0) dcc_logbad(EX_IOERR, "DNSBL helper recvfrom()=0"); if (!DCC_BLOCK_ERROR()) dcc_logbad(EX_IOERR, "DNSBL helper recvfrom():" " %s", ERROR_STR()); if (helper_alarm_hit) helper_exit("idle helper exit"); i = read(helper.pipe_read, &wake_buf, 1); /* The other end of the pipe can be marked * non-blocking by some pthreads * implementations. That makes read() on this * end fail with EAGAIN. When that happens, * fall back on select() or poll(). * Even on such pthread implementations, * it rarely happens. */ if (i < 0 && DCC_BLOCK_ERROR()) { DCC_POLLFD pollfd; DCC_EMSG emsg; pollfd.fd = helper.pipe_read; i = select_poll(emsg, &pollfd, 1, 0, -1); if (i < 0) dcc_logbad(EX_IOERR, "dnsbl HELPER %s", emsg); } /* loof for work after a wake-up call */ if (i > 0) continue; if (helper_alarm_hit) continue; if (i == 0) helper_exit("shutdown"); if (i < 0) { dcc_logbad(EX_OSERR, "DNSBL read(terminate): %s", ERROR_STR()); } } if (req_len != helper.req_len) { if (helper.debug) dcc_trace_msg("DNSBL helper" " recvfrom(parent %s)=%d" " instead of %d", dcc_su2str_err(&req_su), req_len, helper.req_len); continue; } /* we might get stray packets because we cannot * connect to a single port */ if (!DCC_SUnP_EQ(&helper.su, &req_su)) { if (helper.debug) dcc_trace_msg("DNSBL helper" " request from" " %s instead of %s", dcc_su2str_err(&req_su), dcc_su2str_err(&helper.su)); continue; } if (req.hdr.magic != HELPER_MAGIC_REQ || req.hdr.version != HELPER_VERSION) { if (helper.debug) dcc_trace_msg("DNSBL helper" " recvfrom(parent %s)" " magic=%#08x", dcc_su2str_err(&req_su), req.hdr.magic); continue; } break; } gettimeofday(&now, 0); alarm(0); /* do not bother working if it is already too late to answer, * perhaps because a previous helper died */ i = tv_diff2us(&now, &req.hdr.start); if (i >= req.hdr.avail_us) { if (helper.debug > 1) dcc_trace_msg("%s DNSBL helper" " already too late to start;" " used %.1f of %.1f seconds", req.hdr.id, i / (DCC_US*1.0), req.hdr.avail_us / (DCC_US*1.0)); continue; } memset(&resp, 0, sizeof(resp)); resp.hdr.magic = HELPER_MAGIC_RESP; resp.hdr.version = HELPER_VERSION; resp.hdr.sn = req.hdr.sn; /* do the work and send an answer if we have one */ if (!dnsbl_work(&req, &resp)) continue; /* do not answer if it is too late */ gettimeofday(&now, 0); i = tv_diff2us(&now, &req.hdr.start); if (i > (req.hdr.avail_us + DCC_US/2)) { if (helper.debug > 1) dcc_trace_msg("%s DNSBL helper" " too late to answer;" " used %.1f of %.1f seconds", req.hdr.id, i / (DCC_US*1.0), req.hdr.avail_us / (DCC_US*1.0)); continue; } i = sendto(helper.soc, &resp, sizeof(resp), 0, &req_su.sa, DCC_SU_LEN(&req_su)); if (i != sizeof(resp)) { if (i < 0) dcc_error_msg("%s helper sendto(%s): %s", req.hdr.id, dcc_su2str_err(&req_su), ERROR_STR()); else dcc_error_msg("%s helper sendto(%s)=%d", req.hdr.id, dcc_su2str_err(&req_su), i); } } }