/** * Clean up a group list entry. Free malloc'ed structures, drop the * multicast group (if no one else is using it) and free the slot. */ void group_cleanup(int listidx) { int i; for (i = 0; i < MAX_PEND; i++) { free(group_list[listidx].pending[i].naklist); } if ((group_list[listidx].multi.s_addr != 0) && (proxy_type != CLIENT_PROXY) && !other_mcast_users(listidx) && group_list[listidx].multi_join) { multicast_leave(listener, group_list[listidx].group_id, &group_list[listidx].multi, m_interface, interface_count, server_fp, server_fp_count); } if (group_list[listidx].serverkey) { free_RSA_key(group_list[listidx].serverkey); } for (i = 0; i < group_list[listidx].destcount; i++) { if (group_list[listidx].destinfo[i].pubkey) { free_RSA_key(group_list[listidx].destinfo[i].pubkey); } } memset(&group_list[listidx], 0, sizeof(group_list[listidx])); }
/** * Clean up a group list entry. Free malloc'ed structures, drop the * multicast group (if no one else is using it) and free the slot. */ void group_cleanup(struct pr_group_list_t *group) { int i; for (i = 0; i < MAX_PEND; i++) { free(group->pending[i].naklist); } if (!addr_blank(&group->privatemcast) && (proxy_type != CLIENT_PROXY) && !other_mcast_users(group) && group->multi_join) { multicast_leave(listener, group->group_id, &group->privatemcast, m_interface, interface_count, server_fp, server_fp_count); } if (group->server_pubkey.key) { if ((group->keyextype == KEYEX_RSA) || (group->keyextype == KEYEX_ECDH_RSA)) { free_RSA_key(group->server_pubkey.rsa); } else { free_EC_key(group->server_pubkey.ec); } if ((group->keyextype == KEYEX_ECDH_RSA) || (group->keyextype == KEYEX_ECDH_ECDSA)) { free_EC_key(group->server_dhkey.ec); free_EC_key(group->proxy_dhkey.ec); } } for (i = 0; i < group->destcount; i++) { if (group->destinfo[i].pubkey.key) { if ((group->keyextype == KEYEX_RSA) || (group->keyextype == KEYEX_ECDH_RSA)) { free_RSA_key(group->destinfo[i].pubkey.rsa); } else { free_EC_key(group->destinfo[i].pubkey.ec); } if ((group->keyextype == KEYEX_ECDH_RSA) || (group->keyextype == KEYEX_ECDH_ECDSA)) { free_EC_key(group->destinfo[i].dhkey.ec); } } } memset(group, 0, sizeof(struct pr_group_list_t)); }
/** * Clean up a group list entry. Close the file if open, * free malloc'ed structures, drop the multicast group * (if no one else is using it) and free the slot. */ void file_cleanup(int listidx, int abort) { if (group_list[listidx].fileinfo.fd >= 0) { close(group_list[listidx].fileinfo.fd); group_list[listidx].fileinfo.fd = -1; if (tempfile) { move_to_backup(listidx); if (rename(group_list[listidx].fileinfo.temppath, group_list[listidx].fileinfo.filepath) == -1) { syserror(group_list[listidx].group_id, group_list[listidx].file_id, "Couldn't rename from %s to %s", group_list[listidx].fileinfo.temppath, group_list[listidx].fileinfo.filepath); } } if (group_list[listidx].fileinfo.tstamp) { utim_buf utbuf; utbuf.actime = group_list[listidx].fileinfo.tstamp; utbuf.modtime = group_list[listidx].fileinfo.tstamp; if (utime(group_list[listidx].fileinfo.filepath, &utbuf) == -1) { syserror(group_list[listidx].group_id, group_list[listidx].file_id, "utime failed"); } } } if ((group_list[listidx].version == UFTP_V2_VER) || abort || (group_list[listidx].file_id == 0)) { if ((group_list[listidx].multi.s_addr != 0) && !other_mcast_users(listidx) && group_list[listidx].multi_join) { if (server_count > 0) { multicast_leave(listener, group_list[listidx].group_id, &group_list[listidx].multi, m_interface, interface_count, server_keys, server_count); if (has_proxy) { multicast_leave(listener, group_list[listidx].group_id, &group_list[listidx].multi, m_interface, interface_count, &proxy_info, 1); } } else { multicast_leave(listener, group_list[listidx].group_id, &group_list[listidx].multi, m_interface, interface_count, NULL, 0); } } if (group_list[listidx].serverkey) { free_RSA_key(group_list[listidx].serverkey); } if (group_list[listidx].restartinfo && (strcmp(group_list[listidx].restartinfo->name, ""))) { // We have unused restart info from the last run. // Chalk this up as a loss and delete the data file char filepath[MAXPATHNAME]; snprintf(filepath, sizeof(filepath), "%s%c_group_%08X%c%s", tempdir, PATH_SEP, group_list[listidx].group_id, PATH_SEP, group_list[listidx].restartinfo->name); unlink(filepath); } if (abort) { write_restart_file(listidx); } free(group_list[listidx].fileinfo.naklist); free(group_list[listidx].fileinfo.section_done); if (group_list[listidx].restartinfo) { free(group_list[listidx].restartinfo->naklist); free(group_list[listidx].restartinfo->section_done); free(group_list[listidx].restartinfo); } memset(&group_list[listidx], 0, sizeof(group_list[listidx])); } else { // Don't clear the file_id in case we need to respond to late DONEs group_list[listidx].phase = PHASE_MIDGROUP; set_timeout(listidx); free(group_list[listidx].fileinfo.naklist); free(group_list[listidx].fileinfo.section_done); group_list[listidx].fileinfo.naklist = NULL; group_list[listidx].fileinfo.section_done = NULL; } }
/** * Processes a new incoming ANNOUNCE */ void handle_announce(union sockaddr_u *src, unsigned char *packet, unsigned packetlen, struct timeval rxtime) { struct uftp_h *header; struct announce_h *announce; uint32_t *addrlist; int addrlen, rval; struct group_list_t *group; time_t t; struct tm *start_time; char privname[INET6_ADDRSTRLEN], srcname[INET6_ADDRSTRLEN]; char srcfqdn[DESTNAME_LEN]; header = (struct uftp_h *)packet; announce = (struct announce_h *)(packet + sizeof(struct uftp_h)); addrlist = (uint32_t *)((unsigned char *)announce + (announce->hlen * 4)); addrlen = (packetlen - sizeof(struct uftp_h) - (announce->hlen * 4)) / 4; if ((packetlen < sizeof(struct uftp_h) + (announce->hlen * 4U)) || ((announce->hlen * 4U) < sizeof(struct announce_h))) { log1(ntohl(header->group_id), header->group_inst, 0, "Rejecting ANNOUNCE from %08X: invalid message size", ntohl(header->src_id)); return; } if ((addrlen != 0) && (!uid_in_list(addrlist, addrlen))) { log1(ntohl(header->group_id), header->group_inst, 0, "Name not in host list"); return; } if ((group = find_open_slot()) == NULL ) { log0(ntohl(header->group_id), header->group_inst, 0, "Error: maximum number of incoming files exceeded: %d\n", MAXLIST); return; } t = time(NULL); start_time = localtime(&t); snprintf(group->start_date, sizeof(group->start_date), "%04d%02d%02d", start_time->tm_year + 1900, start_time->tm_mon + 1, start_time->tm_mday); snprintf(group->start_time, sizeof(group->start_time), "%02d%02d%02d", start_time->tm_hour, start_time->tm_min, start_time->tm_sec); if (!read_announce(group, packet, src, rxtime, packetlen)) { return; } if ((rval = getnameinfo((struct sockaddr *)src, family_len(*src), srcname, sizeof(srcname), NULL, 0, NI_NUMERICHOST)) != 0) { glog1(group, "getnameinfo failed: %s", gai_strerror(rval)); } if (!noname) { if ((rval = getnameinfo((struct sockaddr *)src, family_len(*src), srcfqdn, sizeof(srcfqdn), NULL, 0, 0)) != 0) { glog1(group, "getnameinfo failed: %s", gai_strerror(rval)); } } else { strncpy(srcfqdn, srcname, sizeof(srcfqdn) - 1); } if ((rval = getnameinfo((struct sockaddr *)&group->multi, family_len(group->multi), privname, sizeof(privname), NULL, 0, NI_NUMERICHOST)) != 0) { glog1(group, "getnameinfo failed: %s", gai_strerror(rval)); } glog2(group, "Received request from %08X at %s (%s)", ntohl(group->src_id), srcfqdn, srcname); glog2(group, "Using private multicast address %s", privname); glog3(group, "grtt = %.6f", group->grtt); glog3(group, "send time: %d.%06d", group->last_server_ts.tv_sec, group->last_server_ts.tv_usec); glog3(group, "receive time: %d.%06d", group->last_server_rx_ts.tv_sec, group->last_server_rx_ts.tv_usec); if (status_file) { fprintf(status_file, "CONNECT;%04d/%02d/%02d-%02d:%02d:%02d;%08X;%08X;%s;%s\n", start_time->tm_year + 1900, start_time->tm_mon + 1, start_time->tm_mday, start_time->tm_hour, start_time->tm_min, start_time->tm_sec, ntohl(group->src_id), group->group_id, srcname, srcfqdn); fflush(status_file); } if (group->restart) { if (group->sync_mode) { glog1(group, "Sync mode and restart mode incompatible"); send_abort(group, "Sync mode and restart mode incompatible"); return; } } if (!addr_blank(&group->multi)) { if (server_count > 0) { if (!is_multicast(&group->multi, 1)) { glog1(group, "Invalid source specific multicast address: %s", privname); send_abort(group, "Invalid source specific multicast address"); return; } if (!other_mcast_users(group)) { if (!multicast_join(listener, group->group_id, &group->multi, m_interface, interface_count, server_keys, server_count)) { send_abort(group, "Error joining multicast group"); return; } if (has_proxy) { if (!multicast_join(listener,group->group_id, &group->multi, m_interface, interface_count, &proxy_info, 1)) { send_abort(group, "Error joining multicast group"); return; } } } } else { if (!is_multicast(&group->multi, 0)) { glog1(group, "Invalid multicast address: %s", privname); send_abort(group, "Invalid multicast address"); return; } if (!other_mcast_users(group)) { if (!multicast_join(listener, group->group_id, &group->multi, m_interface, interface_count, NULL, 0)) { send_abort(group, "Error joining multicast group"); return; } } } group->multi_join = 1; } send_register(group); }
/** * Clean up a group list entry. Close the file if open, * free malloc'ed structures, drop the multicast group * (if no one else is using it) and free the slot. */ void file_cleanup(struct group_list_t *group, int abort_session) { if (group->fileinfo.fd >= 0) { glog2(group, "starting file close"); close(group->fileinfo.fd); glog2(group, "done file close"); group->fileinfo.fd = -1; if (abort_session && !strcmp(tempdir, "")) { if (tempfile) { unlink(group->fileinfo.temppath); } else { unlink(group->fileinfo.filepath); } } else { if (tempfile) { move_to_backup(group); if (rename(group->fileinfo.temppath, group->fileinfo.filepath) == -1) { gsyserror(group, "Couldn't rename from %s to %s", group->fileinfo.temppath,group->fileinfo.filepath); } } if (group->fileinfo.tstamp) { utim_buf utbuf; utbuf.actime = group->fileinfo.tstamp; utbuf.modtime = group->fileinfo.tstamp; if (utime(group->fileinfo.filepath, &utbuf) == -1) { gsyserror(group, "utime failed"); } } } } if (abort_session || (group->file_id == 0)) { if (!addr_blank(&group->multi) && !other_mcast_users(group) && group->multi_join) { if (server_count > 0) { multicast_leave(listener, group->group_id, &group->multi, m_interface, interface_count, server_keys,server_count); if (has_proxy) { multicast_leave(listener, group->group_id, &group->multi, m_interface, interface_count, &proxy_info, 1); } } else { multicast_leave(listener, group->group_id, &group->multi, m_interface, interface_count, NULL, 0); } } if (group->server_pubkey.key) { if (group->keyextype == KEYEX_ECDH_ECDSA) { free_EC_key(group->server_pubkey.ec); } else { free_RSA_key(group->server_pubkey.rsa); } } if (group->server_dhkey.key) { free_EC_key(group->server_dhkey.ec); free_EC_key(group->client_dhkey.ec); } if (group->restartinfo && (strcmp(group->restartinfo->name, ""))) { // We have unused restart info from the last run. // Chalk this up as a loss and delete the data file char filepath[MAXPATHNAME]; snprintf(filepath, sizeof(filepath), "%s%c_group_%08X%c%s", tempdir, PATH_SEP, group->group_id, PATH_SEP, group->restartinfo->name); unlink(filepath); } if (abort_session) { write_restart_file(group); } free(group->loss_history); free(group->fileinfo.naklist); free(group->fileinfo.section_done); free(group->fileinfo.cache); free(group->fileinfo.cache_status); if (group->restartinfo) { free(group->restartinfo->naklist); free(group->restartinfo->section_done); free(group->restartinfo); } memset(group, 0, sizeof(struct group_list_t)); } else { // Don't clear the file_id in case we need to respond to late DONEs if (!strcmp(tempdir, "")) { run_postreceive(group, group->fileinfo.filepath); } group->phase = PHASE_MIDGROUP; set_timeout(group, 0); free(group->fileinfo.naklist); free(group->fileinfo.section_done); free(group->fileinfo.cache); free(group->fileinfo.cache_status); group->fileinfo.naklist = NULL; group->fileinfo.section_done = NULL; group->fileinfo.cache = NULL; group->fileinfo.cache_status = NULL; } }