some cleanup
[enigma2.git] / lib / network / http_file.cpp
1 #include <lib/network/http_file.h>
2 #include <unistd.h>
3 #include <fcntl.h>
4 #include <errno.h>
5 #include <string>
6 #include <shadow.h>
7 #include <pwd.h>
8
9 eHTTPFile::eHTTPFile(eHTTPConnection *c, int _fd, int method, const char *mime): eHTTPDataSource(c), method(method)
10 {
11         fd=_fd;
12         if (method == methodGET)
13         {
14                 c->local_header["Content-Type"]=std::string(mime);
15                 size=lseek(fd, 0, SEEK_END);
16                 char asize[10];
17                 snprintf(asize, 10, "%d", size);
18                 lseek(fd, 0, SEEK_SET);
19                 c->local_header["Content-Length"]=std::string(asize);
20         }
21         connection->code_descr="OK";
22         connection->code=200;
23 }
24
25 int eHTTPFile::doWrite(int bytes)
26 {
27         if (method == methodGET)
28         {
29                 char buff[bytes];
30                 if (!size)
31                         return -1;
32                 int len=bytes;
33                 if (len>size)
34                         len=size;
35                 len=read(fd, buff, len);
36                 if (len<=0)
37                         return -1;
38                 size-=connection->writeBlock(buff, len);
39                 if (!size)
40                         return -1;
41                 else
42                         return 1;
43         } else
44                 return -1;
45 }
46
47 void eHTTPFile::haveData(void *data, int len)
48 {
49         if (method != methodPUT)
50                 return;
51         ::write(fd, data, len);
52 }
53
54 eHTTPFile::~eHTTPFile()
55 {
56         close(fd);
57 }
58
59 eHTTPFilePathResolver::eHTTPFilePathResolver()
60 {
61         translate.setAutoDelete(true);
62 }
63
64
65 static char _base64[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
66
67 static int unbase64(eString &dst, const eString string)
68 {
69         dst="";
70         char c[4];
71         int pos=0;
72         unsigned int i=0;
73         
74         while (1)
75         {
76                 if (i == string.size())
77                         break;
78                 char *ch=strchr(_base64, string[i++]);
79                 if (!ch)
80                 {
81                         i++;
82                         continue;
83                 }
84                 c[pos++]=ch-_base64;
85                 if (pos == 4)
86                 {
87                         char d[3];
88                         d[0]=c[0]<<2;
89                         d[0]|=c[1]>>4;
90                         d[1]=c[1]<<4;
91                         d[1]|=c[2]>>2;
92                         d[2]=c[2]<<6;
93                         d[2]|=c[3];
94                         
95                         dst+=d[0];
96                         if (c[2] != 64)
97                                 dst+=d[1];
98                         if (c[3] != 64)
99                                 dst+=d[2];
100                         pos=0;
101                 }
102         }
103         return pos;
104 }
105
106 int CheckUnixPassword(const char *user, const char *pass)
107 {
108         passwd *pwd=getpwnam(user);
109         if (!pwd)
110                 return -1;
111         char *cpwd=pwd->pw_passwd;
112         if (pwd && (!strcmp(pwd->pw_passwd, "x")))
113         {
114                 spwd *sp=getspnam(user);
115                 if (!sp)                                                // no shadow password defined.
116                         return -1;
117                 cpwd=sp->sp_pwdp;
118         }
119         if (!cpwd)
120                 return -1;
121         if ((*cpwd=='!')||(*cpwd=='*'))          // disabled user
122                 return -2;
123         char *cres=crypt(pass, cpwd);
124         return !!strcmp(cres, cpwd);
125 }
126
127 static int checkAuth(const eString cauth)
128 {
129         eString auth;
130         if (cauth.left(6) != "Basic ")
131                 return -1;
132         if (unbase64(auth, cauth.mid(6)))
133                 return -1;
134         eString username=auth.left(auth.find(":"));
135         eString password=auth.mid(auth.find(":")+1);
136         if (CheckUnixPassword(username.c_str(), password.c_str()))
137                 return -1;
138         return 0;
139 }
140
141 eHTTPDataSource *eHTTPFilePathResolver::getDataSource(eString request, eString path, eHTTPConnection *conn)
142 {
143         int method;
144         eDebug("request = %s, path = %s", request.c_str(), path.c_str());
145         if (request == "GET")
146                 method=eHTTPFile::methodGET;
147         else if (request == "PUT")
148                 method=eHTTPFile::methodPUT;
149         else
150                 return new eHTTPError(conn, 405); // method not allowed
151         if (path.find("../")!=eString::npos)            // evil hax0r
152                 return new eHTTPError(conn, 403);
153         if (path[0] != '/')             // prepend '/'
154                 path.insert(0,"/");
155         if (path[path.length()-1]=='/')
156                 path+="index.html";
157         
158         eHTTPDataSource *data=0;
159         for (ePtrList<eHTTPFilePath>::iterator i(translate); i != translate.end(); ++i)
160         {
161                 if (i->root==path.left(i->root.length()))
162                 {
163                         eString newpath=i->path+path.mid(i->root.length());
164                         if (newpath.find('?'))
165                                 newpath=newpath.left(newpath.find('?'));
166                         eDebug("translated %s to %s", path.c_str(), newpath.c_str());
167
168                         if (i->authorized & ((method==eHTTPFile::methodGET)?1:2))
169                         {
170                                 std::map<std::string, std::string>::iterator i=conn->remote_header.find("Authorization");
171                                 if ((i == conn->remote_header.end()) || checkAuth(i->second))
172                                 {
173                                         conn->local_header["WWW-Authenticate"]="Basic realm=\"dreambox\"";
174                                         return new eHTTPError(conn, 401); // auth req'ed
175                                 }
176                         }
177
178                         int fd=open(newpath.c_str(), (method==eHTTPFile::methodGET)?O_RDONLY:(O_WRONLY|O_CREAT|O_TRUNC), 0644);
179
180                         if (fd==-1)
181                         {
182                                 switch (errno)
183                                 {
184                                 case ENOENT:
185                                         data=new eHTTPError(conn, 404);
186                                         break;
187                                 case EACCES:
188                                         data=new eHTTPError(conn, 403);
189                                         break;
190                                 default:
191                                         data=new eHTTPError(conn, 403); // k.a.
192                                         break;
193                                 }
194                                 break;
195                         }
196                         
197                         eString ext=path.mid(path.rfind('.'));
198                         const char *mime="text/unknown";
199                         if ((ext==".html") || (ext==".htm"))
200                                 mime="text/html";
201                         else if ((ext==".jpeg") || (ext==".jpg"))
202                                 mime="image/jpeg";
203                         else if (ext==".gif")
204                                 mime="image/gif";
205                         else if (ext==".css")
206                                 mime="text/css";
207                         else if (ext==".png")
208                                 mime="image/png";
209                         else if (ext==".xml")
210                                 mime="text/xml";
211                         else if (ext==".xsl")
212                                 mime="text/xsl";
213
214                         data=new eHTTPFile(conn, fd, method, mime);
215                         break;
216                 }
217         }
218         return data;
219 }
220
221 void eHTTPFilePathResolver::addTranslation(eString path, eString root, int authorized)
222 {
223         if (path[path.length()-1]!='/')
224                 path+='/';
225         if (root[root.length()-1]!='/')
226                 root+='/';
227         translate.push_back(new eHTTPFilePath(path, root, authorized));
228 }