static void send_with_socket(RADIUS_PACKET *request) { request->sockfd = sockfd; if (fr_dhcp_send(request) < 0) { fprintf(stderr, "dhcpclient: failed sending: %s\n", fr_syserror(errno)); fr_exit_now(1); } if (!reply_expected) return; reply = fr_dhcp_recv(sockfd); if (!reply) { fprintf(stderr, "dhcpclient: Error receiving reply: %s\n", fr_strerror()); fr_exit_now(1); } if (fr_debug_lvl) print_hex(reply); if (fr_dhcp_decode(reply) < 0) { fprintf(stderr, "dhcpclient: failed decoding\n"); fr_exit_now(1); } }
/** Prints a simple backtrace (if execinfo is available) and calls panic_action if set. * * @param sig caught */ void NEVER_RETURNS fr_fault(int sig) { char cmd[sizeof(panic_action) + 20]; char *out = cmd; size_t left = sizeof(cmd), ret; char const *p = panic_action; char const *q; int code; fprintf(stderr, "FATAL SIGNAL: %s\n", strsignal(sig)); /* * Produce a simple backtrace - They've very basic but at least give us an * idea of the area of the code we hit the issue in. */ #ifdef HAVE_EXECINFO_H size_t frame_count, i; void *stack[MAX_BT_FRAMES]; char **frames; frame_count = backtrace(stack, MAX_BT_FRAMES); frames = backtrace_symbols(stack, frame_count); fprintf(stderr, "Backtrace of last %zu frames:\n", frame_count); for (i = 0; i < frame_count; i++) { fprintf(stderr, "%s\n", frames[i]); /* Leak the backtrace strings, freeing may lead to undefined behaviour... */ } #endif /* No panic action set... */ if (panic_action[0] == '\0') { fprintf(stderr, "No panic action set\n"); fr_exit_now(1); } /* Substitute %p for the current PID (useful for attaching a debugger) */ while ((q = strstr(p, "%p"))) { out += ret = snprintf(out, left, "%.*s%d", (int) (q - p), p, (int) getpid()); if (left <= ret) { oob: fprintf(stderr, "Panic action too long\n"); fr_exit_now(1); } left -= ret; p = q + 2; } if (strlen(p) >= left) goto oob; strlcpy(out, p, left); fprintf(stderr, "Calling: %s\n", cmd); code = system(cmd); fprintf(stderr, "Panic action exited with %i\n", code); fr_exit_now(1); }
static void _fr_talloc_fault(char const *reason) { FR_FAULT_LOG("talloc abort: %s", reason); #ifdef SIGABRT fr_fault(SIGABRT); #endif fr_exit_now(1); }
void fr_suid_down_permanent(void) { if (!doing_setuid) return; if (setresuid(server_uid, server_uid, server_uid) < 0) { ERROR("Failed in permanent switch to uid %s: %s", uid_name, fr_syserror(errno)); fr_exit_now(1); } if (geteuid() != server_uid) { ERROR("Switched to unknown uid"); fr_exit_now(1); } fr_set_dumpable(allow_core_dumps); }
static void send_with_pcap(void) { pcap = fr_pcap_init(NULL, iface, PCAP_INTERFACE_IN_OUT); if (!pcap) { fprintf(stderr, "Failed creating pcap \n"); fr_exit_now(1); } if (fr_pcap_open(pcap) < 0) { fprintf(stderr, "Failed opening interface: %s", fr_strerror()); fr_exit_now(1); } char ip[16]; ip_ntoh(&request->src_ipaddr, ip, sizeof(ip)); char pcap_filter[255]; sprintf(pcap_filter, "udp and dst port %d", client_port); if (fr_pcap_apply_filter(pcap, pcap_filter) < 0) { fprintf(stderr, "Failed setting filter for interface: %s \n", fr_strerror()); fr_exit_now(1); } if (fr_dhcp_send_pcap(pcap, eth_bcast, request) < 0) { fprintf(stderr, "dhcpclient: failed sending: %s\n", pcap_geterr(pcap->handle)); fr_exit_now(1); } if (!reply_expected) return; reply = fr_dhcp_recv_raw_loop(pcap->fd, #ifdef HAVE_LINUX_IF_PACKET_H &ll, #endif request); if (!reply) { fprintf(stderr, "dhcpclient: Error receiving reply\n"); fr_exit_now(1); } }
void fr_suid_down(void) { if (!doing_setuid) return; if (setresuid(-1, server_uid, geteuid()) < 0) { fprintf(stderr, "%s: Failed switching to uid %s: %s\n", progname, uid_name, fr_syserror(errno)); fr_exit_now(1); } if (geteuid() != server_uid) { fprintf(stderr, "%s: Failed switching uid: UID is incorrect\n", progname); fr_exit_now(1); } fr_set_dumpable(allow_core_dumps); }
void fr_suid_up(void) { uid_t ruid, euid, suid; if (getresuid(&ruid, &euid, &suid) < 0) { ERROR("Failed getting saved UID's"); fr_exit_now(1); } if (setresuid(-1, suid, -1) < 0) { ERROR("Failed switching to privileged user"); fr_exit_now(1); } if (geteuid() != suid) { ERROR("Switched to unknown UID"); fr_exit_now(1); } }
/** Log a fatal error, then exit * */ void log_fatal(char const *fmt, ...) { va_list ap; va_start(ap, fmt); fr_vlog(&default_log, L_ERR, fmt, ap); va_end(ap); fr_exit_now(1); }
void fr_suid_down(void) { if (!uid_name) return; if (setuid(server_uid) < 0) { fprintf(stderr, "%s: Failed switching to uid %s: %s\n", progname, uid_name, fr_syserror(errno)); fr_exit_now(1); } fr_set_dumpable(allow_core_dumps); }
/** Create a VALUE_PAIR and add it to a list of VALUE_PAIR s * * @note This function ALWAYS returns. If we're OOM, then it causes the * @note server to exit, so you don't need to check the return value. * * @param[in] ctx Context to allocate VALUE_PAIRs in. * @param[out] vps List to add new VALUE_PAIR to, if NULL will just * return VALUE_PAIR. * @param[in] attribute number. * @param[in] vendor number. * @return a new VLAUE_PAIR or causes server to exit on error. */ VALUE_PAIR *radius_paircreate(TALLOC_CTX *ctx, VALUE_PAIR **vps, unsigned int attribute, unsigned int vendor) { VALUE_PAIR *vp; vp = paircreate(ctx, attribute, vendor); if (!vp) { ERROR("No memory!"); rad_assert("No memory" == NULL); fr_exit_now(1); } if (vps) pairadd(vps, vp); return vp; }
/** Handle a network control message callback for a new worker * * @param[in] ctx the network * @param[in] data the message * @param[in] data_size size of the data * @param[in] now the current time */ static void fr_network_worker_callback(void *ctx, void const *data, size_t data_size, UNUSED fr_time_t now) { int i; fr_network_t *nr = ctx; fr_worker_t *worker; fr_network_worker_t *w; rad_assert(data_size == sizeof(worker)); memcpy(&worker, data, data_size); (void) talloc_get_type_abort(worker, fr_worker_t); MEM(w = talloc_zero(nr, fr_network_worker_t)); w->worker = worker; w->channel = fr_worker_channel_create(worker, w, nr->control); if (!w->channel) fr_exit_now(1); fr_channel_master_ctx_add(w->channel, w); /* * Insert the worker into the array of workers. */ for (i = 0; i < nr->max_workers; i++) { if (nr->workers[i]) continue; nr->workers[i] = w; nr->num_workers++; return; } /* * Run out of room to put workers! */ rad_assert(0 == 1); }
int main(int argc, char **argv) { char *p; int c; char const *radius_dir = RADDBDIR; char const *dict_dir = DICTDIR; char const *filename = NULL; DICT_ATTR const *da; fr_debug_lvl = 0; while ((c = getopt(argc, argv, "d:D:f:hr:t:vxi:" )) != EOF) switch(c) { case 'D': dict_dir = optarg; break; case 'd': radius_dir = optarg; break; case 'f': filename = optarg; break; case 'i': iface = optarg; break; case 'r': if (!isdigit((int) *optarg)) usage(); retries = atoi(optarg); if ((retries == 0) || (retries > 1000)) usage(); break; case 't': if (!isdigit((int) *optarg)) usage(); timeout = atof(optarg); break; case 'v': printf("%s\n", dhcpclient_version); exit(0); case 'x': fr_debug_lvl++; fr_log_fp = stdout; break; case 'h': default: usage(); } argc -= (optind - 1); argv += (optind - 1); if (argc < 2) usage(); /* convert timeout to a struct timeval */ #define USEC 1000000 tv_timeout.tv_sec = timeout; tv_timeout.tv_usec = ((timeout - (float) tv_timeout.tv_sec) * USEC); if (dict_init(dict_dir, RADIUS_DICTIONARY) < 0) { fr_perror("radclient"); return 1; } if (dict_read(radius_dir, RADIUS_DICTIONARY) == -1) { fr_perror("radclient"); return 1; } fr_strerror(); /* Clear the error buffer */ /* * Ensure that dictionary.dhcp is loaded. */ da = dict_attrbyname("DHCP-Message-Type"); if (!da) { if (dict_read(dict_dir, "dictionary.dhcp") < 0) { fprintf(stderr, "Failed reading dictionary.dhcp: %s\n", fr_strerror()); return -1; } } /* * Resolve hostname. */ server_ipaddr.af = AF_INET; if (strcmp(argv[1], "-") != 0) { char const *hostname = argv[1]; char const *portname = argv[1]; char buffer[256]; if (*argv[1] == '[') { /* IPv6 URL encoded */ p = strchr(argv[1], ']'); if ((size_t) (p - argv[1]) >= sizeof(buffer)) { usage(); } memcpy(buffer, argv[1] + 1, p - argv[1] - 1); buffer[p - argv[1] - 1] = '\0'; hostname = buffer; portname = p + 1; } p = strchr(portname, ':'); if (p && (strchr(p + 1, ':') == NULL)) { *p = '\0'; portname = p + 1; } else { portname = NULL; } if (ip_hton(&server_ipaddr, AF_INET, hostname, false) < 0) { fprintf(stderr, "dhcpclient: Failed to find IP address for host %s: %s\n", hostname, fr_syserror(errno)); fr_exit_now(1); } /* * Strip port from hostname if needed. */ if (portname) server_port = atoi(portname); } /* * See what kind of request we want to send. */ if (argc >= 3) { if (!isdigit((int) argv[2][0])) { packet_code = fr_str2int(request_types, argv[2], -2); if (packet_code == -2) { fprintf(stderr, "Unknown packet type: %s\n", argv[2]); usage(); } } else { packet_code = atoi(argv[2]); } } if (server_port == 0) server_port = 67; request_init(filename); /* * No data read. Die. */ if (!request || !request->vps) { fprintf(stderr, "dhcpclient: Nothing to send.\n"); fr_exit_now(1); } /* * Sanity check. */ if (!request->code) { fprintf(stderr, "dhcpclient: Command was %s, and request did not contain DHCP-Message-Type nor Packet-Type.\n", (argc >= 3) ? "'auto'" : "unspecified"); exit(1); } if ((request->code == PW_DHCP_RELEASE) || (request->code == PW_DHCP_DECLINE)) { /* These kind of packets do not get a reply, so don't wait for one. */ reply_expected = false; } /* * Bind to the first specified IP address and port. * This means we ignore later ones. */ if (request->src_ipaddr.af == AF_UNSPEC) { memset(&client_ipaddr, 0, sizeof(client_ipaddr)); client_ipaddr.af = server_ipaddr.af; client_port = 0; } else { client_ipaddr = request->src_ipaddr; client_port = request->src_port; } /* set "raw mode" if an interface is specified and if destination IP address is the broadcast address. */ if (iface) { iface_ind = if_nametoindex(iface); if (iface_ind <= 0) { fprintf(stderr, "dhcpclient: unknown interface: %s\n", iface); fr_exit_now(1); } if (server_ipaddr.ipaddr.ip4addr.s_addr == 0xFFFFFFFF) { fprintf(stderr, "dhcpclient: Using interface: %s (index: %d) in raw packet mode\n", iface, iface_ind); raw_mode = true; } } if (request->src_ipaddr.af == AF_UNSPEC) { request->src_ipaddr = client_ipaddr; request->src_port = client_port; } if (request->dst_ipaddr.af == AF_UNSPEC) { request->dst_ipaddr = server_ipaddr; request->dst_port = server_port; } /* * Encode the packet */ if (fr_dhcp_encode(request) < 0) { fprintf(stderr, "dhcpclient: failed encoding: %s\n", fr_strerror()); fr_exit_now(1); } if (fr_debug_lvl) print_hex(request); #ifdef HAVE_LIBPCAP if (raw_mode) { send_with_pcap(); } else #endif { send_with_socket(); } if (reply && fr_debug_lvl) print_hex(reply); if (reply && fr_dhcp_decode(reply) < 0) { fprintf(stderr, "dhcpclient: failed decoding\n"); return 1; } dict_free(); if (success) return 0; return 1; }
static void send_with_socket(void) { #ifdef HAVE_LINUX_IF_PACKET_H if (raw_mode) { sockfd = fr_socket_packet(iface_ind, &ll); } else #endif { sockfd = fr_socket(&client_ipaddr, client_port); } if (sockfd < 0) { fprintf(stderr, "dhcpclient: socket: %s\n", fr_strerror()); fr_exit_now(1); } /* * Set option 'receive timeout' on socket. * Note: in case of a timeout, the error will be "Resource temporarily unavailable". */ if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv_timeout,sizeof(struct timeval)) == -1) { fprintf(stderr, "dhcpclient: failed setting socket timeout: %s\n", fr_syserror(errno)); fr_exit_now(1); } request->sockfd = sockfd; #ifdef HAVE_LINUX_IF_PACKET_H if (raw_mode) { if (fr_dhcp_send_raw_packet(sockfd, &ll, request) < 0) { fprintf(stderr, "dhcpclient: failed sending (fr_dhcp_send_raw_packet): %s\n", fr_syserror(errno)); fr_exit_now(1); } if (!reply_expected) return; reply = fr_dhcp_recv_raw_loop(sockfd, &ll, request); if (!reply) { fprintf(stderr, "dhcpclient: Error receiving reply (fr_dhcp_recv_raw_loop)\n"); fr_exit_now(1); } } else #endif { if (fr_dhcp_send_socket(request) < 0) { fprintf(stderr, "dhcpclient: failed sending: %s\n", fr_syserror(errno)); fr_exit_now(1); } if (!reply_expected) return; reply = fr_dhcp_recv_socket(sockfd); if (!reply) { fprintf(stderr, "dhcpclient: Error receiving reply %s\n", fr_strerror()); fr_exit_now(1); } } }
int main(int argc, char **argv) { struct sockaddr_in from, to, in; char buf[TESTLEN]; char *destip = DESTIP; int port = DEF_PORT; int n, server_socket, client_socket, fl, tl, pid; if (argc > 1) destip = argv[1]; if (argc > 2) port = atoi(argv[2]); in.sin_family = AF_INET; in.sin_addr.s_addr = INADDR_ANY; in.sin_port = htons(port); fl = tl = sizeof(struct sockaddr_in); memset(&from, 0, sizeof(from)); memset(&to, 0, sizeof(to)); switch(pid = fork()) { case -1: perror("fork"); return 0; case 0: /* child */ usleep(100000); goto client; } /* parent: server */ server_socket = socket(PF_INET, SOCK_DGRAM, 0); if (udpfromto_init(server_socket) != 0) { perror("udpfromto_init\n"); waitpid(pid, NULL, WNOHANG); return 0; } if (bind(server_socket, (struct sockaddr *)&in, sizeof(in)) < 0) { perror("server: bind"); waitpid(pid, NULL, WNOHANG); return 0; } printf("server: waiting for packets on INADDR_ANY:%d\n", port); if ((n = recvfromto(server_socket, buf, sizeof(buf), 0, (struct sockaddr *)&from, &fl, (struct sockaddr *)&to, &tl)) < 0) { perror("server: recvfromto"); waitpid(pid, NULL, WNOHANG); return 0; } printf("server: received a packet of %d bytes [%s] ", n, buf); printf("(src ip:port %s:%d ", inet_ntoa(from.sin_addr), ntohs(from.sin_port)); printf(" dst ip:port %s:%d)\n", inet_ntoa(to.sin_addr), ntohs(to.sin_port)); printf("server: replying from address packet was received on to source address\n"); if ((n = sendfromto(server_socket, buf, n, 0, (struct sockaddr *)&to, tl, (struct sockaddr *)&from, fl)) < 0) { perror("server: sendfromto"); } waitpid(pid, NULL, 0); return 0; client: close(server_socket); client_socket = socket(PF_INET, SOCK_DGRAM, 0); if (udpfromto_init(client_socket) != 0) { perror("udpfromto_init"); fr_exit_now(0); } /* bind client on different port */ in.sin_port = htons(port+1); if (bind(client_socket, (struct sockaddr *)&in, sizeof(in)) < 0) { perror("client: bind"); fr_exit_now(0); } in.sin_port = htons(port); in.sin_addr.s_addr = inet_addr(destip); printf("client: sending packet to %s:%d\n", destip, port); if (sendto(client_socket, TESTSTRING, TESTLEN, 0, (struct sockaddr *)&in, sizeof(in)) < 0) { perror("client: sendto"); fr_exit_now(0); } printf("client: waiting for reply from server on INADDR_ANY:%d\n", port+1); if ((n = recvfromto(client_socket, buf, sizeof(buf), 0, (struct sockaddr *)&from, &fl, (struct sockaddr *)&to, &tl)) < 0) { perror("client: recvfromto"); fr_exit_now(0); } printf("client: received a packet of %d bytes [%s] ", n, buf); printf("(src ip:port %s:%d", inet_ntoa(from.sin_addr), ntohs(from.sin_port)); printf(" dst ip:port %s:%d)\n", inet_ntoa(to.sin_addr), ntohs(to.sin_port)); fr_exit_now(0); }
int main(int argc, char **argv) { static uint16_t server_port = 0; static int packet_code = 0; static fr_ipaddr_t server_ipaddr; static fr_ipaddr_t client_ipaddr; int c; char const *radius_dir = RADDBDIR; char const *dict_dir = DICTDIR; char const *filename = NULL; DICT_ATTR const *da; RADIUS_PACKET *request = NULL; #ifdef HAVE_LINUX_IF_PACKET_H bool raw_mode = false; #endif fr_debug_lvl = 0; while ((c = getopt(argc, argv, "d:D:f:hr:t:vx" #ifdef HAVE_LINUX_IF_PACKET_H "i:" #endif )) != EOF) switch(c) { case 'D': dict_dir = optarg; break; case 'd': radius_dir = optarg; break; case 'f': filename = optarg; break; #ifdef HAVE_LINUX_IF_PACKET_H case 'i': iface = optarg; break; #endif case 'r': if (!isdigit((int) *optarg)) usage(); retries = atoi(optarg); if ((retries == 0) || (retries > 1000)) usage(); break; case 't': if (!isdigit((int) *optarg)) usage(); timeout = atof(optarg); break; case 'v': printf("%s\n", dhcpclient_version); exit(0); case 'x': fr_debug_lvl++; fr_log_fp = stdout; break; case 'h': default: usage(); } argc -= (optind - 1); argv += (optind - 1); if (argc < 2) usage(); /* convert timeout to a struct timeval */ #define USEC 1000000 tv_timeout.tv_sec = timeout; tv_timeout.tv_usec = ((timeout - (float) tv_timeout.tv_sec) * USEC); if (dict_init(dict_dir, RADIUS_DICTIONARY) < 0) { fr_perror("radclient"); return 1; } if (dict_read(radius_dir, RADIUS_DICTIONARY) == -1) { fr_perror("radclient"); return 1; } fr_strerror(); /* Clear the error buffer */ /* * Ensure that dictionary.dhcp is loaded. */ da = dict_attrbyname("DHCP-Message-Type"); if (!da) { if (dict_read(dict_dir, "dictionary.dhcp") < 0) { fprintf(stderr, "Failed reading dictionary.dhcp: %s\n", fr_strerror()); return -1; } } /* * Resolve hostname. */ server_ipaddr.af = AF_INET; if (strcmp(argv[1], "-") != 0) { if (fr_pton_port(&server_ipaddr, &server_port, argv[1], -1, AF_INET, true) < 0) { fprintf(stderr, "dhcpclient: Failed parsing IP:port - %s", fr_strerror()); exit(1); } client_ipaddr.af = server_ipaddr.af; } /* * See what kind of request we want to send. */ if (argc >= 3) { if (!isdigit((int) argv[2][0])) { packet_code = fr_str2int(request_types, argv[2], -2); if (packet_code == -2) { fprintf(stderr, "Unknown packet type: %s\n", argv[2]); usage(); } } else { packet_code = atoi(argv[2]); } } if (!server_port) server_port = 67; #ifdef HAVE_LINUX_IF_PACKET_H /* * set "raw mode" if an interface is specified and if destination * IP address is the broadcast address. */ if (iface) { iface_ind = if_nametoindex(iface); if (iface_ind <= 0) { fprintf(stderr, "dhcpclient: unknown interface: %s\n", iface); fr_exit_now(1); } if (server_ipaddr.ipaddr.ip4addr.s_addr == 0xFFFFFFFF) { DEBUG("dhcpclient: Using interface: %s (index: %d) in raw packet mode\n", iface, iface_ind); raw_mode = true; } } if (raw_mode) { sockfd = fr_socket_packet(iface_ind, &ll); } else #endif { sockfd = fr_socket(&client_ipaddr, server_port + 1); } if (sockfd < 0) { fprintf(stderr, "dhcpclient: socket: %s\n", fr_strerror()); fr_exit_now(1); } /* * Set option 'receive timeout' on socket. * Note: in case of a timeout, the error will be "Resource temporarily unavailable". */ if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv_timeout,sizeof(struct timeval)) == -1) { fprintf(stderr, "dhcpclient: failed setting socket timeout: %s\n", fr_syserror(errno)); fr_exit_now(1); } request = request_init(filename); if (!request || !request->vps) { fprintf(stderr, "dhcpclient: Nothing to send.\n"); fr_exit_now(1); } /* * Set defaults if they weren't specified via pairs */ if (request->src_port == 0) request->src_port = server_port + 1; if (request->dst_port == 0) request->dst_port = server_port; if (request->src_ipaddr.af == AF_UNSPEC) request->src_ipaddr = client_ipaddr; if (request->dst_ipaddr.af == AF_UNSPEC) request->dst_ipaddr = server_ipaddr; if (!request->code) request->code = packet_code; /* * Sanity check. */ if (!request->code) { fprintf(stderr, "dhcpclient: Command was %s, and request did not contain DHCP-Message-Type nor Packet-Type.\n", (argc >= 3) ? "'auto'" : "unspecified"); exit(1); } if ((request->code == PW_DHCP_RELEASE) || (request->code == PW_DHCP_DECLINE)) { /* These kind of packets do not get a reply, so don't wait for one. */ reply_expected = false; } /* * Encode the packet */ if (fr_dhcp_encode(request) < 0) { fprintf(stderr, "dhcpclient: failed encoding: %s\n", fr_strerror()); fr_exit_now(1); } if (fr_debug_lvl) print_hex(request); #ifdef HAVE_LINUX_IF_PACKET_H if (raw_mode) { if (fr_dhcp_send_raw_packet(sockfd, &ll, request) < 0) { fprintf(stderr, "dhcpclient: failed sending (fr_dhcp_send_raw_packet): %s\n", fr_syserror(errno)); fr_exit_now(1); } if (reply_expected) { reply = fr_dhcp_recv_raw_loop(sockfd, &ll, request); if (!reply) { fprintf(stderr, "dhcpclient: Error receiving reply (fr_dhcp_recv_raw_loop)\n"); fr_exit_now(1); } } } else #endif { send_with_socket(request); } dict_free(); if (success) return 0; return 1; }
/** Prints a simple backtrace (if execinfo is available) and calls panic_action if set. * * @param sig caught */ NEVER_RETURNS void fr_fault(int sig) { char cmd[sizeof(panic_action) + 20]; char *out = cmd; size_t left = sizeof(cmd), ret; char const *p = panic_action; char const *q; int code; /* * If a debugger is attached, we don't want to run the panic action, * as it may interfere with the operation of the debugger. * If something calls us directly we just raise the signal and let * the debugger handle it how it wants. */ if (fr_debug_state == DEBUG_STATE_ATTACHED) { FR_FAULT_LOG("RAISING SIGNAL: %s", strsignal(sig)); raise(sig); goto finish; } /* * Makes the backtraces slightly cleaner */ memset(cmd, 0, sizeof(cmd)); FR_FAULT_LOG("CAUGHT SIGNAL: %s", strsignal(sig)); /* * Check for administrator sanity. */ if (fr_fault_check_permissions() < 0) { FR_FAULT_LOG("Refusing to execute panic action: %s", fr_strerror()); goto finish; } /* * Run the callback if one was registered */ if (panic_cb && (panic_cb(sig) < 0)) goto finish; /* * Produce a simple backtrace - They're very basic but at least give us an * idea of the area of the code we hit the issue in. * * See below in fr_fault_setup() and * https://sourceware.org/bugzilla/show_bug.cgi?id=16159 * for why we only print backtraces in debug builds if we're using GLIBC. */ #if defined(HAVE_EXECINFO) && (!defined(NDEBUG) || !defined(__GNUC__)) if (fr_fault_log_fd >= 0) { size_t frame_count; void *stack[MAX_BT_FRAMES]; frame_count = backtrace(stack, MAX_BT_FRAMES); FR_FAULT_LOG("Backtrace of last %zu frames:", frame_count); backtrace_symbols_fd(stack, frame_count, fr_fault_log_fd); } #endif /* No panic action set... */ if (panic_action[0] == '\0') { FR_FAULT_LOG("No panic action set"); goto finish; } /* Substitute %p for the current PID (useful for attaching a debugger) */ while ((q = strstr(p, "%p"))) { out += ret = snprintf(out, left, "%.*s%d", (int) (q - p), p, (int) getpid()); if (left <= ret) { oob: FR_FAULT_LOG("Panic action too long"); fr_exit_now(1); } left -= ret; p = q + 2; } if (strlen(p) >= left) goto oob; strlcpy(out, p, left); { bool disable = false; FR_FAULT_LOG("Calling: %s", cmd); /* * Here we temporarily enable the dumpable flag so if GBD or LLDB * is called in the panic_action, they can pattach to the running * process. */ if (fr_get_dumpable_flag() == 0) { if ((fr_set_dumpable_flag(true) < 0) || !fr_get_dumpable_flag()) { FR_FAULT_LOG("Failed setting dumpable flag, pattach may not work: %s", fr_strerror()); } else { disable = true; } FR_FAULT_LOG("Temporarily setting PR_DUMPABLE to 1"); } code = system(cmd); /* * We only want to error out here, if dumpable was originally disabled * and we managed to change the value to enabled, but failed * setting it back to disabled. */ if (disable) { FR_FAULT_LOG("Resetting PR_DUMPABLE to 0"); if (fr_set_dumpable_flag(false) < 0) { FR_FAULT_LOG("Failed resetting dumpable flag to off: %s", fr_strerror()); FR_FAULT_LOG("Exiting due to insecure process state"); fr_exit_now(1); } } FR_FAULT_LOG("Panic action exited with %i", code); fr_exit_now(code); } finish: /* * (Re-)Raise the signal, so that if we're running under * a debugger, the debugger can break when it receives * the signal. */ fr_unset_signal(sig); /* Make sure we don't get into a loop */ raise(sig); fr_exit_now(1); /* Function marked as noreturn */ }
int main(int argc, char **argv) { static uint16_t server_port = 0; static int packet_code = 0; static fr_ipaddr_t server_ipaddr; static fr_ipaddr_t client_ipaddr; int c; char const *raddb_dir = RADDBDIR; char const *dict_dir = DICTDIR; char const *filename = NULL; RADIUS_PACKET *request = NULL; RADIUS_PACKET *reply = NULL; TALLOC_CTX *autofree = talloc_autofree_context(); int ret; fr_debug_lvl = 1; fr_log_fp = stdout; while ((c = getopt(argc, argv, "d:D:f:hr:t:vxi:")) != -1) switch(c) { case 'D': dict_dir = optarg; break; case 'd': raddb_dir = optarg; break; case 'f': filename = optarg; break; case 'i': iface = optarg; break; case 'r': if (!isdigit((int) *optarg)) usage(); retries = atoi(optarg); if ((retries == 0) || (retries > 1000)) usage(); break; case 't': if (!isdigit((int) *optarg)) usage(); timeout = atof(optarg); break; case 'v': DEBUG("%s", dhcpclient_version); exit(0); case 'x': fr_debug_lvl++; break; case 'h': default: usage(); } argc -= (optind - 1); argv += (optind - 1); if (argc < 2) usage(); /* convert timeout to a struct timeval */ #define USEC 1000000 tv_timeout.tv_sec = timeout; tv_timeout.tv_usec = ((timeout - (float) tv_timeout.tv_sec) * USEC); if (fr_dict_global_init(autofree, dict_dir) < 0) { fr_perror("dhcpclient"); exit(EXIT_FAILURE); } if (fr_dict_autoload(dhcpclient_dict) < 0) { fr_perror("dhcpclient"); exit(EXIT_FAILURE); } if (fr_dict_attr_autoload(dhcpclient_dict_attr) < 0) { fr_perror("dhcpclient"); exit(EXIT_FAILURE); } if (fr_dict_read(dict_freeradius, raddb_dir, FR_DICTIONARY_FILE) == -1) { fr_perror("dhcpclient"); exit(EXIT_FAILURE); } fr_strerror(); /* Clear the error buffer */ /* * Initialise the DHCPv4 library */ fr_dhcpv4_global_init(); /* * Resolve hostname. */ server_ipaddr.af = AF_INET; if (strcmp(argv[1], "-") != 0) { if (fr_inet_pton_port(&server_ipaddr, &server_port, argv[1], strlen(argv[1]), AF_UNSPEC, true, true) < 0) { fr_perror("dhcpclient"); fr_exit_now(1); } client_ipaddr.af = server_ipaddr.af; } /* * See what kind of request we want to send. */ if (argc >= 3) { if (!isdigit((int) argv[2][0])) { packet_code = fr_str2int(request_types, argv[2], -2); if (packet_code == -2) { ERROR("Unknown packet type: %s", argv[2]); usage(); } } else { packet_code = atoi(argv[2]); } } if (!server_port) server_port = 67; /* * set "raw mode" if an interface is specified and if destination * IP address is the broadcast address. */ if (iface) { iface_ind = if_nametoindex(iface); if (iface_ind <= 0) { ERROR("Unknown interface: %s", iface); exit(EXIT_FAILURE); } if (server_ipaddr.addr.v4.s_addr == 0xFFFFFFFF) { ERROR("Using interface: %s (index: %d) in raw packet mode", iface, iface_ind); raw_mode = true; } } request = request_init(filename); if (!request || !request->vps) { ERROR("Nothing to send"); exit(EXIT_FAILURE); } /* * Set defaults if they weren't specified via pairs */ if (request->src_port == 0) request->src_port = server_port + 1; if (request->dst_port == 0) request->dst_port = server_port; if (request->src_ipaddr.af == AF_UNSPEC) request->src_ipaddr = client_ipaddr; if (request->dst_ipaddr.af == AF_UNSPEC) request->dst_ipaddr = server_ipaddr; if (!request->code) request->code = packet_code; /* * Sanity check. */ if (!request->code) { ERROR("Command was %s, and request did not contain DHCP-Message-Type nor Packet-Type", (argc >= 3) ? "'auto'" : "unspecified"); exit(EXIT_FAILURE); } /* * These kind of packets do not get a reply, so don't wait for one. */ if ((request->code == FR_DHCP_RELEASE) || (request->code == FR_DHCP_DECLINE)) { reply_expected = false; } /* * Encode the packet */ if (fr_dhcpv4_packet_encode(request) < 0) { ERROR("Failed encoding packet"); exit(EXIT_FAILURE); } /* * Decode to produce VALUE_PAIRs from the default field */ if (fr_debug_lvl) { fr_dhcpv4_packet_decode(request); dhcp_packet_debug(request, false); } #ifdef HAVE_LIBPCAP if (raw_mode) { ret = send_with_pcap(&reply, request); } else #endif { ret = send_with_socket(&reply, request); } if (reply) { if (fr_dhcpv4_packet_decode(reply) < 0) { ERROR("Failed decoding packet"); ret = -1; } dhcp_packet_debug(reply, true); } fr_dhcpv4_global_free(); fr_dict_autofree(dhcpclient_dict); return ret < 0 ? 1 : 0; }