/* * net.c * * Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005 Red Hat, Inc. * 2006, 2007, 2008, 2009 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Author(s): David Cantrell */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../pyanaconda/isys/isys.h" #include "../pyanaconda/isys/ethtool.h" #include "../pyanaconda/isys/iface.h" #include "../pyanaconda/isys/log.h" #include "lang.h" #include "loader.h" #include "loadermisc.h" #include "method.h" #include "net.h" #include "windows.h" #include "ibft.h" #include #include #include #include #include #include #include /* boot flags */ extern uint64_t flags; /** * Callback function for the CIDR entry boxes on the manual TCP/IP * configuration window. * * @param co The entry field that triggered the callback. * @param dptr Pointer to intfconfig_s data structure for this field. * @see intfconfig_s */ static void cidrCallback(newtComponent co, void * dptr) { struct intfconfig_s * data = dptr; int cidr, upper = 0; if (co == data->cidr4Entry) { if (data->cidr4 == NULL && data->ipv4 == NULL) return; if (isValidIPv4Address(data->cidr4)) return; errno = 0; cidr = strtol(data->cidr4, NULL, 10); if ((errno == ERANGE && (cidr == LONG_MIN || cidr == LONG_MAX)) || (errno != 0 && cidr == 0)) { logMessage(ERROR, "%s: %d: %m", __func__, __LINE__); abort(); } if (strcmp(data->ipv4, "")) upper = 32; #ifdef ENABLE_IPV6 } else if (co == data->cidr6Entry) { if (data->cidr6 == NULL && data->ipv6 == NULL) return; errno = 0; cidr = strtol(data->cidr6, NULL, 10); if ((errno == ERANGE && (cidr == LONG_MIN || cidr == LONG_MAX)) || (errno != 0 && cidr == 0)) { logMessage(ERROR, "%s: %d: %m", __func__, __LINE__); abort(); } if (strcmp(data->ipv6, "")) upper = 128; #endif } if (upper != 0) { if (cidr < 1 || cidr > upper) { newtWinMessage(_("Invalid Prefix"), _("Retry"), _("Prefix must be between 1 and 32 " "for IPv4 networks or between 1 and 128 " "for IPv6 networks")); } } } static void ipCallback(newtComponent co, void * dptr) { int i; char *buf, *octet; struct intfconfig_s * data = dptr; if (co == data->ipv4Entry) { /* do we need to guess a netmask for the user? */ if (data->cidr4 == NULL && data->ipv4 != NULL) { buf = strdup(data->ipv4); octet = strtok(buf, "."); errno = 0; i = strtol(octet, NULL, 10); if ((errno == ERANGE && (i == LONG_MIN || i == LONG_MAX)) || (errno != 0 && i == 0)) { logMessage(ERROR, "%s: %d: %m", __func__, __LINE__); abort(); } free(buf); free(octet); if (i >= 0 && i <= 127) newtEntrySet(data->cidr4Entry, "8", 1); else if (i >= 128 && i <= 191) newtEntrySet(data->cidr4Entry, "16", 1); else if (i >= 192 && i <= 222) newtEntrySet(data->cidr4Entry, "24", 1); } return; #ifdef ENABLE_IPV6 } else if (co == data->ipv6Entry) { /* users must provide a mask, we can't guess for ipv6 */ return; #endif } } static void setMethodSensitivity(void *dptr, int radio_button_count) { int i = 0; for (i = 0; i < radio_button_count; i++) { newtCheckboxSetFlags(*((newtComponent *) dptr), NEWT_FLAG_DISABLED, NEWT_FLAGS_TOGGLE); dptr += sizeof (newtComponent); } return; } static void v4MethodCallback(newtComponent co, void *dptr) { setMethodSensitivity(dptr, 2); return; } #ifdef ENABLE_IPV6 static void v6MethodCallback(newtComponent co, void *dptr) { setMethodSensitivity(dptr, 3); return; } #endif static void parseEthtoolSettings(struct loaderData_s * loaderData) { char * option, * buf; ethtool_duplex duplex = ETHTOOL_DUPLEX_UNSPEC; ethtool_speed speed = ETHTOOL_SPEED_UNSPEC; buf = strdup(loaderData->ethtool); option = strtok(buf, " "); while (option) { if (option[strlen(option) - 1] == '\"') option[strlen(option) - 1] = '\0'; if (option[0] == '\"') option++; if (!strncmp(option, "duplex", 6)) { if (!strncmp(option + 7, "full", 4)) duplex = ETHTOOL_DUPLEX_FULL; else if (!strncmp(option + 7, "half", 4)) duplex = ETHTOOL_DUPLEX_HALF; else logMessage(WARNING, "Unknown duplex setting: %s", option + 7); option = strtok(NULL, " "); } else if (!strncmp("speed", option, 5)) { if (!strncmp(option + 6, "1000", 4)) speed = ETHTOOL_SPEED_1000; else if (!strncmp(option + 6, "100", 3)) speed = ETHTOOL_SPEED_100; else if (!strncmp(option + 6, "10", 2)) speed = ETHTOOL_SPEED_10; else logMessage(WARNING, "Unknown speed setting: %s", option + 6); option = strtok(NULL, " "); } else { logMessage(WARNING, "Unknown ethtool setting: %s", option); } option = strtok(NULL, " "); } setEthtoolSettings(loaderData->netDev, speed, duplex); free(buf); } /* given loader data from kickstart, populate network configuration struct */ void setupIfaceStruct(iface_t * iface, struct loaderData_s * loaderData) { struct in_addr addr; struct in6_addr addr6; char * c; memset(&addr, 0, sizeof(addr)); memset(&addr6, 0, sizeof(addr6)); if (loaderData->ethtool) { parseEthtoolSettings(loaderData); } if (loaderData->netCls_set) { iface->vendorclass = loaderData->netCls; } else { iface->vendorclass = NULL; } if (loaderData->ipinfo_set && loaderData->ipv4 != NULL) { /* this is iBFT configured device */ if (!strncmp(loaderData->ipv4, "ibft", 4)) { iface->ipv4method = IPV4_IBFT_METHOD; /* this is how we specify dhcp */ } else if (!strncmp(loaderData->ipv4, "dhcp", 4)) { iface->dhcptimeout = loaderData->dhcpTimeout; iface->ipv4method = IPV4_DHCP_METHOD; } else if (inet_pton(AF_INET, loaderData->ipv4, &addr) >= 1) { iface->ipaddr.s_addr = addr.s_addr; iface->ipv4method = IPV4_MANUAL_METHOD; } else { /* invalid ip information, disable the setting of ip info */ loaderData->ipinfo_set = 0; iface->ipv4method = 0; loaderData->ipv4 = NULL; } } if (loaderData->netmask != NULL) { if (inet_pton(AF_INET, loaderData->netmask, &iface->netmask) <= 0) { logMessage(ERROR, "%s (%d): %s", __func__, __LINE__, strerror(errno)); } } if (loaderData->gateway != NULL) { if (inet_pton(AF_INET, loaderData->gateway, &iface->gateway) <= 0) { logMessage(ERROR, "%s (%d): %s", __func__, __LINE__, strerror(errno)); } } #ifdef ENABLE_IPV6 if (loaderData->ipv6info_set && loaderData->ipv6 != NULL) { if (!strncmp(loaderData->ipv6, "dhcp", 4)) { iface->ipv6method = IPV6_DHCP_METHOD; } else if (!strncmp(loaderData->ipv6, "auto", 4)) { iface->ipv6method = IPV6_AUTO_METHOD; } else if (inet_pton(AF_INET6, loaderData->ipv6, &addr6) >= 1) { memcpy(&iface->ip6addr, &addr6, sizeof(struct in6_addr)); iface->ipv6method = IPV6_MANUAL_METHOD; iface->ip6prefix = 0; if (loaderData->ipv6prefix) { int prefix; errno = 0; prefix = strtol(loaderData->ipv6prefix, NULL, 10); if ((errno == ERANGE && (prefix == LONG_MIN || prefix == LONG_MAX)) || (errno != 0 && prefix == 0)) { logMessage(ERROR, "%s: %d: %m", __func__, __LINE__); abort(); } if (prefix > 0 || prefix <= 128) { iface->ip6prefix = prefix; } } } else { iface->ipv6method = 0; loaderData->ipv6info_set = 0; loaderData->ipv6 = NULL; } } if (loaderData->gateway6 != NULL) { if (inet_pton(AF_INET6, loaderData->gateway6, &iface->gateway6) <= 0) { logMessage(ERROR, "%s (%d): %s", __func__, __LINE__, strerror(errno)); } } #endif if (loaderData->dns) { char * buf; char ret[INET6_ADDRSTRLEN+1]; buf = strdup(loaderData->dns); /* Scan the dns parameter for multiple comma-separated IP addresses */ c = strtok(buf, ","); while ((iface->numdns < MAXNS) && (c != NULL)) { if (inet_pton(AF_INET, c, &addr) >= 1) { iface->dns[iface->numdns] = strdup(c); iface->numdns++; if (inet_ntop(AF_INET, &addr, ret, INET_ADDRSTRLEN) == NULL) { logMessage(ERROR, "%s (%d): %s", __func__, __LINE__, strerror(errno)); } else { logMessage(DEBUGLVL, "adding dns4 %s", ret); c = strtok(NULL, ","); } } else if (inet_pton(AF_INET6, c, &addr6) >= 1) { iface->dns[iface->numdns] = strdup(c); iface->numdns++; if (inet_ntop(AF_INET6, &addr6, ret, INET6_ADDRSTRLEN) == NULL) { logMessage(ERROR, "%s (%d): %s", __func__, __LINE__, strerror(errno)); } else { logMessage(DEBUGLVL, "adding dns6 %s", ret); c = strtok(NULL, ","); } } } logMessage(INFO, "dnsservers is %s", loaderData->dns); } if (loaderData->domain) { logMessage(INFO, "dnsdomains is %s", loaderData->domain); iface->domain = strdup(loaderData->domain); } if (loaderData->hostname) { logMessage(INFO, "setting specified hostname of %s", loaderData->hostname); iface->hostname = strdup(loaderData->hostname); } if (loaderData->mtu) { iface->mtu = loaderData->mtu; } if (loaderData->peerid) { iface->peerid = strdup(loaderData->peerid); } if (loaderData->subchannels) { iface->subchannels = strdup(loaderData->subchannels); } if (loaderData->ctcprot) { iface->ctcprot = strdup(loaderData->ctcprot); } if (loaderData->portname) { iface->portname = strdup(loaderData->portname); } if (loaderData->nettype) { iface->nettype = strdup(loaderData->nettype); } if (loaderData->ethtool) { parseEthtoolSettings(loaderData); } if (loaderData->options) { iface->options = strdup(loaderData->options); } if (loaderData->wepkey) { if (is_wireless_device(loaderData->netDev)) { iface->wepkey = strdup(loaderData->wepkey); } else { iface->wepkey = NULL; } } if (loaderData->essid) { if (is_wireless_device(loaderData->netDev)) { iface->ssid = strdup(loaderData->essid); } else { iface->ssid = NULL; } } if (loaderData->noDns) { iface->flags |= IFACE_FLAGS_NO_WRITE_RESOLV_CONF; } iface->dhcptimeout = loaderData->dhcpTimeout; if (loaderData->macaddr) { iface->macaddr = strdup(loaderData->macaddr); } return; } int readNetConfig(char * device, iface_t * iface, char * dhcpclass, int methodNum) { int err; int ret; int i = 0; struct netconfopts opts; struct in_addr addr; struct intfconfig_s ipcomps; /* ipcomps contains the user interface components */ ipcomps.ipv4 = NULL; ipcomps.cidr4 = NULL; ipcomps.gw = NULL; #ifdef ENABLE_IPV6 ipcomps.ipv6 = NULL; ipcomps.cidr6 = NULL; ipcomps.gw6 = NULL; #endif ipcomps.ns = NULL; /* init opts */ opts.ipv4Choice = 0; opts.v4Method = 0; #ifdef ENABLE_IPV6 opts.ipv6Choice = 0; opts.v6Method = 0; #endif /* JKFIXME: we really need a way to override this and be able to change * our network config */ if (!FL_ASKNETWORK(flags) && ((iface->ipv4method > IPV4_UNUSED_METHOD) || (iface->ipv6method > IPV4_UNUSED_METHOD))) { logMessage(INFO, "doing kickstart... setting it up"); err = writeEnabledNetInfo(iface); if (err) { logMessage(ERROR, "failed to write %s data for %s (%d)", SYSCONFIG_PATH, iface->device, err); return LOADER_BACK; } i = wait_for_iface_activation(iface->device); newtPopWindow(); if (i > 0) { if (FL_CMDLINE(flags)) { fprintf(stderr, _("There was an error configuring your network " "interface.")); fprintf(stderr, _("\nThis cannot be corrected in cmdline mode.\n" "Halting.\n")); exit(1); } newtWinMessage(_("Network Error"), _("Retry"), _("There was an error configuring your network " "interface.")); /* Clear out ip selections to allow for re-entry */ iface->ipv4method = IPV4_UNUSED_METHOD; iface->ipv6method = IPV6_UNUSED_METHOD; return LOADER_ERROR; } return LOADER_NOOP; } /* dhcp/manual network configuration loop */ i = 1; while (i == 1) { ret = configureTCPIP(device, iface, &opts, methodNum); if (ret == LOADER_NOOP) { /* dhcp selected, proceed */ i = 0; } else if (ret == LOADER_OK) { /* do manual configuration */ ret = manualNetConfig(device, iface, &ipcomps, &opts); if (ret == LOADER_BACK) { continue; } else if (ret == LOADER_OK) { i = 0; } } else if (ret == LOADER_BACK) { return LOADER_BACK; } } /* calculate any missing IPv4 pieces */ if (opts.ipv4Choice == '*') { memset(&addr, 0, sizeof(addr)); addr.s_addr = (iface->ipaddr.s_addr) & (iface->netmask.s_addr); if (iface->broadcast.s_addr == 0) { iface->broadcast.s_addr = addr.s_addr | ~(iface->netmask.s_addr); } } /* bring up the interface */ err = writeEnabledNetInfo(iface); if (err) { logMessage(ERROR, "failed to write %s data for %s (%d)", SYSCONFIG_PATH, iface->device, err); iface->ipv4method = IPV4_UNUSED_METHOD; iface->ipv6method = IPV6_UNUSED_METHOD; return LOADER_BACK; } i = wait_for_iface_activation(iface->device); newtPopWindow(); if (i > 0) { newtWinMessage(_("Network Error"), _("Retry"), _("There was an error configuring your network " "interface.")); /* Clear out selections to allow for re-entry */ iface->ipv4method = IPV4_UNUSED_METHOD; iface->ipv6method = IPV6_UNUSED_METHOD; return LOADER_ERROR; } return LOADER_OK; } int configureTCPIP(char * device, iface_t * iface, struct netconfopts * opts, int methodNum) { int i = 0, z = 0, skipForm = 0, ret; newtComponent f, okay, back, answer; newtComponent ipv4Checkbox, v4Method[2]; #ifdef ENABLE_IPV6 newtComponent ipv6Checkbox, v6Method[3]; #endif newtGrid grid, checkgrid, buttons; /* UI WINDOW 1: ask for ipv4 choice, ipv6 choice, and conf methods */ /* IPv4 checkbox */ if (!opts->ipv4Choice) { if (FL_NOIPV4(flags) && !FL_IP_PARAM(flags)) opts->ipv4Choice = ' '; else opts->ipv4Choice = '*'; } ipv4Checkbox = newtCheckbox(-1, -1, _("Enable IPv4 support"), opts->ipv4Choice, NULL, &(opts->ipv4Choice)); v4Method[0] = newtRadiobutton(-1, -1, DHCP_METHOD_STR, (opts->v4Method == 0), NULL); v4Method[1] = newtRadiobutton(-1, -1, MANUAL_METHOD_STR, (opts->v4Method == 1), v4Method[0]); #ifdef ENABLE_IPV6 /* IPv6 checkbox */ if (!opts->ipv6Choice) { if (FL_NOIPV6(flags) && !FL_IPV6_PARAM(flags)) opts->ipv6Choice = ' '; else opts->ipv6Choice = '*'; } ipv6Checkbox = newtCheckbox(-1, -1, _("Enable IPv6 support"), opts->ipv6Choice, NULL, &(opts->ipv6Choice)); v6Method[0] = newtRadiobutton(-1, -1, AUTO_METHOD_STR, (opts->v6Method == 0), NULL); v6Method[1] = newtRadiobutton(-1, -1, DHCPV6_METHOD_STR, (opts->v6Method == 1), v6Method[0]); v6Method[2] = newtRadiobutton(-1, -1, MANUAL_METHOD_STR, (opts->v6Method == 2), v6Method[1]); #endif /* button bar at the bottom of the window */ buttons = newtButtonBar(_("OK"), &okay, _("Back"), &back, NULL); /* checkgrid contains the toggle options for net configuration */ #ifdef ENABLE_IPV6 checkgrid = newtCreateGrid(1, 8); #else checkgrid = newtCreateGrid(1, 3); #endif newtGridSetField(checkgrid, 0, 0, NEWT_GRID_COMPONENT, ipv4Checkbox, 0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0); for (i = 1; i < 3; i++) newtGridSetField(checkgrid, 0, i, NEWT_GRID_COMPONENT, v4Method[i-1], 7, 0, 0, 0, NEWT_ANCHOR_LEFT, 0); #ifdef ENABLE_IPV6 newtGridSetField(checkgrid, 0, 4, NEWT_GRID_COMPONENT, ipv6Checkbox, 0, 1, 0, 0, NEWT_ANCHOR_LEFT, 0); for (i = 5; i < 8; i++) newtGridSetField(checkgrid, 0, i, NEWT_GRID_COMPONENT, v6Method[i-5], 7, 0, 0, 0, NEWT_ANCHOR_LEFT, 0); #endif /* main window layout */ grid = newtCreateGrid(1, 2); newtGridSetField(grid, 0, 0, NEWT_GRID_SUBGRID, checkgrid, 0, 0, 0, 1, 0, 0); newtGridSetField(grid, 0, 1, NEWT_GRID_SUBGRID, buttons, 0, 0, 0, 0, 0, NEWT_GRID_FLAG_GROWX); f = newtForm(NULL, NULL, 0); newtGridAddComponentsToForm(grid, f, 1); newtGridWrappedWindow(grid, _("Configure TCP/IP")); newtGridFree(grid, 1); /* callbacks */ newtComponentAddCallback(ipv4Checkbox, v4MethodCallback, &v4Method); #ifdef ENABLE_IPV6 newtComponentAddCallback(ipv6Checkbox, v6MethodCallback, &v6Method); #endif /* match radio button sensitivity to initial checkbox choices */ if (opts->ipv4Choice == ' ') setMethodSensitivity(&v4Method, 2); #ifdef ENABLE_IPV6 if (opts->ipv6Choice == ' ') setMethodSensitivity(&v6Method, 3); #endif #ifdef ENABLE_IPV6 /* If the user provided any of the following boot paramters, skip * prompting for network configuration information: * ip= ipv6= * noipv4 noipv6 * ip= noipv6 * ipv6= noipv4 */ if ((iface->ipv4method > IPV4_UNUSED_METHOD && iface->ipv6method > IPV6_UNUSED_METHOD) || /* both */ (iface->ipv4method > IPV4_UNUSED_METHOD && FL_NOIPV6(flags)) || /* only ipv4 */ (FL_NOIPV4(flags) && iface->ipv6method > IPV6_UNUSED_METHOD) || /* only ipv6 */ (FL_NOIPV4(flags) && FL_NOIPV6(flags))) { /* neither ipv4 or ipv6 -- what else? */ skipForm = 1; newtPopWindow(); logMessage(DEBUGLVL, "in configureTCPIP(), detected network boot args, skipping form"); } #else if (iface->ipv4method > IPV4_UNUSED_METHOD || FL_NOIPV4(flags)) { skipForm = 1; newtPopWindow(); logMessage(DEBUGLVL, "in configureTCPIP(), detected network boot args, skipping form"); } #endif /* run the form */ do { if (!skipForm) { answer = newtRunForm(f); if (answer == back) { newtFormDestroy(f); newtPopWindow(); return LOADER_BACK; } /* need at least one stack */ #ifdef ENABLE_IPV6 if (opts->ipv4Choice == ' ' && opts->ipv6Choice == ' ') { #else if (opts->ipv4Choice == ' ') { #endif newtWinMessage(_("Missing Protocol"), _("Retry"), _("You must select at least one protocol (IPv4 " "or IPv6).")); continue; } /* NFS only works over IPv4 */ if (opts->ipv4Choice == ' ' && methodNum == METHOD_NFS) { newtWinMessage(_("IPv4 Needed for NFS"), _("Retry"), _("NFS installation method requires IPv4 support.")); continue; } } /* what TCP/IP stacks do we use? what conf methods? */ if (opts->ipv4Choice == '*') { flags &= ~LOADER_FLAGS_NOIPV4; for (z = IPV4_FIRST_METHOD; z <= IPV4_LAST_METHOD; z++) if (newtRadioGetCurrent(v4Method[0]) == v4Method[z-1]) iface->ipv4method = z; } else { flags |= LOADER_FLAGS_NOIPV4; } #ifdef ENABLE_IPV6 if (opts->ipv6Choice == '*') { flags &= ~LOADER_FLAGS_NOIPV6; for (z = IPV6_FIRST_METHOD; z <= IPV6_LAST_METHOD; z++) if (newtRadioGetCurrent(v6Method[0]) == v6Method[z-1]) iface->ipv6method = z; } else { flags |= LOADER_FLAGS_NOIPV6; } #endif /* update opts keeping method choice for UI */ for (z = IPV4_FIRST_METHOD; z <= IPV4_LAST_METHOD; z++) { if (newtRadioGetCurrent(v4Method[0]) == v4Method[z-1]) opts->v4Method = z-1; } #ifdef ENABLE_IPV6 for (z = IPV6_FIRST_METHOD; z <= IPV6_LAST_METHOD; z++) { if (newtRadioGetCurrent(v6Method[0]) == v6Method[z-1]) opts->v6Method = z-1; } #endif /* do interface configuration (call DHCP here, or return for manual) */ #ifdef ENABLE_IPV6 if ((!FL_NOIPV4(flags) && iface->ipv4method == IPV4_MANUAL_METHOD) || (!FL_NOIPV6(flags) && iface->ipv6method == IPV6_MANUAL_METHOD)) { #else if (!FL_NOIPV4(flags) && iface->ipv4method == IPV4_MANUAL_METHOD) { #endif /* manual IP configuration selected */ ret = LOADER_OK; i = 1; #ifdef ENABLE_IPV6 } else if (!FL_NOIPV4(flags) || !FL_NOIPV6(flags)) { #else } else if (!FL_NOIPV4(flags)) { #endif /* only auto configuration selected, exit the loop */ ret = LOADER_NOOP; i = 1; } } while (i != 1); newtFormDestroy(f); newtPopWindow(); return ret; } int manualNetConfig(char * device, iface_t * iface, struct intfconfig_s * ipcomps, struct netconfopts * opts) { int i, rows, pos, cidr, have[2], stack[2]; char *buf = NULL; char ret[48]; #ifdef ENABLE_IPV6 int prefix; #endif struct in_addr *tmpaddr = NULL; newtComponent f, okay, back, answer; newtGrid egrid = NULL; newtGrid qgrid = NULL; #ifdef ENABLE_IPV6 newtGrid rgrid = NULL; #endif newtGrid buttons, grid; newtComponent text = NULL; memset(ret, '\0', INET6_ADDRSTRLEN+1); /* so we don't perform this test over and over */ stack[IPV4] = opts->ipv4Choice == '*' && iface->ipv4method == IPV4_MANUAL_METHOD; #ifdef ENABLE_IPV6 stack[IPV6] = opts->ipv6Choice == '*' && iface->ipv6method == IPV6_MANUAL_METHOD; #endif /* UI WINDOW 2 (optional): manual IP config for non-DHCP installs */ rows = 2; for (i = 0; i < 2; i++) { if (stack[i]) { rows++; } } egrid = newtCreateGrid(4, rows); pos = 0; /* IPv4 entry items */ if (stack[IPV4]) { newtGridSetField(egrid, 0, pos, NEWT_GRID_COMPONENT, newtLabel(-1, -1, _("IPv4 address:")), 0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0); ipcomps->ipv4Entry = newtEntry(-1, -1, NULL, 16, &ipcomps->ipv4, 0); ipcomps->cidr4Entry = newtEntry(-1, -1, NULL, 16, &ipcomps->cidr4, 0); /* use a nested grid for ipv4 addr & netmask */ qgrid = newtCreateGrid(3, 1); newtGridSetField(qgrid, 0, 0, NEWT_GRID_COMPONENT, ipcomps->ipv4Entry, 1, 0, 0, 0, NEWT_ANCHOR_LEFT, 0); newtGridSetField(qgrid, 1, 0, NEWT_GRID_COMPONENT, newtLabel(-1, -1, _("/")), 1, 0, 0, 0, NEWT_ANCHOR_LEFT, 0); newtGridSetField(qgrid, 2, 0, NEWT_GRID_COMPONENT, ipcomps->cidr4Entry, 1, 0, 0, 0, NEWT_ANCHOR_LEFT, 0); newtGridSetField(egrid, 1, pos, NEWT_GRID_SUBGRID, qgrid, 0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0); newtComponentAddCallback(ipcomps->ipv4Entry, ipCallback, ipcomps); newtComponentAddCallback(ipcomps->cidr4Entry, cidrCallback, ipcomps); /* populate fields if we have data already */ if (iface_have_in_addr(&iface->ipaddr)) { if (inet_ntop(AF_INET, &iface->ipaddr, ret, INET_ADDRSTRLEN) == NULL) { logMessage(ERROR, "%s (%d): %s", __func__, __LINE__, strerror(errno)); } } if (*ret) { newtEntrySet(ipcomps->ipv4Entry, ret, 1); } if (iface_have_in_addr(&iface->netmask)) { if (inet_ntop(AF_INET, &iface->netmask, ret, INET_ADDRSTRLEN) == NULL) { logMessage(ERROR, "%s (%d): %s", __func__, __LINE__, strerror(errno)); } } if (*ret) { newtEntrySet(ipcomps->cidr4Entry, ret, 1); } pos++; } #ifdef ENABLE_IPV6 /* IPv6 entry items */ if (stack[IPV6]) { newtGridSetField(egrid, 0, pos, NEWT_GRID_COMPONENT, newtLabel(-1, -1, _("IPv6 address:")), 0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0); ipcomps->ipv6Entry = newtEntry(-1, -1, NULL, 41, &ipcomps->ipv6, 0); ipcomps->cidr6Entry = newtEntry(-1, -1, NULL, 4, &ipcomps->cidr6, 0); /* use a nested grid for ipv6 addr & netmask */ rgrid = newtCreateGrid(3, 1); newtGridSetField(rgrid, 0, 0, NEWT_GRID_COMPONENT, ipcomps->ipv6Entry, 1, 0, 0, 0, NEWT_ANCHOR_LEFT, 0); newtGridSetField(rgrid, 1, 0, NEWT_GRID_COMPONENT, newtLabel(-1, -1, _("/")), 1, 0, 0, 0, NEWT_ANCHOR_LEFT, 0); newtGridSetField(rgrid, 2, 0, NEWT_GRID_COMPONENT, ipcomps->cidr6Entry, 1, 0, 0, 0, NEWT_ANCHOR_LEFT, 0); newtGridSetField(egrid, 1, pos, NEWT_GRID_SUBGRID, rgrid, 0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0); newtComponentAddCallback(ipcomps->ipv6Entry, ipCallback, ipcomps); newtComponentAddCallback(ipcomps->cidr6Entry, cidrCallback, ipcomps); /* populate fields if we have data already */ if (iface_have_in6_addr(&iface->ip6addr)) { if (inet_ntop(AF_INET6, &iface->ip6addr, ret, INET6_ADDRSTRLEN) == NULL) { logMessage(ERROR, "%s (%d): %s", __func__, __LINE__, strerror(errno)); } } if (*ret) { newtEntrySet(ipcomps->ipv6Entry, ret, 1); } if (iface->ip6prefix) { if (asprintf(&buf, "%d", iface->ip6prefix) == -1) { buf = NULL; } } else if (iface->ip6prefix) { if (asprintf(&buf, "%d", iface->ip6prefix) == -1) { buf = NULL; } } if (buf != NULL) { newtEntrySet(ipcomps->cidr6Entry, buf, 1); free(buf); } pos++; } #endif /* common entry items */ ipcomps->gwEntry = newtEntry(-1, -1, NULL, 41, &ipcomps->gw, 0); ipcomps->nsEntry = newtEntry(-1, -1, NULL, 41, &ipcomps->ns, 0); newtGridSetField(egrid, 0, pos, NEWT_GRID_COMPONENT, newtLabel(-1, -1, _("Gateway:")), 0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0); newtGridSetField(egrid, 1, pos, NEWT_GRID_COMPONENT, ipcomps->gwEntry, 1, 0, 0, 0, NEWT_ANCHOR_LEFT, 0); pos++; newtGridSetField(egrid, 0, pos, NEWT_GRID_COMPONENT, newtLabel(-1, -1, _("Name Server:")), 0, 0, 0, 0, NEWT_ANCHOR_LEFT, 0); newtGridSetField(egrid, 1, pos, NEWT_GRID_COMPONENT, ipcomps->nsEntry, 1, 0, 0, 0, NEWT_ANCHOR_LEFT, 0); if (iface_have_in_addr(&iface->gateway)) { if (inet_ntop(AF_INET, &iface->gateway, ret, INET_ADDRSTRLEN) == NULL) { logMessage(ERROR, "%s (%d): %s", __func__, __LINE__, strerror(errno)); } else { newtEntrySet(ipcomps->gwEntry, ret, 1); } } else if (iface_have_in6_addr(&iface->gateway6)) { if (inet_ntop(AF_INET6, &iface->gateway6, ret, INET6_ADDRSTRLEN) == NULL) { logMessage(ERROR, "%s (%d): %s", __func__, __LINE__, strerror(errno)); } else { newtEntrySet(ipcomps->gwEntry, ret, 1); } } if (iface->numdns) { newtEntrySet(ipcomps->nsEntry, iface->dns[0], 1); } else if (iface->numdns) { newtEntrySet(ipcomps->nsEntry, iface->dns[0], 1); } newtComponentAddCallback(ipcomps->gwEntry, ipCallback, ipcomps); newtComponentAddCallback(ipcomps->nsEntry, ipCallback, ipcomps); /* button bar at the bottom of the window */ buttons = newtButtonBar(_("OK"), &okay, _("Back"), &back, NULL); /* main window layout */ grid = newtCreateGrid(1, 3); checked_asprintf(&buf, _("Enter the IPv4 and/or the IPv6 address and prefix " "(address / prefix). For IPv4, the dotted-quad " "netmask or the CIDR-style prefix are acceptable. " "The gateway and name server fields must be valid IPv4 " "or IPv6 addresses.")); text = newtTextboxReflowed(-1, -1, buf, 52, 0, 10, 0); newtGridSetField(grid, 0, 0, NEWT_GRID_COMPONENT, text, 0, 0, 0, 1, NEWT_ANCHOR_LEFT, 0); newtGridSetField(grid, 0, 1, NEWT_GRID_SUBGRID, egrid, 0, 0, 0, 1, NEWT_ANCHOR_LEFT, 0); newtGridSetField(grid, 0, 2, NEWT_GRID_SUBGRID, buttons, 0, 0, 0, 0, 0, NEWT_GRID_FLAG_GROWX); f = newtForm(NULL, NULL, 0); newtGridAddComponentsToForm(grid, f, 1); newtGridWrappedWindow(grid, _("Manual TCP/IP Configuration")); newtGridFree(grid, 1); have[IPV4] = 0; have[IPV6] = 0; for (i = IPV4; i <= IPV6; i++) { if (!stack[i]) { have[i] = 2; } } /* run the form */ while ((have[IPV4] != 2) || (have[IPV6] != 2)) { answer = newtRunForm(f); /* collect IPv4 data */ if (stack[IPV4]) { if (ipcomps->ipv4) { if (inet_pton(AF_INET, ipcomps->ipv4, &iface->ipaddr) <= 0) { logMessage(ERROR, "%s (%d): %s", __func__, __LINE__, strerror(errno)); } else { have[IPV4]++; } } if (ipcomps->cidr4) { if (inet_pton(AF_INET, ipcomps->cidr4, &iface->netmask) >= 1) { have[IPV4]++; } else { errno = 0; cidr = strtol(ipcomps->cidr4, NULL, 10); if ((errno == ERANGE && (cidr == LONG_MIN || cidr == LONG_MAX)) || (errno != 0 && cidr == 0)) { logMessage(ERROR, "%s: %d: %m", __func__, __LINE__); abort(); } if (cidr >= 1 && cidr <= 32) { tmpaddr = iface_prefix2netmask(cidr); if (tmpaddr != NULL) { memcpy(&iface->netmask, tmpaddr, sizeof(struct in_addr)); have[IPV4]++; } else { iface->netmask.s_addr = 0; } } } } } #ifdef ENABLE_IPV6 /* collect IPv6 data */ if (stack[IPV6]) { if (ipcomps->ipv6) { if (inet_pton(AF_INET6, ipcomps->ipv6, &iface->ip6addr) <= 0) { logMessage(ERROR, "%s (%d): %s", __func__, __LINE__, strerror(errno)); } else { have[IPV6]++; } } if (ipcomps->cidr6) { errno = 0; prefix = strtol(ipcomps->cidr6, NULL, 10); if ((errno == ERANGE && (prefix == LONG_MIN || prefix == LONG_MAX)) || (errno != 0 && prefix == 0)) { logMessage(ERROR, "%s: %d: %m", __func__, __LINE__); abort(); } if (prefix > 0 || prefix <= 128) { iface->ip6prefix = prefix; have[IPV6]++; } } } #endif /* collect common network settings */ if (ipcomps->gw) { if (inet_pton(AF_INET, ipcomps->gw, &iface->gateway) <= 0) { memset(&iface->gateway, 0, sizeof(iface->gateway)); if (inet_pton(AF_INET6, ipcomps->gw, &iface->gateway6) <= 0) { logMessage(ERROR, "%s (%d): %s", __func__, __LINE__, strerror(errno)); memset(&iface->gateway6, 0, sizeof(iface->gateway6)); } } } /* gather nameservers */ if (ipcomps->ns) { #ifdef ENABLE_IPV6 if (isValidIPv4Address(ipcomps->ns) || isValidIPv6Address(ipcomps->ns)) { #else if (isValidIPv4Address(ipcomps->ns)) { #endif iface->dns[0] = strdup(ipcomps->ns); if (iface->numdns < 1) iface->numdns = 1; } } /* user selected back, but we've saved what they entered already */ if (answer == back) { newtFormDestroy(f); newtPopWindow(); free(buf); return LOADER_BACK; } /* we might be done now */ if (stack[IPV4] && have[IPV4] != 2) { have[IPV4] = 0; newtWinMessage(_("Missing Information"), _("Retry"), _("You must enter both a valid IPv4 address and a " "network mask or CIDR prefix.")); } #ifdef ENABLE_IPV6 if (stack[IPV6] && have[IPV6] != 2) { have[IPV6] = 0; newtWinMessage(_("Missing Information"), _("Retry"), _("You must enter both a valid IPv6 address and a " "CIDR prefix.")); } #endif strcpy(iface->device, device); } free(buf); newtFormDestroy(f); newtPopWindow(); return LOADER_OK; } /* * By default, we disable all network interfaces and then only * bring up the ones the user wants. */ int writeDisabledNetInfo(void) { int i = 0, rc; struct device **devs = NULL; devs = getDevices(DEVICE_NETWORK); if (devs == NULL) { return 1; } for (i = 0; devs[i]; i++) { /* remove dhclient-DEVICE.conf if we have it */ if ((rc = removeDhclientConfFile(devs[i]->device)) != 0) { return rc; } /* write disabled ifcfg-DEVICE file */ if (!is_wireless_device(devs[i]->device)) if ((rc = writeDisabledIfcfgFile(devs[i]->device)) != 0) return rc; } return 0; } int removeIfcfgFile(char *device) { char *fname = NULL; checked_asprintf(&fname, "%s/ifcfg-%s", NETWORK_SCRIPTS_PATH, device); if (!access(fname, R_OK|W_OK)) { if (unlink(fname)) { logMessage(ERROR, "error removing %s", fname); } } free(fname); return 0; } int removeDhclientConfFile(char *device) { char *ofile = NULL; if (asprintf(&ofile, "/etc/dhcp/dhclient-%s.conf", device) == -1) { return 5; } if (!access(ofile, R_OK|W_OK)) { if (unlink(ofile)) { logMessage(ERROR, "error removing %s", ofile); } } free(ofile); return 0; } int writeDisabledIfcfgFile(char *device) { char *ofile = NULL; char *nfile = NULL; FILE *fp = NULL; checked_asprintf(&ofile, "%s/.ifcfg-%s", NETWORK_SCRIPTS_PATH, device); checked_asprintf(&nfile, "%s/ifcfg-%s", NETWORK_SCRIPTS_PATH, device); if ((fp = fopen(ofile, "w")) == NULL) { free(ofile); return 2; } fprintf(fp, "DEVICE=%s\n", device); fprintf(fp, "HWADDR=%s\n", iface_mac2str(device)); fprintf(fp, "ONBOOT=no\n"); fprintf(fp, "NM_CONTROLLED=no\n"); if (fclose(fp) == EOF) { return 3; } if (rename(ofile, nfile) == -1) { free(ofile); free(nfile); return 4; } if (ofile) { free(ofile); ofile = NULL; } if (nfile) { free(nfile); nfile = NULL; } return 0; } /* * Write out network interface control files: * /etc/sysconfig/network-scripts/ifcfg-DEVICE * /etc/sysconfig/network */ int writeEnabledNetInfo(iface_t *iface) { int i = 0; mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; FILE *fp = NULL; char buf[INET6_ADDRSTRLEN+1]; char *ofile = NULL; char *nfile = NULL; struct utsname kv; memset(&buf, '\0', sizeof(buf)); if ((mkdir(NETWORK_SCRIPTS_PATH, mode) == -1) && (errno != EEXIST)) { return 16; } /* write vendor class */ if (iface->vendorclass == NULL) { if (uname(&kv) == -1) { iface->vendorclass = "anaconda"; } else { if (asprintf(&iface->vendorclass, "anaconda-%s %s %s", kv.sysname, kv.release, kv.machine) == -1 ) { return 20; } } } if (asprintf(&ofile, "/etc/dhcp/dhclient-%s.conf", iface->device) == -1) { return 17; } if ((fp = fopen(ofile, "w")) == NULL) { free(ofile); return 18; } fprintf(fp, "send vendor-class-identifier \"%s\";\n", iface->vendorclass); if (fclose(fp) == EOF) { free(ofile); return 19; } if (ofile) { free(ofile); ofile = NULL; } /* write out new ifcfg-DEVICE file */ if (asprintf(&ofile, "%s/.ifcfg-%s", NETWORK_SCRIPTS_PATH, iface->device) == -1) { return 1; } if (asprintf(&nfile, "%s/ifcfg-%s", NETWORK_SCRIPTS_PATH, iface->device) == -1) { return 13; } if ((fp = fopen(ofile, "w")) == NULL) { free(ofile); return 2; } fprintf(fp, "DEVICE=%s\n", iface->device); #if !defined(__s390__) && !defined(__s390x__) fprintf(fp, "HWADDR=%s\n", iface_mac2str(iface->device)); #endif fprintf(fp, "ONBOOT=yes\n"); if (!FL_NOIPV4(flags)) { if (iface->ipv4method == IPV4_IBFT_METHOD) { fprintf(fp, "BOOTPROTO=ibft\n"); } else if (iface->ipv4method == IPV4_DHCP_METHOD) { fprintf(fp, "BOOTPROTO=dhcp\n"); } else if (iface->ipv4method == IPV4_MANUAL_METHOD) { fprintf(fp, "BOOTPROTO=static\n"); if (iface_have_in_addr(&iface->ipaddr)) { if (inet_ntop(AF_INET, &iface->ipaddr, buf, INET_ADDRSTRLEN) == NULL) { free(ofile); fclose(fp); return 3; } fprintf(fp, "IPADDR=%s\n", buf); } if (iface_have_in_addr(&iface->netmask)) { if (inet_ntop(AF_INET, &iface->netmask, buf, INET_ADDRSTRLEN) == NULL) { free(ofile); fclose(fp); return 4; } fprintf(fp, "NETMASK=%s\n", buf); } if (iface_have_in_addr(&iface->broadcast)) { if (inet_ntop(AF_INET, &iface->broadcast, buf, INET_ADDRSTRLEN) == NULL) { free(ofile); fclose(fp); return 5; } fprintf(fp, "BROADCAST=%s\n", buf); } if (iface_have_in_addr(&iface->gateway)) { if (inet_ntop(AF_INET, &iface->gateway, buf, INET_ADDRSTRLEN) == NULL) { free(ofile); fclose(fp); return 6; } fprintf(fp, "GATEWAY=%s\n", buf); } } } #ifdef ENABLE_IPV6 if (!FL_NOIPV6(flags)) { if (iface->ipv6method == IPV6_AUTO_METHOD || iface->ipv6method == IPV6_DHCP_METHOD || iface->ipv6method == IPV6_MANUAL_METHOD) { fprintf(fp, "IPV6INIT=yes\n"); if (iface->ipv6method == IPV6_AUTO_METHOD) { fprintf(fp, "IPV6_AUTOCONF=yes\n"); } else if (iface->ipv6method == IPV6_DHCP_METHOD) { fprintf(fp, "IPV6_AUTOCONF=no\n"); fprintf(fp, "DHCPV6C=yes\n"); } else if (iface->ipv6method == IPV6_MANUAL_METHOD) { fprintf(fp, "IPV6_AUTOCONF=no\n"); if (iface_have_in6_addr(&iface->ip6addr)) { if (inet_ntop(AF_INET6, &iface->ip6addr, buf, INET6_ADDRSTRLEN) == NULL) { free(ofile); fclose(fp); return 7; } if (iface->ip6prefix) { fprintf(fp, "IPV6ADDR=%s/%d\n", buf, iface->ip6prefix); } else { fprintf(fp, "IPV6ADDR=%s\n", buf); } } } if (iface_have_in6_addr(&iface->gateway6)) { if (inet_ntop(AF_INET6, &iface->gateway6, buf, INET6_ADDRSTRLEN) == NULL) { free(ofile); fclose(fp); return 8; } fprintf(fp, "IPV6_DEFAULTGW=%s\n", buf); } } } #endif if (iface->numdns > 0) { for (i = 0; i < iface->numdns; i++) { fprintf(fp, "DNS%d=%s\n", i+1, iface->dns[i]); } } if (iface->hostname && iface->ipv4method == IPV4_DHCP_METHOD) { fprintf(fp, "DHCP_HOSTNAME=%s\n", iface->hostname); } if (iface->domain) { fprintf(fp, "DOMAIN=\"%s\"\n", iface->domain); } if (iface->mtu) { fprintf(fp, "MTU=%d\n", iface->mtu); } if (iface->peerid) { fprintf(fp, "PEERID=%s\n", iface->peerid); } if (iface->subchannels) { fprintf(fp, "SUBCHANNELS=%s\n", iface->subchannels); } if (iface->portname) { fprintf(fp, "PORTNAME=%s\n", iface->portname); } if (iface->nettype) { fprintf(fp, "NETTYPE=%s\n", iface->nettype); } if (iface->ctcprot) { fprintf(fp, "CTCPROT=%s\n", iface->ctcprot); } if (iface->options) { fprintf(fp, "OPTIONS=\'%s\'\n", iface->options); } if (iface->macaddr) { fprintf(fp, "MACADDR=%s\n", iface->macaddr); } if (!iface->defroute) { fprintf(fp, "DEFROUTE=no\n"); logMessage(INFO, "not setting default route via %s", iface->device); } if (fclose(fp) == EOF) { free(ofile); free(nfile); return 8; } if (rename(ofile, nfile) == -1) { free(ofile); free(nfile); return 14; } if (ofile) { free(ofile); } if (nfile) { free(nfile); } return 0; } /* if multiple interfaces get one to use from user. */ /* NOTE - uses kickstart data available in loaderData */ int chooseNetworkInterface(struct loaderData_s * loaderData) { int i, rc, ask, idrc, secs, deviceNums = 0, deviceNum, foundDev = 0; unsigned int max = 40; char **devices; char **deviceNames; char *ksMacAddr = NULL, *seconds = strdup("10"), *idstr = NULL; struct device **devs; int lookForLink = 0; struct newtWinEntry entry[] = {{N_("Seconds:"), (char **) &seconds, 0}, {NULL, NULL, 0 }}; devs = getDevices(DEVICE_NETWORK); if (!devs) { logMessage(ERROR, "no network devices in choose network device!"); return LOADER_ERROR; } for (i = 0; devs[i]; i++); devices = alloca((i + 1) * sizeof(*devices)); deviceNames = alloca((i + 1) * sizeof(*devices)); if (loaderData->netDev && (loaderData->netDev_set) == 1) { if ((loaderData->bootIf && (loaderData->bootIf_set) == 1) && !strcasecmp(loaderData->netDev, "bootif")) { ksMacAddr = g_ascii_strup(loaderData->bootIf, -1); } else { ksMacAddr = g_ascii_strup(loaderData->netDev, -1); } } for (i = 0; devs[i]; i++) { if (!devs[i]->device) continue; if (devs[i]->description) { deviceNames[deviceNums] = alloca(strlen(devs[i]->device) + strlen(devs[i]->description) + 4); sprintf(deviceNames[deviceNums],"%s - %.50s", devs[i]->device, devs[i]->description); if (strlen(deviceNames[deviceNums]) > max) max = strlen(deviceNames[deviceNums]); devices[deviceNums] = devs[i]->device; } else { devices[deviceNums] = devs[i]->device; deviceNames[deviceNums] = devs[i]->device; } deviceNums++; /* this device has been set and we don't really need to ask * about it again... */ if (loaderData->netDev && (loaderData->netDev_set == 1)) { if (!strcmp(loaderData->netDev, devs[i]->device)) { foundDev = 1; } else if (ksMacAddr != NULL) { /* maybe it's a mac address */ char *devmacaddr = iface_mac2str(devs[i]->device); if ((devmacaddr != NULL) && !strcmp(ksMacAddr, devmacaddr)) { foundDev = 1; free(loaderData->netDev); loaderData->netDev = devs[i]->device; if (devmacaddr != NULL) free(devmacaddr); break; } if (devmacaddr != NULL) free(devmacaddr); } } } if (ksMacAddr) free(ksMacAddr); if (foundDev == 1) return LOADER_NOOP; devices[deviceNums] = NULL; deviceNames[deviceNums] = NULL; qsort(devices, deviceNums, sizeof(*devices), simpleStringCmp); qsort(deviceNames, deviceNums, sizeof(*devices), simpleStringCmp); /* ASSERT: we should *ALWAYS* have a network device when we get here */ if (!deviceNums) { logMessage(CRITICAL, "no network device in chooseNetworkInterface"); return LOADER_ERROR; } /* If there is iBFT table and ksdevice doesn't say otherwise, use it */ while (!loaderData->netDev_set || !strcmp(loaderData->netDev, "ibft")) { char *devmacaddr = NULL; char *ibftmacaddr = ""; /* get MAC from the iBFT table */ if (!(ibftmacaddr = ibft_iface_mac())) { /* iBFT not present or error */ logMessage(INFO, "No iBFT table detected."); break; } logMessage(INFO, "looking for iBFT configured device %s with link", ibftmacaddr); for (i = 0; devs[i]; i++) { if (!devs[i]->device) continue; devmacaddr = iface_mac2str(devs[i]->device); if(!strcasecmp(devmacaddr, ibftmacaddr)){ logMessage(INFO, "%s has the right MAC (%s), checking for link", devs[i]->device, devmacaddr); free(devmacaddr); /* wait for the link (max 5s) */ for (rc = 0; rc < 5; rc++) { if (get_link_status(devs[i]->device) == 0) { logMessage(INFO, "%s still has no link, waiting", devs[i]->device); sleep(1); } else { lookForLink = 0; loaderData->netDev = devs[i]->device; loaderData->netDev_set = 1; logMessage(INFO, "%s has link, using it", devs[i]->device); /* set the IP method to ibft if not requested differently */ if (loaderData->ipv4 == NULL) { loaderData->ipv4 = strdup("ibft"); loaderData->ipinfo_set = 1; logMessage(INFO, "%s will be configured using iBFT values", devices[i]); } return LOADER_NOOP; } } logMessage(INFO, "%s has no link, skipping it", devices[i]); break; } else { free(devmacaddr); } } break; } if ((loaderData->netDev && (loaderData->netDev_set == 1)) && !strcmp(loaderData->netDev, "link")) { lookForLink = 1; } if (lookForLink) { logMessage(INFO, "looking for first netDev with link"); for (rc = 0; rc < 5; rc++) { for (i = 0; i < deviceNums; i++) { if (get_link_status(devices[i]) == 1) { loaderData->netDev = devices[i]; logMessage(INFO, "%s has link, using it", devices[i]); return LOADER_NOOP; } } sleep(1); } logMessage(WARNING, "wanted netdev with link, but none present. prompting"); } /* JKFIXME: if we only have one interface and it doesn't have link, * do we go ahead? */ if (deviceNums == 1) { logMessage(INFO, "only have one network device: %s", devices[0]); loaderData->netDev = devices[0]; loaderData->netDev_set = 1; return LOADER_NOOP; } if (FL_CMDLINE(flags)) { fprintf(stderr, "No way to determine which NIC to use, and cannot " "prompt in cmdline\nmode. Halting.\n"); fprintf(stderr, "Please use the ksdevice= parameter to specify the " "device name (e.g., eth0)\n or the MAC address of " "the NIC to use for installation.\n"); exit(1); } startNewt(); if (max > 70) max = 70; /* JKFIXME: should display link status */ deviceNum = 0; ask = 1; while (ask) { rc = newtWinMenu(_("Networking Device"), _("You have multiple network devices on this system. " "Which would you like to install through?"), max, 10, 10, deviceNums < 6 ? deviceNums : 6, deviceNames, &deviceNum, _("OK"), _("Identify"), _("Back"), NULL); if (rc == 2) { if (!devices[deviceNum]) { logMessage(ERROR, "NIC %d contains no device name", deviceNum); continue; } checked_asprintf(&idstr, "%s %s %s", _("You can identify the physical port for"), devices[deviceNum], _("by flashing the LED lights for a number of " "seconds. Enter a number between 1 and 30 to " "set the duration to flash the LED port " "lights.")); i = 1; while (i) { idrc = newtWinEntries(_("Identify NIC"), idstr, 50, 5, 15, 24, entry, _("OK"), _("Back"), NULL); if (idrc == 0 || idrc == 1) { errno = 0; secs = strtol((const char *) seconds, NULL, 10); if (errno == EINVAL || errno == ERANGE) { logMessage(ERROR, "strtol() failure in %s: %m", __func__); continue; } if (secs <=0 || secs > 300) { newtWinMessage(_("Invalid Duration"), _("OK"), _("You must enter the number of " "seconds as an integer between 1 " "and 30.")); continue; } idrc = 41 + strlen(devices[deviceNum]); if (secs > 9) { idrc += 1; } winStatus(idrc, 3, NULL, _("Flashing %s port lights for %d seconds."), devices[deviceNum], secs); if (identifyNIC(devices[deviceNum], secs)) { logMessage(ERROR, "error during physical NIC identification"); } newtPopWindow(); i = 0; } else if (idrc == 2) { i = 0; } } } else if (rc == 3) { ask = 0; return LOADER_BACK; } else { ask = 0; } } loaderData->netDev = devices[deviceNum]; return LOADER_OK; } /* JKFIXME: bad name. this function brings up networking early on a * kickstart install so that we can do things like grab the ks.cfg from * the network */ int kickstartNetworkUp(struct loaderData_s * loaderData, iface_t * iface) { int rc = -1; if ((is_nm_connected() == TRUE) && (loaderData->netDev != NULL) && (loaderData->netDev_set == 1)) return 0; iface_init_iface_t(iface); if (loaderData->essid != NULL) { checkIPsettings(&(loaderData->ipinfo_set), &(loaderData->ipv4), &(loaderData->gateway), &(loaderData->netmask)); if (loaderData->wepkey != NULL) rc = add_and_activate_wifi_connection(&(loaderData->netDev), loaderData->essid, WIFI_PROTECTION_WEP, loaderData->wepkey, loaderData->ipinfo_set, loaderData->ipv4, loaderData->gateway, loaderData->dns, loaderData->netmask); else if (loaderData->wpakey != NULL) rc = add_and_activate_wifi_connection(&(loaderData->netDev), loaderData->essid, WIFI_PROTECTION_WPA, loaderData->wpakey, loaderData->ipinfo_set, loaderData->ipv4, loaderData->gateway, loaderData->dns, loaderData->netmask); else rc = add_and_activate_wifi_connection(&(loaderData->netDev), loaderData->essid, WIFI_PROTECTION_UNPROTECTED, NULL, loaderData->ipinfo_set, loaderData->ipv4, loaderData->gateway, loaderData->dns, loaderData->netmask); if (rc == WIFI_ACTIVATION_OK) { loaderData->netDev_set = 1; return 0; } else logMessage(ERROR, "wifi activation failed"); } return activateDevice(loaderData, iface); } int disconnectDevice(char *device) { int rc; if ((rc = removeDhclientConfFile(device)) != 0) { logMessage(ERROR, "removeDhclientConfFile failure (%s): %d", __func__, rc); } /* * This will disconnect the device */ if ((rc = removeIfcfgFile(device)) != 0) { logMessage(ERROR, "removeIfcfgFile failure (%s): %d", __func__, rc); return rc; } if ((rc = wait_for_iface_disconnection(device)) != 0) { return rc; } if ((rc = writeDisabledIfcfgFile(device)) != 0) { logMessage(ERROR, "writeDisabledIfcfgFile failure (%s): %d", __func__, rc); return rc; } return 0; } int activateDevice(struct loaderData_s * loaderData, iface_t * iface) { int rc; do { do { /* this is smart and does the right thing based on whether or not * we have ksdevice= specified */ rc = chooseNetworkInterface(loaderData); if (rc == LOADER_ERROR) { /* JKFIXME: ask for a driver disk? */ logMessage(ERROR, "no network drivers for doing kickstart"); return -1; } else if (rc == LOADER_BACK) { return -1; } /* insert device into iface structure */ strcpy(iface->device, loaderData->netDev); break; } while (1); if (is_iface_activated(iface->device)) { logMessage(INFO, "device %s is already activated", iface->device); if ((rc = disconnectDevice(iface->device)) != 0) { logMessage(ERROR, "device disconnection failed with return code %d", rc); return -1; } } /* we don't want to end up asking about interface more than once * if we're in a kickstart-ish case (#100724) */ loaderData->netDev_set = 1; /* default to DHCP for IPv4 if nothing is provided */ if (loaderData->ipv4 == NULL) { loaderData->ipv4 = strdup("dhcp"); loaderData->ipinfo_set = 1; } setupIfaceStruct(iface, loaderData); rc = readNetConfig(loaderData->netDev, iface, loaderData->netCls, loaderData->method); if (rc == LOADER_ERROR) { logMessage(ERROR, "unable to activate device %s", iface->device); return -1; } else if (rc == LOADER_BACK) { /* Going back to the interface selection screen, so unset anything * we set before attempting to bring the incorrect interface up. */ logMessage(ERROR, "unable to activate device %s", iface->device); if ((rc = removeDhclientConfFile(iface->device)) != 0) { logMessage(ERROR, "removeDhclientConfFile failure (%s): %d", __func__, rc); } if ((rc = writeDisabledIfcfgFile(iface->device)) != 0) { logMessage(ERROR, "writeDisabledIfcfgFile failure (%s): %d", __func__, rc); } /* Forget network device so we prompt the user */ loaderData->netDev_set = 0; /* Forget IP information so we prompt the user */ loaderData->ipinfo_set = 0; free(loaderData->ipv4); loaderData->ipv4 = NULL; break; } else { break; } } while (1); return 0; } void splitHostname (char *str, char **host, char **port) { char *rightbrack = strchr(str, ']'); char *firstcolon = strchr(str, ':'); char *secondcolon = strrchr(str, ':'); *host = NULL; *port = NULL; if (*str == '[' && rightbrack) { /* An IPv6 address surrounded by brackets, optionally with a colon and * port number. */ char *colon = strrchr(rightbrack, ':'); if (colon) { *host = strndup(str+1, rightbrack-1-str); *port = strdup(colon+1); } else *host = strndup(str+1, rightbrack-1-str); } else if (firstcolon && secondcolon && firstcolon != secondcolon) { /* An IPv6 address without brackets. Don't make the user surround the * address with brackets if there's no port number. */ *host = strdup(str); } else { /* An IPv4 address, optionally with a colon and port number. */ char *colon = strrchr(str, ':'); if (colon) { *host = strndup(str, colon-str); *port = strdup(colon+1); } else *host = strdup(str); } } /* * Wait for activation of iface by NetworkManager, return non-zero on error. */ int wait_for_iface_activation(char *ifname) { int count = 0, i; NMClient *client = NULL; GMainLoop *loop; GMainContext *ctx; const GPtrArray *devices; NMDevice *device = NULL; if (ifname == NULL) { return 1; } logMessage(DEBUGLVL, "activating device %s", ifname); /* display status */ if (FL_CMDLINE(flags)) { printf(_("Waiting for NetworkManager to configure %s.\n"), ifname); } else { winStatus(55, 3, NULL, _("Waiting for NetworkManager to configure %s.\n"), ifname, 0); } g_type_init(); client = nm_client_new(); if (!client) { logMessage(ERROR, "%s (%d): could not connect to system bus", __func__, __LINE__); return 2; } devices = nm_client_get_devices(client); for (i = 0; i < devices->len; i++) { NMDevice *candidate = g_ptr_array_index(devices, i); const char *name = nm_device_get_iface(candidate); if (!strcmp(name, ifname)) { device = candidate; break; } } if (device == NULL) { logMessage(ERROR, "%s (%d): network device %s not found", __func__, __LINE__, ifname); g_object_unref(client); return 3; } /* Create a loop for processing dbus signals */ loop = g_main_loop_new(NULL, FALSE); ctx = g_main_loop_get_context(loop); /* pump the loop until all the messages are clear */ while (g_main_context_pending (ctx)) { g_main_context_iteration (ctx, FALSE); } /* send message and block until a reply or error comes back */ while (count < 45) { /* pump the loop again to clear the messages */ while (g_main_context_pending (ctx)) { g_main_context_iteration (ctx, FALSE); } if (nm_device_get_state(device) == NM_DEVICE_STATE_ACTIVATED) { logMessage(INFO, "%s (%d): device %s activated", __func__, __LINE__, ifname); res_init(); g_main_loop_unref(loop); g_object_unref(client); return 0; } sleep(1); count++; } g_main_loop_unref(loop); g_object_unref(client); return 3; } /* * Wait for disconnection of iface by NetworkManager, return non-zero on error. */ int wait_for_iface_disconnection(char *ifname) { int count = 0, i; NMClient *client = NULL; GMainLoop *loop; GMainContext *ctx; const GPtrArray *devices; NMDevice *device = NULL; if (ifname == NULL) { return 1; } logMessage(INFO, "disconnecting device %s", ifname); g_type_init(); client = nm_client_new(); if (!client) { logMessage(ERROR, "%s (%d): could not connect to system bus", __func__, __LINE__); return 2; } devices = nm_client_get_devices(client); for (i = 0; i < devices->len; i++) { NMDevice *candidate = g_ptr_array_index(devices, i); const char *name = nm_device_get_iface(candidate); if (!strcmp(name, ifname)) { device = candidate; break; } } if (device == NULL) { logMessage(ERROR, "%s (%d): network device %s not found", __func__, __LINE__, ifname); g_object_unref(client); return 3; } /* Create a loop for processing dbus signals */ loop = g_main_loop_new(NULL, FALSE); ctx = g_main_loop_get_context(loop); /* pump the loop until all the messages are clear */ while (g_main_context_pending (ctx)) { g_main_context_iteration (ctx, FALSE); } /* send message and block until a reply or error comes back */ while (count < 5) { /* pump the loop again to clear the messages */ while (g_main_context_pending (ctx)) { g_main_context_iteration (ctx, FALSE); } if (nm_device_get_state(device) == NM_DEVICE_STATE_DISCONNECTED) { logMessage(INFO, "%s (%d): device %s disconnected", __func__, __LINE__, ifname); res_init(); g_main_loop_unref(loop); g_object_unref(client); return 0; } sleep(1); count++; } g_main_loop_unref(loop); g_object_unref(client); return 3; } int isValidIPv4Address(const char *address) { int rc; struct in_addr addr; if ((rc = inet_pton(AF_INET, address, &addr)) >= 1) { return 1; } else if (rc == 0) { return 0; } else { logMessage(ERROR, "%s (%d): %s", __func__, __LINE__, strerror(errno)); return 0; } } #ifdef ENABLE_IPV6 int isValidIPv6Address(const char *address) { int rc; struct in6_addr addr; if ((rc = inet_pton(AF_INET6, address, &addr)) >= 1) { return 1; } else if (rc == 0) { return 0; } else { logMessage(ERROR, "%s (%d): %s", __func__, __LINE__, strerror(errno)); return 0; } } #endif int isURLRemote(char *url) { if (url == NULL) { return 0; } if (!strncmp(url, "http", 4) || !strncmp(url, "ftp://", 6) || !strncmp(url, "nfs:", 4)) { return 1; } else { return 0; } } gboolean byte_array_cmp(const GByteArray *array, char *string) { //returns TRUE if array and char* contain the same strings int i=0; gboolean ret = TRUE; if (array->len != strlen(string)) { return FALSE; } while (ilen && ret) { ret = ret && array->data[i] == string[i]; i++; } return ret; } NMAccessPoint* get_best_ap(NMDeviceWifi *device, char *ssid) { const GPtrArray *aps; int i; NMAccessPoint *candidate = NULL; guint8 max = 0; aps = nm_device_wifi_get_access_points(device); if (!aps) return NULL; for (i = 0; i < aps->len; i++) { NMAccessPoint *ap = g_ptr_array_index(aps, i); const GByteArray *byte_ssid = nm_access_point_get_ssid(ap); if (byte_array_cmp(byte_ssid, ssid)) { if (nm_access_point_get_strength(ap) > max) { max = nm_access_point_get_strength(ap); candidate = ap; } } } return candidate; } gboolean get_device_and_ap(NMClient *client, char **iface, char *ssid, NMDeviceWifi **device, NMAccessPoint **ap) { //returns TRUE if device and ap (according to iface and ssid) //were found //iface, device and ap are used for storing the results //iface is also used as argument const GPtrArray *devices; int i; NMAccessPoint *candidate_ap = NULL; NMDevice *candidate = NULL; char *tmp_iface = NULL; char *dev_iface = NULL; devices = nm_client_get_devices(client); for (i = 0; i < devices->len; i++) { candidate = g_ptr_array_index(devices, i); tmp_iface = (char *)nm_device_get_iface(candidate); if (!tmp_iface) continue; dev_iface = strdup((char *)tmp_iface); if (strcmp(*iface, "") && strcmp(dev_iface, *iface)) continue; if (NM_IS_DEVICE_WIFI(candidate)) { candidate_ap = get_best_ap((NMDeviceWifi*)candidate, ssid); if (candidate_ap != NULL) { *device = (NMDeviceWifi*)candidate; *ap = candidate_ap; *iface = dev_iface; return TRUE; } } else free(dev_iface); } return FALSE; } static void add_cb(NMClient *client, const char *connection_path, const char *active_path, GError *error, gpointer user_data) { if (error) logMessage(ERROR, "Error adding wifi connection: %s", error->message); } gboolean ip_str_to_nbo(char* ip, guint32 *result) { //get NBO representation of ip address struct in_addr tmp_addr = { 0 }; if (inet_pton(AF_INET, ip, &tmp_addr) == 1) { *result = tmp_addr.s_addr; return TRUE; } else return FALSE; } int add_and_activate_wifi_connection(char **iface, char *ssid, int protection, char *password, int ip_method_manual, char *address, char *gateway, char *dns, char *netmask) { NMClient *client = NULL; NMDeviceWifi *device = NULL; NMAccessPoint *ap = NULL; GMainLoop *loop; GMainContext *ctx; DBusGConnection *DBconnection; GError *error; GByteArray *ssid_ba; int ssid_len; gboolean success = FALSE; gint8 count = 0, ret; NMConnection *connection; NMSettingConnection *s_con; NMSettingWireless *s_wireless; NMSettingWirelessSecurity *s_sec; NMSettingIP4Config *s_ip; char *uuid; char *buf; if (*iface == NULL) *iface = ""; error = NULL; DBconnection = dbus_g_bus_get(DBUS_BUS_SYSTEM, &error); if (DBconnection == NULL) { g_error_free(error); return WIFI_ACTIVATION_DBUS_ERROR; } client = nm_client_new(); if (!client) return WIFI_ACTIVATION_NM_CLIENT_ERROR; if (!nm_client_wireless_hardware_get_enabled(client)) return WIFI_ACTIVATION_WIFI_HW_DISABLED; if (!nm_client_wireless_get_enabled(client)) nm_client_wireless_set_enabled(client, TRUE); if (!ssid) return WIFI_ACTIVATION_BAD_SSID; ssid_len = strlen(ssid); if (!ssid_len || ssid_len > 32) return WIFI_ACTIVATION_BAD_SSID; ssid_ba = g_byte_array_sized_new(ssid_len); g_byte_array_append(ssid_ba, (unsigned char *) ssid, ssid_len); loop = g_main_loop_new(NULL, FALSE); ctx = g_main_loop_get_context(loop); while (g_main_context_pending(ctx)) g_main_context_iteration(ctx, FALSE); /* display status */ if (FL_CMDLINE(flags)) printf(_("Waiting for NetworkManager to activate wifi.\n")); else winStatus(55, 3, NULL, _("Waiting for NetworkManager to activate wifi.\n"), 0); while (count < 45 && !success) { while (g_main_context_pending(ctx)) g_main_context_iteration(ctx, FALSE); success = get_device_and_ap(client, iface, ssid, &device, &ap); sleep(1); count++; } if (!FL_CMDLINE(flags)) newtPopWindow(); if (!success) return WIFI_ACTIVATION_CANNOT_FIND_AP; connection = nm_connection_new(); s_con = (NMSettingConnection*) nm_setting_connection_new(); uuid = nm_utils_uuid_generate(); g_object_set(G_OBJECT (s_con), NM_SETTING_CONNECTION_UUID, uuid, NM_SETTING_CONNECTION_ID, ssid, NM_SETTING_CONNECTION_TYPE, "802-11-wireless", NULL); g_free(uuid); nm_connection_add_setting(connection, NM_SETTING (s_con)); s_wireless = (NMSettingWireless*) nm_setting_wireless_new(); g_object_set(G_OBJECT (s_wireless), NM_SETTING_WIRELESS_SSID, ssid_ba, NM_SETTING_WIRELESS_MODE, "infrastructure", NULL); g_byte_array_free(ssid_ba, TRUE); if ((protection == WIFI_PROTECTION_WEP) || protection == WIFI_PROTECTION_WPA) { g_object_set(G_OBJECT (s_wireless), NM_SETTING_WIRELESS_SEC, "802-11-wireless-security", NULL); } nm_connection_add_setting(connection, NM_SETTING (s_wireless)); if (protection == WIFI_PROTECTION_WEP) { s_sec = (NMSettingWirelessSecurity*) nm_setting_wireless_security_new(); g_object_set (G_OBJECT (s_sec), NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "none", NM_SETTING_WIRELESS_SECURITY_WEP_TX_KEYIDX, 0, NM_SETTING_WIRELESS_SECURITY_WEP_KEY_TYPE, 1, NM_SETTING_WIRELESS_SECURITY_WEP_KEY0, password, NULL); if (strlen(password) == 32) { g_object_set(G_OBJECT (s_sec), NM_SETTING_WIRELESS_SECURITY_WEP_KEY_TYPE, 2, NULL); } nm_connection_add_setting(connection, NM_SETTING (s_sec)); } else if (protection == WIFI_PROTECTION_WPA) { s_sec = (NMSettingWirelessSecurity*) nm_setting_wireless_security_new(); g_object_set(G_OBJECT (s_sec), NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "wpa-psk", NM_SETTING_WIRELESS_SECURITY_PSK, password, NULL); nm_connection_add_setting(connection, NM_SETTING (s_sec)); } if (ip_method_manual) { GPtrArray *addresses = g_ptr_array_new(); GArray *address_array = g_array_new(FALSE, FALSE, sizeof(guint32)); guint32 nbo_ip = 0; guint32 nbo_gw = 0; guint32 nbo_dns = 0; guint32 nbo_netmask = 0; guint32 nbo_prefix = 0; char *dns_addr = NULL; ip_str_to_nbo(address, &nbo_ip); if (gateway) ip_str_to_nbo(gateway, &nbo_gw); nbo_prefix = nm_utils_ip4_get_default_prefix(nbo_ip); if (netmask && ip_str_to_nbo(netmask, &nbo_netmask)) nbo_prefix = nm_utils_ip4_netmask_to_prefix(nbo_netmask); g_array_append_val(address_array, nbo_ip); g_array_append_val(address_array, nbo_prefix); g_array_append_val(address_array, nbo_gw); g_ptr_array_add(addresses, address_array); s_ip = (NMSettingIP4Config*) nm_setting_ip4_config_new(); g_object_set(G_OBJECT (s_ip), NM_SETTING_IP4_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_MANUAL, NM_SETTING_IP4_CONFIG_ADDRESSES, addresses, NULL); if (dns) { count = 0; buf = strdup(dns); dns_addr = strtok(buf, ","); while (dns_addr && count <= MAXNS) { if (ip_str_to_nbo(dns_addr, &nbo_dns)) { nm_setting_ip4_config_add_dns(s_ip, nbo_dns); count++; } dns_addr = strtok(NULL, ","); } } nm_connection_add_setting(connection, NM_SETTING (s_ip)); g_array_free(address_array, TRUE); g_ptr_array_free(addresses, TRUE); } const char *ap_path = nm_object_get_path((NMObject*) ap); nm_client_add_and_activate_connection(client, connection, (NMDevice*) device, ap_path, (NMClientAddActivateFn) add_cb, NULL); ret = wait_for_iface_activation(*iface); if (!FL_CMDLINE(flags)) newtPopWindow(); if (ret == 0) { g_main_loop_unref(loop); return WIFI_ACTIVATION_OK; } *iface = NULL; g_main_loop_unref(loop); return WIFI_ACTIVATION_TIMED_OUT; } gboolean checkIPsettings (int *ip_info_set, char **ip, char **gateway, char **netmask) { gboolean ok = TRUE; guint32 tmp = 0; if (*ip && !ip_str_to_nbo(*ip, &tmp)) { free(*ip); *ip = NULL; *ip_info_set = 0; ok = FALSE; } if (*gateway && !ip_str_to_nbo(*gateway, &tmp)) { free(*gateway); *gateway = NULL; ok = FALSE; } if (*netmask && !ip_str_to_nbo(*netmask, &tmp)) { free(*netmask); *netmask = NULL; ok = FALSE; } return ok; } /* vim:set shiftwidth=4 softtabstop=4: */