/* * urls.c - url handling code * * Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Red Hat, Inc. * All rights reserved. * * 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): Erik Troan * Matt Wilson * Michael Fulbright * Jeremy Katz */ #include #include #include #include #include #include #include #include #include #include #include #include "ftp.h" #include "lang.h" #include "loader.h" #include "loadermisc.h" #include "urls.h" #include "log.h" #include "windows.h" #include "net.h" /* boot flags */ extern uint64_t flags; /* convert a url (ftp or http) to a ui */ int convertURLToUI(char *url, struct iurlinfo *ui) { char *chptr; memset(ui, 0, sizeof(*ui)); if (!strncmp("ftp://", url, 6)) { ui->protocol = URL_METHOD_FTP; url += 6; /* There could be a username/password on here */ if ((chptr = strchr(url, '@'))) { if ((chptr = strchr(url, ':'))) { *chptr = '\0'; ui->login = strdup(url); url = chptr + 1; chptr = strchr(url, '@'); *chptr = '\0'; ui->password = strdup(url); url = chptr + 1; } else { chptr = strchr(url, '@'); *chptr = '\0'; ui->login = strdup(url); url = chptr + 1; } } } else if (!strncmp("http://", url, 7)) { ui->protocol = URL_METHOD_HTTP; url += 7; } else { logMessage(ERROR, "unknown url protocol '%s'", url); return -1; } /* url is left pointing at the hostname */ chptr = strchr(url, '/'); if (chptr != NULL) { *chptr = '\0'; ui->address = strdup(url); url = chptr; *url = '/'; ui->prefix = strdup(url); } else { ui->address = strdup(url); ui->prefix = strdup("/"); } logMessage(DEBUGLVL, "url address %s", ui->address); logMessage(DEBUGLVL, "url prefix %s", ui->prefix); return 0; } static char * getLoginName(char * login, struct iurlinfo *ui) { int i; i = 0; /* password w/o login isn't useful */ if (ui->login && strlen(ui->login)) { i += strlen(ui->login) + 5; if (strlen(ui->password)) i += 3*strlen(ui->password) + 5; if (ui->login || ui->password) { login = malloc(i); strcpy(login, ui->login); if (ui->password) { char * chptr; char code[4]; strcat(login, ":"); for (chptr = ui->password; *chptr; chptr++) { sprintf(code, "%%%2x", *chptr); strcat(login, code); } strcat(login, "@"); } } } return login; } /* convert a UI to a URL, returns allocated string */ char *convertUIToURL(struct iurlinfo *ui) { char *login, *finalPrefix, *url, *p; if (!(strcmp)(ui->prefix, "/")) finalPrefix = "/."; else finalPrefix = ui->prefix; login = ""; login = getLoginName(login, ui); url = malloc(strlen(finalPrefix) + 25 + strlen(ui->address) + strlen(login)); /* sanitize url so we dont have problems like bug #101265 */ /* basically avoid duplicate /'s */ if (ui->protocol == URL_METHOD_HTTP) { for (p=finalPrefix; *p == '/' && *(p+1) && *(p+1) == '/'; p++); finalPrefix = p; } sprintf(url, "%s://%s%s%s", ui->protocol == URL_METHOD_FTP ? "ftp" : "http", login, ui->address, finalPrefix); return url; } /* extraHeaders only applicable for http and used for pulling ks from http */ /* see ftp.c:httpGetFileDesc() for details */ /* set to NULL if not needed */ int urlinstStartTransfer(struct iurlinfo * ui, char *path, char *extraHeaders, struct progressCBdata **data, long long *size) { int fd, port; int family = -1; struct in_addr addr; struct in6_addr addr6; char *hostname, *portstr, *fileName; struct hostent *host; logMessage(INFO, "transferring %s://%s%s to a fd", ui->protocol == URL_METHOD_FTP ? "ftp" : "http", ui->address, path); splitHostname(ui->address, &hostname, &portstr); if (portstr == NULL) { port = -1; } else { errno = 0; port = strtol(portstr, NULL, 10); if ((errno == ERANGE && (port == LONG_MIN || port == LONG_MAX)) || (errno != 0 && port == 0)) { logMessage(ERROR, "%s: %d: %m", __func__, __LINE__); abort(); } } if (inet_pton(AF_INET, hostname, &addr) >= 1) family = AF_INET; else if (inet_pton(AF_INET6, hostname, &addr6) >= 1) family = AF_INET6; else { if ((host = gethostbyname(hostname)) == NULL) { logMessage(ERROR, "cannot determine address family of %s: %s", hostname, hstrerror(h_errno)); return -1; } else family = host->h_addrtype; } if (ui->protocol == URL_METHOD_FTP) { ui->ftpPort = ftpOpen(hostname, family, ui->login ? ui->login : "anonymous", ui->password ? ui->password : "rhinstall@", port); if (ui->ftpPort < 0) { if (hostname) free(hostname); return -2; } fd = ftpGetFileDesc(ui->ftpPort, addr6, family, path, size); if (fd < 0) { close(ui->ftpPort); if (hostname) free(hostname); return -1; } } else { fd = httpGetFileDesc(hostname, port, path, extraHeaders, size); if (fd < 0) { if (portstr) free(portstr); return -1; } } fileName = strrchr(path, '/'); if (FL_CMDLINE(flags)) { printf("%s %s...\n", _("Retrieving"), fileName+1); } else if (*size) { *data = winProgressBar(70, 5, _("Retrieving"), "%s %s...", _("Retrieving"), fileName+1); } else { winStatus(70, 3, _("Retrieving"), "%s %s...", _("Retrieving"), fileName+1); } if (hostname) free(hostname); return fd; } int urlinstFinishTransfer(struct iurlinfo * ui, int fd, struct progressCBdata **data) { if (*data) free(*data); if (ui->protocol == URL_METHOD_FTP) close(ui->ftpPort); close(fd); if (!FL_CMDLINE(flags)) newtPopWindow(); return 0; } char * addrToIp(char * hostname) { struct in_addr ad; struct in6_addr ad6; char *ret; struct hostent *host; if ((ret = malloc(INET6_ADDRSTRLEN+1)) == NULL) return hostname; if (inet_ntop(AF_INET, &ad, ret, INET_ADDRSTRLEN) != NULL) return ret; else if (inet_ntop(AF_INET6, &ad6, ret, INET6_ADDRSTRLEN) != NULL) return ret; else if ((host = gethostbyname(hostname)) != NULL) return host->h_name; else return NULL; } int urlMainSetupPanel(struct iurlinfo * ui) { newtComponent form, okay, cancel, urlEntry; newtComponent answer, text; char *url = ""; char * reflowedText = NULL; int width, height; newtGrid buttons, grid; char * chptr; char * buf = NULL; /* Populate the UI with whatever initial value we've got. */ if (ui && ui->prefix) url = convertUIToURL(ui); buttons = newtButtonBar(_("OK"), &okay, _("Back"), &cancel, NULL); if (asprintf(&buf, _("Please enter the URL containing the %s installation image on your server."), getProductName()) == -1) { logMessage(CRITICAL, "%s: %d: %m", __func__, __LINE__); abort(); } reflowedText = newtReflowText(buf, 47, 5, 5, &width, &height); free(buf); text = newtTextbox(-1, -1, width, height, NEWT_TEXTBOX_WRAP); newtTextboxSetText(text, reflowedText); free(reflowedText); urlEntry = newtEntry(22, 8, url, 60, (const char **) &url, NEWT_ENTRY_SCROLL); grid = newtCreateGrid(1, 3); newtGridSetField(grid, 0, 0, NEWT_GRID_COMPONENT, text, 0, 0, 0, 1, 0, 0); newtGridSetField(grid, 0, 1, NEWT_GRID_COMPONENT, urlEntry, 0, 0, 0, 1, 0, 0); newtGridSetField(grid, 0, 2, NEWT_GRID_SUBGRID, buttons, 0, 0, 0, 0, 0, NEWT_GRID_FLAG_GROWX); form = newtForm(NULL, NULL, 0); newtGridAddComponentsToForm(grid, form, 1); newtGridWrappedWindow(grid, _("URL Setup")); newtGridFree(grid, 1); do { answer = newtRunForm(form); if (answer != cancel) { if (!strlen(url)) { newtWinMessage(_("Error"), _("OK"), _("You must enter a URL.")); continue; } if (!strstr(url, "http://") && !strstr(url, "ftp://")) { newtWinMessage(_("Error"), _("OK"), _("URL must be either an ftp or http URL")); continue; } /* Now split up the URL we were given into its components for * ease of checking. */ if (convertURLToUI(url, ui) == -1) continue; if (!addrToIp(ui->address)) { newtWinMessage(_("Unknown Host"), _("OK"), _("%s is not a valid hostname."), ui->address); continue; } } break; } while (1); if (answer == cancel) { newtFormDestroy(form); newtPopWindow(); return LOADER_BACK; } /* Get rid of trailing /'s */ chptr = ui->prefix + strlen(ui->prefix) - 1; while (chptr > ui->prefix && *chptr == '/') chptr--; chptr++; *chptr = '\0'; newtFormDestroy(form); newtPopWindow(); return 0; }