diff --git a/usr.sbin/ancontrol/ancontrol.c b/usr.sbin/ancontrol/ancontrol.c index 008970d9b08e..4a114538a19f 100644 --- a/usr.sbin/ancontrol/ancontrol.c +++ b/usr.sbin/ancontrol/ancontrol.c @@ -1,1781 +1,1780 @@ /* * Copyright 1997, 1998, 1999 * Bill Paul . All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Bill Paul. * 4. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ #if 0 #ifndef lint static const char copyright[] = "@(#) Copyright (c) 1997, 1998, 1999\ Bill Paul. All rights reserved."; #endif #endif #include __FBSDID("$FreeBSD$"); #include -#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static int an_getval(const char *, struct an_req *); static void an_setval(const char *, struct an_req *); static void an_printwords(const u_int16_t *, int); static void an_printspeeds(const u_int8_t *, int); static void an_printbool(int); static void an_printhex(const char *, int); static void an_printstr(char *, int); static void an_dumpstatus(const char *); static void an_dumpstats(const char *); static void an_dumpconfig(const char *); static void an_dumpcaps(const char *); static void an_dumpssid(const char *); static void an_dumpap(const char *); static void an_setconfig(const char *, int, void *); static void an_setssid(const char *, int, void *); static void an_setap(const char *, int, void *); static void an_setspeed(const char *, int, void *); static void an_readkeyinfo(const char *); #ifdef ANCACHE static void an_zerocache(const char *); static void an_readcache(const char *); #endif static int an_hex2int(char); static void an_str2key(const char *, struct an_ltv_key *); static void an_setkeys(const char *, const char *, int); static void an_enable_tx_key(const char *, const char *); static void an_enable_leap_mode(const char *, const char *); static void an_dumprssimap(const char *); static void usage(const char *); #define ACT_DUMPSTATS 1 #define ACT_DUMPCONFIG 2 #define ACT_DUMPSTATUS 3 #define ACT_DUMPCAPS 4 #define ACT_DUMPSSID 5 #define ACT_DUMPAP 6 #define ACT_SET_OPMODE 7 #define ACT_SET_SSID 8 #define ACT_SET_FREQ 11 #define ACT_SET_AP1 12 #define ACT_SET_AP2 13 #define ACT_SET_AP3 14 #define ACT_SET_AP4 15 #define ACT_SET_DRIVERNAME 16 #define ACT_SET_SCANMODE 17 #define ACT_SET_TXRATE 18 #define ACT_SET_RTS_THRESH 19 #define ACT_SET_PWRSAVE 20 #define ACT_SET_DIVERSITY_RX 21 #define ACT_SET_DIVERSITY_TX 22 #define ACT_SET_RTS_RETRYLIM 23 #define ACT_SET_WAKE_DURATION 24 #define ACT_SET_BEACON_PERIOD 25 #define ACT_SET_TXPWR 26 #define ACT_SET_FRAG_THRESH 27 #define ACT_SET_NETJOIN 28 #define ACT_SET_MYNAME 29 #define ACT_SET_MAC 30 #define ACT_DUMPCACHE 31 #define ACT_ZEROCACHE 32 #define ACT_ENABLE_WEP 33 #define ACT_SET_KEY_TYPE 34 #define ACT_SET_KEYS 35 #define ACT_ENABLE_TX_KEY 36 #define ACT_SET_MONITOR_MODE 37 #define ACT_SET_LEAP_MODE 38 #define ACT_DUMPRSSIMAP 39 static int an_getval(const char *iface, struct an_req *areq) { struct ifreq ifr; int s, okay = 1; bzero(&ifr, sizeof(ifr)); strlcpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name)); ifr.ifr_data = (caddr_t)areq; s = socket(AF_INET, SOCK_DGRAM, 0); if (s == -1) err(1, "socket"); if (ioctl(s, SIOCGAIRONET, &ifr) == -1) { okay = 0; err(1, "SIOCGAIRONET"); } close(s); return (okay); } static void an_setval(const char *iface, struct an_req *areq) { struct ifreq ifr; int s; bzero(&ifr, sizeof(ifr)); strlcpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name)); ifr.ifr_data = (caddr_t)areq; s = socket(AF_INET, SOCK_DGRAM, 0); if (s == -1) err(1, "socket"); if (ioctl(s, SIOCSAIRONET, &ifr) == -1) err(1, "SIOCSAIRONET"); close(s); return; } static void an_printstr(char *str, int len) { int i; for (i = 0; i < len - 1; i++) { if (str[i] == '\0') str[i] = ' '; } printf("[ %.*s ]", len, str); } static void an_printwords(const u_int16_t *w, int len) { int i; printf("[ "); for (i = 0; i < len; i++) printf("%u ", w[i]); printf("]"); } static void an_printspeeds(const u_int8_t *w, int len) { int i; printf("[ "); for (i = 0; i < len && w[i]; i++) printf("%2.1fMbps ", w[i] * 0.500); printf("]"); } static void an_printbool(int val) { if (val) printf("[ On ]"); else printf("[ Off ]"); } static void an_printhex(const char *ptr, int len) { int i; printf("[ "); for (i = 0; i < len; i++) { printf("%02x", ptr[i] & 0xFF); if (i < (len - 1)) printf(":"); } printf(" ]"); } static void an_dumpstatus(const char *iface) { struct an_ltv_status *sts; struct an_req areq; struct an_ltv_rssi_map an_rssimap; int rssimap_valid = 0; /* * Try to get RSSI to percent and dBM table */ an_rssimap.an_len = sizeof(an_rssimap); an_rssimap.an_type = AN_RID_RSSI_MAP; rssimap_valid = an_getval(iface, (struct an_req*)&an_rssimap); if (rssimap_valid) printf("RSSI table:\t\t[ present ]\n"); else printf("RSSI table:\t\t[ not available ]\n"); areq.an_len = sizeof(areq); areq.an_type = AN_RID_STATUS; an_getval(iface, &areq); sts = (struct an_ltv_status *)&areq; printf("MAC address:\t\t"); an_printhex((char *)&sts->an_macaddr, ETHER_ADDR_LEN); printf("\nOperating mode:\t\t[ "); if (sts->an_opmode & AN_STATUS_OPMODE_CONFIGURED) printf("configured "); if (sts->an_opmode & AN_STATUS_OPMODE_MAC_ENABLED) printf("MAC ON "); if (sts->an_opmode & AN_STATUS_OPMODE_RX_ENABLED) printf("RX ON "); if (sts->an_opmode & AN_STATUS_OPMODE_IN_SYNC) printf("synced "); if (sts->an_opmode & AN_STATUS_OPMODE_ASSOCIATED) printf("associated "); if (sts->an_opmode & AN_STATUS_OPMODE_LEAP) printf("LEAP "); if (sts->an_opmode & AN_STATUS_OPMODE_ERROR) printf("error "); printf("]\n"); printf("Error code:\t\t"); an_printhex((char *)&sts->an_errcode, 1); if (rssimap_valid) printf("\nSignal strength:\t[ %u%% ]", an_rssimap.an_entries[ sts->an_normalized_strength].an_rss_pct); else printf("\nSignal strength:\t[ %u%% ]", sts->an_normalized_strength); printf("\nAverage Noise:\t\t[ %u%% ]", sts->an_avg_noise_prev_min_pc); if (rssimap_valid) printf("\nSignal quality:\t\t[ %u%% ]", an_rssimap.an_entries[ sts->an_cur_signal_quality].an_rss_pct); else printf("\nSignal quality:\t\t[ %u ]", sts->an_cur_signal_quality); printf("\nMax Noise:\t\t[ %u%% ]", sts->an_max_noise_prev_min_pc); /* * XXX: This uses the old definition of the rate field (units of * 500kbps). Technically the new definition is that this field * contains arbitrary values, but no devices which need this * support exist and the IEEE seems to intend to use the old * definition until they get something big so we'll keep using * it as well because this will work with new cards with * rate <= 63.5Mbps. */ printf("\nCurrent TX rate:\t[ %u%s ]", sts->an_current_tx_rate / 2, (sts->an_current_tx_rate % 2) ? ".5" : ""); printf("\nCurrent SSID:\t\t"); an_printstr((char *)&sts->an_ssid, sts->an_ssidlen); printf("\nCurrent AP name:\t"); an_printstr((char *)&sts->an_ap_name, 16); printf("\nCurrent BSSID:\t\t"); an_printhex((char *)&sts->an_cur_bssid, ETHER_ADDR_LEN); printf("\nBeacon period:\t\t"); an_printwords(&sts->an_beacon_period, 1); printf("\nDTIM period:\t\t"); an_printwords(&sts->an_dtim_period, 1); printf("\nATIM duration:\t\t"); an_printwords(&sts->an_atim_duration, 1); printf("\nHOP period:\t\t"); an_printwords(&sts->an_hop_period, 1); printf("\nChannel set:\t\t"); an_printwords(&sts->an_channel_set, 1); printf("\nCurrent channel:\t"); an_printwords(&sts->an_cur_channel, 1); printf("\nHops to backbone:\t"); an_printwords(&sts->an_hops_to_backbone, 1); printf("\nTotal AP load:\t\t"); an_printwords(&sts->an_ap_total_load, 1); printf("\nOur generated load:\t"); an_printwords(&sts->an_our_generated_load, 1); printf("\nAccumulated ARL:\t"); an_printwords(&sts->an_accumulated_arl, 1); printf("\n"); return; } static void an_dumpcaps(const char *iface) { struct an_ltv_caps *caps; struct an_req areq; u_int16_t tmp; areq.an_len = sizeof(areq); areq.an_type = AN_RID_CAPABILITIES; an_getval(iface, &areq); caps = (struct an_ltv_caps *)&areq; printf("OUI:\t\t\t"); an_printhex((char *)&caps->an_oui, 3); printf("\nProduct number:\t\t"); an_printwords(&caps->an_prodnum, 1); printf("\nManufacturer name:\t"); an_printstr((char *)&caps->an_manufname, 32); printf("\nProduce name:\t\t"); an_printstr((char *)&caps->an_prodname, 16); printf("\nFirmware version:\t"); an_printstr((char *)&caps->an_prodvers, 1); printf("\nOEM MAC address:\t"); an_printhex((char *)&caps->an_oemaddr, ETHER_ADDR_LEN); printf("\nAironet MAC address:\t"); an_printhex((char *)&caps->an_aironetaddr, ETHER_ADDR_LEN); printf("\nRadio type:\t\t[ "); if (caps->an_radiotype & AN_RADIOTYPE_80211_FH) printf("802.11 FH"); else if (caps->an_radiotype & AN_RADIOTYPE_80211_DS) printf("802.11 DS"); else if (caps->an_radiotype & AN_RADIOTYPE_LM2000_DS) printf("LM2000 DS"); else printf("unknown (%x)", caps->an_radiotype); printf(" ]"); printf("\nRegulatory domain:\t"); an_printwords(&caps->an_regdomain, 1); printf("\nAssigned CallID:\t"); an_printhex((char *)&caps->an_callid, 6); printf("\nSupported speeds:\t"); an_printspeeds(caps->an_rates, 8); printf("\nRX Diversity:\t\t[ "); if (caps->an_rx_diversity == AN_DIVERSITY_FACTORY_DEFAULT) printf("factory default"); else if (caps->an_rx_diversity == AN_DIVERSITY_ANTENNA_1_ONLY) printf("antenna 1 only"); else if (caps->an_rx_diversity == AN_DIVERSITY_ANTENNA_2_ONLY) printf("antenna 2 only"); else if (caps->an_rx_diversity == AN_DIVERSITY_ANTENNA_1_AND_2) printf("antenna 1 and 2"); printf(" ]"); printf("\nTX Diversity:\t\t[ "); if (caps->an_tx_diversity == AN_DIVERSITY_FACTORY_DEFAULT) printf("factory default"); else if (caps->an_tx_diversity == AN_DIVERSITY_ANTENNA_1_ONLY) printf("antenna 1 only"); else if (caps->an_tx_diversity == AN_DIVERSITY_ANTENNA_2_ONLY) printf("antenna 2 only"); else if (caps->an_tx_diversity == AN_DIVERSITY_ANTENNA_1_AND_2) printf("antenna 1 and 2"); printf(" ]"); printf("\nSupported power levels:\t"); an_printwords(caps->an_tx_powerlevels, 8); printf("\nHardware revision:\t"); tmp = ntohs(caps->an_hwrev); an_printhex((char *)&tmp, 2); printf("\nSoftware revision:\t"); tmp = ntohs(caps->an_fwrev); an_printhex((char *)&tmp, 2); printf("\nSoftware subrevision:\t"); tmp = ntohs(caps->an_fwsubrev); an_printhex((char *)&tmp, 2); printf("\nInterface revision:\t"); tmp = ntohs(caps->an_ifacerev); an_printhex((char *)&tmp, 2); printf("\nBootblock revision:\t"); tmp = ntohs(caps->an_bootblockrev); an_printhex((char *)&tmp, 2); printf("\n"); return; } static void an_dumpstats(const char *iface) { struct an_ltv_stats *stats; struct an_req areq; areq.an_len = sizeof(areq); areq.an_type = AN_RID_32BITS_CUM; an_getval(iface, &areq); stats = (struct an_ltv_stats *)((uint16_t *)&areq - 1); printf("RX overruns:\t\t\t\t\t[ %u ]\n", stats->an_rx_overruns); printf("RX PLCP CSUM errors:\t\t\t\t[ %u ]\n", stats->an_rx_plcp_csum_errs); printf("RX PLCP format errors:\t\t\t\t[ %u ]\n", stats->an_rx_plcp_format_errs); printf("RX PLCP length errors:\t\t\t\t[ %u ]\n", stats->an_rx_plcp_len_errs); printf("RX MAC CRC errors:\t\t\t\t[ %u ]\n", stats->an_rx_mac_crc_errs); printf("RX MAC CRC OK:\t\t\t\t\t[ %u ]\n", stats->an_rx_mac_crc_ok); printf("RX WEP errors:\t\t\t\t\t[ %u ]\n", stats->an_rx_wep_errs); printf("RX WEP OK:\t\t\t\t\t[ %u ]\n", stats->an_rx_wep_ok); printf("Long retries:\t\t\t\t\t[ %u ]\n", stats->an_retry_long); printf("Short retries:\t\t\t\t\t[ %u ]\n", stats->an_retry_short); printf("Retries exhausted:\t\t\t\t[ %u ]\n", stats->an_retry_max); printf("Bad ACK:\t\t\t\t\t[ %u ]\n", stats->an_no_ack); printf("Bad CTS:\t\t\t\t\t[ %u ]\n", stats->an_no_cts); printf("RX good ACKs:\t\t\t\t\t[ %u ]\n", stats->an_rx_ack_ok); printf("RX good CTSs:\t\t\t\t\t[ %u ]\n", stats->an_rx_cts_ok); printf("TX good ACKs:\t\t\t\t\t[ %u ]\n", stats->an_tx_ack_ok); printf("TX good RTSs:\t\t\t\t\t[ %u ]\n", stats->an_tx_rts_ok); printf("TX good CTSs:\t\t\t\t\t[ %u ]\n", stats->an_tx_cts_ok); printf("LMAC multicasts transmitted:\t\t\t[ %u ]\n", stats->an_tx_lmac_mcasts); printf("LMAC broadcasts transmitted:\t\t\t[ %u ]\n", stats->an_tx_lmac_bcasts); printf("LMAC unicast frags transmitted:\t\t\t[ %u ]\n", stats->an_tx_lmac_ucast_frags); printf("LMAC unicasts transmitted:\t\t\t[ %u ]\n", stats->an_tx_lmac_ucasts); printf("Beacons transmitted:\t\t\t\t[ %u ]\n", stats->an_tx_beacons); printf("Beacons received:\t\t\t\t[ %u ]\n", stats->an_rx_beacons); printf("Single transmit collisions:\t\t\t[ %u ]\n", stats->an_tx_single_cols); printf("Multiple transmit collisions:\t\t\t[ %u ]\n", stats->an_tx_multi_cols); printf("Transmits without deferrals:\t\t\t[ %u ]\n", stats->an_tx_defers_no); printf("Transmits deferred due to protocol:\t\t[ %u ]\n", stats->an_tx_defers_prot); printf("Transmits deferred due to energy detect:\t\t[ %u ]\n", stats->an_tx_defers_energy); printf("RX duplicate frames/frags:\t\t\t[ %u ]\n", stats->an_rx_dups); printf("RX partial frames:\t\t\t\t[ %u ]\n", stats->an_rx_partial); printf("TX max lifetime exceeded:\t\t\t[ %u ]\n", stats->an_tx_too_old); printf("RX max lifetime exceeded:\t\t\t[ %u ]\n", stats->an_tx_too_old); printf("Sync lost due to too many missed beacons:\t[ %u ]\n", stats->an_lostsync_missed_beacons); printf("Sync lost due to ARL exceeded:\t\t\t[ %u ]\n", stats->an_lostsync_arl_exceeded); printf("Sync lost due to deauthentication:\t\t[ %u ]\n", stats->an_lostsync_deauthed); printf("Sync lost due to disassociation:\t\t[ %u ]\n", stats->an_lostsync_disassociated); printf("Sync lost due to excess change in TSF timing:\t[ %u ]\n", stats->an_lostsync_tsf_timing); printf("Host transmitted multicasts:\t\t\t[ %u ]\n", stats->an_tx_host_mcasts); printf("Host transmitted broadcasts:\t\t\t[ %u ]\n", stats->an_tx_host_bcasts); printf("Host transmitted unicasts:\t\t\t[ %u ]\n", stats->an_tx_host_ucasts); printf("Host transmission failures:\t\t\t[ %u ]\n", stats->an_tx_host_failed); printf("Host received multicasts:\t\t\t[ %u ]\n", stats->an_rx_host_mcasts); printf("Host received broadcasts:\t\t\t[ %u ]\n", stats->an_rx_host_bcasts); printf("Host received unicasts:\t\t\t\t[ %u ]\n", stats->an_rx_host_ucasts); printf("Host receive discards:\t\t\t\t[ %u ]\n", stats->an_rx_host_discarded); printf("HMAC transmitted multicasts:\t\t\t[ %u ]\n", stats->an_tx_hmac_mcasts); printf("HMAC transmitted broadcasts:\t\t\t[ %u ]\n", stats->an_tx_hmac_bcasts); printf("HMAC transmitted unicasts:\t\t\t[ %u ]\n", stats->an_tx_hmac_ucasts); printf("HMAC transmissions failed:\t\t\t[ %u ]\n", stats->an_tx_hmac_failed); printf("HMAC received multicasts:\t\t\t[ %u ]\n", stats->an_rx_hmac_mcasts); printf("HMAC received broadcasts:\t\t\t[ %u ]\n", stats->an_rx_hmac_bcasts); printf("HMAC received unicasts:\t\t\t\t[ %u ]\n", stats->an_rx_hmac_ucasts); printf("HMAC receive discards:\t\t\t\t[ %u ]\n", stats->an_rx_hmac_discarded); printf("HMAC transmits accepted:\t\t\t[ %u ]\n", stats->an_tx_hmac_accepted); printf("SSID mismatches:\t\t\t\t[ %u ]\n", stats->an_ssid_mismatches); printf("Access point mismatches:\t\t\t[ %u ]\n", stats->an_ap_mismatches); printf("Speed mismatches:\t\t\t\t[ %u ]\n", stats->an_rates_mismatches); printf("Authentication rejects:\t\t\t\t[ %u ]\n", stats->an_auth_rejects); printf("Authentication timeouts:\t\t\t[ %u ]\n", stats->an_auth_timeouts); printf("Association rejects:\t\t\t\t[ %u ]\n", stats->an_assoc_rejects); printf("Association timeouts:\t\t\t\t[ %u ]\n", stats->an_assoc_timeouts); printf("Management frames received:\t\t\t[ %u ]\n", stats->an_rx_mgmt_pkts); printf("Management frames transmitted:\t\t\t[ %u ]\n", stats->an_tx_mgmt_pkts); printf("Refresh frames received:\t\t\t[ %u ]\n", stats->an_rx_refresh_pkts), printf("Refresh frames transmitted:\t\t\t[ %u ]\n", stats->an_tx_refresh_pkts), printf("Poll frames received:\t\t\t\t[ %u ]\n", stats->an_rx_poll_pkts); printf("Poll frames transmitted:\t\t\t[ %u ]\n", stats->an_tx_poll_pkts); printf("Host requested sync losses:\t\t\t[ %u ]\n", stats->an_lostsync_hostreq); printf("Host transmitted bytes:\t\t\t\t[ %u ]\n", stats->an_host_tx_bytes); printf("Host received bytes:\t\t\t\t[ %u ]\n", stats->an_host_rx_bytes); printf("Uptime in microseconds:\t\t\t\t[ %u ]\n", stats->an_uptime_usecs); printf("Uptime in seconds:\t\t\t\t[ %u ]\n", stats->an_uptime_secs); printf("Sync lost due to better AP:\t\t\t[ %u ]\n", stats->an_lostsync_better_ap); } static void an_dumpap(const char *iface) { struct an_ltv_aplist *ap; struct an_req areq; areq.an_len = sizeof(areq); areq.an_type = AN_RID_APLIST; an_getval(iface, &areq); ap = (struct an_ltv_aplist *)&areq; printf("Access point 1:\t\t\t"); an_printhex((char *)&ap->an_ap1, ETHER_ADDR_LEN); printf("\nAccess point 2:\t\t\t"); an_printhex((char *)&ap->an_ap2, ETHER_ADDR_LEN); printf("\nAccess point 3:\t\t\t"); an_printhex((char *)&ap->an_ap3, ETHER_ADDR_LEN); printf("\nAccess point 4:\t\t\t"); an_printhex((char *)&ap->an_ap4, ETHER_ADDR_LEN); printf("\n"); return; } static void an_dumpssid(const char *iface) { struct an_ltv_ssidlist_new *ssid; struct an_req areq; int i, max; areq.an_len = sizeof(areq); areq.an_type = AN_RID_SSIDLIST; an_getval(iface, &areq); max = (areq.an_len - 4) / sizeof(struct an_ltv_ssid_entry); if ( max > MAX_SSIDS ) { printf("Too many SSIDs only printing %d of %d\n", MAX_SSIDS, max); max = MAX_SSIDS; } ssid = (struct an_ltv_ssidlist_new *)&areq; for (i = 0; i < max; i++) printf("SSID %2d:\t\t\t[ %.*s ]\n", i + 1, ssid->an_entry[i].an_len, ssid->an_entry[i].an_ssid); return; } static void an_dumpconfig(const char *iface) { struct an_ltv_genconfig *cfg; struct an_req areq; unsigned char diversity; areq.an_len = sizeof(areq); areq.an_type = AN_RID_ACTUALCFG; an_getval(iface, &areq); cfg = (struct an_ltv_genconfig *)&areq; printf("Operating mode:\t\t\t\t[ "); if ((cfg->an_opmode & 0x7) == AN_OPMODE_IBSS_ADHOC) printf("ad-hoc"); if ((cfg->an_opmode & 0x7) == AN_OPMODE_INFRASTRUCTURE_STATION) printf("infrastructure"); if ((cfg->an_opmode & 0x7) == AN_OPMODE_AP) printf("access point"); if ((cfg->an_opmode & 0x7) == AN_OPMODE_AP_REPEATER) printf("access point repeater"); printf(" ]"); printf("\nReceive mode:\t\t\t\t[ "); if ((cfg->an_rxmode & 0x7) == AN_RXMODE_BC_MC_ADDR) printf("broadcast/multicast/unicast"); if ((cfg->an_rxmode & 0x7) == AN_RXMODE_BC_ADDR) printf("broadcast/unicast"); if ((cfg->an_rxmode & 0x7) == AN_RXMODE_ADDR) printf("unicast"); if ((cfg->an_rxmode & 0x7) == AN_RXMODE_80211_MONITOR_CURBSS) printf("802.11 monitor, current BSSID"); if ((cfg->an_rxmode & 0x7) == AN_RXMODE_80211_MONITOR_ANYBSS) printf("802.11 monitor, any BSSID"); if ((cfg->an_rxmode & 0x7) == AN_RXMODE_LAN_MONITOR_CURBSS) printf("LAN monitor, current BSSID"); printf(" ]"); printf("\nFragment threshold:\t\t\t"); an_printwords(&cfg->an_fragthresh, 1); printf("\nRTS threshold:\t\t\t\t"); an_printwords(&cfg->an_rtsthresh, 1); printf("\nMAC address:\t\t\t\t"); an_printhex((char *)&cfg->an_macaddr, ETHER_ADDR_LEN); printf("\nSupported rates:\t\t\t"); an_printspeeds(cfg->an_rates, 8); printf("\nShort retry limit:\t\t\t"); an_printwords(&cfg->an_shortretry_limit, 1); printf("\nLong retry limit:\t\t\t"); an_printwords(&cfg->an_longretry_limit, 1); printf("\nTX MSDU lifetime:\t\t\t"); an_printwords(&cfg->an_tx_msdu_lifetime, 1); printf("\nRX MSDU lifetime:\t\t\t"); an_printwords(&cfg->an_rx_msdu_lifetime, 1); printf("\nStationary:\t\t\t\t"); an_printbool(cfg->an_stationary); printf("\nOrdering:\t\t\t\t"); an_printbool(cfg->an_ordering); printf("\nDevice type:\t\t\t\t[ "); if (cfg->an_devtype == AN_DEVTYPE_PC4500) printf("PC4500"); else if (cfg->an_devtype == AN_DEVTYPE_PC4800) printf("PC4800"); else printf("unknown (%x)", cfg->an_devtype); printf(" ]"); printf("\nScanning mode:\t\t\t\t[ "); if (cfg->an_scanmode == AN_SCANMODE_ACTIVE) printf("active"); if (cfg->an_scanmode == AN_SCANMODE_PASSIVE) printf("passive"); if (cfg->an_scanmode == AN_SCANMODE_AIRONET_ACTIVE) printf("Aironet active"); printf(" ]"); printf("\nProbe delay:\t\t\t\t"); an_printwords(&cfg->an_probedelay, 1); printf("\nProbe energy timeout:\t\t\t"); an_printwords(&cfg->an_probe_energy_timeout, 1); printf("\nProbe response timeout:\t\t\t"); an_printwords(&cfg->an_probe_response_timeout, 1); printf("\nBeacon listen timeout:\t\t\t"); an_printwords(&cfg->an_beacon_listen_timeout, 1); printf("\nIBSS join network timeout:\t\t"); an_printwords(&cfg->an_ibss_join_net_timeout, 1); printf("\nAuthentication timeout:\t\t\t"); an_printwords(&cfg->an_auth_timeout, 1); printf("\nWEP enabled:\t\t\t\t[ "); if (cfg->an_authtype & AN_AUTHTYPE_PRIVACY_IN_USE) { if (cfg->an_authtype & AN_AUTHTYPE_LEAP) printf("LEAP"); else if (cfg->an_authtype & AN_AUTHTYPE_ALLOW_UNENCRYPTED) printf("mixed cell"); else printf("full"); } else printf("no"); printf(" ]"); printf("\nAuthentication type:\t\t\t[ "); if ((cfg->an_authtype & AN_AUTHTYPE_MASK) == AN_AUTHTYPE_NONE) printf("none"); if ((cfg->an_authtype & AN_AUTHTYPE_MASK) == AN_AUTHTYPE_OPEN) printf("open"); if ((cfg->an_authtype & AN_AUTHTYPE_MASK) == AN_AUTHTYPE_SHAREDKEY) printf("shared key"); printf(" ]"); printf("\nAssociation timeout:\t\t\t"); an_printwords(&cfg->an_assoc_timeout, 1); printf("\nSpecified AP association timeout:\t"); an_printwords(&cfg->an_specified_ap_timeout, 1); printf("\nOffline scan interval:\t\t\t"); an_printwords(&cfg->an_offline_scan_interval, 1); printf("\nOffline scan duration:\t\t\t"); an_printwords(&cfg->an_offline_scan_duration, 1); printf("\nLink loss delay:\t\t\t"); an_printwords(&cfg->an_link_loss_delay, 1); printf("\nMax beacon loss time:\t\t\t"); an_printwords(&cfg->an_max_beacon_lost_time, 1); printf("\nRefresh interval:\t\t\t"); an_printwords(&cfg->an_refresh_interval, 1); printf("\nPower save mode:\t\t\t[ "); if (cfg->an_psave_mode == AN_PSAVE_NONE) printf("none"); if (cfg->an_psave_mode == AN_PSAVE_CAM) printf("constantly awake mode"); if (cfg->an_psave_mode == AN_PSAVE_PSP) printf("PSP"); if (cfg->an_psave_mode == AN_PSAVE_PSP_CAM) printf("PSP-CAM (fast PSP)"); printf(" ]"); printf("\nSleep through DTIMs:\t\t\t"); an_printbool(cfg->an_sleep_for_dtims); printf("\nPower save listen interval:\t\t"); an_printwords(&cfg->an_listen_interval, 1); printf("\nPower save fast listen interval:\t"); an_printwords(&cfg->an_fast_listen_interval, 1); printf("\nPower save listen decay:\t\t"); an_printwords(&cfg->an_listen_decay, 1); printf("\nPower save fast listen decay:\t\t"); an_printwords(&cfg->an_fast_listen_decay, 1); printf("\nAP/ad-hoc Beacon period:\t\t"); an_printwords(&cfg->an_beacon_period, 1); printf("\nAP/ad-hoc ATIM duration:\t\t"); an_printwords(&cfg->an_atim_duration, 1); printf("\nAP/ad-hoc current channel:\t\t"); an_printwords(&cfg->an_ds_channel, 1); printf("\nAP/ad-hoc DTIM period:\t\t\t"); an_printwords(&cfg->an_dtim_period, 1); printf("\nRadio type:\t\t\t\t[ "); if (cfg->an_radiotype & AN_RADIOTYPE_80211_FH) printf("802.11 FH"); else if (cfg->an_radiotype & AN_RADIOTYPE_80211_DS) printf("802.11 DS"); else if (cfg->an_radiotype & AN_RADIOTYPE_LM2000_DS) printf("LM2000 DS"); else printf("unknown (%x)", cfg->an_radiotype); printf(" ]"); printf("\nRX Diversity:\t\t\t\t[ "); diversity = cfg->an_diversity & 0xFF; if (diversity == AN_DIVERSITY_FACTORY_DEFAULT) printf("factory default"); else if (diversity == AN_DIVERSITY_ANTENNA_1_ONLY) printf("antenna 1 only"); else if (diversity == AN_DIVERSITY_ANTENNA_2_ONLY) printf("antenna 2 only"); else if (diversity == AN_DIVERSITY_ANTENNA_1_AND_2) printf("antenna 1 and 2"); printf(" ]"); printf("\nTX Diversity:\t\t\t\t[ "); diversity = (cfg->an_diversity >> 8) & 0xFF; if (diversity == AN_DIVERSITY_FACTORY_DEFAULT) printf("factory default"); else if (diversity == AN_DIVERSITY_ANTENNA_1_ONLY) printf("antenna 1 only"); else if (diversity == AN_DIVERSITY_ANTENNA_2_ONLY) printf("antenna 2 only"); else if (diversity == AN_DIVERSITY_ANTENNA_1_AND_2) printf("antenna 1 and 2"); printf(" ]"); printf("\nTransmit power level:\t\t\t"); an_printwords(&cfg->an_tx_power, 1); printf("\nRSS threshold:\t\t\t\t"); an_printwords(&cfg->an_rss_thresh, 1); printf("\nNode name:\t\t\t\t"); an_printstr((char *)&cfg->an_nodename, 16); printf("\nARL threshold:\t\t\t\t"); an_printwords(&cfg->an_arl_thresh, 1); printf("\nARL decay:\t\t\t\t"); an_printwords(&cfg->an_arl_decay, 1); printf("\nARL delay:\t\t\t\t"); an_printwords(&cfg->an_arl_delay, 1); printf("\nConfiguration:\t\t\t\t[ "); if (cfg->an_home_product & AN_HOME_NETWORK) printf("Home Configuration"); else printf("Enterprise Configuration"); printf(" ]"); printf("\n"); printf("\n"); an_readkeyinfo(iface); } static void an_dumprssimap(const char *iface) { struct an_ltv_rssi_map *rssi; struct an_req areq; int i; areq.an_len = sizeof(areq); areq.an_type = AN_RID_RSSI_MAP; an_getval(iface, &areq); rssi = (struct an_ltv_rssi_map *)&areq; printf("idx\tpct\t dBm\n"); for (i = 0; i < 0xFF; i++) { /* * negate the dBm value: it's the only way the power * level makes sense */ printf("%3d\t%3d\t%4d\n", i, rssi->an_entries[i].an_rss_pct, - rssi->an_entries[i].an_rss_dbm); } } static void usage(const char *p) { fprintf(stderr, "usage: %s -i iface -A (show specified APs)\n", p); fprintf(stderr, "\t%s -i iface -N (show specified SSIDss)\n", p); fprintf(stderr, "\t%s -i iface -S (show NIC status)\n", p); fprintf(stderr, "\t%s -i iface -I (show NIC capabilities)\n", p); fprintf(stderr, "\t%s -i iface -T (show stats counters)\n", p); fprintf(stderr, "\t%s -i iface -C (show current config)\n", p); fprintf(stderr, "\t%s -i iface -R (show RSSI map)\n", p); fprintf(stderr, "\t%s -i iface -t 0-4 (set TX speed)\n", p); fprintf(stderr, "\t%s -i iface -s 0-3 (set power save mode)\n", p); fprintf(stderr, "\t%s -i iface [-v 1-4] -a AP (specify AP)\n", p); fprintf(stderr, "\t%s -i iface -b val (set beacon period)\n", p); fprintf(stderr, "\t%s -i iface [-v 0|1] -d val (set diversity)\n", p); fprintf(stderr, "\t%s -i iface -j val (set netjoin timeout)\n", p); fprintf(stderr, "\t%s -i iface -e 0-4 (enable transmit key)\n", p); fprintf(stderr, "\t%s -i iface [-v 0-8] -k key (set key)\n", p); fprintf(stderr, "\t%s -i iface -K 0-2 (no auth/open/shared secret)\n", p); fprintf(stderr, "\t%s -i iface -W 0-2 (no WEP/full WEP/mixed cell)\n", p); fprintf(stderr, "\t%s -i iface -l val (set station name)\n", p); fprintf(stderr, "\t%s -i iface -m val (set MAC address)\n", p); fprintf(stderr, "\t%s -i iface [-v 1-3] -n SSID " "(specify SSID)\n", p); fprintf(stderr, "\t%s -i iface -o 0|1 (set operating mode)\n", p); fprintf(stderr, "\t%s -i iface -c val (set ad-hoc channel)\n", p); fprintf(stderr, "\t%s -i iface -f val (set frag threshold)\n", p); fprintf(stderr, "\t%s -i iface -r val (set RTS threshold)\n", p); fprintf(stderr, "\t%s -i iface -M 0-15 (set monitor mode)\n", p); fprintf(stderr, "\t%s -i iface -L user (enter LEAP authentication mode)\n", p); #ifdef ANCACHE fprintf(stderr, "\t%s -i iface -Q print signal quality cache\n", p); fprintf(stderr, "\t%s -i iface -Z zero out signal cache\n", p); #endif fprintf(stderr, "\t%s -h (display this message)\n", p); exit(1); } static void an_setconfig(const char *iface, int act, void *arg) { struct an_ltv_genconfig *cfg; struct an_ltv_caps *caps; struct an_req areq; struct an_req areq_caps; u_int16_t diversity = 0; struct ether_addr *addr; int i; areq.an_len = sizeof(areq); areq.an_type = AN_RID_GENCONFIG; an_getval(iface, &areq); cfg = (struct an_ltv_genconfig *)&areq; areq_caps.an_len = sizeof(areq); areq_caps.an_type = AN_RID_CAPABILITIES; an_getval(iface, &areq_caps); caps = (struct an_ltv_caps *)&areq_caps; switch(act) { case ACT_SET_OPMODE: cfg->an_opmode = atoi(arg); break; case ACT_SET_FREQ: cfg->an_ds_channel = atoi(arg); break; case ACT_SET_PWRSAVE: cfg->an_psave_mode = atoi(arg); break; case ACT_SET_SCANMODE: cfg->an_scanmode = atoi(arg); break; case ACT_SET_DIVERSITY_RX: case ACT_SET_DIVERSITY_TX: switch(atoi(arg)) { case 0: diversity = AN_DIVERSITY_FACTORY_DEFAULT; break; case 1: diversity = AN_DIVERSITY_ANTENNA_1_ONLY; break; case 2: diversity = AN_DIVERSITY_ANTENNA_2_ONLY; break; case 3: diversity = AN_DIVERSITY_ANTENNA_1_AND_2; break; default: errx(1, "bad diversity setting: %u", diversity); break; } if (act == ACT_SET_DIVERSITY_RX) { cfg->an_diversity &= 0xFF00; cfg->an_diversity |= diversity; } else { cfg->an_diversity &= 0x00FF; cfg->an_diversity |= (diversity << 8); } break; case ACT_SET_TXPWR: for (i = 0; i < 8; i++) { if (caps->an_tx_powerlevels[i] == atoi(arg)) break; } if (i == 8) errx(1, "unsupported power level: %dmW", atoi(arg)); cfg->an_tx_power = atoi(arg); break; case ACT_SET_RTS_THRESH: cfg->an_rtsthresh = atoi(arg); break; case ACT_SET_RTS_RETRYLIM: cfg->an_shortretry_limit = cfg->an_longretry_limit = atoi(arg); break; case ACT_SET_BEACON_PERIOD: cfg->an_beacon_period = atoi(arg); break; case ACT_SET_WAKE_DURATION: cfg->an_atim_duration = atoi(arg); break; case ACT_SET_FRAG_THRESH: cfg->an_fragthresh = atoi(arg); break; case ACT_SET_NETJOIN: cfg->an_ibss_join_net_timeout = atoi(arg); break; case ACT_SET_MYNAME: bzero(cfg->an_nodename, 16); strncpy((char *)&cfg->an_nodename, optarg, 16); break; case ACT_SET_MAC: addr = ether_aton((char *)arg); if (addr == NULL) errx(1, "badly formatted address"); bzero(cfg->an_macaddr, ETHER_ADDR_LEN); bcopy(addr, &cfg->an_macaddr, ETHER_ADDR_LEN); break; case ACT_ENABLE_WEP: switch (atoi (arg)) { case 0: /* no WEP */ cfg->an_authtype &= ~(AN_AUTHTYPE_PRIVACY_IN_USE | AN_AUTHTYPE_ALLOW_UNENCRYPTED | AN_AUTHTYPE_LEAP); break; case 1: /* full WEP */ cfg->an_authtype |= AN_AUTHTYPE_PRIVACY_IN_USE; cfg->an_authtype &= ~AN_AUTHTYPE_ALLOW_UNENCRYPTED; cfg->an_authtype &= ~AN_AUTHTYPE_LEAP; break; case 2: /* mixed cell */ cfg->an_authtype = AN_AUTHTYPE_PRIVACY_IN_USE | AN_AUTHTYPE_ALLOW_UNENCRYPTED; break; } break; case ACT_SET_KEY_TYPE: cfg->an_authtype = (cfg->an_authtype & ~AN_AUTHTYPE_MASK) | atoi(arg); break; case ACT_SET_MONITOR_MODE: areq.an_type = AN_RID_MONITOR_MODE; cfg->an_len = atoi(arg); /* mode is put in length */ break; default: errx(1, "unknown action"); break; } an_setval(iface, &areq); exit(0); } static void an_setspeed(const char *iface, int act __unused, void *arg) { struct an_req areq; struct an_ltv_caps *caps; u_int16_t speed; areq.an_len = sizeof(areq); areq.an_type = AN_RID_CAPABILITIES; an_getval(iface, &areq); caps = (struct an_ltv_caps *)&areq; switch(atoi(arg)) { case 0: speed = 0; break; case 1: speed = AN_RATE_1MBPS; break; case 2: speed = AN_RATE_2MBPS; break; case 3: if (caps->an_rates[2] != AN_RATE_5_5MBPS) errx(1, "5.5Mbps not supported on this card"); speed = AN_RATE_5_5MBPS; break; case 4: if (caps->an_rates[3] != AN_RATE_11MBPS) errx(1, "11Mbps not supported on this card"); speed = AN_RATE_11MBPS; break; default: errx(1, "unsupported speed"); break; } areq.an_len = 6; areq.an_type = AN_RID_TX_SPEED; areq.an_val[0] = speed; an_setval(iface, &areq); exit(0); } static void an_setap(const char *iface, int act, void *arg) { struct an_ltv_aplist *ap; struct an_req areq; struct ether_addr *addr; areq.an_len = sizeof(areq); areq.an_type = AN_RID_APLIST; an_getval(iface, &areq); ap = (struct an_ltv_aplist *)&areq; addr = ether_aton((char *)arg); if (addr == NULL) errx(1, "badly formatted address"); switch(act) { case ACT_SET_AP1: bzero(ap->an_ap1, ETHER_ADDR_LEN); bcopy(addr, &ap->an_ap1, ETHER_ADDR_LEN); break; case ACT_SET_AP2: bzero(ap->an_ap2, ETHER_ADDR_LEN); bcopy(addr, &ap->an_ap2, ETHER_ADDR_LEN); break; case ACT_SET_AP3: bzero(ap->an_ap3, ETHER_ADDR_LEN); bcopy(addr, &ap->an_ap3, ETHER_ADDR_LEN); break; case ACT_SET_AP4: bzero(ap->an_ap4, ETHER_ADDR_LEN); bcopy(addr, &ap->an_ap4, ETHER_ADDR_LEN); break; default: errx(1, "unknown action"); break; } an_setval(iface, &areq); exit(0); } static void an_setssid(const char *iface, int act, void *arg) { struct an_ltv_ssidlist_new *ssid; struct an_req areq; int max; areq.an_len = sizeof(areq); areq.an_type = AN_RID_SSIDLIST; an_getval(iface, &areq); ssid = (struct an_ltv_ssidlist_new *)&areq; max = (areq.an_len - 4) / sizeof(struct an_ltv_ssid_entry); if ( max > MAX_SSIDS ) { printf("Too many SSIDs only printing %d of %d\n", MAX_SSIDS, max); max = MAX_SSIDS; } if ( act > max ) { errx(1, "bad modifier %d: there " "are only %d SSID settings", act, max); exit(1); } bzero(ssid->an_entry[act-1].an_ssid, sizeof(ssid->an_entry[act-1].an_ssid)); strlcpy(ssid->an_entry[act-1].an_ssid, (char *)arg, sizeof(ssid->an_entry[act-1].an_ssid)); ssid->an_entry[act-1].an_len = strlen(ssid->an_entry[act-1].an_ssid); an_setval(iface, &areq); exit(0); } #ifdef ANCACHE static void an_zerocache(const char *iface) { struct an_req areq; bzero(&areq, sizeof(areq)); areq.an_len = 0; areq.an_type = AN_RID_ZERO_CACHE; an_getval(iface, &areq); } static void an_readcache(const char *iface) { struct an_req areq; uint16_t *an_sigitems; struct an_sigcache *sc; int i; if (iface == NULL) errx(1, "must specify interface name"); bzero(&areq, sizeof(areq)); areq.an_len = AN_MAX_DATALEN; areq.an_type = AN_RID_READ_CACHE; an_getval(iface, &areq); an_sigitems = areq.an_val; sc = (struct an_sigcache *)((int32_t *)areq.an_val + 1); for (i = 0; i < *an_sigitems; i++) { printf("[%d/%d]:", i+1, *an_sigitems); printf(" %02x:%02x:%02x:%02x:%02x:%02x,", sc->macsrc[0]&0xff, sc->macsrc[1]&0xff, sc->macsrc[2]&0xff, sc->macsrc[3]&0xff, sc->macsrc[4]&0xff, sc->macsrc[5]&0xff); printf(" %d.%d.%d.%d,",((sc->ipsrc >> 0) & 0xff), ((sc->ipsrc >> 8) & 0xff), ((sc->ipsrc >> 16) & 0xff), ((sc->ipsrc >> 24) & 0xff)); printf(" sig: %d, noise: %d, qual: %d\n", sc->signal, sc->noise, sc->quality); sc++; } } #endif static int an_hex2int(char c) { if (c >= '0' && c <= '9') return (c - '0'); if (c >= 'A' && c <= 'F') return (c - 'A' + 10); if (c >= 'a' && c <= 'f') return (c - 'a' + 10); return (0); } static void an_str2key(const char *s, struct an_ltv_key *k) { int n, i; char *p; /* Is this a hex string? */ if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) { /* Yes, convert to int. */ n = 0; p = (char *)&k->key[0]; for (i = 2; s[i] != '\0' && s[i + 1] != '\0'; i+= 2) { *p++ = (an_hex2int(s[i]) << 4) + an_hex2int(s[i + 1]); n++; } if (s[i] != '\0') errx(1, "hex strings must be of even length"); k->klen = n; } else { /* No, just copy it in. */ bcopy(s, k->key, strlen(s)); k->klen = strlen(s); } return; } static void an_setkeys(const char *iface, const char *key, int keytype) { struct an_req areq; struct an_ltv_key *k; bzero(&areq, sizeof(areq)); k = (struct an_ltv_key *)&areq; if (strlen(key) > 28) { err(1, "encryption key must be no " "more than 18 characters long"); } an_str2key(key, k); k->kindex=keytype/2; if (!(k->klen==0 || k->klen==5 || k->klen==13)) { err(1, "encryption key must be 0, 5 or 13 bytes long"); } /* default mac and only valid one (from manual) 1.0.0.0.0.0 */ k->mac[0]=1; k->mac[1]=0; k->mac[2]=0; k->mac[3]=0; k->mac[4]=0; k->mac[5]=0; switch(keytype & 1) { case 0: areq.an_len = sizeof(struct an_ltv_key); areq.an_type = AN_RID_WEP_PERM; an_setval(iface, &areq); break; case 1: areq.an_len = sizeof(struct an_ltv_key); areq.an_type = AN_RID_WEP_TEMP; an_setval(iface, &areq); break; } } static void an_readkeyinfo(const char *iface) { struct an_req areq; struct an_ltv_genconfig *cfg; struct an_ltv_key *k; int i; int home; areq.an_len = sizeof(areq); areq.an_type = AN_RID_ACTUALCFG; an_getval(iface, &areq); cfg = (struct an_ltv_genconfig *)&areq; if (cfg->an_home_product & AN_HOME_NETWORK) home = 1; else home = 0; bzero(&areq, sizeof(areq)); k = (struct an_ltv_key *)&areq; printf("WEP Key status:\n"); areq.an_type = AN_RID_WEP_TEMP; /* read first key */ for(i=0; i<5; i++) { areq.an_len = sizeof(struct an_ltv_key); an_getval(iface, &areq); if (k->kindex == 0xffff) break; switch (k->klen) { case 0: printf("\tKey %u is unset\n", k->kindex); break; case 5: printf("\tKey %u is set 40 bits\n", k->kindex); break; case 13: printf("\tKey %u is set 128 bits\n", k->kindex); break; default: printf("\tWEP Key %d has an unknown size %u\n", i, k->klen); } areq.an_type = AN_RID_WEP_PERM; /* read next key */ } k->kindex = 0xffff; areq.an_len = sizeof(struct an_ltv_key); an_getval(iface, &areq); printf("\tThe active transmit key is %d\n", 4 * home + k->mac[0]); return; } static void an_enable_tx_key(const char *iface, const char *arg) { struct an_req areq; struct an_ltv_key *k; struct an_ltv_genconfig *config; bzero(&areq, sizeof(areq)); /* set home or not home mode */ areq.an_len = sizeof(struct an_ltv_genconfig); areq.an_type = AN_RID_GENCONFIG; an_getval(iface, &areq); config = (struct an_ltv_genconfig *)&areq; if (atoi(arg) == 4) { config->an_home_product |= AN_HOME_NETWORK; }else{ config->an_home_product &= ~AN_HOME_NETWORK; } an_setval(iface, &areq); bzero(&areq, sizeof(areq)); k = (struct an_ltv_key *)&areq; /* From a Cisco engineer write the transmit key to use in the first MAC, index is FFFF*/ k->kindex=0xffff; k->klen=0; k->mac[0]=atoi(arg); k->mac[1]=0; k->mac[2]=0; k->mac[3]=0; k->mac[4]=0; k->mac[5]=0; areq.an_len = sizeof(struct an_ltv_key); areq.an_type = AN_RID_WEP_PERM; an_setval(iface, &areq); } static void an_enable_leap_mode(const char *iface, const char *username) { struct an_req areq; struct an_ltv_status *sts; struct an_ltv_genconfig *cfg; struct an_ltv_caps *caps; struct an_ltv_leap_username an_username; struct an_ltv_leap_password an_password; char *password; MD4_CTX context; int len; int i; char unicode_password[LEAP_PASSWORD_MAX * 2]; areq.an_len = sizeof(areq); areq.an_type = AN_RID_CAPABILITIES; an_getval(iface, &areq); caps = (struct an_ltv_caps *)&areq; if (!caps->an_softcaps & AN_AUTHTYPE_LEAP) { fprintf(stderr, "Firmware does not support LEAP\n"); exit(1); } bzero(&an_username, sizeof(an_username)); bzero(&an_password, sizeof(an_password)); len = strlen(username); if (len > LEAP_USERNAME_MAX) { printf("Username too long (max %d)\n", LEAP_USERNAME_MAX); exit(1); } strncpy(an_username.an_username, username, len); an_username.an_username_len = len; an_username.an_len = sizeof(an_username); an_username.an_type = AN_RID_LEAPUSERNAME; password = getpass("Enter LEAP password:"); len = strlen(password); if (len > LEAP_PASSWORD_MAX) { printf("Password too long (max %d)\n", LEAP_PASSWORD_MAX); exit(1); } bzero(&unicode_password, sizeof(unicode_password)); for(i = 0; i < len; i++) { unicode_password[i * 2] = *password++; } /* First half */ MD4Init(&context); MD4Update(&context, unicode_password, len * 2); MD4Final(&an_password.an_password[0], &context); /* Second half */ MD4Init (&context); MD4Update (&context, &an_password.an_password[0], 16); MD4Final (&an_password.an_password[16], &context); an_password.an_password_len = 32; an_password.an_len = sizeof(an_password); an_password.an_type = AN_RID_LEAPPASSWORD; an_setval(iface, (struct an_req *)&an_username); an_setval(iface, (struct an_req *)&an_password); areq.an_len = sizeof(areq); areq.an_type = AN_RID_GENCONFIG; an_getval(iface, &areq); cfg = (struct an_ltv_genconfig *)&areq; cfg->an_authtype = (AN_AUTHTYPE_PRIVACY_IN_USE | AN_AUTHTYPE_LEAP); an_setval(iface, &areq); sts = (struct an_ltv_status *)&areq; areq.an_type = AN_RID_STATUS; for (i = 60; i > 0; i--) { an_getval(iface, &areq); if (sts->an_opmode & AN_STATUS_OPMODE_LEAP) { printf("Authenticated\n"); break; } sleep(1); } if (i == 0) { fprintf(stderr, "Failed LEAP authentication\n"); exit(1); } } int main(int argc, char *argv[]) { int ch; int act = 0; const char *iface = NULL; int modifier = 0; char *key = NULL; void *arg = NULL; char *p = argv[0]; /* Get the interface name */ opterr = 0; ch = getopt(argc, argv, "i:"); if (ch == 'i') { iface = optarg; } else { if (argc > 1 && *argv[1] != '-') { iface = argv[1]; optind = 2; } else { iface = "an0"; optind = 1; } optreset = 1; } opterr = 1; while ((ch = getopt(argc, argv, "ANISCTRht:a:e:o:s:n:v:d:j:b:c:f:r:p:w:m:l:k:K:W:QZM:L:")) != -1) { switch(ch) { case 'Z': #ifdef ANCACHE act = ACT_ZEROCACHE; #else errx(1, "ANCACHE not available"); #endif break; case 'Q': #ifdef ANCACHE act = ACT_DUMPCACHE; #else errx(1, "ANCACHE not available"); #endif break; case 'A': act = ACT_DUMPAP; break; case 'N': act = ACT_DUMPSSID; break; case 'S': act = ACT_DUMPSTATUS; break; case 'I': act = ACT_DUMPCAPS; break; case 'T': act = ACT_DUMPSTATS; break; case 'C': act = ACT_DUMPCONFIG; break; case 'R': act = ACT_DUMPRSSIMAP; break; case 't': act = ACT_SET_TXRATE; arg = optarg; break; case 's': act = ACT_SET_PWRSAVE; arg = optarg; break; case 'p': act = ACT_SET_TXPWR; arg = optarg; break; case 'v': modifier = atoi(optarg); break; case 'a': switch(modifier) { case 0: case 1: act = ACT_SET_AP1; break; case 2: act = ACT_SET_AP2; break; case 3: act = ACT_SET_AP3; break; case 4: act = ACT_SET_AP4; break; default: errx(1, "bad modifier %d: there " "are only 4 access point settings", modifier); usage(p); break; } arg = optarg; break; case 'b': act = ACT_SET_BEACON_PERIOD; arg = optarg; break; case 'd': switch(modifier) { case 0: act = ACT_SET_DIVERSITY_RX; break; case 1: act = ACT_SET_DIVERSITY_TX; break; default: errx(1, "must specify RX or TX diversity"); break; } if (!isdigit(*optarg)) { errx(1, "%s is not numeric", optarg); exit(1); } arg = optarg; break; case 'j': act = ACT_SET_NETJOIN; arg = optarg; break; case 'l': act = ACT_SET_MYNAME; arg = optarg; break; case 'm': act = ACT_SET_MAC; arg = optarg; break; case 'n': if (modifier == 0) modifier = 1; act = ACT_SET_SSID; arg = optarg; break; case 'o': act = ACT_SET_OPMODE; arg = optarg; break; case 'c': act = ACT_SET_FREQ; arg = optarg; break; case 'f': act = ACT_SET_FRAG_THRESH; arg = optarg; break; case 'W': act = ACT_ENABLE_WEP; arg = optarg; break; case 'K': act = ACT_SET_KEY_TYPE; arg = optarg; break; case 'k': act = ACT_SET_KEYS; key = optarg; break; case 'e': act = ACT_ENABLE_TX_KEY; arg = optarg; break; case 'q': act = ACT_SET_RTS_RETRYLIM; arg = optarg; break; case 'r': act = ACT_SET_RTS_THRESH; arg = optarg; break; case 'w': act = ACT_SET_WAKE_DURATION; arg = optarg; break; case 'M': act = ACT_SET_MONITOR_MODE; arg = optarg; break; case 'L': act = ACT_SET_LEAP_MODE; arg = optarg; break; case 'h': default: usage(p); } } if (iface == NULL || (!act && !key)) usage(p); switch(act) { case ACT_DUMPSTATUS: an_dumpstatus(iface); break; case ACT_DUMPCAPS: an_dumpcaps(iface); break; case ACT_DUMPSTATS: an_dumpstats(iface); break; case ACT_DUMPCONFIG: an_dumpconfig(iface); break; case ACT_DUMPSSID: an_dumpssid(iface); break; case ACT_DUMPAP: an_dumpap(iface); break; case ACT_DUMPRSSIMAP: an_dumprssimap(iface); break; case ACT_SET_SSID: an_setssid(iface, modifier, arg); break; case ACT_SET_AP1: case ACT_SET_AP2: case ACT_SET_AP3: case ACT_SET_AP4: an_setap(iface, act, arg); break; case ACT_SET_TXRATE: an_setspeed(iface, act, arg); break; #ifdef ANCACHE case ACT_ZEROCACHE: an_zerocache(iface); break; case ACT_DUMPCACHE: an_readcache(iface); break; #endif case ACT_SET_KEYS: an_setkeys(iface, key, modifier); break; case ACT_ENABLE_TX_KEY: an_enable_tx_key(iface, arg); break; case ACT_SET_LEAP_MODE: an_enable_leap_mode(iface, arg); break; default: an_setconfig(iface, act, arg); break; } exit(0); } diff --git a/usr.sbin/ifmcstat/ifmcstat.c b/usr.sbin/ifmcstat/ifmcstat.c index e45e36d143c3..5ee432860d40 100644 --- a/usr.sbin/ifmcstat/ifmcstat.c +++ b/usr.sbin/ifmcstat/ifmcstat.c @@ -1,1241 +1,1240 @@ /* $KAME: ifmcstat.c,v 1.48 2006/11/15 05:13:59 itojun Exp $ */ /* * Copyright (c) 2007-2009 Bruce Simpson. * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the project nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define KERNEL # include #undef KERNEL #define _KERNEL #define SYSCTL_DECL(x) # include #undef SYSCTL_DECL #undef _KERNEL #ifdef INET6 #include #define _KERNEL # include #undef _KERNEL #endif /* INET6 */ #include #include #include #include -#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* XXX: This file currently assumes INET and KVM support in the base system. */ #ifndef INET #define INET #endif extern void printb(const char *, unsigned int, const char *); union sockunion { struct sockaddr_storage ss; struct sockaddr sa; struct sockaddr_dl sdl; #ifdef INET struct sockaddr_in sin; #endif #ifdef INET6 struct sockaddr_in6 sin6; #endif }; typedef union sockunion sockunion_t; uint32_t ifindex = 0; int af = AF_UNSPEC; #ifdef WITH_KVM int Kflag = 0; #endif int vflag = 0; #define sa_equal(a1, a2) \ (bcmp((a1), (a2), ((a1))->sa_len) == 0) #define sa_dl_equal(a1, a2) \ ((((struct sockaddr_dl *)(a1))->sdl_len == \ ((struct sockaddr_dl *)(a2))->sdl_len) && \ (bcmp(LLADDR((struct sockaddr_dl *)(a1)), \ LLADDR((struct sockaddr_dl *)(a2)), \ ((struct sockaddr_dl *)(a1))->sdl_alen) == 0)) /* * Most of the code in this utility is to support the use of KVM for * post-mortem debugging of the multicast code. */ #ifdef WITH_KVM #ifdef INET static void if_addrlist(struct ifaddr *); static struct in_multi * in_multientry(struct in_multi *); #endif /* INET */ #ifdef INET6 static void if6_addrlist(struct ifaddr *); static struct in6_multi * in6_multientry(struct in6_multi *); #endif /* INET6 */ static void kread(u_long, void *, int); static void ll_addrlist(struct ifaddr *); static int ifmcstat_kvm(const char *kernel, const char *core); #define KREAD(addr, buf, type) \ kread((u_long)addr, (void *)buf, sizeof(type)) kvm_t *kvmd; struct nlist nl[] = { { "_ifnet", 0, 0, 0, 0, }, { "", 0, 0, 0, 0, }, }; #define N_IFNET 0 #endif /* WITH_KVM */ static int ifmcstat_getifmaddrs(void); #ifdef INET static void in_ifinfo(struct igmp_ifinfo *); static const char * inm_mode(u_int mode); #endif #ifdef INET6 static void in6_ifinfo(struct mld_ifinfo *); static const char * inet6_n2a(struct in6_addr *); #endif int main(int, char **); static void usage() { fprintf(stderr, "usage: ifmcstat [-i interface] [-f address family]" " [-v]" #ifdef WITH_KVM " [-K] [-M core] [-N system]" #endif "\n"); exit(EX_USAGE); } static const char *options = "i:f:vM:N:" #ifdef WITH_KVM "K" #endif ; int main(int argc, char **argv) { int c, error; #ifdef WITH_KVM const char *kernel = NULL; const char *core = NULL; #endif while ((c = getopt(argc, argv, options)) != -1) { switch (c) { case 'i': if ((ifindex = if_nametoindex(optarg)) == 0) { fprintf(stderr, "%s: unknown interface\n", optarg); exit(EX_NOHOST); } break; case 'f': #ifdef INET if (strcmp(optarg, "inet") == 0) { af = AF_INET; break; } #endif #ifdef INET6 if (strcmp(optarg, "inet6") == 0) { af = AF_INET6; break; } #endif if (strcmp(optarg, "link") == 0) { af = AF_LINK; break; } fprintf(stderr, "%s: unknown address family\n", optarg); exit(EX_USAGE); /*NOTREACHED*/ break; #ifdef WITH_KVM case 'K': ++Kflag; break; #endif case 'v': ++vflag; break; #ifdef WITH_KVM case 'M': core = strdup(optarg); break; case 'N': kernel = strdup(optarg); break; #endif default: usage(); break; /*NOTREACHED*/ } } if (af == AF_LINK && vflag) usage(); #ifdef WITH_KVM if (Kflag) error = ifmcstat_kvm(kernel, core); /* * If KVM failed, and user did not explicitly specify a core file, * or force KVM backend to be disabled, try the sysctl backend. */ if (!Kflag || (error != 0 && (core == NULL && kernel == NULL))) #endif error = ifmcstat_getifmaddrs(); if (error != 0) exit(EX_OSERR); exit(EX_OK); /*NOTREACHED*/ } #ifdef INET static void in_ifinfo(struct igmp_ifinfo *igi) { printf("\t"); switch (igi->igi_version) { case IGMP_VERSION_1: case IGMP_VERSION_2: case IGMP_VERSION_3: printf("igmpv%d", igi->igi_version); break; default: printf("igmpv?(%d)", igi->igi_version); break; } printb(" flags", igi->igi_flags, "\020\1SILENT\2LOOPBACK"); if (igi->igi_version == IGMP_VERSION_3) { printf(" rv %u qi %u qri %u uri %u", igi->igi_rv, igi->igi_qi, igi->igi_qri, igi->igi_uri); } if (vflag >= 2) { printf(" v1timer %u v2timer %u v3timer %u", igi->igi_v1_timer, igi->igi_v2_timer, igi->igi_v3_timer); } printf("\n"); } static const char *inm_modes[] = { "undefined", "include", "exclude", }; static const char * inm_mode(u_int mode) { if (mode >= MCAST_UNDEFINED && mode <= MCAST_EXCLUDE) return (inm_modes[mode]); return (NULL); } #endif /* INET */ #ifdef WITH_KVM static int ifmcstat_kvm(const char *kernel, const char *core) { char buf[_POSIX2_LINE_MAX], ifname[IFNAMSIZ]; struct ifnet *ifp, *nifp, ifnet; if ((kvmd = kvm_openfiles(kernel, core, NULL, O_RDONLY, buf)) == NULL) { perror("kvm_openfiles"); return (-1); } if (kvm_nlist(kvmd, nl) < 0) { perror("kvm_nlist"); return (-1); } if (nl[N_IFNET].n_value == 0) { printf("symbol %s not found\n", nl[N_IFNET].n_name); return (-1); } KREAD(nl[N_IFNET].n_value, &ifp, struct ifnet *); while (ifp) { KREAD(ifp, &ifnet, struct ifnet); nifp = ifnet.if_link.tqe_next; if (ifindex && ifindex != ifnet.if_index) goto next; printf("%s:\n", if_indextoname(ifnet.if_index, ifname)); #ifdef INET if_addrlist(TAILQ_FIRST(&ifnet.if_addrhead)); #endif #ifdef INET6 if6_addrlist(TAILQ_FIRST(&ifnet.if_addrhead)); #endif if (vflag) ll_addrlist(TAILQ_FIRST(&ifnet.if_addrhead)); next: ifp = nifp; } return (0); } static void kread(u_long addr, void *buf, int len) { if (kvm_read(kvmd, addr, buf, len) != len) { perror("kvm_read"); exit(EX_OSERR); } } static void ll_addrlist(struct ifaddr *ifap) { char addrbuf[NI_MAXHOST]; struct ifaddr ifa; struct sockaddr sa; struct sockaddr_dl sdl; struct ifaddr *ifap0; int error; if (af && af != AF_LINK) return; ifap0 = ifap; while (ifap) { KREAD(ifap, &ifa, struct ifaddr); if (ifa.ifa_addr == NULL) goto nextifap; KREAD(ifa.ifa_addr, &sa, struct sockaddr); if (sa.sa_family != PF_LINK) goto nextifap; KREAD(ifa.ifa_addr, &sdl, struct sockaddr_dl); if (sdl.sdl_alen == 0) goto nextifap; addrbuf[0] = '\0'; error = getnameinfo((struct sockaddr *)&sdl, sdl.sdl_len, addrbuf, sizeof(addrbuf), NULL, 0, NI_NUMERICHOST); printf("\tlink %s\n", addrbuf); nextifap: ifap = ifa.ifa_link.tqe_next; } if (ifap0) { struct ifnet ifnet; struct ifmultiaddr ifm, *ifmp = 0; KREAD(ifap0, &ifa, struct ifaddr); KREAD(ifa.ifa_ifp, &ifnet, struct ifnet); if (TAILQ_FIRST(&ifnet.if_multiaddrs)) ifmp = TAILQ_FIRST(&ifnet.if_multiaddrs); while (ifmp) { KREAD(ifmp, &ifm, struct ifmultiaddr); if (ifm.ifma_addr == NULL) goto nextmulti; KREAD(ifm.ifma_addr, &sa, struct sockaddr); if (sa.sa_family != AF_LINK) goto nextmulti; KREAD(ifm.ifma_addr, &sdl, struct sockaddr_dl); addrbuf[0] = '\0'; error = getnameinfo((struct sockaddr *)&sdl, sdl.sdl_len, addrbuf, sizeof(addrbuf), NULL, 0, NI_NUMERICHOST); printf("\t\tgroup %s refcnt %d\n", addrbuf, ifm.ifma_refcount); nextmulti: ifmp = TAILQ_NEXT(&ifm, ifma_link); } } } #ifdef INET6 static void in6_ifinfo(struct mld_ifinfo *mli) { printf("\t"); switch (mli->mli_version) { case MLD_VERSION_1: case MLD_VERSION_2: printf("mldv%d", mli->mli_version); break; default: printf("mldv?(%d)", mli->mli_version); break; } printb(" flags", mli->mli_flags, "\020\1SILENT"); if (mli->mli_version == MLD_VERSION_2) { printf(" rv %u qi %u qri %u uri %u", mli->mli_rv, mli->mli_qi, mli->mli_qri, mli->mli_uri); } if (vflag >= 2) { printf(" v1timer %u v2timer %u", mli->mli_v1_timer, mli->mli_v2_timer); } printf("\n"); } static void if6_addrlist(struct ifaddr *ifap) { struct ifnet ifnet; struct ifaddr ifa; struct sockaddr sa; struct in6_ifaddr if6a; struct ifaddr *ifap0; if (af && af != AF_INET6) return; ifap0 = ifap; while (ifap) { KREAD(ifap, &ifa, struct ifaddr); if (ifa.ifa_addr == NULL) goto nextifap; KREAD(ifa.ifa_addr, &sa, struct sockaddr); if (sa.sa_family != PF_INET6) goto nextifap; KREAD(ifap, &if6a, struct in6_ifaddr); printf("\tinet6 %s\n", inet6_n2a(&if6a.ia_addr.sin6_addr)); /* * Print per-link MLD information, if available. */ if (ifa.ifa_ifp != NULL) { struct in6_ifextra ie; struct mld_ifinfo mli; KREAD(ifa.ifa_ifp, &ifnet, struct ifnet); KREAD(ifnet.if_afdata[AF_INET6], &ie, struct in6_ifextra); if (ie.mld_ifinfo != NULL) { KREAD(ie.mld_ifinfo, &mli, struct mld_ifinfo); in6_ifinfo(&mli); } } nextifap: ifap = ifa.ifa_link.tqe_next; } if (ifap0) { struct ifnet ifnet; struct ifmultiaddr ifm, *ifmp = 0; struct sockaddr_dl sdl; KREAD(ifap0, &ifa, struct ifaddr); KREAD(ifa.ifa_ifp, &ifnet, struct ifnet); if (TAILQ_FIRST(&ifnet.if_multiaddrs)) ifmp = TAILQ_FIRST(&ifnet.if_multiaddrs); while (ifmp) { KREAD(ifmp, &ifm, struct ifmultiaddr); if (ifm.ifma_addr == NULL) goto nextmulti; KREAD(ifm.ifma_addr, &sa, struct sockaddr); if (sa.sa_family != AF_INET6) goto nextmulti; (void)in6_multientry((struct in6_multi *) ifm.ifma_protospec); if (ifm.ifma_lladdr == 0) goto nextmulti; KREAD(ifm.ifma_lladdr, &sdl, struct sockaddr_dl); printf("\t\t\tmcast-macaddr %s refcnt %d\n", ether_ntoa((struct ether_addr *)LLADDR(&sdl)), ifm.ifma_refcount); nextmulti: ifmp = TAILQ_NEXT(&ifm, ifma_link); } } } static struct in6_multi * in6_multientry(struct in6_multi *mc) { struct in6_multi multi; KREAD(mc, &multi, struct in6_multi); printf("\t\tgroup %s", inet6_n2a(&multi.in6m_addr)); printf(" refcnt %u\n", multi.in6m_refcount); return (multi.in6m_entry.le_next); } #endif /* INET6 */ #ifdef INET static void if_addrlist(struct ifaddr *ifap) { struct ifaddr ifa; struct ifnet ifnet; struct sockaddr sa; struct in_ifaddr ia; struct ifaddr *ifap0; if (af && af != AF_INET) return; ifap0 = ifap; while (ifap) { KREAD(ifap, &ifa, struct ifaddr); if (ifa.ifa_addr == NULL) goto nextifap; KREAD(ifa.ifa_addr, &sa, struct sockaddr); if (sa.sa_family != PF_INET) goto nextifap; KREAD(ifap, &ia, struct in_ifaddr); printf("\tinet %s\n", inet_ntoa(ia.ia_addr.sin_addr)); /* * Print per-link IGMP information, if available. */ if (ifa.ifa_ifp != NULL) { struct in_ifinfo ii; struct igmp_ifinfo igi; KREAD(ifa.ifa_ifp, &ifnet, struct ifnet); KREAD(ifnet.if_afdata[AF_INET], &ii, struct in_ifinfo); if (ii.ii_igmp != NULL) { KREAD(ii.ii_igmp, &igi, struct igmp_ifinfo); in_ifinfo(&igi); } } nextifap: ifap = ifa.ifa_link.tqe_next; } if (ifap0) { struct ifmultiaddr ifm, *ifmp = 0; struct sockaddr_dl sdl; KREAD(ifap0, &ifa, struct ifaddr); KREAD(ifa.ifa_ifp, &ifnet, struct ifnet); if (TAILQ_FIRST(&ifnet.if_multiaddrs)) ifmp = TAILQ_FIRST(&ifnet.if_multiaddrs); while (ifmp) { KREAD(ifmp, &ifm, struct ifmultiaddr); if (ifm.ifma_addr == NULL) goto nextmulti; KREAD(ifm.ifma_addr, &sa, struct sockaddr); if (sa.sa_family != AF_INET) goto nextmulti; (void)in_multientry((struct in_multi *) ifm.ifma_protospec); if (ifm.ifma_lladdr == 0) goto nextmulti; KREAD(ifm.ifma_lladdr, &sdl, struct sockaddr_dl); printf("\t\t\tmcast-macaddr %s refcnt %d\n", ether_ntoa((struct ether_addr *)LLADDR(&sdl)), ifm.ifma_refcount); nextmulti: ifmp = TAILQ_NEXT(&ifm, ifma_link); } } } static const char *inm_states[] = { "not-member", "silent", "idle", "lazy", "sleeping", "awakening", "query-pending", "sg-query-pending", "leaving" }; static const char * inm_state(u_int state) { if (state >= IGMP_NOT_MEMBER && state <= IGMP_LEAVING_MEMBER) return (inm_states[state]); return (NULL); } #if 0 static struct ip_msource * ims_min_kvm(struct in_multi *pinm) { struct ip_msource ims0; struct ip_msource *tmp, *parent; parent = NULL; tmp = RB_ROOT(&pinm->inm_srcs); while (tmp) { parent = tmp; KREAD(tmp, &ims0, struct ip_msource); tmp = RB_LEFT(&ims0, ims_link); } return (parent); /* kva */ } /* XXX This routine is buggy. See RB_NEXT in sys/tree.h. */ static struct ip_msource * ims_next_kvm(struct ip_msource *ims) { struct ip_msource ims0, ims1; struct ip_msource *tmp; KREAD(ims, &ims0, struct ip_msource); if (RB_RIGHT(&ims0, ims_link)) { ims = RB_RIGHT(&ims0, ims_link); KREAD(ims, &ims1, struct ip_msource); while ((tmp = RB_LEFT(&ims1, ims_link))) { KREAD(tmp, &ims0, struct ip_msource); ims = RB_LEFT(&ims0, ims_link); } } else { tmp = RB_PARENT(&ims0, ims_link); if (tmp) { KREAD(tmp, &ims1, struct ip_msource); if (ims == RB_LEFT(&ims1, ims_link)) ims = tmp; } else { while ((tmp = RB_PARENT(&ims0, ims_link))) { KREAD(tmp, &ims1, struct ip_msource); if (ims == RB_RIGHT(&ims1, ims_link)) { ims = tmp; KREAD(ims, &ims0, struct ip_msource); } else break; } ims = RB_PARENT(&ims0, ims_link); } } return (ims); /* kva */ } static void inm_print_sources_kvm(struct in_multi *pinm) { struct ip_msource ims0; struct ip_msource *ims; struct in_addr src; int cnt; uint8_t fmode; cnt = 0; fmode = pinm->inm_st[1].iss_fmode; if (fmode == MCAST_UNDEFINED) return; for (ims = ims_min_kvm(pinm); ims != NULL; ims = ims_next_kvm(ims)) { if (cnt == 0) printf(" srcs "); KREAD(ims, &ims0, struct ip_msource); /* Only print sources in-mode at t1. */ if (fmode != ims_get_mode(pinm, ims, 1)) continue; src.s_addr = htonl(ims0.ims_haddr); printf("%s%s", (cnt++ == 0 ? "" : ","), inet_ntoa(src)); } } #endif static struct in_multi * in_multientry(struct in_multi *pinm) { struct in_multi inm; const char *state, *mode; KREAD(pinm, &inm, struct in_multi); printf("\t\tgroup %s", inet_ntoa(inm.inm_addr)); printf(" refcnt %u", inm.inm_refcount); state = inm_state(inm.inm_state); if (state) printf(" state %s", state); else printf(" state (%d)", inm.inm_state); mode = inm_mode(inm.inm_st[1].iss_fmode); if (mode) printf(" mode %s", mode); else printf(" mode (%d)", inm.inm_st[1].iss_fmode); if (vflag >= 2) { printf(" asm %u ex %u in %u rec %u", (u_int)inm.inm_st[1].iss_asm, (u_int)inm.inm_st[1].iss_ex, (u_int)inm.inm_st[1].iss_in, (u_int)inm.inm_st[1].iss_rec); } #if 0 /* Buggy. */ if (vflag) inm_print_sources_kvm(&inm); #endif printf("\n"); return (NULL); } #endif /* INET */ #endif /* WITH_KVM */ #ifdef INET6 static const char * inet6_n2a(struct in6_addr *p) { static char buf[NI_MAXHOST]; struct sockaddr_in6 sin6; u_int32_t scopeid; const int niflags = NI_NUMERICHOST; memset(&sin6, 0, sizeof(sin6)); sin6.sin6_family = AF_INET6; sin6.sin6_len = sizeof(struct sockaddr_in6); sin6.sin6_addr = *p; if (IN6_IS_ADDR_LINKLOCAL(p) || IN6_IS_ADDR_MC_LINKLOCAL(p) || IN6_IS_ADDR_MC_NODELOCAL(p)) { scopeid = ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]); if (scopeid) { sin6.sin6_scope_id = scopeid; sin6.sin6_addr.s6_addr[2] = 0; sin6.sin6_addr.s6_addr[3] = 0; } } if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len, buf, sizeof(buf), NULL, 0, niflags) == 0) { return (buf); } else { return ("(invalid)"); } } #endif /* INET6 */ #ifdef INET /* * Retrieve per-group source filter mode and lists via sysctl. */ static void inm_print_sources_sysctl(uint32_t ifindex, struct in_addr gina) { #define MAX_SYSCTL_TRY 5 int mib[7]; int ntry = 0; size_t mibsize; size_t len; size_t needed; size_t cnt; int i; char *buf; struct in_addr *pina; uint32_t *p; uint32_t fmode; const char *modestr; mibsize = sizeof(mib) / sizeof(mib[0]); if (sysctlnametomib("net.inet.ip.mcast.filters", mib, &mibsize) == -1) { perror("sysctlnametomib"); return; } needed = 0; mib[5] = ifindex; mib[6] = gina.s_addr; /* 32 bits wide */ mibsize = sizeof(mib) / sizeof(mib[0]); do { if (sysctl(mib, mibsize, NULL, &needed, NULL, 0) == -1) { perror("sysctl net.inet.ip.mcast.filters"); return; } if ((buf = malloc(needed)) == NULL) { perror("malloc"); return; } if (sysctl(mib, mibsize, buf, &needed, NULL, 0) == -1) { if (errno != ENOMEM || ++ntry >= MAX_SYSCTL_TRY) { perror("sysctl"); goto out_free; } free(buf); buf = NULL; } } while (buf == NULL); len = needed; if (len < sizeof(uint32_t)) { perror("sysctl"); goto out_free; } p = (uint32_t *)buf; fmode = *p++; len -= sizeof(uint32_t); modestr = inm_mode(fmode); if (modestr) printf(" mode %s", modestr); else printf(" mode (%u)", fmode); if (vflag == 0) goto out_free; cnt = len / sizeof(struct in_addr); pina = (struct in_addr *)p; for (i = 0; i < cnt; i++) { if (i == 0) printf(" srcs "); fprintf(stdout, "%s%s", (i == 0 ? "" : ","), inet_ntoa(*pina++)); len -= sizeof(struct in_addr); } if (len > 0) { fprintf(stderr, "warning: %u trailing bytes from %s\n", (unsigned int)len, "net.inet.ip.mcast.filters"); } out_free: free(buf); #undef MAX_SYSCTL_TRY } #endif /* INET */ #ifdef INET6 /* * Retrieve MLD per-group source filter mode and lists via sysctl. * * Note: The 128-bit IPv6 group addres needs to be segmented into * 32-bit pieces for marshaling to sysctl. So the MIB name ends * up looking like this: * a.b.c.d.e.ifindex.g[0].g[1].g[2].g[3] * Assumes that pgroup originated from the kernel, so its components * are already in network-byte order. */ static void in6m_print_sources_sysctl(uint32_t ifindex, struct in6_addr *pgroup) { #define MAX_SYSCTL_TRY 5 char addrbuf[INET6_ADDRSTRLEN]; int mib[10]; int ntry = 0; int *pi; size_t mibsize; size_t len; size_t needed; size_t cnt; int i; char *buf; struct in6_addr *pina; uint32_t *p; uint32_t fmode; const char *modestr; mibsize = sizeof(mib) / sizeof(mib[0]); if (sysctlnametomib("net.inet6.ip6.mcast.filters", mib, &mibsize) == -1) { perror("sysctlnametomib"); return; } needed = 0; mib[5] = ifindex; pi = (int *)pgroup; for (i = 0; i < 4; i++) mib[6 + i] = *pi++; mibsize = sizeof(mib) / sizeof(mib[0]); do { if (sysctl(mib, mibsize, NULL, &needed, NULL, 0) == -1) { perror("sysctl net.inet6.ip6.mcast.filters"); return; } if ((buf = malloc(needed)) == NULL) { perror("malloc"); return; } if (sysctl(mib, mibsize, buf, &needed, NULL, 0) == -1) { if (errno != ENOMEM || ++ntry >= MAX_SYSCTL_TRY) { perror("sysctl"); goto out_free; } free(buf); buf = NULL; } } while (buf == NULL); len = needed; if (len < sizeof(uint32_t)) { perror("sysctl"); goto out_free; } p = (uint32_t *)buf; fmode = *p++; len -= sizeof(uint32_t); modestr = inm_mode(fmode); if (modestr) printf(" mode %s", modestr); else printf(" mode (%u)", fmode); if (vflag == 0) goto out_free; cnt = len / sizeof(struct in6_addr); pina = (struct in6_addr *)p; for (i = 0; i < cnt; i++) { if (i == 0) printf(" srcs "); inet_ntop(AF_INET6, (const char *)pina++, addrbuf, INET6_ADDRSTRLEN); fprintf(stdout, "%s%s", (i == 0 ? "" : ","), addrbuf); len -= sizeof(struct in6_addr); } if (len > 0) { fprintf(stderr, "warning: %u trailing bytes from %s\n", (unsigned int)len, "net.inet6.ip6.mcast.filters"); } out_free: free(buf); #undef MAX_SYSCTL_TRY } #endif /* INET6 */ static int ifmcstat_getifmaddrs(void) { char thisifname[IFNAMSIZ]; char addrbuf[NI_MAXHOST]; struct ifaddrs *ifap, *ifa; struct ifmaddrs *ifmap, *ifma; sockunion_t lastifasa; sockunion_t *psa, *pgsa, *pllsa, *pifasa; char *pcolon; char *pafname; uint32_t lastifindex, thisifindex; int error; error = 0; ifap = NULL; ifmap = NULL; lastifindex = 0; thisifindex = 0; lastifasa.ss.ss_family = AF_UNSPEC; if (getifaddrs(&ifap) != 0) { warn("getifmaddrs"); return (-1); } if (getifmaddrs(&ifmap) != 0) { warn("getifmaddrs"); error = -1; goto out; } for (ifma = ifmap; ifma; ifma = ifma->ifma_next) { error = 0; if (ifma->ifma_name == NULL || ifma->ifma_addr == NULL) continue; psa = (sockunion_t *)ifma->ifma_name; if (psa->sa.sa_family != AF_LINK) { fprintf(stderr, "WARNING: Kernel returned invalid data.\n"); error = -1; break; } /* Filter on interface name. */ thisifindex = psa->sdl.sdl_index; if (ifindex != 0 && thisifindex != ifindex) continue; /* Filter on address family. */ pgsa = (sockunion_t *)ifma->ifma_addr; if (af != 0 && pgsa->sa.sa_family != af) continue; strlcpy(thisifname, link_ntoa(&psa->sdl), IFNAMSIZ); pcolon = strchr(thisifname, ':'); if (pcolon) *pcolon = '\0'; /* Only print the banner for the first ifmaddrs entry. */ if (lastifindex == 0 || lastifindex != thisifindex) { lastifindex = thisifindex; fprintf(stdout, "%s:\n", thisifname); } /* * Currently, multicast joins only take place on the * primary IPv4 address, and only on the link-local IPv6 * address, as per IGMPv2/3 and MLDv1/2 semantics. * Therefore, we only look up the primary address on * the first pass. */ pifasa = NULL; for (ifa = ifap; ifa; ifa = ifa->ifa_next) { if ((strcmp(ifa->ifa_name, thisifname) != 0) || (ifa->ifa_addr == NULL) || (ifa->ifa_addr->sa_family != pgsa->sa.sa_family)) continue; /* * For AF_INET6 only the link-local address should * be returned. If built without IPv6 support, * skip this address entirely. */ pifasa = (sockunion_t *)ifa->ifa_addr; if (pifasa->sa.sa_family == AF_INET6 #ifdef INET6 && !IN6_IS_ADDR_LINKLOCAL(&pifasa->sin6.sin6_addr) #endif ) { pifasa = NULL; continue; } break; } if (pifasa == NULL) continue; /* primary address not found */ if (!vflag && pifasa->sa.sa_family == AF_LINK) continue; /* Parse and print primary address, if not already printed. */ if (lastifasa.ss.ss_family == AF_UNSPEC || ((lastifasa.ss.ss_family == AF_LINK && !sa_dl_equal(&lastifasa.sa, &pifasa->sa)) || !sa_equal(&lastifasa.sa, &pifasa->sa))) { switch (pifasa->sa.sa_family) { case AF_INET: pafname = "inet"; break; case AF_INET6: pafname = "inet6"; break; case AF_LINK: pafname = "link"; break; default: pafname = "unknown"; break; } switch (pifasa->sa.sa_family) { case AF_INET6: #ifdef INET6 { const char *p = inet6_n2a(&pifasa->sin6.sin6_addr); strlcpy(addrbuf, p, sizeof(addrbuf)); break; } #else /* FALLTHROUGH */ #endif case AF_INET: case AF_LINK: error = getnameinfo(&pifasa->sa, pifasa->sa.sa_len, addrbuf, sizeof(addrbuf), NULL, 0, NI_NUMERICHOST); if (error) perror("getnameinfo"); break; default: addrbuf[0] = '\0'; break; } fprintf(stdout, "\t%s %s\n", pafname, addrbuf); #ifdef INET /* * Print per-link IGMP information, if available. */ if (pifasa->sa.sa_family == AF_INET) { struct igmp_ifinfo igi; size_t mibsize, len; int mib[5]; mibsize = sizeof(mib) / sizeof(mib[0]); if (sysctlnametomib("net.inet.igmp.ifinfo", mib, &mibsize) == -1) { perror("sysctlnametomib"); goto next_ifnet; } mib[mibsize] = thisifindex; len = sizeof(struct igmp_ifinfo); if (sysctl(mib, mibsize + 1, &igi, &len, NULL, 0) == -1) { perror("sysctl net.inet.igmp.ifinfo"); goto next_ifnet; } in_ifinfo(&igi); } #endif /* INET */ #ifdef INET6 /* * Print per-link MLD information, if available. */ if (pifasa->sa.sa_family == AF_INET6) { struct mld_ifinfo mli; size_t mibsize, len; int mib[5]; mibsize = sizeof(mib) / sizeof(mib[0]); if (sysctlnametomib("net.inet6.mld.ifinfo", mib, &mibsize) == -1) { perror("sysctlnametomib"); goto next_ifnet; } mib[mibsize] = thisifindex; len = sizeof(struct mld_ifinfo); if (sysctl(mib, mibsize + 1, &mli, &len, NULL, 0) == -1) { perror("sysctl net.inet6.mld.ifinfo"); goto next_ifnet; } in6_ifinfo(&mli); } #endif /* INET6 */ #if defined(INET) || defined(INET6) next_ifnet: #endif lastifasa = *pifasa; } /* Print this group address. */ #ifdef INET6 if (pgsa->sa.sa_family == AF_INET6) { const char *p = inet6_n2a(&pgsa->sin6.sin6_addr); strlcpy(addrbuf, p, sizeof(addrbuf)); } else #endif { error = getnameinfo(&pgsa->sa, pgsa->sa.sa_len, addrbuf, sizeof(addrbuf), NULL, 0, NI_NUMERICHOST); if (error) perror("getnameinfo"); } fprintf(stdout, "\t\tgroup %s", addrbuf); #ifdef INET if (pgsa->sa.sa_family == AF_INET) { inm_print_sources_sysctl(thisifindex, pgsa->sin.sin_addr); } #endif #ifdef INET6 if (pgsa->sa.sa_family == AF_INET6) { in6m_print_sources_sysctl(thisifindex, &pgsa->sin6.sin6_addr); } #endif fprintf(stdout, "\n"); /* Link-layer mapping, if present. */ pllsa = (sockunion_t *)ifma->ifma_lladdr; if (pllsa != NULL) { error = getnameinfo(&pllsa->sa, pllsa->sa.sa_len, addrbuf, sizeof(addrbuf), NULL, 0, NI_NUMERICHOST); fprintf(stdout, "\t\t\tmcast-macaddr %s\n", addrbuf); } } out: if (ifmap != NULL) freeifmaddrs(ifmap); if (ifap != NULL) freeifaddrs(ifap); return (error); } diff --git a/usr.sbin/nfsd/nfsd.c b/usr.sbin/nfsd/nfsd.c index 656cb143d179..c5cec5ead4f4 100644 --- a/usr.sbin/nfsd/nfsd.c +++ b/usr.sbin/nfsd/nfsd.c @@ -1,1076 +1,1075 @@ /* * Copyright (c) 1989, 1993, 1994 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Rick Macklem at The University of Guelph. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint static const char copyright[] = "@(#) Copyright (c) 1989, 1993, 1994\n\ The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #ifndef lint #if 0 static char sccsid[] = "@(#)nfsd.c 8.9 (Berkeley) 3/29/95"; #endif static const char rcsid[] = "$FreeBSD$"; #endif /* not lint */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include -#include /* Global defs */ #ifdef DEBUG #define syslog(e, s...) fprintf(stderr,s) int debug = 1; #else int debug = 0; #endif #define NFSD_STABLERESTART "/var/db/nfs-stablerestart" #define NFSD_STABLEBACKUP "/var/db/nfs-stablerestart.bak" #define MAXNFSDCNT 256 #define DEFNFSDCNT 4 pid_t children[MAXNFSDCNT]; /* PIDs of children */ int nfsdcnt; /* number of children */ int new_syscall; int run_v4server = 1; /* Force running of nfsv4 server */ int nfssvc_nfsd; /* Set to correct NFSSVC_xxx flag */ int stablefd = -1; /* Fd for the stable restart file */ int backupfd; /* Fd for the backup stable restart file */ void cleanup(int); void child_cleanup(int); void killchildren(void); void nfsd_exit(int); void nonfs(int); void reapchild(int); int setbindhost(struct addrinfo **ia, const char *bindhost, struct addrinfo hints); void start_server(int); void unregistration(void); void usage(void); void open_stable(int *, int *); void copy_stable(int, int); void backup_stable(int); /* * Nfs server daemon mostly just a user context for nfssvc() * * 1 - do file descriptor and signal cleanup * 2 - fork the nfsd(s) * 3 - create server socket(s) * 4 - register socket with rpcbind * * For connectionless protocols, just pass the socket into the kernel via. * nfssvc(). * For connection based sockets, loop doing accepts. When you get a new * socket from accept, pass the msgsock into the kernel via. nfssvc(). * The arguments are: * -r - reregister with rpcbind * -d - unregister with rpcbind * -t - support tcp nfs clients * -u - support udp nfs clients * -e - forces it to run a server that supports nfsv4 * followed by "n" which is the number of nfsds' to fork off */ int main(int argc, char **argv) { struct nfsd_addsock_args addsockargs; struct addrinfo *ai_udp, *ai_tcp, *ai_udp6, *ai_tcp6, hints; struct netconfig *nconf_udp, *nconf_tcp, *nconf_udp6, *nconf_tcp6; struct netbuf nb_udp, nb_tcp, nb_udp6, nb_tcp6; struct sockaddr_in inetpeer; struct sockaddr_in6 inet6peer; fd_set ready, sockbits; fd_set v4bits, v6bits; int ch, connect_type_cnt, i, maxsock, msgsock; socklen_t len; int on = 1, unregister, reregister, sock; int tcp6sock, ip6flag, tcpflag, tcpsock; int udpflag, ecode, error, s, srvcnt; int bindhostc, bindanyflag, rpcbreg, rpcbregcnt; int nfssvc_addsock; char **bindhost = NULL; pid_t pid; nfsdcnt = DEFNFSDCNT; unregister = reregister = tcpflag = maxsock = 0; bindanyflag = udpflag = connect_type_cnt = bindhostc = 0; #define GETOPT "ah:n:rdtueo" #define USAGE "[-ardtueo] [-n num_servers] [-h bindip]" while ((ch = getopt(argc, argv, GETOPT)) != -1) switch (ch) { case 'a': bindanyflag = 1; break; case 'n': nfsdcnt = atoi(optarg); if (nfsdcnt < 1 || nfsdcnt > MAXNFSDCNT) { warnx("nfsd count %d; reset to %d", nfsdcnt, DEFNFSDCNT); nfsdcnt = DEFNFSDCNT; } break; case 'h': bindhostc++; bindhost = realloc(bindhost,sizeof(char *)*bindhostc); if (bindhost == NULL) errx(1, "Out of memory"); bindhost[bindhostc-1] = strdup(optarg); if (bindhost[bindhostc-1] == NULL) errx(1, "Out of memory"); break; case 'r': reregister = 1; break; case 'd': unregister = 1; break; case 't': tcpflag = 1; break; case 'u': udpflag = 1; break; case 'e': /* now a no-op, since this is the default */ break; case 'o': run_v4server = 0; break; default: case '?': usage(); }; if (!tcpflag && !udpflag) udpflag = 1; argv += optind; argc -= optind; /* * XXX * Backward compatibility, trailing number is the count of daemons. */ if (argc > 1) usage(); if (argc == 1) { nfsdcnt = atoi(argv[0]); if (nfsdcnt < 1 || nfsdcnt > MAXNFSDCNT) { warnx("nfsd count %d; reset to %d", nfsdcnt, DEFNFSDCNT); nfsdcnt = DEFNFSDCNT; } } /* * Unless the "-o" option was specified, try and run "nfsd". * If "-o" was specified, try and run "nfsserver". */ if (run_v4server > 0) { if (modfind("nfsd") < 0) { /* Not present in kernel, try loading it */ if (kldload("nfsd") < 0 || modfind("nfsd") < 0) errx(1, "NFS server is not available"); } } else if (modfind("nfsserver") < 0) { /* Not present in kernel, try loading it */ if (kldload("nfsserver") < 0 || modfind("nfsserver") < 0) errx(1, "NFS server is not available"); } ip6flag = 1; s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); if (s == -1) { if (errno != EPROTONOSUPPORT) err(1, "socket"); ip6flag = 0; } else if (getnetconfigent("udp6") == NULL || getnetconfigent("tcp6") == NULL) { ip6flag = 0; } if (s != -1) close(s); if (bindhostc == 0 || bindanyflag) { bindhostc++; bindhost = realloc(bindhost,sizeof(char *)*bindhostc); if (bindhost == NULL) errx(1, "Out of memory"); bindhost[bindhostc-1] = strdup("*"); if (bindhost[bindhostc-1] == NULL) errx(1, "Out of memory"); } if (unregister) { unregistration(); exit (0); } if (reregister) { if (udpflag) { memset(&hints, 0, sizeof hints); hints.ai_flags = AI_PASSIVE; hints.ai_family = AF_INET; hints.ai_socktype = SOCK_DGRAM; hints.ai_protocol = IPPROTO_UDP; ecode = getaddrinfo(NULL, "nfs", &hints, &ai_udp); if (ecode != 0) err(1, "getaddrinfo udp: %s", gai_strerror(ecode)); nconf_udp = getnetconfigent("udp"); if (nconf_udp == NULL) err(1, "getnetconfigent udp failed"); nb_udp.buf = ai_udp->ai_addr; nb_udp.len = nb_udp.maxlen = ai_udp->ai_addrlen; if ((!rpcb_set(NFS_PROGRAM, 2, nconf_udp, &nb_udp)) || (!rpcb_set(NFS_PROGRAM, 3, nconf_udp, &nb_udp))) err(1, "rpcb_set udp failed"); freeaddrinfo(ai_udp); } if (udpflag && ip6flag) { memset(&hints, 0, sizeof hints); hints.ai_flags = AI_PASSIVE; hints.ai_family = AF_INET6; hints.ai_socktype = SOCK_DGRAM; hints.ai_protocol = IPPROTO_UDP; ecode = getaddrinfo(NULL, "nfs", &hints, &ai_udp6); if (ecode != 0) err(1, "getaddrinfo udp6: %s", gai_strerror(ecode)); nconf_udp6 = getnetconfigent("udp6"); if (nconf_udp6 == NULL) err(1, "getnetconfigent udp6 failed"); nb_udp6.buf = ai_udp6->ai_addr; nb_udp6.len = nb_udp6.maxlen = ai_udp6->ai_addrlen; if ((!rpcb_set(NFS_PROGRAM, 2, nconf_udp6, &nb_udp6)) || (!rpcb_set(NFS_PROGRAM, 3, nconf_udp6, &nb_udp6))) err(1, "rpcb_set udp6 failed"); freeaddrinfo(ai_udp6); } if (tcpflag) { memset(&hints, 0, sizeof hints); hints.ai_flags = AI_PASSIVE; hints.ai_family = AF_INET; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; ecode = getaddrinfo(NULL, "nfs", &hints, &ai_tcp); if (ecode != 0) err(1, "getaddrinfo tcp: %s", gai_strerror(ecode)); nconf_tcp = getnetconfigent("tcp"); if (nconf_tcp == NULL) err(1, "getnetconfigent tcp failed"); nb_tcp.buf = ai_tcp->ai_addr; nb_tcp.len = nb_tcp.maxlen = ai_tcp->ai_addrlen; if ((!rpcb_set(NFS_PROGRAM, 2, nconf_tcp, &nb_tcp)) || (!rpcb_set(NFS_PROGRAM, 3, nconf_tcp, &nb_tcp))) err(1, "rpcb_set tcp failed"); freeaddrinfo(ai_tcp); } if (tcpflag && ip6flag) { memset(&hints, 0, sizeof hints); hints.ai_flags = AI_PASSIVE; hints.ai_family = AF_INET6; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; ecode = getaddrinfo(NULL, "nfs", &hints, &ai_tcp6); if (ecode != 0) err(1, "getaddrinfo tcp6: %s", gai_strerror(ecode)); nconf_tcp6 = getnetconfigent("tcp6"); if (nconf_tcp6 == NULL) err(1, "getnetconfigent tcp6 failed"); nb_tcp6.buf = ai_tcp6->ai_addr; nb_tcp6.len = nb_tcp6.maxlen = ai_tcp6->ai_addrlen; if ((!rpcb_set(NFS_PROGRAM, 2, nconf_tcp6, &nb_tcp6)) || (!rpcb_set(NFS_PROGRAM, 3, nconf_tcp6, &nb_tcp6))) err(1, "rpcb_set tcp6 failed"); freeaddrinfo(ai_tcp6); } exit (0); } if (debug == 0) { daemon(0, 0); (void)signal(SIGHUP, SIG_IGN); (void)signal(SIGINT, SIG_IGN); /* * nfsd sits in the kernel most of the time. It needs * to ignore SIGTERM/SIGQUIT in order to stay alive as long * as possible during a shutdown, otherwise loopback * mounts will not be able to unmount. */ (void)signal(SIGTERM, SIG_IGN); (void)signal(SIGQUIT, SIG_IGN); } (void)signal(SIGSYS, nonfs); (void)signal(SIGCHLD, reapchild); (void)signal(SIGUSR2, backup_stable); openlog("nfsd", LOG_PID, LOG_DAEMON); /* * For V4, we open the stablerestart file and call nfssvc() * to get it loaded. This is done before the daemons do the * regular nfssvc() call to service NFS requests. * (This way the file remains open until the last nfsd is killed * off.) * It and the backup copy will be created as empty files * the first time this nfsd is started and should never be * deleted/replaced if at all possible. It should live on a * local, non-volatile storage device that does not do hardware * level write-back caching. (See SCSI doc for more information * on how to prevent write-back caching on SCSI disks.) */ if (run_v4server > 0) { open_stable(&stablefd, &backupfd); if (stablefd < 0) { syslog(LOG_ERR, "Can't open %s\n", NFSD_STABLERESTART); exit(1); } /* This system call will fail for old kernels, but that's ok. */ nfssvc(NFSSVC_BACKUPSTABLE, NULL); if (nfssvc(NFSSVC_STABLERESTART, (caddr_t)&stablefd) < 0) { syslog(LOG_ERR, "Can't read stable storage file\n"); exit(1); } nfssvc_addsock = NFSSVC_NFSDADDSOCK; nfssvc_nfsd = NFSSVC_NFSDNFSD; new_syscall = TRUE; } else { nfssvc_addsock = NFSSVC_ADDSOCK; nfssvc_nfsd = NFSSVC_NFSD; /* * Figure out if the kernel supports the new-style * NFSSVC_NFSD. Old kernels will return ENXIO because they * don't recognise the flag value, new ones will return EINVAL * because argp is NULL. */ new_syscall = FALSE; if (nfssvc(NFSSVC_NFSD, NULL) < 0 && errno == EINVAL) new_syscall = TRUE; } if (!new_syscall) { /* If we use UDP only, we start the last server below. */ srvcnt = tcpflag ? nfsdcnt : nfsdcnt - 1; for (i = 0; i < srvcnt; i++) { switch ((pid = fork())) { case -1: syslog(LOG_ERR, "fork: %m"); nfsd_exit(1); case 0: break; default: children[i] = pid; continue; } (void)signal(SIGUSR1, child_cleanup); setproctitle("server"); start_server(0); } } else if (tcpflag) { /* * For TCP mode, we fork once to start the first * kernel nfsd thread. The kernel will add more * threads as needed. */ pid = fork(); if (pid == -1) { syslog(LOG_ERR, "fork: %m"); nfsd_exit(1); } if (pid) { children[0] = pid; } else { (void)signal(SIGUSR1, child_cleanup); setproctitle("server"); start_server(0); } } (void)signal(SIGUSR1, cleanup); FD_ZERO(&v4bits); FD_ZERO(&v6bits); FD_ZERO(&sockbits); rpcbregcnt = 0; /* Set up the socket for udp and rpcb register it. */ if (udpflag) { rpcbreg = 0; for (i = 0; i < bindhostc; i++) { memset(&hints, 0, sizeof hints); hints.ai_flags = AI_PASSIVE; hints.ai_family = AF_INET; hints.ai_socktype = SOCK_DGRAM; hints.ai_protocol = IPPROTO_UDP; if (setbindhost(&ai_udp, bindhost[i], hints) == 0) { rpcbreg = 1; rpcbregcnt++; if ((sock = socket(ai_udp->ai_family, ai_udp->ai_socktype, ai_udp->ai_protocol)) < 0) { syslog(LOG_ERR, "can't create udp socket"); nfsd_exit(1); } if (bind(sock, ai_udp->ai_addr, ai_udp->ai_addrlen) < 0) { syslog(LOG_ERR, "can't bind udp addr %s: %m", bindhost[i]); nfsd_exit(1); } freeaddrinfo(ai_udp); addsockargs.sock = sock; addsockargs.name = NULL; addsockargs.namelen = 0; if (nfssvc(nfssvc_addsock, &addsockargs) < 0) { syslog(LOG_ERR, "can't Add UDP socket"); nfsd_exit(1); } (void)close(sock); } } if (rpcbreg == 1) { memset(&hints, 0, sizeof hints); hints.ai_flags = AI_PASSIVE; hints.ai_family = AF_INET; hints.ai_socktype = SOCK_DGRAM; hints.ai_protocol = IPPROTO_UDP; ecode = getaddrinfo(NULL, "nfs", &hints, &ai_udp); if (ecode != 0) { syslog(LOG_ERR, "getaddrinfo udp: %s", gai_strerror(ecode)); nfsd_exit(1); } nconf_udp = getnetconfigent("udp"); if (nconf_udp == NULL) err(1, "getnetconfigent udp failed"); nb_udp.buf = ai_udp->ai_addr; nb_udp.len = nb_udp.maxlen = ai_udp->ai_addrlen; if ((!rpcb_set(NFS_PROGRAM, 2, nconf_udp, &nb_udp)) || (!rpcb_set(NFS_PROGRAM, 3, nconf_udp, &nb_udp))) err(1, "rpcb_set udp failed"); freeaddrinfo(ai_udp); } } /* Set up the socket for udp6 and rpcb register it. */ if (udpflag && ip6flag) { rpcbreg = 0; for (i = 0; i < bindhostc; i++) { memset(&hints, 0, sizeof hints); hints.ai_flags = AI_PASSIVE; hints.ai_family = AF_INET6; hints.ai_socktype = SOCK_DGRAM; hints.ai_protocol = IPPROTO_UDP; if (setbindhost(&ai_udp6, bindhost[i], hints) == 0) { rpcbreg = 1; rpcbregcnt++; if ((sock = socket(ai_udp6->ai_family, ai_udp6->ai_socktype, ai_udp6->ai_protocol)) < 0) { syslog(LOG_ERR, "can't create udp6 socket"); nfsd_exit(1); } if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof on) < 0) { syslog(LOG_ERR, "can't set v6-only binding for " "udp6 socket: %m"); nfsd_exit(1); } if (bind(sock, ai_udp6->ai_addr, ai_udp6->ai_addrlen) < 0) { syslog(LOG_ERR, "can't bind udp6 addr %s: %m", bindhost[i]); nfsd_exit(1); } freeaddrinfo(ai_udp6); addsockargs.sock = sock; addsockargs.name = NULL; addsockargs.namelen = 0; if (nfssvc(nfssvc_addsock, &addsockargs) < 0) { syslog(LOG_ERR, "can't add UDP6 socket"); nfsd_exit(1); } (void)close(sock); } } if (rpcbreg == 1) { memset(&hints, 0, sizeof hints); hints.ai_flags = AI_PASSIVE; hints.ai_family = AF_INET6; hints.ai_socktype = SOCK_DGRAM; hints.ai_protocol = IPPROTO_UDP; ecode = getaddrinfo(NULL, "nfs", &hints, &ai_udp6); if (ecode != 0) { syslog(LOG_ERR, "getaddrinfo udp6: %s", gai_strerror(ecode)); nfsd_exit(1); } nconf_udp6 = getnetconfigent("udp6"); if (nconf_udp6 == NULL) err(1, "getnetconfigent udp6 failed"); nb_udp6.buf = ai_udp6->ai_addr; nb_udp6.len = nb_udp6.maxlen = ai_udp6->ai_addrlen; if ((!rpcb_set(NFS_PROGRAM, 2, nconf_udp6, &nb_udp6)) || (!rpcb_set(NFS_PROGRAM, 3, nconf_udp6, &nb_udp6))) err(1, "rpcb_set udp6 failed"); freeaddrinfo(ai_udp6); } } /* Set up the socket for tcp and rpcb register it. */ if (tcpflag) { rpcbreg = 0; for (i = 0; i < bindhostc; i++) { memset(&hints, 0, sizeof hints); hints.ai_flags = AI_PASSIVE; hints.ai_family = AF_INET; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; if (setbindhost(&ai_tcp, bindhost[i], hints) == 0) { rpcbreg = 1; rpcbregcnt++; if ((tcpsock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { syslog(LOG_ERR, "can't create tpc socket"); nfsd_exit(1); } if (setsockopt(tcpsock, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0) syslog(LOG_ERR, "setsockopt SO_REUSEADDR: %m"); if (bind(tcpsock, ai_tcp->ai_addr, ai_tcp->ai_addrlen) < 0) { syslog(LOG_ERR, "can't bind tcp addr %s: %m", bindhost[i]); nfsd_exit(1); } if (listen(tcpsock, 5) < 0) { syslog(LOG_ERR, "listen failed"); nfsd_exit(1); } freeaddrinfo(ai_tcp); FD_SET(tcpsock, &sockbits); FD_SET(tcpsock, &v4bits); maxsock = tcpsock; connect_type_cnt++; } } if (rpcbreg == 1) { memset(&hints, 0, sizeof hints); hints.ai_flags = AI_PASSIVE; hints.ai_family = AF_INET; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; ecode = getaddrinfo(NULL, "nfs", &hints, &ai_tcp); if (ecode != 0) { syslog(LOG_ERR, "getaddrinfo tcp: %s", gai_strerror(ecode)); nfsd_exit(1); } nconf_tcp = getnetconfigent("tcp"); if (nconf_tcp == NULL) err(1, "getnetconfigent tcp failed"); nb_tcp.buf = ai_tcp->ai_addr; nb_tcp.len = nb_tcp.maxlen = ai_tcp->ai_addrlen; if ((!rpcb_set(NFS_PROGRAM, 2, nconf_tcp, &nb_tcp)) || (!rpcb_set(NFS_PROGRAM, 3, nconf_tcp, &nb_tcp))) err(1, "rpcb_set tcp failed"); freeaddrinfo(ai_tcp); } } /* Set up the socket for tcp6 and rpcb register it. */ if (tcpflag && ip6flag) { rpcbreg = 0; for (i = 0; i < bindhostc; i++) { memset(&hints, 0, sizeof hints); hints.ai_flags = AI_PASSIVE; hints.ai_family = AF_INET6; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; if (setbindhost(&ai_tcp6, bindhost[i], hints) == 0) { rpcbreg = 1; rpcbregcnt++; if ((tcp6sock = socket(ai_tcp6->ai_family, ai_tcp6->ai_socktype, ai_tcp6->ai_protocol)) < 0) { syslog(LOG_ERR, "can't create tcp6 socket"); nfsd_exit(1); } if (setsockopt(tcp6sock, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0) syslog(LOG_ERR, "setsockopt SO_REUSEADDR: %m"); if (setsockopt(tcp6sock, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof on) < 0) { syslog(LOG_ERR, "can't set v6-only binding for tcp6 " "socket: %m"); nfsd_exit(1); } if (bind(tcp6sock, ai_tcp6->ai_addr, ai_tcp6->ai_addrlen) < 0) { syslog(LOG_ERR, "can't bind tcp6 addr %s: %m", bindhost[i]); nfsd_exit(1); } if (listen(tcp6sock, 5) < 0) { syslog(LOG_ERR, "listen failed"); nfsd_exit(1); } freeaddrinfo(ai_tcp6); FD_SET(tcp6sock, &sockbits); FD_SET(tcp6sock, &v6bits); if (maxsock < tcp6sock) maxsock = tcp6sock; connect_type_cnt++; } } if (rpcbreg == 1) { memset(&hints, 0, sizeof hints); hints.ai_flags = AI_PASSIVE; hints.ai_family = AF_INET6; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; ecode = getaddrinfo(NULL, "nfs", &hints, &ai_tcp6); if (ecode != 0) { syslog(LOG_ERR, "getaddrinfo tcp6: %s", gai_strerror(ecode)); nfsd_exit(1); } nconf_tcp6 = getnetconfigent("tcp6"); if (nconf_tcp6 == NULL) err(1, "getnetconfigent tcp6 failed"); nb_tcp6.buf = ai_tcp6->ai_addr; nb_tcp6.len = nb_tcp6.maxlen = ai_tcp6->ai_addrlen; if ((!rpcb_set(NFS_PROGRAM, 2, nconf_tcp6, &nb_tcp6)) || (!rpcb_set(NFS_PROGRAM, 3, nconf_tcp6, &nb_tcp6))) err(1, "rpcb_set tcp6 failed"); freeaddrinfo(ai_tcp6); } } if (rpcbregcnt == 0) { syslog(LOG_ERR, "rpcb_set() failed, nothing to do: %m"); nfsd_exit(1); } if (tcpflag && connect_type_cnt == 0) { syslog(LOG_ERR, "tcp connects == 0, nothing to do: %m"); nfsd_exit(1); } setproctitle("master"); /* * We always want a master to have a clean way to to shut nfsd down * (with unregistration): if the master is killed, it unregisters and * kills all children. If we run for UDP only (and so do not have to * loop waiting waiting for accept), we instead make the parent * a "server" too. start_server will not return. */ if (!tcpflag) start_server(1); /* * Loop forever accepting connections and passing the sockets * into the kernel for the mounts. */ for (;;) { ready = sockbits; if (connect_type_cnt > 1) { if (select(maxsock + 1, &ready, NULL, NULL, NULL) < 1) { error = errno; if (error == EINTR) continue; syslog(LOG_ERR, "select failed: %m"); nfsd_exit(1); } } for (tcpsock = 0; tcpsock <= maxsock; tcpsock++) { if (FD_ISSET(tcpsock, &ready)) { if (FD_ISSET(tcpsock, &v4bits)) { len = sizeof(inetpeer); if ((msgsock = accept(tcpsock, (struct sockaddr *)&inetpeer, &len)) < 0) { error = errno; syslog(LOG_ERR, "accept failed: %m"); if (error == ECONNABORTED || error == EINTR) continue; nfsd_exit(1); } memset(inetpeer.sin_zero, 0, sizeof(inetpeer.sin_zero)); if (setsockopt(msgsock, SOL_SOCKET, SO_KEEPALIVE, (char *)&on, sizeof(on)) < 0) syslog(LOG_ERR, "setsockopt SO_KEEPALIVE: %m"); addsockargs.sock = msgsock; addsockargs.name = (caddr_t)&inetpeer; addsockargs.namelen = len; nfssvc(nfssvc_addsock, &addsockargs); (void)close(msgsock); } else if (FD_ISSET(tcpsock, &v6bits)) { len = sizeof(inet6peer); if ((msgsock = accept(tcpsock, (struct sockaddr *)&inet6peer, &len)) < 0) { error = errno; syslog(LOG_ERR, "accept failed: %m"); if (error == ECONNABORTED || error == EINTR) continue; nfsd_exit(1); } if (setsockopt(msgsock, SOL_SOCKET, SO_KEEPALIVE, (char *)&on, sizeof(on)) < 0) syslog(LOG_ERR, "setsockopt " "SO_KEEPALIVE: %m"); addsockargs.sock = msgsock; addsockargs.name = (caddr_t)&inet6peer; addsockargs.namelen = len; nfssvc(nfssvc_addsock, &addsockargs); (void)close(msgsock); } } } } } int setbindhost(struct addrinfo **ai, const char *bindhost, struct addrinfo hints) { int ecode; u_int32_t host_addr[4]; /* IPv4 or IPv6 */ const char *hostptr; if (bindhost == NULL || strcmp("*", bindhost) == 0) hostptr = NULL; else hostptr = bindhost; if (hostptr != NULL) { switch (hints.ai_family) { case AF_INET: if (inet_pton(AF_INET, hostptr, host_addr) == 1) { hints.ai_flags = AI_NUMERICHOST; } else { if (inet_pton(AF_INET6, hostptr, host_addr) == 1) return (1); } break; case AF_INET6: if (inet_pton(AF_INET6, hostptr, host_addr) == 1) { hints.ai_flags = AI_NUMERICHOST; } else { if (inet_pton(AF_INET, hostptr, host_addr) == 1) return (1); } break; default: break; } } ecode = getaddrinfo(hostptr, "nfs", &hints, ai); if (ecode != 0) { syslog(LOG_ERR, "getaddrinfo %s: %s", bindhost, gai_strerror(ecode)); return (1); } return (0); } void usage(void) { (void)fprintf(stderr, "usage: nfsd %s\n", USAGE); exit(1); } void nonfs(__unused int signo) { syslog(LOG_ERR, "missing system call: NFS not available"); } void reapchild(__unused int signo) { pid_t pid; int i; while ((pid = wait3(NULL, WNOHANG, NULL)) > 0) { for (i = 0; i < nfsdcnt; i++) if (pid == children[i]) children[i] = -1; } } void unregistration(void) { if ((!rpcb_unset(NFS_PROGRAM, 2, NULL)) || (!rpcb_unset(NFS_PROGRAM, 3, NULL))) syslog(LOG_ERR, "rpcb_unset failed"); } void killchildren(void) { int i; for (i = 0; i < nfsdcnt; i++) { if (children[i] > 0) kill(children[i], SIGKILL); } } /* * Cleanup master after SIGUSR1. */ void cleanup(__unused int signo) { nfsd_exit(0); } /* * Cleanup child after SIGUSR1. */ void child_cleanup(__unused int signo) { exit(0); } void nfsd_exit(int status) { killchildren(); unregistration(); exit(status); } void start_server(int master) { char principal[MAXHOSTNAMELEN + 5]; struct nfsd_nfsd_args nfsdargs; int status, error; char hostname[MAXHOSTNAMELEN + 1], *cp; struct addrinfo *aip, hints; status = 0; if (new_syscall) { gethostname(hostname, sizeof (hostname)); snprintf(principal, sizeof (principal), "nfs@%s", hostname); if ((cp = strchr(hostname, '.')) == NULL || *(cp + 1) == '\0') { /* If not fully qualified, try getaddrinfo() */ memset((void *)&hints, 0, sizeof (hints)); hints.ai_flags = AI_CANONNAME; error = getaddrinfo(hostname, NULL, &hints, &aip); if (error == 0) { if (aip->ai_canonname != NULL && (cp = strchr(aip->ai_canonname, '.')) != NULL && *(cp + 1) != '\0') snprintf(principal, sizeof (principal), "nfs@%s", aip->ai_canonname); freeaddrinfo(aip); } } nfsdargs.principal = principal; nfsdargs.minthreads = nfsdcnt; nfsdargs.maxthreads = nfsdcnt; error = nfssvc(nfssvc_nfsd, &nfsdargs); if (error < 0 && errno == EAUTH) { /* * This indicates that it could not register the * rpcsec_gss credentials, usually because the * gssd daemon isn't running. * (only the experimental server with nfsv4) */ syslog(LOG_ERR, "No gssd, using AUTH_SYS only"); principal[0] = '\0'; error = nfssvc(nfssvc_nfsd, &nfsdargs); } if (error < 0) { syslog(LOG_ERR, "nfssvc: %m"); status = 1; } } else { if (nfssvc(NFSSVC_OLDNFSD, NULL) < 0) { syslog(LOG_ERR, "nfssvc: %m"); status = 1; } } if (master) nfsd_exit(status); else exit(status); } /* * Open the stable restart file and return the file descriptor for it. */ void open_stable(int *stable_fdp, int *backup_fdp) { int stable_fd, backup_fd = -1, ret; struct stat st, backup_st; /* Open and stat the stable restart file. */ stable_fd = open(NFSD_STABLERESTART, O_RDWR, 0); if (stable_fd < 0) stable_fd = open(NFSD_STABLERESTART, O_RDWR | O_CREAT, 0600); if (stable_fd >= 0) { ret = fstat(stable_fd, &st); if (ret < 0) { close(stable_fd); stable_fd = -1; } } /* Open and stat the backup stable restart file. */ if (stable_fd >= 0) { backup_fd = open(NFSD_STABLEBACKUP, O_RDWR, 0); if (backup_fd < 0) backup_fd = open(NFSD_STABLEBACKUP, O_RDWR | O_CREAT, 0600); if (backup_fd >= 0) { ret = fstat(backup_fd, &backup_st); if (ret < 0) { close(backup_fd); backup_fd = -1; } } if (backup_fd < 0) { close(stable_fd); stable_fd = -1; } } *stable_fdp = stable_fd; *backup_fdp = backup_fd; if (stable_fd < 0) return; /* Sync up the 2 files, as required. */ if (st.st_size > 0) copy_stable(stable_fd, backup_fd); else if (backup_st.st_size > 0) copy_stable(backup_fd, stable_fd); } /* * Copy the stable restart file to the backup or vice versa. */ void copy_stable(int from_fd, int to_fd) { int cnt, ret; static char buf[1024]; ret = lseek(from_fd, (off_t)0, SEEK_SET); if (ret >= 0) ret = lseek(to_fd, (off_t)0, SEEK_SET); if (ret >= 0) ret = ftruncate(to_fd, (off_t)0); if (ret >= 0) do { cnt = read(from_fd, buf, 1024); if (cnt > 0) ret = write(to_fd, buf, cnt); else if (cnt < 0) ret = cnt; } while (cnt > 0 && ret >= 0); if (ret >= 0) ret = fsync(to_fd); if (ret < 0) syslog(LOG_ERR, "stable restart copy failure: %m"); } /* * Back up the stable restart file when indicated by the kernel. */ void backup_stable(__unused int signo) { if (stablefd >= 0) copy_stable(stablefd, backupfd); } diff --git a/usr.sbin/pmcstat/pmcpl_calltree.c b/usr.sbin/pmcstat/pmcpl_calltree.c index c647a325a020..af3317a36def 100644 --- a/usr.sbin/pmcstat/pmcpl_calltree.c +++ b/usr.sbin/pmcstat/pmcpl_calltree.c @@ -1,1045 +1,1044 @@ /*- * Copyright (c) 2009, Fabien Thomas * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * Process hwpmc(4) samples as calltree. * * Output file format compatible with Kcachegrind (kdesdk). * Handle top mode with a sorted tree display. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include -#include #include #include #include #include #include #include #include "pmcstat.h" #include "pmcstat_log.h" #include "pmcstat_top.h" #include "pmcpl_calltree.h" #define PMCPL_CT_GROWSIZE 4 static pmcstat_interned_string pmcpl_ct_prevfn; static int pmcstat_skiplink = 0; struct pmcpl_ct_node; /* Get the sample value for PMC a. */ #define PMCPL_CT_SAMPLE(a, b) \ ((a) < (b)->npmcs ? (b)->sb[a] : 0) /* Get the sample value in percent related to rsamples. */ #define PMCPL_CT_SAMPLEP(a, b) \ (PMCPL_CT_SAMPLE(a, b) * 100.0 / rsamples->sb[a]) struct pmcpl_ct_sample { int npmcs; /* Max pmc index available. */ unsigned *sb; /* Sample buffer for 0..npmcs. */ }; struct pmcpl_ct_arc { struct pmcpl_ct_sample pcta_samples; struct pmcpl_ct_sample pcta_callid; unsigned pcta_call; struct pmcpl_ct_node *pcta_child; }; struct pmcpl_ct_instr { uintfptr_t pctf_func; struct pmcpl_ct_sample pctf_samples; }; /* * Each calltree node is tracked by a pmcpl_ct_node struct. */ struct pmcpl_ct_node { #define PMCPL_PCT_TAG 0x00000001 /* Loop detection. */ uint32_t pct_flags; struct pmcstat_image *pct_image; uintfptr_t pct_func; struct pmcpl_ct_sample pct_samples; int pct_narc; int pct_arc_c; struct pmcpl_ct_arc *pct_arc; /* TODO: optimize for large number of items. */ int pct_ninstr; int pct_instr_c; struct pmcpl_ct_instr *pct_instr; }; struct pmcpl_ct_node_hash { struct pmcpl_ct_node *pch_ctnode; LIST_ENTRY(pmcpl_ct_node_hash) pch_next; }; struct pmcpl_ct_sample pmcpl_ct_callid; #define PMCPL_CT_MAXCOL PMC_CALLCHAIN_DEPTH_MAX #define PMCPL_CT_MAXLINE 1024 /* TODO: dynamic. */ struct pmcpl_ct_line { unsigned ln_sum; unsigned ln_index; }; struct pmcpl_ct_line pmcpl_ct_topmax[PMCPL_CT_MAXLINE+1]; struct pmcpl_ct_node *pmcpl_ct_topscreen[PMCPL_CT_MAXCOL+1][PMCPL_CT_MAXLINE+1]; /* * All nodes indexed by function/image name are placed in a hash table. */ static LIST_HEAD(,pmcpl_ct_node_hash) pmcpl_ct_node_hash[PMCSTAT_NHASH]; /* * Root node for the graph. */ static struct pmcpl_ct_node *pmcpl_ct_root; /* * Prototypes */ /* * Initialize a samples. */ static void pmcpl_ct_samples_init(struct pmcpl_ct_sample *samples) { samples->npmcs = 0; samples->sb = NULL; } /* * Free a samples. */ static void pmcpl_ct_samples_free(struct pmcpl_ct_sample *samples) { samples->npmcs = 0; free(samples->sb); samples->sb = NULL; } /* * Grow a sample block to store pmcstat_npmcs PMCs. */ static void pmcpl_ct_samples_grow(struct pmcpl_ct_sample *samples) { int npmcs; /* Enough storage. */ if (pmcstat_npmcs <= samples->npmcs) return; npmcs = samples->npmcs + max(pmcstat_npmcs - samples->npmcs, PMCPL_CT_GROWSIZE); samples->sb = realloc(samples->sb, npmcs * sizeof(unsigned)); if (samples->sb == NULL) errx(EX_SOFTWARE, "ERROR: out of memory"); bzero((char *)samples->sb + samples->npmcs * sizeof(unsigned), (npmcs - samples->npmcs) * sizeof(unsigned)); samples->npmcs = npmcs; } /* * Compute the sum of all root arcs. */ static void pmcpl_ct_samples_root(struct pmcpl_ct_sample *samples) { int i, pmcin; pmcpl_ct_samples_init(samples); pmcpl_ct_samples_grow(samples); for (i = 0; i < pmcpl_ct_root->pct_narc; i++) for (pmcin = 0; pmcin < pmcstat_npmcs; pmcin++) samples->sb[pmcin] += PMCPL_CT_SAMPLE(pmcin, &pmcpl_ct_root->pct_arc[i].pcta_samples); } /* * Grow the arc table. */ static void pmcpl_ct_arc_grow(int cursize, int *maxsize, struct pmcpl_ct_arc **items) { int nmaxsize; if (cursize < *maxsize) return; nmaxsize = *maxsize + max(cursize + 1 - *maxsize, PMCPL_CT_GROWSIZE); *items = realloc(*items, nmaxsize * sizeof(struct pmcpl_ct_arc)); if (*items == NULL) errx(EX_SOFTWARE, "ERROR: out of memory"); bzero((char *)*items + *maxsize * sizeof(struct pmcpl_ct_arc), (nmaxsize - *maxsize) * sizeof(struct pmcpl_ct_arc)); *maxsize = nmaxsize; } /* * Grow the instr table. */ static void pmcpl_ct_instr_grow(int cursize, int *maxsize, struct pmcpl_ct_instr **items) { int nmaxsize; if (cursize < *maxsize) return; nmaxsize = *maxsize + max(cursize + 1 - *maxsize, PMCPL_CT_GROWSIZE); *items = realloc(*items, nmaxsize * sizeof(struct pmcpl_ct_instr)); if (*items == NULL) errx(EX_SOFTWARE, "ERROR: out of memory"); bzero((char *)*items + *maxsize * sizeof(struct pmcpl_ct_instr), (nmaxsize - *maxsize) * sizeof(struct pmcpl_ct_instr)); *maxsize = nmaxsize; } /* * Add a new instruction sample to given node. */ static void pmcpl_ct_instr_add(struct pmcpl_ct_node *ct, int pmcin, uintfptr_t pc) { int i; struct pmcpl_ct_instr *in; for (i = 0; ipct_ninstr; i++) { if (ct->pct_instr[i].pctf_func == pc) { in = &ct->pct_instr[i]; pmcpl_ct_samples_grow(&in->pctf_samples); in->pctf_samples.sb[pmcin]++; return; } } pmcpl_ct_instr_grow(ct->pct_ninstr, &ct->pct_instr_c, &ct->pct_instr); in = &ct->pct_instr[ct->pct_ninstr]; in->pctf_func = pc; pmcpl_ct_samples_init(&in->pctf_samples); pmcpl_ct_samples_grow(&in->pctf_samples); in->pctf_samples.sb[pmcin] = 1; ct->pct_ninstr++; } /* * Allocate a new node. */ static struct pmcpl_ct_node * pmcpl_ct_node_allocate(struct pmcstat_image *image, uintfptr_t pc) { struct pmcpl_ct_node *ct; if ((ct = malloc(sizeof(*ct))) == NULL) err(EX_OSERR, "ERROR: Cannot allocate callgraph node"); ct->pct_flags = 0; ct->pct_image = image; ct->pct_func = pc; pmcpl_ct_samples_init(&ct->pct_samples); ct->pct_narc = 0; ct->pct_arc_c = 0; ct->pct_arc = NULL; ct->pct_ninstr = 0; ct->pct_instr_c = 0; ct->pct_instr = NULL; return (ct); } /* * Free a node. */ static void pmcpl_ct_node_free(struct pmcpl_ct_node *ct) { int i; for (i = 0; i < ct->pct_narc; i++) { pmcpl_ct_samples_free(&ct->pct_arc[i].pcta_samples); pmcpl_ct_samples_free(&ct->pct_arc[i].pcta_callid); } pmcpl_ct_samples_free(&ct->pct_samples); free(ct->pct_arc); free(ct->pct_instr); free(ct); } /* * Clear the graph tag on each node. */ static void pmcpl_ct_node_cleartag(void) { int i; struct pmcpl_ct_node_hash *pch; for (i = 0; i < PMCSTAT_NHASH; i++) LIST_FOREACH(pch, &pmcpl_ct_node_hash[i], pch_next) pch->pch_ctnode->pct_flags &= ~PMCPL_PCT_TAG; pmcpl_ct_root->pct_flags &= ~PMCPL_PCT_TAG; } /* * Print the callchain line by line with maximum cost at top. */ static int pmcpl_ct_node_dumptop(int pmcin, struct pmcpl_ct_node *ct, struct pmcpl_ct_sample *rsamples, int x, int *y) { int i, terminal; struct pmcpl_ct_arc *arc; if (ct->pct_flags & PMCPL_PCT_TAG) return 0; ct->pct_flags |= PMCPL_PCT_TAG; if (x >= PMCPL_CT_MAXCOL) { pmcpl_ct_topscreen[x][*y] = NULL; return 1; } pmcpl_ct_topscreen[x][*y] = ct; /* * Check if this is a terminal node. * We need to check that some samples exist * for at least one arc for that PMC. */ terminal = 1; for (i = 0; i < ct->pct_narc; i++) { arc = &ct->pct_arc[i]; if (PMCPL_CT_SAMPLE(pmcin, &arc->pcta_samples) != 0 && PMCPL_CT_SAMPLEP(pmcin, &arc->pcta_samples) > pmcstat_threshold && (arc->pcta_child->pct_flags & PMCPL_PCT_TAG) == 0) { terminal = 0; break; } } if (ct->pct_narc == 0 || terminal) { pmcpl_ct_topscreen[x+1][*y] = NULL; if (*y >= PMCPL_CT_MAXLINE) return 1; *y = *y + 1; for (i=0; i < x; i++) pmcpl_ct_topscreen[i][*y] = pmcpl_ct_topscreen[i][*y - 1]; return 0; } for (i = 0; i < ct->pct_narc; i++) { if (PMCPL_CT_SAMPLE(pmcin, &ct->pct_arc[i].pcta_samples) == 0) continue; if (PMCPL_CT_SAMPLEP(pmcin, &ct->pct_arc[i].pcta_samples) > pmcstat_threshold) { if (pmcpl_ct_node_dumptop(pmcin, ct->pct_arc[i].pcta_child, rsamples, x+1, y)) return 1; } } return 0; } /* * Compare two top line by sum. */ static int pmcpl_ct_line_compare(const void *a, const void *b) { const struct pmcpl_ct_line *ct1, *ct2; ct1 = (const struct pmcpl_ct_line *) a; ct2 = (const struct pmcpl_ct_line *) b; /* Sort in reverse order */ if (ct1->ln_sum < ct2->ln_sum) return (1); if (ct1->ln_sum > ct2->ln_sum) return (-1); return (0); } /* * Format and display given PMC index. */ static void pmcpl_ct_node_printtop(struct pmcpl_ct_sample *rsamples, int pmcin, int maxy) { #undef TS #undef TSI #define TS(x, y) (pmcpl_ct_topscreen[x][y]) #define TSI(x, y) (pmcpl_ct_topscreen[x][pmcpl_ct_topmax[y].ln_index]) int v_attrs, ns_len, vs_len, is_len, width, indentwidth, x, y; float v; char ns[30], vs[10], is[20]; struct pmcpl_ct_node *ct; struct pmcstat_symbol *sym; const char *space = " "; /* * Sort by line cost. */ for (y = 0; ; y++) { ct = TS(1, y); if (ct == NULL) break; pmcpl_ct_topmax[y].ln_sum = 0; pmcpl_ct_topmax[y].ln_index = y; for (x = 1; TS(x, y) != NULL; x++) { pmcpl_ct_topmax[y].ln_sum += PMCPL_CT_SAMPLE(pmcin, &TS(x, y)->pct_samples); } } qsort(pmcpl_ct_topmax, y, sizeof(pmcpl_ct_topmax[0]), pmcpl_ct_line_compare); pmcpl_ct_topmax[y].ln_index = y; for (y = 0; y < maxy; y++) { ct = TSI(1, y); if (ct == NULL) break; if (y > 0) PMCSTAT_PRINTW("\n"); /* Output sum. */ v = pmcpl_ct_topmax[y].ln_sum * 100.0 / rsamples->sb[pmcin]; snprintf(vs, sizeof(vs), "%.1f", v); v_attrs = PMCSTAT_ATTRPERCENT(v); PMCSTAT_ATTRON(v_attrs); PMCSTAT_PRINTW("%5.5s ", vs); PMCSTAT_ATTROFF(v_attrs); width = indentwidth = 5 + 1; for (x = 1; (ct = TSI(x, y)) != NULL; x++) { vs[0] = '\0'; vs_len = 0; is[0] = '\0'; is_len = 0; /* Format value. */ v = PMCPL_CT_SAMPLEP(pmcin, &ct->pct_samples); if (v > pmcstat_threshold) vs_len = snprintf(vs, sizeof(vs), "(%.1f%%)", v); v_attrs = PMCSTAT_ATTRPERCENT(v); if (pmcstat_skiplink && v <= pmcstat_threshold) { strlcpy(ns, ".", sizeof(ns)); ns_len = 1; } else { sym = pmcstat_symbol_search(ct->pct_image, ct->pct_func); if (sym != NULL) { ns_len = snprintf(ns, sizeof(ns), "%s", pmcstat_string_unintern(sym->ps_name)); } else ns_len = snprintf(ns, sizeof(ns), "%p", (void *)ct->pct_func); /* Format image. */ if (x == 1 || TSI(x-1, y)->pct_image != ct->pct_image) is_len = snprintf(is, sizeof(is), "@%s", pmcstat_string_unintern(ct->pct_image->pi_name)); /* Check for line wrap. */ width += ns_len + is_len + vs_len + 1; } if (width >= pmcstat_displaywidth) { maxy--; if (y >= maxy) break; PMCSTAT_PRINTW("\n%*s", indentwidth, space); width = indentwidth + ns_len + is_len + vs_len; } PMCSTAT_ATTRON(v_attrs); PMCSTAT_PRINTW("%s%s%s ", ns, is, vs); PMCSTAT_ATTROFF(v_attrs); } } } /* * Output top mode snapshot. */ void pmcpl_ct_topdisplay(void) { int y; struct pmcpl_ct_sample r, *rsamples; rsamples = &r; pmcpl_ct_samples_root(rsamples); pmcpl_ct_node_cleartag(); PMCSTAT_PRINTW("%5.5s %s\n", "%SAMP", "CALLTREE"); y = 0; if (pmcpl_ct_node_dumptop(pmcstat_pmcinfilter, pmcpl_ct_root, rsamples, 0, &y)) PMCSTAT_PRINTW("...\n"); pmcpl_ct_topscreen[1][y] = NULL; pmcpl_ct_node_printtop(rsamples, pmcstat_pmcinfilter, pmcstat_displayheight - 2); pmcpl_ct_samples_free(rsamples); } /* * Handle top mode keypress. */ int pmcpl_ct_topkeypress(int c, WINDOW *w) { switch (c) { case 'f': pmcstat_skiplink = !pmcstat_skiplink; wprintw(w, "skip empty link %s", pmcstat_skiplink ? "on" : "off"); break; } return 0; } /* * Look for a callgraph node associated with pmc `pmcid' in the global * hash table that corresponds to the given `pc' value in the process map * `ppm'. */ static struct pmcpl_ct_node * pmcpl_ct_node_hash_lookup_pc(struct pmcpl_ct_node *parent, struct pmcstat_pcmap *ppm, uintfptr_t pc, int pmcin) { struct pmcstat_symbol *sym; struct pmcstat_image *image; struct pmcpl_ct_node *ct; struct pmcpl_ct_node_hash *h; struct pmcpl_ct_arc *arc; uintfptr_t loadaddress; int i; unsigned int hash; assert(parent != NULL); image = ppm->ppm_image; loadaddress = ppm->ppm_lowpc + image->pi_vaddr - image->pi_start; pc -= loadaddress; /* Convert to an offset in the image. */ /* * Try determine the function at this offset. If we can't * find a function round leave the `pc' value alone. */ if ((sym = pmcstat_symbol_search(image, pc)) != NULL) pc = sym->ps_start; else pmcstat_stats.ps_samples_unknown_function++; for (hash = i = 0; i < (int)sizeof(uintfptr_t); i++) hash += (pc >> i) & 0xFF; hash &= PMCSTAT_HASH_MASK; ct = NULL; LIST_FOREACH(h, &pmcpl_ct_node_hash[hash], pch_next) { ct = h->pch_ctnode; assert(ct != NULL); if (ct->pct_image == image && ct->pct_func == pc) { /* * Find related arc in parent node and * increment the sample count. */ for (i = 0; i < parent->pct_narc; i++) { if (parent->pct_arc[i].pcta_child == ct) { arc = &parent->pct_arc[i]; pmcpl_ct_samples_grow(&arc->pcta_samples); arc->pcta_samples.sb[pmcin]++; /* Estimate call count. */ pmcpl_ct_samples_grow(&arc->pcta_callid); if (pmcpl_ct_callid.sb[pmcin] - arc->pcta_callid.sb[pmcin] > 1) arc->pcta_call++; arc->pcta_callid.sb[pmcin] = pmcpl_ct_callid.sb[pmcin]; return (ct); } } /* * No arc found for us, add ourself to the parent. */ pmcpl_ct_arc_grow(parent->pct_narc, &parent->pct_arc_c, &parent->pct_arc); arc = &parent->pct_arc[parent->pct_narc]; pmcpl_ct_samples_grow(&arc->pcta_samples); arc->pcta_samples.sb[pmcin] = 1; arc->pcta_call = 1; pmcpl_ct_samples_grow(&arc->pcta_callid); arc->pcta_callid.sb[pmcin] = pmcpl_ct_callid.sb[pmcin]; arc->pcta_child = ct; parent->pct_narc++; return (ct); } } /* * We haven't seen this (pmcid, pc) tuple yet, so allocate a * new callgraph node and a new hash table entry for it. */ ct = pmcpl_ct_node_allocate(image, pc); if ((h = malloc(sizeof(*h))) == NULL) err(EX_OSERR, "ERROR: Could not allocate callgraph node"); h->pch_ctnode = ct; LIST_INSERT_HEAD(&pmcpl_ct_node_hash[hash], h, pch_next); pmcpl_ct_arc_grow(parent->pct_narc, &parent->pct_arc_c, &parent->pct_arc); arc = &parent->pct_arc[parent->pct_narc]; pmcpl_ct_samples_grow(&arc->pcta_samples); arc->pcta_samples.sb[pmcin] = 1; arc->pcta_call = 1; pmcpl_ct_samples_grow(&arc->pcta_callid); arc->pcta_callid.sb[pmcin] = pmcpl_ct_callid.sb[pmcin]; arc->pcta_child = ct; parent->pct_narc++; return (ct); } /* * Record a callchain. */ void pmcpl_ct_process(struct pmcstat_process *pp, struct pmcstat_pmcrecord *pmcr, uint32_t nsamples, uintfptr_t *cc, int usermode, uint32_t cpu) { int n, pmcin; struct pmcstat_pcmap *ppm[PMC_CALLCHAIN_DEPTH_MAX]; struct pmcstat_process *km; struct pmcpl_ct_node *parent, *child; (void) cpu; assert(nsamples>0 && nsamples<=PMC_CALLCHAIN_DEPTH_MAX); /* Get the PMC index. */ pmcin = pmcr->pr_pmcin; /* * Validate mapping for the callchain. * Go from bottom to first invalid entry. */ km = pmcstat_kernproc; for (n = 0; n < (int)nsamples; n++) { ppm[n] = pmcstat_process_find_map(usermode ? pp : km, cc[n]); if (ppm[n] == NULL) { /* Detect full frame capture (kernel + user). */ if (!usermode) { ppm[n] = pmcstat_process_find_map(pp, cc[n]); if (ppm[n] != NULL) km = pp; } } if (ppm[n] == NULL) break; } if (n-- == 0) { pmcstat_stats.ps_callchain_dubious_frames++; pmcr->pr_dubious_frames++; return; } /* Increase the call generation counter. */ pmcpl_ct_samples_grow(&pmcpl_ct_callid); pmcpl_ct_callid.sb[pmcin]++; /* * Iterate remaining addresses. */ for (parent = pmcpl_ct_root, child = NULL; n >= 0; n--) { child = pmcpl_ct_node_hash_lookup_pc(parent, ppm[n], cc[n], pmcin); if (child == NULL) { pmcstat_stats.ps_callchain_dubious_frames++; continue; } parent = child; } /* * Increment the sample count for this PMC. */ if (child != NULL) { pmcpl_ct_samples_grow(&child->pct_samples); child->pct_samples.sb[pmcin]++; /* Update per instruction sample if required. */ if (args.pa_ctdumpinstr) pmcpl_ct_instr_add(child, pmcin, cc[0] - (ppm[0]->ppm_lowpc + ppm[0]->ppm_image->pi_vaddr - ppm[0]->ppm_image->pi_start)); } } /* * Print node self cost. */ static void pmcpl_ct_node_printself(struct pmcpl_ct_node *ct) { int i, j, line; uintptr_t addr; struct pmcstat_symbol *sym; char sourcefile[PATH_MAX]; char funcname[PATH_MAX]; /* * Object binary. */ #ifdef PMCPL_CT_OPTIMIZEFN if (pmcpl_ct_prevfn != ct->pct_image->pi_fullpath) { #endif pmcpl_ct_prevfn = ct->pct_image->pi_fullpath; fprintf(args.pa_graphfile, "ob=%s\n", pmcstat_string_unintern(pmcpl_ct_prevfn)); #ifdef PMCPL_CT_OPTIMIZEFN } #endif /* * Function name. */ if (pmcstat_image_addr2line(ct->pct_image, ct->pct_func, sourcefile, sizeof(sourcefile), &line, funcname, sizeof(funcname))) { fprintf(args.pa_graphfile, "fn=%s\n", funcname); } else { sym = pmcstat_symbol_search(ct->pct_image, ct->pct_func); if (sym != NULL) fprintf(args.pa_graphfile, "fn=%s\n", pmcstat_string_unintern(sym->ps_name)); else fprintf(args.pa_graphfile, "fn=%p\n", (void *)(ct->pct_image->pi_vaddr + ct->pct_func)); } /* * Self cost. */ if (ct->pct_ninstr > 0) { for (i = 0; i < ct->pct_ninstr; i++) { addr = ct->pct_image->pi_vaddr + ct->pct_instr[i].pctf_func; line = 0; if (pmcstat_image_addr2line(ct->pct_image, addr, sourcefile, sizeof(sourcefile), &line, funcname, sizeof(funcname))) fprintf(args.pa_graphfile, "fl=%s\n", sourcefile); fprintf(args.pa_graphfile, "%p %u", (void *)addr, line); for (j = 0; jpct_instr[i].pctf_samples)); fprintf(args.pa_graphfile, "\n"); } } else { addr = ct->pct_image->pi_vaddr + ct->pct_func; line = 0; if (pmcstat_image_addr2line(ct->pct_image, addr, sourcefile, sizeof(sourcefile), &line, funcname, sizeof(funcname))) fprintf(args.pa_graphfile, "fl=%s\n", sourcefile); fprintf(args.pa_graphfile, "* *"); for (i = 0; ipct_samples)); fprintf(args.pa_graphfile, "\n"); } } /* * Print node child cost. */ static void pmcpl_ct_node_printchild(struct pmcpl_ct_node *ct) { int i, j, line; uintptr_t addr; struct pmcstat_symbol *sym; struct pmcpl_ct_node *child; char sourcefile[PATH_MAX]; char funcname[PATH_MAX]; /* * Child cost. * TODO: attach child cost to the real position in the funtion. * TODO: cfn= / call addr() / addr(call ) */ for (i=0 ; ipct_narc; i++) { child = ct->pct_arc[i].pcta_child; /* Object binary. */ #ifdef PMCPL_CT_OPTIMIZEFN if (pmcpl_ct_prevfn != child->pct_image->pi_fullpath) { #endif pmcpl_ct_prevfn = child->pct_image->pi_fullpath; fprintf(args.pa_graphfile, "cob=%s\n", pmcstat_string_unintern(pmcpl_ct_prevfn)); #if PMCPL_CT_OPTIMIZEFN } #endif /* Child function name. */ addr = child->pct_image->pi_vaddr + child->pct_func; /* Child function source file. */ if (pmcstat_image_addr2line(child->pct_image, addr, sourcefile, sizeof(sourcefile), &line, funcname, sizeof(funcname))) { fprintf(args.pa_graphfile, "cfn=%s\n", funcname); fprintf(args.pa_graphfile, "cfl=%s\n", sourcefile); } else { sym = pmcstat_symbol_search(child->pct_image, child->pct_func); if (sym != NULL) fprintf(args.pa_graphfile, "cfn=%s\n", pmcstat_string_unintern(sym->ps_name)); else fprintf(args.pa_graphfile, "cfn=%p\n", (void *)addr); } /* Child function address, line and call count. */ fprintf(args.pa_graphfile, "calls=%u %p %u\n", ct->pct_arc[i].pcta_call, (void *)addr, line); if (ct->pct_image != NULL) { /* Call address, line, sample. */ addr = ct->pct_image->pi_vaddr + ct->pct_func; line = 0; if (pmcstat_image_addr2line(ct->pct_image, addr, sourcefile, sizeof(sourcefile), &line, funcname, sizeof(funcname))) fprintf(args.pa_graphfile, "%p %u", (void *)addr, line); else fprintf(args.pa_graphfile, "* *"); } else fprintf(args.pa_graphfile, "* *"); for (j = 0; jpct_arc[i].pcta_samples)); fprintf(args.pa_graphfile, "\n"); } } /* * Clean the PMC name for Kcachegrind formula */ static void pmcpl_ct_fixup_pmcname(char *s) { char *p; for (p = s; *p; p++) if (!isalnum(*p)) *p = '_'; } /* * Print a calltree (KCachegrind) for all PMCs. */ static void pmcpl_ct_print(void) { int n, i; struct pmcpl_ct_node_hash *pch; struct pmcpl_ct_sample rsamples; char name[40]; pmcpl_ct_samples_root(&rsamples); pmcpl_ct_prevfn = NULL; fprintf(args.pa_graphfile, "version: 1\n" "creator: pmcstat\n" "positions: instr line\n" "events:"); for (i=0; ipch_ctnode); pmcpl_ct_node_printchild(pch->pch_ctnode); } pmcpl_ct_samples_free(&rsamples); } int pmcpl_ct_configure(char *opt) { if (strncmp(opt, "skiplink=", 9) == 0) { pmcstat_skiplink = atoi(opt+9); } else return (0); return (1); } int pmcpl_ct_init(void) { int i; pmcpl_ct_prevfn = NULL; pmcpl_ct_root = pmcpl_ct_node_allocate(NULL, 0); for (i = 0; i < PMCSTAT_NHASH; i++) LIST_INIT(&pmcpl_ct_node_hash[i]); pmcpl_ct_samples_init(&pmcpl_ct_callid); return (0); } void pmcpl_ct_shutdown(FILE *mf) { int i; struct pmcpl_ct_node_hash *pch, *pchtmp; (void) mf; if (args.pa_flags & FLAG_DO_CALLGRAPHS) pmcpl_ct_print(); /* * Free memory. */ for (i = 0; i < PMCSTAT_NHASH; i++) { LIST_FOREACH_SAFE(pch, &pmcpl_ct_node_hash[i], pch_next, pchtmp) { pmcpl_ct_node_free(pch->pch_ctnode); free(pch); } } pmcpl_ct_node_free(pmcpl_ct_root); pmcpl_ct_root = NULL; pmcpl_ct_samples_free(&pmcpl_ct_callid); } diff --git a/usr.sbin/ppp/nat_cmd.c b/usr.sbin/ppp/nat_cmd.c index 48f894aedc47..accb149315ce 100644 --- a/usr.sbin/ppp/nat_cmd.c +++ b/usr.sbin/ppp/nat_cmd.c @@ -1,602 +1,601 @@ /*- * Copyright (c) 2001 Charles Mott * Brian Somers * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #include #include #include #include #include -#include #include #include #include #include #include #include #include #include #ifdef LOCALNAT #include "alias.h" #else #include #endif #include "layer.h" #include "proto.h" #include "defs.h" #include "command.h" #include "log.h" #include "nat_cmd.h" #include "descriptor.h" #include "prompt.h" #include "timer.h" #include "fsm.h" #include "slcompress.h" #include "throughput.h" #include "iplist.h" #include "mbuf.h" #include "lqr.h" #include "hdlc.h" #include "ncpaddr.h" #include "ip.h" #include "ipcp.h" #include "ipv6cp.h" #include "lcp.h" #include "ccp.h" #include "link.h" #include "mp.h" #include "filter.h" #ifndef NORADIUS #include "radius.h" #endif #include "ncp.h" #include "bundle.h" #define NAT_EXTRABUF (13) static int StrToAddr(const char *, struct in_addr *); static int StrToPortRange(const char *, u_short *, u_short *, const char *); static int StrToAddrAndPort(const char *, struct in_addr *, u_short *, u_short *, const char *); extern struct libalias *la; static void lowhigh(u_short *a, u_short *b) { if (a > b) { u_short c; c = *b; *b = *a; *a = c; } } int nat_RedirectPort(struct cmdargs const *arg) { if (!arg->bundle->NatEnabled) { prompt_Printf(arg->prompt, "Alias not enabled\n"); return 1; } else if (arg->argc == arg->argn + 3 || arg->argc == arg->argn + 4) { char proto_constant; const char *proto; struct in_addr localaddr; u_short hlocalport, llocalport; struct in_addr aliasaddr; u_short haliasport, laliasport; struct in_addr remoteaddr; u_short hremoteport, lremoteport; struct alias_link *link; int error; proto = arg->argv[arg->argn]; if (strcmp(proto, "tcp") == 0) { proto_constant = IPPROTO_TCP; } else if (strcmp(proto, "udp") == 0) { proto_constant = IPPROTO_UDP; } else { prompt_Printf(arg->prompt, "port redirect: protocol must be" " tcp or udp\n"); return -1; } error = StrToAddrAndPort(arg->argv[arg->argn+1], &localaddr, &llocalport, &hlocalport, proto); if (error) { prompt_Printf(arg->prompt, "nat port: error reading localaddr:port\n"); return -1; } error = StrToPortRange(arg->argv[arg->argn+2], &laliasport, &haliasport, proto); if (error) { prompt_Printf(arg->prompt, "nat port: error reading alias port\n"); return -1; } aliasaddr.s_addr = INADDR_ANY; if (arg->argc == arg->argn + 4) { error = StrToAddrAndPort(arg->argv[arg->argn+3], &remoteaddr, &lremoteport, &hremoteport, proto); if (error) { prompt_Printf(arg->prompt, "nat port: error reading " "remoteaddr:port\n"); return -1; } } else { remoteaddr.s_addr = INADDR_ANY; lremoteport = hremoteport = 0; } lowhigh(&llocalport, &hlocalport); lowhigh(&laliasport, &haliasport); lowhigh(&lremoteport, &hremoteport); if (haliasport - laliasport != hlocalport - llocalport) { prompt_Printf(arg->prompt, "nat port: local & alias port ranges " "are not equal\n"); return -1; } if (hremoteport && hremoteport - lremoteport != hlocalport - llocalport) { prompt_Printf(arg->prompt, "nat port: local & remote port ranges " "are not equal\n"); return -1; } do { link = LibAliasRedirectPort(la, localaddr, htons(llocalport), remoteaddr, htons(lremoteport), aliasaddr, htons(laliasport), proto_constant); if (link == NULL) { prompt_Printf(arg->prompt, "nat port: %d: error %d\n", laliasport, error); return 1; } llocalport++; if (hremoteport) lremoteport++; } while (laliasport++ < haliasport); return 0; } return -1; } int nat_RedirectAddr(struct cmdargs const *arg) { if (!arg->bundle->NatEnabled) { prompt_Printf(arg->prompt, "nat not enabled\n"); return 1; } else if (arg->argc == arg->argn+2) { int error; struct in_addr localaddr, aliasaddr; struct alias_link *link; error = StrToAddr(arg->argv[arg->argn], &localaddr); if (error) { prompt_Printf(arg->prompt, "address redirect: invalid local address\n"); return 1; } error = StrToAddr(arg->argv[arg->argn+1], &aliasaddr); if (error) { prompt_Printf(arg->prompt, "address redirect: invalid alias address\n"); prompt_Printf(arg->prompt, "usage: nat %s %s\n", arg->cmd->name, arg->cmd->syntax); return 1; } link = LibAliasRedirectAddr(la, localaddr, aliasaddr); if (link == NULL) { prompt_Printf(arg->prompt, "address redirect: packet aliasing" " engine error\n"); prompt_Printf(arg->prompt, "usage: nat %s %s\n", arg->cmd->name, arg->cmd->syntax); } } else return -1; return 0; } int nat_RedirectProto(struct cmdargs const *arg) { if (!arg->bundle->NatEnabled) { prompt_Printf(arg->prompt, "nat not enabled\n"); return 1; } else if (arg->argc >= arg->argn + 2 && arg->argc <= arg->argn + 4) { struct in_addr localIP, publicIP, remoteIP; struct alias_link *link; struct protoent *pe; int error; unsigned len; len = strlen(arg->argv[arg->argn]); if (len == 0) { prompt_Printf(arg->prompt, "proto redirect: invalid protocol\n"); return 1; } if (strspn(arg->argv[arg->argn], "01234567") == len) pe = getprotobynumber(atoi(arg->argv[arg->argn])); else pe = getprotobyname(arg->argv[arg->argn]); if (pe == NULL) { prompt_Printf(arg->prompt, "proto redirect: invalid protocol\n"); return 1; } error = StrToAddr(arg->argv[arg->argn + 1], &localIP); if (error) { prompt_Printf(arg->prompt, "proto redirect: invalid src address\n"); return 1; } if (arg->argc >= arg->argn + 3) { error = StrToAddr(arg->argv[arg->argn + 2], &publicIP); if (error) { prompt_Printf(arg->prompt, "proto redirect: invalid alias address\n"); prompt_Printf(arg->prompt, "usage: nat %s %s\n", arg->cmd->name, arg->cmd->syntax); return 1; } } else publicIP.s_addr = INADDR_ANY; if (arg->argc == arg->argn + 4) { error = StrToAddr(arg->argv[arg->argn + 2], &remoteIP); if (error) { prompt_Printf(arg->prompt, "proto redirect: invalid dst address\n"); prompt_Printf(arg->prompt, "usage: nat %s %s\n", arg->cmd->name, arg->cmd->syntax); return 1; } } else remoteIP.s_addr = INADDR_ANY; link = LibAliasRedirectProto(la, localIP, remoteIP, publicIP, pe->p_proto); if (link == NULL) { prompt_Printf(arg->prompt, "proto redirect: packet aliasing" " engine error\n"); prompt_Printf(arg->prompt, "usage: nat %s %s\n", arg->cmd->name, arg->cmd->syntax); } } else return -1; return 0; } static int StrToAddr(const char *str, struct in_addr *addr) { struct hostent *hp; if (inet_aton(str, addr)) return 0; hp = gethostbyname(str); if (!hp) { log_Printf(LogWARN, "StrToAddr: Unknown host %s.\n", str); return -1; } *addr = *((struct in_addr *) hp->h_addr); return 0; } static int StrToPort(const char *str, u_short *port, const char *proto) { struct servent *sp; char *end; *port = strtol(str, &end, 10); if (*end != '\0') { sp = getservbyname(str, proto); if (sp == NULL) { log_Printf(LogWARN, "StrToAddr: Unknown port or service %s/%s.\n", str, proto); return -1; } *port = ntohs(sp->s_port); } return 0; } static int StrToPortRange(const char *str, u_short *low, u_short *high, const char *proto) { char *minus; int res; minus = strchr(str, '-'); if (minus) *minus = '\0'; /* Cheat the const-ness ! */ res = StrToPort(str, low, proto); if (minus) *minus = '-'; /* Cheat the const-ness ! */ if (res == 0) { if (minus) res = StrToPort(minus + 1, high, proto); else *high = *low; } return res; } static int StrToAddrAndPort(const char *str, struct in_addr *addr, u_short *low, u_short *high, const char *proto) { char *colon; int res; colon = strchr(str, ':'); if (!colon) { log_Printf(LogWARN, "StrToAddrAndPort: %s is missing port number.\n", str); return -1; } *colon = '\0'; /* Cheat the const-ness ! */ res = StrToAddr(str, addr); *colon = ':'; /* Cheat the const-ness ! */ if (res != 0) return -1; return StrToPortRange(colon + 1, low, high, proto); } int nat_ProxyRule(struct cmdargs const *arg) { char cmd[LINE_LEN]; int f, pos; size_t len; if (arg->argn >= arg->argc) return -1; for (f = arg->argn, pos = 0; f < arg->argc; f++) { len = strlen(arg->argv[f]); if (sizeof cmd - pos < len + (len ? 1 : 0)) break; if (len) cmd[pos++] = ' '; strcpy(cmd + pos, arg->argv[f]); pos += len; } return LibAliasProxyRule(la, cmd); } int nat_SetTarget(struct cmdargs const *arg) { struct in_addr addr; if (arg->argc == arg->argn) { addr.s_addr = INADDR_ANY; LibAliasSetTarget(la, addr); return 0; } if (arg->argc != arg->argn + 1) return -1; if (!strcasecmp(arg->argv[arg->argn], "MYADDR")) { addr.s_addr = INADDR_ANY; LibAliasSetTarget(la, addr); return 0; } addr = GetIpAddr(arg->argv[arg->argn]); if (addr.s_addr == INADDR_NONE) { log_Printf(LogWARN, "%s: invalid address\n", arg->argv[arg->argn]); return 1; } LibAliasSetTarget(la, addr); return 0; } #ifndef NO_FW_PUNCH int nat_PunchFW(struct cmdargs const *arg) { char *end; long base, count; if (arg->argc == arg->argn) { LibAliasSetMode(la, 0, PKT_ALIAS_PUNCH_FW); return 0; } if (arg->argc != arg->argn + 2) return -1; base = strtol(arg->argv[arg->argn], &end, 10); if (*end != '\0' || base < 0) return -1; count = strtol(arg->argv[arg->argn + 1], &end, 10); if (*end != '\0' || count < 0) return -1; LibAliasSetFWBase(la, base, count); LibAliasSetMode(la, PKT_ALIAS_PUNCH_FW, PKT_ALIAS_PUNCH_FW); return 0; } #endif int nat_SkinnyPort(struct cmdargs const *arg) { char *end; long port; if (arg->argc == arg->argn) { LibAliasSetSkinnyPort(la, 0); return 0; } if (arg->argc != arg->argn + 1) return -1; port = strtol(arg->argv[arg->argn], &end, 10); if (*end != '\0' || port < 0) return -1; LibAliasSetSkinnyPort(la, port); return 0; } static struct mbuf * nat_LayerPush(struct bundle *bundle, struct link *l __unused, struct mbuf *bp, int pri __unused, u_short *proto) { if (!bundle->NatEnabled || *proto != PROTO_IP) return bp; log_Printf(LogDEBUG, "nat_LayerPush: PROTO_IP -> PROTO_IP\n"); m_settype(bp, MB_NATOUT); /* Ensure there's a bit of extra buffer for the NAT code... */ bp = m_pullup(m_append(bp, NULL, NAT_EXTRABUF)); LibAliasOut(la, MBUF_CTOP(bp), bp->m_len); bp->m_len = ntohs(((struct ip *)MBUF_CTOP(bp))->ip_len); return bp; } static struct mbuf * nat_LayerPull(struct bundle *bundle, struct link *l __unused, struct mbuf *bp, u_short *proto) { static int gfrags; int ret, len, nfrags; struct mbuf **last; char *fptr; if (!bundle->NatEnabled || *proto != PROTO_IP) return bp; log_Printf(LogDEBUG, "nat_LayerPull: PROTO_IP -> PROTO_IP\n"); m_settype(bp, MB_NATIN); /* Ensure there's a bit of extra buffer for the NAT code... */ bp = m_pullup(m_append(bp, NULL, NAT_EXTRABUF)); ret = LibAliasIn(la, MBUF_CTOP(bp), bp->m_len); bp->m_len = ntohs(((struct ip *)MBUF_CTOP(bp))->ip_len); if (bp->m_len > MAX_MRU) { log_Printf(LogWARN, "nat_LayerPull: Problem with IP header length (%lu)\n", (unsigned long)bp->m_len); m_freem(bp); return NULL; } switch (ret) { case PKT_ALIAS_OK: break; case PKT_ALIAS_UNRESOLVED_FRAGMENT: /* Save the data for later */ if ((fptr = malloc(bp->m_len)) == NULL) { log_Printf(LogWARN, "nat_LayerPull: Dropped unresolved fragment -" " out of memory!\n"); m_freem(bp); bp = NULL; } else { bp = mbuf_Read(bp, fptr, bp->m_len); LibAliasSaveFragment(la, fptr); log_Printf(LogDEBUG, "Store another frag (%lu) - now %d\n", (unsigned long)((struct ip *)fptr)->ip_id, ++gfrags); } break; case PKT_ALIAS_FOUND_HEADER_FRAGMENT: /* Fetch all the saved fragments and chain them on the end of `bp' */ last = &bp->m_nextpkt; nfrags = 0; while ((fptr = LibAliasGetFragment(la, MBUF_CTOP(bp))) != NULL) { nfrags++; LibAliasFragmentIn(la, MBUF_CTOP(bp), fptr); len = ntohs(((struct ip *)fptr)->ip_len); *last = m_get(len, MB_NATIN); memcpy(MBUF_CTOP(*last), fptr, len); free(fptr); last = &(*last)->m_nextpkt; } gfrags -= nfrags; log_Printf(LogDEBUG, "Found a frag header (%lu) - plus %d more frags (no" "w %d)\n", (unsigned long)((struct ip *)MBUF_CTOP(bp))->ip_id, nfrags, gfrags); break; case PKT_ALIAS_IGNORED: if (LibAliasSetMode(la, 0, 0) & PKT_ALIAS_DENY_INCOMING) { log_Printf(LogTCPIP, "NAT engine denied data:\n"); m_freem(bp); bp = NULL; } else if (log_IsKept(LogTCPIP)) { log_Printf(LogTCPIP, "NAT engine ignored data:\n"); PacketCheck(bundle, AF_INET, MBUF_CTOP(bp), bp->m_len, NULL, NULL, NULL); } break; default: log_Printf(LogWARN, "nat_LayerPull: Dropped a packet (%d)....\n", ret); m_freem(bp); bp = NULL; break; } return bp; } struct layer natlayer = { LAYER_NAT, "nat", nat_LayerPush, nat_LayerPull }; diff --git a/usr.sbin/rpc.yppasswdd/yppasswdd_main.c b/usr.sbin/rpc.yppasswdd/yppasswdd_main.c index 8c8969165274..38719c4a5c1a 100644 --- a/usr.sbin/rpc.yppasswdd/yppasswdd_main.c +++ b/usr.sbin/rpc.yppasswdd/yppasswdd_main.c @@ -1,353 +1,352 @@ /* * Copyright (c) 1995, 1996 * Bill Paul . All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Bill Paul. * 4. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* getenv, exit */ -#include #include /* strcmp */ #include #include #include #include #include /* for pmap_unset */ #include #include #include "yppasswd.h" #include "yppasswdd_extern.h" #include "yppasswd_private.h" #include "ypxfr_extern.h" #include "yp_extern.h" #ifndef SIG_PF #define SIG_PF void(*)(int) #endif #ifdef DEBUG #define RPC_SVC_FG #endif #define _RPCSVC_CLOSEDOWN 120 int _rpcpmstart = 0; /* Started by a port monitor ? */ static int _rpcfdtype; /* Whether Stream or Datagram ? */ /* States a server can be in wrt request */ #define _IDLE 0 #define _SERVED 1 #define _SERVING 2 static char _localhost[] = "localhost"; static char _passwd_byname[] = "passwd.byname"; extern int _rpcsvcstate; /* Set when a request is serviced */ static char _progname[] = "rpc.yppasswdd"; char *progname = _progname; static char _yp_dir[] = _PATH_YP; char *yp_dir = _yp_dir; static char _passfile_default[] = _PATH_YP "master.passwd"; char *passfile_default = _passfile_default; char *passfile; char *yppasswd_domain = NULL; int no_chsh = 0; int no_chfn = 0; int allow_additions = 0; int multidomain = 0; int verbose = 0; int resvport = 1; int inplace = 0; char sockname[] = YP_SOCKNAME; static void terminate(int sig __unused) { rpcb_unset(YPPASSWDPROG, YPPASSWDVERS, NULL); rpcb_unset(MASTER_YPPASSWDPROG, MASTER_YPPASSWDVERS, NULL); unlink(sockname); exit(0); } static void reload(int sig __unused) { load_securenets(); } static void closedown(int sig __unused) { if (_rpcsvcstate == _IDLE) { extern fd_set svc_fdset; static int size; int i, openfd; if (_rpcfdtype == SOCK_DGRAM) { unlink(sockname); exit(0); } if (size == 0) { size = getdtablesize(); } for (i = 0, openfd = 0; i < size && openfd < 2; i++) if (FD_ISSET(i, &svc_fdset)) openfd++; if (openfd <= 1) { unlink(sockname); exit(0); } } if (_rpcsvcstate == _SERVED) _rpcsvcstate = _IDLE; (void) signal(SIGALRM, (SIG_PF) closedown); (void) alarm(_RPCSVC_CLOSEDOWN/2); } static void usage(void) { fprintf(stderr, "%s\n%s\n", "usage: rpc.yppasswdd [-t master.passwd file] [-d domain] [-p path] [-s]", " [-f] [-m] [-i] [-a] [-v] [-u] [-h]"); exit(1); } int main(int argc, char *argv[]) { struct rlimit rlim; SVCXPRT *transp = NULL; struct sockaddr_in saddr; socklen_t asize = sizeof (saddr); struct netconfig *nconf; struct sigaction sa; void *localhandle; int ch; char *mastername; char myname[MAXHOSTNAMELEN + 2]; int maxrec = RPC_MAXDATASIZE; extern int debug; debug = 1; while ((ch = getopt(argc, argv, "t:d:p:sfamuivh")) != -1) { switch (ch) { case 't': passfile_default = optarg; break; case 'd': yppasswd_domain = optarg; break; case 's': no_chsh++; break; case 'f': no_chfn++; break; case 'p': yp_dir = optarg; break; case 'a': allow_additions++; break; case 'm': multidomain++; break; case 'i': inplace++; break; case 'v': verbose++; break; case 'u': resvport = 0; break; default: case 'h': usage(); break; } } if (yppasswd_domain == NULL) { if (yp_get_default_domain(&yppasswd_domain)) { yp_error("no domain specified and system domain \ name isn't set -- aborting"); usage(); } } load_securenets(); if (getrpcport(_localhost, YPPROG, YPVERS, IPPROTO_UDP) <= 0) { yp_error("no ypserv processes registered with local portmap"); yp_error("this host is not an NIS server -- aborting"); exit(1); } if ((mastername = ypxfr_get_master(yppasswd_domain, _passwd_byname, _localhost, 0)) == NULL) { yp_error("can't get name of NIS master server for domain %s", yppasswd_domain); exit(1); } if (gethostname((char *)&myname, sizeof(myname)) == -1) { yp_error("can't get local hostname: %s", strerror(errno)); exit(1); } if (strncasecmp(mastername, (char *)&myname, sizeof(myname))) { yp_error("master of %s is %s, but we are %s", "passwd.byname", mastername, myname); yp_error("this host is not the NIS master server for \ the %s domain -- aborting", yppasswd_domain); exit(1); } debug = 0; if (getsockname(0, (struct sockaddr *)&saddr, &asize) == 0) { socklen_t ssize = sizeof (int); if (saddr.sin_family != AF_INET) exit(1); if (getsockopt(0, SOL_SOCKET, SO_TYPE, (char *)&_rpcfdtype, &ssize) == -1) exit(1); _rpcpmstart = 1; } if (!debug && _rpcpmstart == 0) { if (daemon(0,0)) { err(1,"cannot fork"); } } openlog("rpc.yppasswdd", LOG_PID, LOG_DAEMON); memset(&sa, 0, sizeof(sa)); sa.sa_flags = SA_NOCLDWAIT; sigaction(SIGCHLD, &sa, NULL); rpcb_unset(YPPASSWDPROG, YPPASSWDVERS, NULL); rpcb_unset(MASTER_YPPASSWDPROG, MASTER_YPPASSWDVERS, NULL); rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrec); if (svc_create(yppasswdprog_1, YPPASSWDPROG, YPPASSWDVERS, "netpath") == 0) { yp_error("cannot create yppasswd service."); exit(1); } if (svc_create(master_yppasswdprog_1, MASTER_YPPASSWDPROG, MASTER_YPPASSWDVERS, "netpath") == 0) { yp_error("cannot create master_yppasswd service."); exit(1); } nconf = NULL; localhandle = setnetconfig(); while ((nconf = getnetconfig(localhandle)) != NULL) { if (nconf->nc_protofmly != NULL && strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) break; } if (nconf == NULL) { yp_error("getnetconfigent unix: %s", nc_sperror()); exit(1); } unlink(sockname); transp = svcunix_create(RPC_ANYSOCK, 0, 0, sockname); if (transp == NULL) { yp_error("cannot create AF_LOCAL service."); exit(1); } if (!svc_reg(transp, MASTER_YPPASSWDPROG, MASTER_YPPASSWDVERS, master_yppasswdprog_1, nconf)) { yp_error("unable to register (MASTER_YPPASSWDPROG, \ MASTER_YPPASSWDVERS, unix)."); exit(1); } endnetconfig(localhandle); /* Only root may connect() to the AF_UNIX link. */ if (chmod(sockname, 0)) err(1, "chmod of %s failed", sockname); if (transp == (SVCXPRT *)NULL) { yp_error("could not create a handle"); exit(1); } if (_rpcpmstart) { (void) signal(SIGALRM, (SIG_PF) closedown); (void) alarm(_RPCSVC_CLOSEDOWN/2); } /* Unlimited resource limits. */ rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY; (void)setrlimit(RLIMIT_CPU, &rlim); (void)setrlimit(RLIMIT_FSIZE, &rlim); (void)setrlimit(RLIMIT_STACK, &rlim); (void)setrlimit(RLIMIT_DATA, &rlim); (void)setrlimit(RLIMIT_RSS, &rlim); /* Don't drop core (not really necessary, but GP's). */ rlim.rlim_cur = rlim.rlim_max = 0; (void)setrlimit(RLIMIT_CORE, &rlim); /* Turn off signals. */ (void)signal(SIGALRM, SIG_IGN); (void)signal(SIGHUP, (SIG_PF) reload); (void)signal(SIGINT, SIG_IGN); (void)signal(SIGPIPE, SIG_IGN); (void)signal(SIGQUIT, SIG_IGN); (void)signal(SIGTERM, (SIG_PF) terminate); svc_run(); yp_error("svc_run returned"); exit(1); /* NOTREACHED */ } diff --git a/usr.sbin/rpc.ypupdated/update.c b/usr.sbin/rpc.ypupdated/update.c index 72a7128beb21..956b057ac9c3 100644 --- a/usr.sbin/rpc.ypupdated/update.c +++ b/usr.sbin/rpc.ypupdated/update.c @@ -1,330 +1,329 @@ /* * Sun RPC is a product of Sun Microsystems, Inc. and is provided for * unrestricted use provided that this legend is included on all tape * media and as a part of the software program in whole or part. Users * may copy or modify Sun RPC without charge, but are not authorized * to license or distribute it to anyone else except as part of a product or * program developed by the user or with the express written consent of * Sun Microsystems, Inc. * * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. * * Sun RPC is provided with no support and without any obligation on the * part of Sun Microsystems, Inc. to assist in its use, correction, * modification or enhancement. * * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC * OR ANY PART THEREOF. * * In no event will Sun Microsystems, Inc. be liable for any lost revenue * or profits or other special, indirect and consequential damages, even if * Sun has been advised of the possibility of such damages. * * Sun Microsystems, Inc. * 2550 Garcia Avenue * Mountain View, California 94043 */ #ifndef lint #if 0 static char sccsid[] = "@(#)update.c 1.2 91/03/11 Copyr 1986 Sun Micro"; #endif static const char rcsid[] = "$FreeBSD$"; #endif /* not lint */ /* * Copyright (C) 1986, 1989, Sun Microsystems, Inc. */ /* * Administrative tool to add a new user to the publickey database */ #include #include #include #include #include #ifdef YP #include #include #include #include #endif /* YP */ #include #include #include -#include #include "ypupdated_extern.h" #ifdef YP #define MAXMAPNAMELEN 256 #else #define YPOP_CHANGE 1 /* change, do not add */ #define YPOP_INSERT 2 /* add, do not change */ #define YPOP_DELETE 3 /* delete this entry */ #define YPOP_STORE 4 /* add, or change */ #endif #ifdef YP static char SHELL[] = "/bin/sh"; static char YPDBPATH[]="/var/yp"; /* This is defined but not used! */ static char PKMAP[] = "publickey.byname"; static char UPDATEFILE[] = "updaters"; static char PKFILE[] = "/etc/publickey"; #endif /* YP */ #ifdef YP static int _openchild(char *, FILE **, FILE **); /* * Determine if requester is allowed to update the given map, * and update it if so. Returns the yp status, which is zero * if there is no access violation. */ int mapupdate(char *requester, char *mapname, u_int op, u_int keylen, char *key, u_int datalen, char *data) { char updater[MAXMAPNAMELEN + 40]; FILE *childargs; FILE *childrslt; #ifdef WEXITSTATUS int status; #else union wait status; #endif pid_t pid; u_int yperrno; #ifdef DEBUG printf("%s %s\n", key, data); #endif (void)sprintf(updater, "make -s -f %s/%s %s", YPDBPATH, /* !!! */ UPDATEFILE, mapname); pid = _openchild(updater, &childargs, &childrslt); if (pid < 0) { return (YPERR_YPERR); } /* * Write to child */ (void)fprintf(childargs, "%s\n", requester); (void)fprintf(childargs, "%u\n", op); (void)fprintf(childargs, "%u\n", keylen); (void)fwrite(key, (int)keylen, 1, childargs); (void)fprintf(childargs, "\n"); (void)fprintf(childargs, "%u\n", datalen); (void)fwrite(data, (int)datalen, 1, childargs); (void)fprintf(childargs, "\n"); (void)fclose(childargs); /* * Read from child */ (void)fscanf(childrslt, "%d", &yperrno); (void)fclose(childrslt); (void)wait(&status); #ifdef WEXITSTATUS if (WEXITSTATUS(status) != 0) #else if (status.w_retcode != 0) #endif return (YPERR_YPERR); return (yperrno); } /* * returns pid, or -1 for failure */ static int _openchild(char *command, FILE **fto, FILE **ffrom) { int i; pid_t pid; int pdto[2]; int pdfrom[2]; char *com; struct rlimit rl; if (pipe(pdto) < 0) { goto error1; } if (pipe(pdfrom) < 0) { goto error2; } switch (pid = fork()) { case -1: goto error3; case 0: /* * child: read from pdto[0], write into pdfrom[1] */ (void)close(0); (void)dup(pdto[0]); (void)close(1); (void)dup(pdfrom[1]); getrlimit(RLIMIT_NOFILE, &rl); for (i = rl.rlim_max - 1; i >= 3; i--) { (void) close(i); } com = malloc((unsigned) strlen(command) + 6); if (com == NULL) { _exit(~0); } (void)sprintf(com, "exec %s", command); execl(SHELL, basename(SHELL), "-c", com, (char *)NULL); _exit(~0); default: /* * parent: write into pdto[1], read from pdfrom[0] */ *fto = fdopen(pdto[1], "w"); (void)close(pdto[0]); *ffrom = fdopen(pdfrom[0], "r"); (void)close(pdfrom[1]); break; } return (pid); /* * error cleanup and return */ error3: (void)close(pdfrom[0]); (void)close(pdfrom[1]); error2: (void)close(pdto[0]); (void)close(pdto[1]); error1: return (-1); } static char * basename(char *path) { char *p; p = strrchr(path, '/'); if (p == NULL) { return (path); } else { return (p + 1); } } #else /* YP */ static int match(char *, char *); /* * Determine if requester is allowed to update the given map, * and update it if so. Returns the status, which is zero * if there is no access violation. This function updates * the local file and then shuts up. */ int localupdate(char *name, char *filename, u_int op, u_int keylen __unused, char *key, u_int datalen __unused, char *data) { char line[256]; FILE *rf; FILE *wf; char *tmpname; int err; /* * Check permission */ if (strcmp(name, key) != 0) { return (ERR_ACCESS); } if (strcmp(name, "nobody") == 0) { /* * Can't change "nobody"s key. */ return (ERR_ACCESS); } /* * Open files */ tmpname = malloc(strlen(filename) + 4); if (tmpname == NULL) { return (ERR_MALLOC); } sprintf(tmpname, "%s.tmp", filename); rf = fopen(filename, "r"); if (rf == NULL) { return (ERR_READ); } wf = fopen(tmpname, "w"); if (wf == NULL) { return (ERR_WRITE); } err = -1; while (fgets(line, sizeof (line), rf)) { if (err < 0 && match(line, name)) { switch (op) { case YPOP_INSERT: err = ERR_KEY; break; case YPOP_STORE: case YPOP_CHANGE: fprintf(wf, "%s %s\n", key, data); err = 0; break; case YPOP_DELETE: /* do nothing */ err = 0; break; } } else { fputs(line, wf); } } if (err < 0) { switch (op) { case YPOP_CHANGE: case YPOP_DELETE: err = ERR_KEY; break; case YPOP_INSERT: case YPOP_STORE: err = 0; fprintf(wf, "%s %s\n", key, data); break; } } fclose(wf); fclose(rf); if (err == 0) { if (rename(tmpname, filename) < 0) { return (ERR_DBASE); } } else { if (unlink(tmpname) < 0) { return (ERR_DBASE); } } return (err); } static int match(char *line, char *name) { int len; len = strlen(name); return (strncmp(line, name, len) == 0 && (line[len] == ' ' || line[len] == '\t')); } #endif /* !YP */ diff --git a/usr.sbin/rpc.ypupdated/ypupdated_main.c b/usr.sbin/rpc.ypupdated/ypupdated_main.c index c13af7df4340..92d8374a7162 100644 --- a/usr.sbin/rpc.ypupdated/ypupdated_main.c +++ b/usr.sbin/rpc.ypupdated/ypupdated_main.c @@ -1,286 +1,285 @@ /* * Copyright (c) 1995, 1996 * Bill Paul . All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Bill Paul. * 4. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include "ypupdate_prot.h" #include #include /* getenv, exit */ #include /* for pmap_unset */ #include #include /* strcmp */ #include #ifdef __cplusplus #include /* getdtablesize, open */ #endif /* __cplusplus */ #include #include #include #include #include #include #include -#include #include #include "ypupdated_extern.h" #include "yp_extern.h" #ifndef SIG_PF #define SIG_PF void(*)(int) #endif #ifdef DEBUG #define RPC_SVC_FG #endif #define _RPCSVC_CLOSEDOWN 120 int _rpcpmstart; /* Started by a port monitor ? */ static int _rpcfdtype; /* Whether Stream or Datagram ? */ /* States a server can be in wrt request */ #define _IDLE 0 #define _SERVED 1 #define _SERVING 2 extern int _rpcsvcstate; /* Set when a request is serviced */ char *progname = "rpc.ypupdated"; char *yp_dir = "/var/yp/"; static void _msgout(char* msg) { #ifdef RPC_SVC_FG if (_rpcpmstart) syslog(LOG_ERR, "%s", msg); else warnx("%s", msg); #else syslog(LOG_ERR, "%s", msg); #endif } static void closedown(int sig) { if (_rpcsvcstate == _IDLE) { extern fd_set svc_fdset; static int size; int i, openfd; if (_rpcfdtype == SOCK_DGRAM) exit(0); if (size == 0) { size = getdtablesize(); } for (i = 0, openfd = 0; i < size && openfd < 2; i++) if (FD_ISSET(i, &svc_fdset)) openfd++; if (openfd <= 1) exit(0); } if (_rpcsvcstate == _SERVED) _rpcsvcstate = _IDLE; (void) signal(SIGALRM, (SIG_PF) closedown); (void) alarm(_RPCSVC_CLOSEDOWN/2); } static void ypupdated_svc_run(void) { #ifdef FD_SETSIZE fd_set readfds; #else int readfds; #endif /* def FD_SETSIZE */ extern int forked; int pid; int fd_setsize = _rpc_dtablesize(); /* Establish the identity of the parent ypupdated process. */ pid = getpid(); for (;;) { #ifdef FD_SETSIZE readfds = svc_fdset; #else readfds = svc_fds; #endif /* def FD_SETSIZE */ switch (select(fd_setsize, &readfds, NULL, NULL, (struct timeval *)0)) { case -1: if (errno == EINTR) { continue; } warn("svc_run: - select failed"); return; case 0: continue; default: svc_getreqset(&readfds); if (forked && pid != getpid()) exit(0); } } } static void reaper(int sig) { int status; if (sig == SIGHUP) { #ifdef foo load_securenets(); #endif return; } if (sig == SIGCHLD) { while (wait3(&status, WNOHANG, NULL) > 0) children--; } else { (void) pmap_unset(YPU_PROG, YPU_VERS); exit(0); } } void usage(void) { fprintf(stderr, "rpc.ypupdatedd [-p path]\n"); exit(0); } int main(int argc, char *argv[]) { register SVCXPRT *transp = NULL; int sock; int proto = 0; struct sockaddr_in saddr; int asize = sizeof (saddr); int ch; while ((ch = getopt(argc, argv, "p:h")) != -1) { switch (ch) { case 'p': yp_dir = optarg; break; default: usage(); break; } } #ifdef foo load_securenets(); #endif if (svc_auth_reg(AUTH_DES, _svcauth_des) == -1) { yp_error("failed to register AUTH_DES flavor"); exit(1); } if (getsockname(0, (struct sockaddr *)&saddr, &asize) == 0) { int ssize = sizeof (int); if (saddr.sin_family != AF_INET) exit(1); if (getsockopt(0, SOL_SOCKET, SO_TYPE, (char *)&_rpcfdtype, &ssize) == -1) exit(1); sock = 0; _rpcpmstart = 1; proto = 0; openlog("rpc.ypupdatedd", LOG_PID, LOG_DAEMON); } else { #ifndef RPC_SVC_FG if (daemon(0,0)) { err(1, "cannot fork"); } openlog("rpc.ypupdated", LOG_PID, LOG_DAEMON); #endif sock = RPC_ANYSOCK; (void) pmap_unset(YPU_PROG, YPU_VERS); } if ((_rpcfdtype == 0) || (_rpcfdtype == SOCK_DGRAM)) { transp = svcudp_create(sock); if (transp == NULL) { _msgout("cannot create udp service."); exit(1); } if (!_rpcpmstart) proto = IPPROTO_UDP; if (!svc_register(transp, YPU_PROG, YPU_VERS, ypu_prog_1, proto)) { _msgout("unable to register (YPU_PROG, YPU_VERS, udp)."); exit(1); } } if ((_rpcfdtype == 0) || (_rpcfdtype == SOCK_STREAM)) { transp = svctcp_create(sock, 0, 0); if (transp == NULL) { _msgout("cannot create tcp service."); exit(1); } if (!_rpcpmstart) proto = IPPROTO_TCP; if (!svc_register(transp, YPU_PROG, YPU_VERS, ypu_prog_1, proto)) { _msgout("unable to register (YPU_PROG, YPU_VERS, tcp)."); exit(1); } } if (transp == (SVCXPRT *)NULL) { _msgout("could not create a handle"); exit(1); } if (_rpcpmstart) { (void) signal(SIGALRM, (SIG_PF) closedown); (void) alarm(_RPCSVC_CLOSEDOWN/2); } (void) signal(SIGPIPE, SIG_IGN); (void) signal(SIGCHLD, (SIG_PF) reaper); (void) signal(SIGTERM, (SIG_PF) reaper); (void) signal(SIGINT, (SIG_PF) reaper); (void) signal(SIGHUP, (SIG_PF) reaper); ypupdated_svc_run(); _msgout("svc_run returned"); exit(1); /* NOTREACHED */ } diff --git a/usr.sbin/rpc.ypupdated/ypupdated_server.c b/usr.sbin/rpc.ypupdated/ypupdated_server.c index c9a50dd36e0c..c4e163a50919 100644 --- a/usr.sbin/rpc.ypupdated/ypupdated_server.c +++ b/usr.sbin/rpc.ypupdated/ypupdated_server.c @@ -1,228 +1,227 @@ /* * Copyright (c) 1995, 1996 * Bill Paul . All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Bill Paul. * 4. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * ypupdate server implementation * * Written by Bill Paul * Center for Telecommunications Research * Columbia University, New York City */ #include __FBSDID("$FreeBSD$"); #include #include #include #include -#include #include #include "ypupdate_prot.h" #include "ypupdated_extern.h" #include "yp_extern.h" #include "ypxfr_extern.h" int children = 0; int forked = 0; /* * Try to avoid spoofing: if a client chooses to use a very large * window and then tries a bunch of randomly chosen encrypted timestamps, * there's a chance he might stumble onto a valid combination. * We therefore reject any RPCs with a window size larger than a preset * value. */ #ifndef WINDOW #define WINDOW (60*60) #endif static enum auth_stat yp_checkauth(struct svc_req *svcreq) { struct authdes_cred *des_cred; switch (svcreq->rq_cred.oa_flavor) { case AUTH_DES: des_cred = (struct authdes_cred *) svcreq->rq_clntcred; if (des_cred->adc_fullname.window > WINDOW) { yp_error("warning: client-specified window size \ was too large -- possible spoof attempt"); return(AUTH_BADCRED); } return(AUTH_OK); break; case AUTH_UNIX: case AUTH_NONE: yp_error("warning: client didn't use DES authentication"); return(AUTH_TOOWEAK); break; default: yp_error("client used unknown auth flavor"); return(AUTH_REJECTEDCRED); break; } } unsigned int * ypu_change_1_svc(struct ypupdate_args *args, struct svc_req *svcreq) { struct authdes_cred *des_cred; static int res; char *netname; enum auth_stat astat; res = 0; astat = yp_checkauth(svcreq); if (astat != AUTH_OK) { svcerr_auth(svcreq->rq_xprt, astat); return(&res); } des_cred = (struct authdes_cred *) svcreq->rq_clntcred; netname = des_cred->adc_fullname.name; res = localupdate(netname, "/etc/publickey", YPOP_CHANGE, args->key.yp_buf_len, args->key.yp_buf_val, args->datum.yp_buf_len, args->datum.yp_buf_val); if (res) return (&res); res = ypmap_update(netname, args->mapname, YPOP_CHANGE, args->key.yp_buf_len, args->key.yp_buf_val, args->datum.yp_buf_len, args->datum.yp_buf_val); return (&res); } unsigned int * ypu_insert_1_svc(struct ypupdate_args *args, struct svc_req *svcreq) { struct authdes_cred *des_cred; static int res; char *netname; enum auth_stat astat; res = 0; astat = yp_checkauth(svcreq); if (astat != AUTH_OK) { svcerr_auth(svcreq->rq_xprt, astat); return(&res); } des_cred = (struct authdes_cred *) svcreq->rq_clntcred; netname = des_cred->adc_fullname.name; res = localupdate(netname, "/etc/publickey", YPOP_INSERT, args->key.yp_buf_len, args->key.yp_buf_val, args->datum.yp_buf_len, args->datum.yp_buf_val); if (res) return (&res); res = ypmap_update(netname, args->mapname, YPOP_INSERT, args->key.yp_buf_len, args->key.yp_buf_val, args->datum.yp_buf_len, args->datum.yp_buf_val); return (&res); } unsigned int * ypu_delete_1_svc(struct ypdelete_args *args, struct svc_req *svcreq) { struct authdes_cred *des_cred; static int res; char *netname; enum auth_stat astat; res = 0; astat = yp_checkauth(svcreq); if (astat != AUTH_OK) { svcerr_auth(svcreq->rq_xprt, astat); return(&res); } des_cred = (struct authdes_cred *) svcreq->rq_clntcred; netname = des_cred->adc_fullname.name; res = localupdate(netname, "/etc/publickey", YPOP_DELETE, args->key.yp_buf_len, args->key.yp_buf_val, 0, NULL); if (res) return (&res); res = ypmap_update(netname, args->mapname, YPOP_DELETE, args->key.yp_buf_len, args->key.yp_buf_val, 0, NULL); return (&res); } unsigned int * ypu_store_1_svc(struct ypupdate_args *args, struct svc_req *svcreq) { struct authdes_cred *des_cred; static int res; char *netname; enum auth_stat astat; res = 0; astat = yp_checkauth(svcreq); if (astat != AUTH_OK) { svcerr_auth(svcreq->rq_xprt, astat); return(&res); } des_cred = (struct authdes_cred *) svcreq->rq_clntcred; netname = des_cred->adc_fullname.name; res = localupdate(netname, "/etc/publickey", YPOP_STORE, args->key.yp_buf_len, args->key.yp_buf_val, args->datum.yp_buf_len, args->datum.yp_buf_val); if (res) return (&res); res = ypmap_update(netname, args->mapname, YPOP_STORE, args->key.yp_buf_len, args->key.yp_buf_val, args->datum.yp_buf_len, args->datum.yp_buf_val); return (&res); } diff --git a/usr.sbin/sysinstall/modules.c b/usr.sbin/sysinstall/modules.c index e9bdb0fe22e9..9c9875fa6b19 100644 --- a/usr.sbin/sysinstall/modules.c +++ b/usr.sbin/sysinstall/modules.c @@ -1,224 +1,223 @@ /*- * Copyright (c) 2000 "HOSOKAWA, Tatsumi" * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #include "sysinstall.h" #include #include #include #include #include -#include #include #include #include #include /* Prototypes */ static int kldModuleFire(dialogMenuItem *self); #define MODULESDIR "/modules" #define DISTMOUNT "/dist" void moduleInitialize(void) { int fd, len; DIR *dirp; struct dirent *dp; char module[MAXPATHLEN], desc[MAXPATHLEN]; char desc_str[BUFSIZ]; if (!RunningAsInit && !Fake) { /* It's not my job... */ return; } dirp = opendir(MODULESDIR); if (dirp) { while ((dp = readdir(dirp))) { if (dp->d_namlen < (sizeof(".ko") - 1)) continue; if (strcmp(dp->d_name + dp->d_namlen - (sizeof(".ko") - 1), ".ko") == 0) { strcpy(module, MODULESDIR); strcat(module, "/"); strcat(module, dp->d_name); strcpy(desc, module); len = strlen(desc); strcpy(desc + (len - (sizeof(".ko") - 1)), ".dsc"); fd = open(module, O_RDONLY); if (fd < 0) continue; close(fd); fd = open(desc, O_RDONLY); if (fd < 0) { desc_str[0] = 0; } else { len = read(fd, desc_str, BUFSIZ); close(fd); if (len < BUFSIZ) desc_str[len] = 0; } if (desc_str[0]) msgDebug("Loading module %s (%s)\n", dp->d_name, desc_str); else msgDebug("Loading module %s\n", dp->d_name); if (kldload(module) < 0 && errno != EEXIST) { if (desc_str[0]) msgConfirm("Loading module %s failed\n%s", dp->d_name, desc_str); else msgConfirm("Loading module %s failed", dp->d_name); } } if (strcmp(dp->d_name + dp->d_namlen - (sizeof(".ko.gz") - 1), ".ko.gz") == 0) { snprintf(module, sizeof(module), "/tmp/%s", dp->d_name); module[strlen(module) - sizeof(".gz")] = '\0'; snprintf(desc, sizeof(desc), "zcat < %s/%s > %s", MODULESDIR, dp->d_name, module); system(desc); if (kldload(module) < 0 && errno != EEXIST) { if (desc_str[0]) msgConfirm("Loading module %s failed\n%s", dp->d_name, desc_str); else msgConfirm("Loading module %s failed", dp->d_name); } unlink(module); } } closedir(dirp); } } void driverFloppyCheck(void) { /* Prompt for the driver floppy if requested. */ if (kenv(KENV_GET, "driver_floppy", NULL, 0) >= 0 && !msgYesNo("Would you like to load kernel modules from the driver floppy?")) (void)kldBrowser(NULL); } int kldBrowser(dialogMenuItem *self) { DMenu *menu = NULL; int i, what = DITEM_SUCCESS, msize, count; DIR *dir; struct dirent *de; char *err; err = NULL; count = 0; if (DITEM_STATUS(mediaSetFloppy(NULL)) == DITEM_FAILURE) { err = "Unable to set media device to floppy."; goto errout; } if (!DEVICE_INIT(mediaDevice)) { err = "Unable to mount floppy filesystem."; goto errout; } msize = sizeof(DMenu) + (sizeof(dialogMenuItem) * 2); if ((menu = malloc(msize)) == NULL) { err = "Failed to allocate memory for menu"; goto errout; } bcopy(&MenuKLD, menu, sizeof(DMenu)); bzero(&menu->items[count], sizeof(menu->items[0])); menu->items[count].prompt = strdup("X Exit"); menu->items[count].title = strdup("Exit this menu (returning to previous)"); menu->items[count].fire = dmenuExit; count++; if ((dir = opendir(DISTMOUNT)) == NULL) { err = "Couldn't open directory"; goto errout; } while ((de = readdir(dir)) != NULL) { if (fnmatch("*.ko", de->d_name, FNM_CASEFOLD)) continue; msize += sizeof(dialogMenuItem); if ((menu = realloc(menu, msize)) == NULL) { err = "Failed to allocate memory for menu item"; goto errout; } bzero(&menu->items[count], sizeof(menu->items[0])); menu->items[count].fire = kldModuleFire; menu->items[count].prompt = strdup(de->d_name); menu->items[count].title = menu->items[count].prompt; count++; } closedir(dir); menu->items[count].prompt = NULL; menu->items[count].title = NULL; dmenuOpenSimple(menu, FALSE); deviceRescan(); errout: mediaClose(); for (i = 0; i < count; i++) free(menu->items[i].prompt); free(menu); if (err != NULL) { what |= DITEM_FAILURE; if (!variable_get(VAR_NO_ERROR)) msgConfirm(err); } return (what); } static int kldModuleFire(dialogMenuItem *self) { char fname[256]; bzero(fname, sizeof(fname)); snprintf(fname, sizeof(fname), "%s/%s", DISTMOUNT, self->prompt); if (kldload(fname) < 0 && errno != EEXIST) { if (!variable_get(VAR_NO_ERROR)) msgConfirm("Loading module %s failed\n", fname); } else { if (!variable_get(VAR_NO_ERROR)) msgConfirm("Loaded module %s OK", fname); } return(0); } diff --git a/usr.sbin/wpa/ndis_events/ndis_events.c b/usr.sbin/wpa/ndis_events/ndis_events.c index e3cd9b5bda57..9c6e9def54a9 100644 --- a/usr.sbin/wpa/ndis_events/ndis_events.c +++ b/usr.sbin/wpa/ndis_events/ndis_events.c @@ -1,354 +1,352 @@ /*- * Copyright (c) 2005 * Bill Paul . All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Bill Paul. * 4. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); /* * This program simulates the behavior of the ndis_events utility * supplied with wpa_supplicant for Windows. The original utility * is designed to translate Windows WMI events. We don't have WMI, * but we need to supply certain event info to wpa_supplicant in * order to make WPA2 work correctly, so we fake up the interface. */ #include -#include #include #include #include -#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static int verbose = 0; static int debug = 0; static int all_events = 0; #define PROGNAME "ndis_events" #define WPA_SUPPLICANT_PORT 9876 #define NDIS_INDICATION_LEN 2048 #define EVENT_CONNECT 0 #define EVENT_DISCONNECT 1 #define EVENT_MEDIA_SPECIFIC 2 #define NDIS_STATUS_MEDIA_CONNECT 0x4001000B #define NDIS_STATUS_MEDIA_DISCONNECT 0x4001000C #define NDIS_STATUS_MEDIA_SPECIFIC_INDICATION 0x40010012 struct ndis_evt { uint32_t ne_sts; uint32_t ne_len; #ifdef notdef char ne_buf[1]; #endif }; static int find_ifname(int, char *); static int announce_event(char *, int, struct sockaddr_in *); static void usage(void); static void dbgmsg(const char *fmt, ...) { va_list ap; va_start(ap, fmt); if (debug) vwarnx(fmt, ap); else vsyslog(LOG_ERR, fmt, ap); va_end(ap); return; } static int find_ifname(idx, name) int idx; char *name; { int mib[6]; size_t needed; struct if_msghdr *ifm; struct sockaddr_dl *sdl; char *buf, *lim, *next; needed = 0; mib[0] = CTL_NET; mib[1] = PF_ROUTE; mib[2] = 0; /* protocol */ mib[3] = 0; /* wildcard address family */ mib[4] = NET_RT_IFLIST; mib[5] = 0; /* no flags */ if (sysctl (mib, 6, NULL, &needed, NULL, 0) < 0) return(EIO); buf = malloc (needed); if (buf == NULL) return(ENOMEM); if (sysctl (mib, 6, buf, &needed, NULL, 0) < 0) { free(buf); return(EIO); } lim = buf + needed; next = buf; while (next < lim) { ifm = (struct if_msghdr *)next; if (ifm->ifm_type == RTM_IFINFO) { sdl = (struct sockaddr_dl *)(ifm + 1); if (ifm->ifm_index == idx) { strncpy(name, sdl->sdl_data, sdl->sdl_nlen); name[sdl->sdl_nlen] = '\0'; free (buf); return (0); } } next += ifm->ifm_msglen; } free (buf); return(ENOENT); } static int announce_event(ifname, sock, dst) char *ifname; int sock; struct sockaddr_in *dst; { int s; char indication[NDIS_INDICATION_LEN]; struct ifreq ifr; struct ndis_evt *e; char buf[512], *pos, *end; int len, type, _type; s = socket(PF_INET, SOCK_DGRAM, 0); if (s < 0) { dbgmsg("socket creation failed"); return(EINVAL); } bzero((char *)&ifr, sizeof(ifr)); e = (struct ndis_evt *)indication; e->ne_len = NDIS_INDICATION_LEN - sizeof(struct ndis_evt); strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); ifr.ifr_data = indication; if (ioctl(s, SIOCGPRIVATE_0, &ifr) < 0) { close(s); if (verbose) { if (errno == ENOENT) dbgmsg("drained all events from %s", ifname, errno); else dbgmsg("failed to read event info from %s: %d", ifname, errno); } return(ENOENT); } if (e->ne_sts == NDIS_STATUS_MEDIA_CONNECT) { type = EVENT_CONNECT; if (verbose) dbgmsg("Received a connect event for %s", ifname); if (!all_events) { close(s); return(0); } } if (e->ne_sts == NDIS_STATUS_MEDIA_DISCONNECT) { type = EVENT_DISCONNECT; if (verbose) dbgmsg("Received a disconnect event for %s", ifname); if (!all_events) { close(s); return(0); } } if (e->ne_sts == NDIS_STATUS_MEDIA_SPECIFIC_INDICATION) { type = EVENT_MEDIA_SPECIFIC; if (verbose) dbgmsg("Received a media-specific event for %s", ifname); } end = buf + sizeof(buf); _type = (int) type; memcpy(buf, &_type, sizeof(_type)); pos = buf + sizeof(_type); len = snprintf(pos + 1, end - pos - 1, "%s", ifname); if (len < 0) { close(s); return(ENOSPC); } if (len > 255) len = 255; *pos = (unsigned char) len; pos += 1 + len; if (e->ne_len) { if (e->ne_len > 255 || 1 + e->ne_len > end - pos) { dbgmsg("Not enough room for send_event data (%d)\n", e->ne_len); close(s); return(ENOSPC); } *pos++ = (unsigned char) e->ne_len; memcpy(pos, (indication) + sizeof(struct ndis_evt), e->ne_len); pos += e->ne_len; } len = sendto(sock, buf, pos - buf, 0, (struct sockaddr *) dst, sizeof(struct sockaddr_in)); close(s); return(0); } static void usage() { fprintf(stderr, "Usage: ndis_events [-a] [-d] [-v]\n"); exit(1); } int main(argc, argv) int argc; char *argv[]; { int s, r, n; struct sockaddr_in sin; char msg[NDIS_INDICATION_LEN]; struct rt_msghdr *rtm; struct if_msghdr *ifm; char ifname[IFNAMSIZ]; int ch; while ((ch = getopt(argc, argv, "dva")) != -1) { switch(ch) { case 'd': debug++; break; case 'v': verbose++; break; case 'a': all_events++; break; default: usage(); break; } } if (!debug && daemon(0, 0)) err(1, "failed to daemonize ourselves"); if (!debug) openlog(PROGNAME, LOG_PID | LOG_CONS, LOG_DAEMON); bzero((char *)&sin, sizeof(sin)); /* Create a datagram socket. */ s = socket(PF_INET, SOCK_DGRAM, 0); if (s < 0) { dbgmsg("socket creation failed"); exit(1); } sin.sin_family = AF_INET; sin.sin_addr.s_addr = inet_addr("127.0.0.1"); sin.sin_port = htons(WPA_SUPPLICANT_PORT); /* Create a routing socket. */ r = socket (PF_ROUTE, SOCK_RAW, 0); if (r < 0) { dbgmsg("routing socket creation failed"); exit(1); } /* Now sit and spin, waiting for events. */ if (verbose) dbgmsg("Listening for events"); while (1) { n = read(r, msg, NDIS_INDICATION_LEN); rtm = (struct rt_msghdr *)msg; if (rtm->rtm_type != RTM_IFINFO) continue; ifm = (struct if_msghdr *)msg; if (find_ifname(ifm->ifm_index, ifname)) continue; if (strstr(ifname, "ndis")) { while(announce_event(ifname, s, &sin) == 0) ; } else { if (verbose) dbgmsg("Skipping ifinfo message from %s", ifname); } } /* NOTREACHED */ exit(0); } diff --git a/usr.sbin/wpa/wpa_supplicant/Packet32.c b/usr.sbin/wpa/wpa_supplicant/Packet32.c index 07da3590308e..876417e6635a 100644 --- a/usr.sbin/wpa/wpa_supplicant/Packet32.c +++ b/usr.sbin/wpa/wpa_supplicant/Packet32.c @@ -1,415 +1,414 @@ /*- * Copyright (c) 2005 * Bill Paul . All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Bill Paul. * 4. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); /* * This file implements a small portion of the Winpcap API for the * Windows NDIS interface in wpa_supplicant. It provides just enough * routines to fool wpa_supplicant into thinking it's really running * in a Windows environment. */ #include #include #include #include -#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "Packet32.h" #define OID_802_11_ADD_KEY 0x0d01011D typedef ULONGLONG NDIS_802_11_KEY_RSC; typedef UCHAR NDIS_802_11_MAC_ADDRESS[6]; typedef struct NDIS_802_11_KEY { ULONG Length; ULONG KeyIndex; ULONG KeyLength; NDIS_802_11_MAC_ADDRESS BSSID; NDIS_802_11_KEY_RSC KeyRSC; UCHAR KeyMaterial[1]; } NDIS_802_11_KEY; typedef struct NDIS_802_11_KEY_COMPAT { ULONG Length; ULONG KeyIndex; ULONG KeyLength; NDIS_802_11_MAC_ADDRESS BSSID; UCHAR Pad[6]; /* Make struct layout match Windows. */ NDIS_802_11_KEY_RSC KeyRSC; #ifdef notdef UCHAR KeyMaterial[1]; #endif } NDIS_802_11_KEY_COMPAT; #define TRUE 1 #define FALSE 0 struct adapter { int socket; char name[IFNAMSIZ]; int prev_roaming; }; PCHAR PacketGetVersion(void) { return("FreeBSD WinPcap compatibility shim v1.0"); } void * PacketOpenAdapter(CHAR *iface) { struct adapter *a; int s; int ifflags; struct ifreq ifr; struct ieee80211req ireq; s = socket(PF_INET, SOCK_DGRAM, 0); if (s == -1) return(NULL); a = malloc(sizeof(struct adapter)); if (a == NULL) return(NULL); a->socket = s; if (strncmp(iface, "\\Device\\NPF_", 12) == 0) iface += 12; else if (strncmp(iface, "\\DEVICE\\", 8) == 0) iface += 8; snprintf(a->name, IFNAMSIZ, "%s", iface); /* Turn off net80211 roaming */ bzero((char *)&ireq, sizeof(ireq)); strncpy(ireq.i_name, iface, sizeof (ifr.ifr_name)); ireq.i_type = IEEE80211_IOC_ROAMING; if (ioctl(a->socket, SIOCG80211, &ireq) == 0) { a->prev_roaming = ireq.i_val; ireq.i_val = IEEE80211_ROAMING_MANUAL; if (ioctl(a->socket, SIOCS80211, &ireq) < 0) fprintf(stderr, "Could not set IEEE80211_ROAMING_MANUAL\n"); } bzero((char *)&ifr, sizeof(ifr)); strncpy(ifr.ifr_name, iface, sizeof (ifr.ifr_name)); if (ioctl(a->socket, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) { free(a); close(s); return(NULL); } ifr.ifr_flags |= IFF_UP; if (ioctl(a->socket, SIOCSIFFLAGS, (caddr_t)&ifr) < 0) { free(a); close(s); return(NULL); } return(a); } int PacketRequest(void *iface, BOOLEAN set, PACKET_OID_DATA *oid) { struct adapter *a; uint32_t retval; struct ifreq ifr; NDIS_802_11_KEY *old; NDIS_802_11_KEY_COMPAT *new; PACKET_OID_DATA *o = NULL; if (iface == NULL) return(-1); a = iface; bzero((char *)&ifr, sizeof(ifr)); /* * This hack is necessary to work around a difference * betwee the GNU C and Microsoft C compilers. The NDIS_802_11_KEY * structure has a uint64_t in it, right after an array of * chars. The Microsoft compiler inserts padding right before * the 64-bit value to align it on a 64-bit boundary, but * GCC only aligns it on a 32-bit boundary. Trying to pass * the GCC-formatted structure to an NDIS binary driver * fails because some of the fields appear to be at the * wrong offsets. * * To get around this, if we detect someone is trying to do * a set operation on OID_802_11_ADD_KEY, we shuffle the data * into a properly padded structure and pass that into the * driver instead. This allows the driver_ndis.c code supplied * with wpa_supplicant to work unmodified. */ if (set == TRUE && oid->Oid == OID_802_11_ADD_KEY) { old = (NDIS_802_11_KEY *)&oid->Data; o = malloc(sizeof(PACKET_OID_DATA) + sizeof(NDIS_802_11_KEY_COMPAT) + old->KeyLength); if (o == NULL) return(0); bzero((char *)o, sizeof(PACKET_OID_DATA) + sizeof(NDIS_802_11_KEY_COMPAT) + old->KeyLength); o->Oid = oid->Oid; o->Length = sizeof(NDIS_802_11_KEY_COMPAT) + old->KeyLength; new = (NDIS_802_11_KEY_COMPAT *)&o->Data; new->KeyRSC = old->KeyRSC; new->Length = o->Length; new->KeyIndex = old->KeyIndex; new->KeyLength = old->KeyLength; bcopy(old->BSSID, new->BSSID, sizeof(NDIS_802_11_MAC_ADDRESS)); bcopy(old->KeyMaterial, (char *)new + sizeof(NDIS_802_11_KEY_COMPAT), new->KeyLength); ifr.ifr_data = (caddr_t)o; } else ifr.ifr_data = (caddr_t)oid; strlcpy(ifr.ifr_name, a->name, sizeof(ifr.ifr_name)); if (set == TRUE) retval = ioctl(a->socket, SIOCSDRVSPEC, &ifr); else retval = ioctl(a->socket, SIOCGDRVSPEC, &ifr); if (o != NULL) free(o); if (retval) return(0); return(1); } int PacketGetAdapterNames(CHAR *namelist, ULONG *len) { int mib[6]; size_t needed; struct if_msghdr *ifm; struct sockaddr_dl *sdl; char *buf, *lim, *next; char *plist; int spc; int i, ifcnt = 0; plist = namelist; spc = 0; bzero(plist, *len); needed = 0; mib[0] = CTL_NET; mib[1] = PF_ROUTE; mib[2] = 0; /* protocol */ mib[3] = 0; /* wildcard address family */ mib[4] = NET_RT_IFLIST; mib[5] = 0; /* no flags */ if (sysctl (mib, 6, NULL, &needed, NULL, 0) < 0) return(FALSE); buf = malloc (needed); if (buf == NULL) return(FALSE); if (sysctl (mib, 6, buf, &needed, NULL, 0) < 0) { free(buf); return(FALSE); } lim = buf + needed; /* Generate interface name list. */ next = buf; while (next < lim) { ifm = (struct if_msghdr *)next; if (ifm->ifm_type == RTM_IFINFO) { sdl = (struct sockaddr_dl *)(ifm + 1); if (strnstr(sdl->sdl_data, "wlan", sdl->sdl_nlen)) { if ((spc + sdl->sdl_nlen) > *len) { free(buf); return(FALSE); } strncpy(plist, sdl->sdl_data, sdl->sdl_nlen); plist += (sdl->sdl_nlen + 1); spc += (sdl->sdl_nlen + 1); ifcnt++; } } next += ifm->ifm_msglen; } /* Insert an extra "" as a spacer */ plist++; spc++; /* * Now generate the interface description list. There * must be a unique description for each interface, and * they have to match what the ndis_events program will * feed in later. To keep this simple, we just repeat * the interface list over again. */ next = buf; while (next < lim) { ifm = (struct if_msghdr *)next; if (ifm->ifm_type == RTM_IFINFO) { sdl = (struct sockaddr_dl *)(ifm + 1); if (strnstr(sdl->sdl_data, "wlan", sdl->sdl_nlen)) { if ((spc + sdl->sdl_nlen) > *len) { free(buf); return(FALSE); } strncpy(plist, sdl->sdl_data, sdl->sdl_nlen); plist += (sdl->sdl_nlen + 1); spc += (sdl->sdl_nlen + 1); ifcnt++; } } next += ifm->ifm_msglen; } free (buf); *len = spc + 1; return(TRUE); } void PacketCloseAdapter(void *iface) { struct adapter *a; struct ifreq ifr; struct ieee80211req ireq; if (iface == NULL) return; a = iface; /* Reset net80211 roaming */ bzero((char *)&ireq, sizeof(ireq)); strncpy(ireq.i_name, a->name, sizeof (ifr.ifr_name)); ireq.i_type = IEEE80211_IOC_ROAMING; ireq.i_val = a->prev_roaming; ioctl(a->socket, SIOCS80211, &ireq); bzero((char *)&ifr, sizeof(ifr)); strncpy(ifr.ifr_name, a->name, sizeof (ifr.ifr_name)); ioctl(a->socket, SIOCGIFFLAGS, (caddr_t)&ifr); ifr.ifr_flags &= ~IFF_UP; ioctl(a->socket, SIOCSIFFLAGS, (caddr_t)&ifr); close(a->socket); free(a); return; } #if __FreeBSD_version < 600000 /* * The version of libpcap in FreeBSD 5.2.1 doesn't have these routines. * Call me insane if you will, but I still run 5.2.1 on my laptop, and * I'd like to use WPA there. */ int pcap_get_selectable_fd(pcap_t *p) { return(pcap_fileno(p)); } /* * The old version of libpcap opens its BPF descriptor in read-only * mode. We need to temporarily create a new one we can write to. */ int pcap_inject(pcap_t *p, const void *buf, size_t len) { int fd; int res, n = 0; char device[sizeof "/dev/bpf0000000000"]; struct ifreq ifr; /* * Go through all the minors and find one that isn't in use. */ do { (void)snprintf(device, sizeof(device), "/dev/bpf%d", n++); fd = open(device, O_RDWR); } while (fd < 0 && errno == EBUSY); if (fd == -1) return(-1); bzero((char *)&ifr, sizeof(ifr)); ioctl(pcap_fileno(p), BIOCGETIF, (caddr_t)&ifr); ioctl(fd, BIOCSETIF, (caddr_t)&ifr); res = write(fd, buf, len); close(fd); return(res); } #endif