const struct remote_security_filter *load_security_filter(int tType, const char **dData, load_reference lLoad) { if (initialized) return NULL; #ifdef HAVE_GCRYPT_H if (!gcry_control(GCRYCTL_ANY_INITIALIZATION_P)) { gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread); gcry_check_version(NULL); //no need to check as of now gcry_control(GCRYCTL_DISABLE_SECMEM, 0); gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0); } #endif gnutls_global_set_log_function(&gnutls_logging); gnutls_global_set_log_level(PARAM_RSVX_TLS_LOGGING); gnutls_global_init(); forwarder_type = tType; const char **initializers = dData, **current = initializers; int argument_count = 0; if (current) while (*current++) argument_count++; if (argument_count > 0 && (current = initializers)) //srp initialization { use_srp_auth = true; const char *passwd = (*current)? *current++ : NULL; const char *srp_passwd = (*current)? *current++ : NULL; const char *srp_passwd_conf = (*current)? *current++ : NULL; if (passwd && strlen(passwd)) { srp_file = passwd; if (!parse_passwd()) { gnutls_global_deinit(); return NULL; } } gnutls_global_init_extra(); if (srp_passwd && strlen(srp_passwd) && srp_passwd_conf && strlen(srp_passwd_conf)) { gnutls_srp_allocate_server_credentials(&srp_server); gnutls_srp_set_server_credentials_file(srp_server, srp_passwd, srp_passwd_conf); } } else //anonymouns initialization { gnutls_anon_allocate_server_credentials(&credentials); gnutls_dh_params_init(&dh_params); gnutls_dh_params_generate2(dh_params, 1024); gnutls_anon_set_server_dh_params(credentials, dh_params); } return &internal_filter; }
/* (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 set_client_passwd(gnutls_srp_client_credentials_t &cCredentials, const struct sockaddr *aAddress, socklen_t lLength, const char *aActual) { //check for updates, but use previous if the file is inaccessible parse_passwd(); gnutls_srp_allocate_client_credentials(&cCredentials); std::string address; int position = data::not_found; if (forwarder_type == RSERVR_REMOTE_NET) { if (!aAddress || lLength != sizeof(struct sockaddr_in)) return; char address_buffer[PARAM_DEFAULT_FORMAT_BUFFER]; int port = ntohs(((const struct sockaddr_in*) aAddress)->sin_port); //try the verbatim request first... if (aActual) { snprintf(address_buffer, sizeof address_buffer, "%s:%i", aActual, port); position = srp_clients.f_find(address_buffer, &check_srp_key_regex); } //then try IP lookup... if (position == data::not_found) { address = inet_ntoa(((const struct sockaddr_in*) aAddress)->sin_addr); snprintf(address_buffer, sizeof address_buffer, "%s:%i", address.c_str(), port); position = srp_clients.f_find(address_buffer, &check_srp_key_regex); } if (position == data::not_found) //then try DNS lookup { char name_buffer[PARAM_DEFAULT_FORMAT_BUFFER]; if (getnameinfo(aAddress, lLength, name_buffer, sizeof name_buffer, NULL, 0, 0x00)) snprintf(address_buffer, sizeof address_buffer, "%s:%i", name_buffer, port); position = srp_clients.f_find(address_buffer, &check_srp_key_regex); } } else if (forwarder_type == RSERVR_REMOTE_LOCAL) { if (!aAddress) return; //try the verbatim request first... if (aActual) position = srp_clients.f_find(aActual, &check_srp_key_regex); if (position == data::not_found) //then try the socket specs (probably the same file name) { address.resize(lLength); strncpy(&address[0], ((const struct sockaddr_un*) aAddress)->sun_path, lLength); position = srp_clients.f_find(address.c_str(), &check_srp_key_regex); } } else return; if (position != data::not_found) gnutls_srp_set_client_credentials(cCredentials, srp_clients[position].value().user.c_str(), srp_clients[position].value().passwd.c_str()); }