1 /*
2  * Copyright (c) 1999
3  *	Philipp Mergenthaler <philipp.mergenthaler@stud.uni-karlsruhe.de>
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  *
27  * $FreeBSD: stable/9/usr.sbin/sysinstall/httpdirect.c 248313 2013-03-15 05:00:51Z dteske $
28  */
29 
30 #include "sysinstall.h"
31 #include <sys/socket.h>
32 #include <netinet/in.h>
33 #include <arpa/inet.h>
34 #include <sys/param.h>
35 #include <netdb.h>
36 
37 extern const char *ftp_dirs[]; /* defined in ftp.c */
38 
39 Boolean
mediaInitHTTPDirect(Device * dev)40 mediaInitHTTPDirect(Device *dev)
41 {
42     bool found=FALSE;		    /* end of header line */
43     char *rel, req[BUFSIZ];
44     int fdir;
45 
46     /*
47      * First verify basic access
48      */
49     checkAccess(TRUE, FALSE);
50     while (variable_get(VAR_HTTP_HOST) == NULL) {
51         if (DITEM_STATUS(mediaSetHTTPDirect(NULL)) == DITEM_FAILURE)
52             return FALSE;
53         checkAccess(TRUE, FALSE);
54     }
55 again:
56     /* If the release is specified as "__RELEASE" or "any", then just
57      * assume that the path the user gave is ok.
58      */
59     rel = variable_get(VAR_RELNAME);
60     /*
61     msgConfirm("rel: -%s-", rel);
62     */
63 
64     if (strcmp(rel, "__RELEASE") && strcmp(rel, "any"))  {
65         for (fdir = 0; ftp_dirs[fdir]; fdir++) {
66             sprintf(req, "%s/%s/%s", variable_get(VAR_HTTP_DIR),
67                 ftp_dirs[fdir], rel);
68             variable_set2(VAR_HTTP_PATH, req, 0);
69             if (checkAccess(FALSE, FALSE)) {
70                 found = TRUE;
71                 break;
72             }
73         }
74     } else {
75         variable_set2(VAR_HTTP_PATH, variable_get(VAR_HTTP_DIR), 0);
76         found = checkAccess(FALSE, FALSE);
77     }
78     if (!found) {
79     	msgConfirm("No such directory: %s\n"
80 		   "please check the URL and try again.", variable_get(VAR_HTTP_PATH));
81         variable_unset(VAR_HTTP_PATH);
82         dialog_clear_norefresh();
83         clear();
84         if (DITEM_STATUS(mediaSetHTTPDirect(NULL)) != DITEM_FAILURE) goto again;
85     }
86     return found;
87 }
88 
89 FILE *
mediaGetHTTPDirect(Device * dev,char * file,Boolean probe)90 mediaGetHTTPDirect(Device *dev, char *file, Boolean probe)
91 {
92     FILE *fp;
93     int rv, s, af;
94     bool el;			/* end of header line */
95     char *cp, buf[PATH_MAX], req[BUFSIZ];
96     struct addrinfo hints, *res, *res0;
97 
98     af = variable_cmp(VAR_IPV6_ENABLE, "YES") ? AF_INET : AF_UNSPEC;
99     memset(&hints, 0, sizeof(hints));
100     hints.ai_family = af;
101     hints.ai_socktype = SOCK_STREAM;
102     hints.ai_protocol = 0;
103     if ((rv = getaddrinfo(variable_get(VAR_HTTP_HOST),
104 			  variable_get(VAR_HTTP_PORT), &hints, &res0)) != 0) {
105 	msgConfirm("%s", gai_strerror(rv));
106 	return NULL;
107     }
108     s = -1;
109     for (res = res0; res; res = res->ai_next) {
110 	if ((s = socket(res->ai_family, res->ai_socktype,
111 			res->ai_protocol)) < 0)
112 	    continue;
113 	if (connect(s, res->ai_addr, res->ai_addrlen) >= 0)
114 	    break;
115 	close(s);
116 	s = -1;
117     }
118     freeaddrinfo(res0);
119     if (s == -1) {
120 	msgConfirm("Couldn't connect to http://%s:%s/",
121 		    variable_get(VAR_HTTP_HOST),variable_get(VAR_HTTP_PORT));
122 	return NULL;
123     }
124 
125     sprintf(req,"GET /%s/%s HTTP/1.0\r\n\r\n",
126 	    variable_get(VAR_HTTP_PATH), file);
127 
128     if (isDebug()) {
129 	msgDebug("sending http request: %s\n",req);
130     }
131     write(s,req,strlen(req));
132 
133 /*
134  *  scan the headers of the response
135  *  this is extremely quick'n dirty
136  *
137  */
138     cp=buf;
139     el=FALSE;
140     rv=read(s,cp,1);
141     while (rv>0) {
142 	if ((*cp == '\012') && el) {
143   	    /* reached end of a header line */
144   	    if (!strncmp(buf,"HTTP",4)) {
145 		rv=strtol((char *)(buf+9),0,0);
146 		*(cp-1)='\0';		/* chop the CRLF off */
147 		if (probe && (rv != 200)) {
148 		    return NULL;
149 		} else if (rv >= 500) {
150 		    msgConfirm("Server error %s when sending %s, you could try an other server",buf, req);
151 		    return NULL;
152 		} else if (rv == 404) {
153 		    msgConfirm("%s was not found, maybe directory or release-version are wrong?",req);
154 		    return NULL;
155 		} else if (rv >= 400) {
156 		    msgConfirm("Client error %s, you could try an other server",buf);
157 		    return NULL;
158 		} else if (rv >= 300) {
159 		    msgConfirm("Error %s",buf);
160 		    return NULL;
161 		} else if (rv != 200) {
162 		    msgConfirm("Error %s when sending %s, you could try an other server",buf, req);
163 		    return NULL;
164 		}
165 	    }
166 	    /* ignore other headers */
167 	    /* check for "\015\012" at beginning of line, i.e. end of headers */
168 	    if ((cp-buf) == 1)
169 		break;
170 	    cp=buf;
171 	    rv=read(s,cp,1);
172 	} else {
173 	    el=FALSE;
174 	    if (*cp == '\015')
175 		el=TRUE;
176 	    cp++;
177 	    rv=read(s,cp,1);
178 	}
179     }
180     fp=fdopen(s,"r");
181     return fp;
182 }
183