Root/package/network/services/uhttpd/src/uhttpd-utils.c

1/*
2 * uhttpd - Tiny single-threaded httpd - Utility functions
3 *
4 * Copyright (C) 2010-2012 Jo-Philipp Wich <xm@subsignal.org>
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18
19#define _XOPEN_SOURCE 500 /* crypt() */
20#define _BSD_SOURCE /* strcasecmp(), strncasecmp() */
21
22#include "uhttpd.h"
23#include "uhttpd-utils.h"
24
25#ifdef HAVE_TLS
26#include "uhttpd-tls.h"
27#endif
28
29
30static char *uh_index_files[] = {
31    "index.html",
32    "index.htm",
33    "default.html",
34    "default.htm"
35};
36
37
38const char * sa_straddr(void *sa)
39{
40    static char str[INET6_ADDRSTRLEN];
41    struct sockaddr_in *v4 = (struct sockaddr_in *)sa;
42    struct sockaddr_in6 *v6 = (struct sockaddr_in6 *)sa;
43
44    if (v4->sin_family == AF_INET)
45        return inet_ntop(AF_INET, &(v4->sin_addr), str, sizeof(str));
46    else
47        return inet_ntop(AF_INET6, &(v6->sin6_addr), str, sizeof(str));
48}
49
50const char * sa_strport(void *sa)
51{
52    static char str[6];
53    snprintf(str, sizeof(str), "%i", sa_port(sa));
54    return str;
55}
56
57int sa_port(void *sa)
58{
59    return ntohs(((struct sockaddr_in6 *)sa)->sin6_port);
60}
61
62int sa_rfc1918(void *sa)
63{
64    struct sockaddr_in *v4 = (struct sockaddr_in *)sa;
65    unsigned long a = htonl(v4->sin_addr.s_addr);
66
67    if (v4->sin_family == AF_INET)
68    {
69        return ((a >= 0x0A000000) && (a <= 0x0AFFFFFF)) ||
70               ((a >= 0xAC100000) && (a <= 0xAC1FFFFF)) ||
71               ((a >= 0xC0A80000) && (a <= 0xC0A8FFFF));
72    }
73
74    return 0;
75}
76
77/* Simple strstr() like function that takes len arguments for both haystack and needle. */
78char *strfind(char *haystack, int hslen, const char *needle, int ndlen)
79{
80    int match = 0;
81    int i, j;
82
83    for (i = 0; i < hslen; i++)
84    {
85        if (haystack[i] == needle[0])
86        {
87            match = ((ndlen == 1) || ((i + ndlen) <= hslen));
88
89            for (j = 1; (j < ndlen) && ((i + j) < hslen); j++)
90            {
91                if (haystack[i+j] != needle[j])
92                {
93                    match = 0;
94                    break;
95                }
96            }
97
98            if (match)
99                return &haystack[i];
100        }
101    }
102
103    return NULL;
104}
105
106bool uh_socket_wait(int fd, int sec, bool write)
107{
108    int rv;
109    struct timeval timeout;
110
111    fd_set fds;
112
113    FD_ZERO(&fds);
114    FD_SET(fd, &fds);
115
116    timeout.tv_sec = sec;
117    timeout.tv_usec = 0;
118
119    while (((rv = select(fd+1, write ? NULL : &fds, write ? &fds : NULL,
120                         NULL, &timeout)) < 0) && (errno == EINTR))
121    {
122        D("IO: FD(%d) select interrupted: %s\n",
123                fd, strerror(errno));
124
125        continue;
126    }
127
128    if (rv <= 0)
129    {
130        D("IO: FD(%d) appears dead (rv=%d)\n", fd, rv);
131        return false;
132    }
133
134    return true;
135}
136
137static int __uh_raw_send(struct client *cl, const char *buf, int len, int sec,
138                         int (*wfn) (struct client *, const char *, int))
139{
140    ssize_t rv;
141    int fd = cl->fd.fd;
142
143    while (true)
144    {
145        if ((rv = wfn(cl, buf, len)) < 0)
146        {
147            if (errno == EINTR)
148            {
149                D("IO: FD(%d) interrupted\n", cl->fd.fd);
150                continue;
151            }
152            else if ((sec > 0) && (errno == EAGAIN || errno == EWOULDBLOCK))
153            {
154                if (!uh_socket_wait(fd, sec, true))
155                    return -1;
156            }
157            else
158            {
159                D("IO: FD(%d) write error: %s\n", fd, strerror(errno));
160                return -1;
161            }
162        }
163        /*
164         * It is not entirely clear whether rv = 0 on nonblocking sockets
165         * is an error. In real world fuzzing tests, not handling it as close
166         * led to tight infinite loops in this send procedure, so treat it as
167         * closed and break out.
168         */
169        else if (rv == 0)
170        {
171            D("IO: FD(%d) appears closed\n", fd);
172            return 0;
173        }
174        else if (rv < len)
175        {
176            D("IO: FD(%d) short write %d/%d bytes\n", fd, rv, len);
177            len -= rv;
178            buf += rv;
179            continue;
180        }
181        else
182        {
183            D("IO: FD(%d) sent %d/%d bytes\n", fd, rv, len);
184            return rv;
185        }
186    }
187}
188
189int uh_tcp_send_lowlevel(struct client *cl, const char *buf, int len)
190{
191    return write(cl->fd.fd, buf, len);
192}
193
194int uh_raw_send(int fd, const char *buf, int len, int sec)
195{
196    struct client_light cl = { .fd = { .fd = fd } };
197    return __uh_raw_send((struct client *)&cl, buf, len, sec,
198                         uh_tcp_send_lowlevel);
199}
200
201int uh_tcp_send(struct client *cl, const char *buf, int len)
202{
203    int seconds = cl->server->conf->network_timeout;
204#ifdef HAVE_TLS
205    if (cl->tls)
206        return __uh_raw_send(cl, buf, len, seconds,
207                             cl->server->conf->tls_send);
208#endif
209    return __uh_raw_send(cl, buf, len, seconds, uh_tcp_send_lowlevel);
210}
211
212static int __uh_raw_recv(struct client *cl, char *buf, int len, int sec,
213                         int (*rfn) (struct client *, char *, int))
214{
215    ssize_t rv;
216    int fd = cl->fd.fd;
217
218    while (true)
219    {
220        if ((rv = rfn(cl, buf, len)) < 0)
221        {
222            if (errno == EINTR)
223            {
224                continue;
225            }
226            else if ((sec > 0) && (errno == EAGAIN || errno == EWOULDBLOCK))
227            {
228                if (!uh_socket_wait(fd, sec, false))
229                    return -1;
230            }
231            else
232            {
233                D("IO: FD(%d) read error: %s\n", fd, strerror(errno));
234                return -1;
235            }
236        }
237        else if (rv == 0)
238        {
239            D("IO: FD(%d) appears closed\n", fd);
240            return 0;
241        }
242        else
243        {
244            D("IO: FD(%d) read %d bytes\n", fd, rv);
245            return rv;
246        }
247    }
248}
249
250int uh_tcp_recv_lowlevel(struct client *cl, char *buf, int len)
251{
252    return read(cl->fd.fd, buf, len);
253}
254
255int uh_raw_recv(int fd, char *buf, int len, int sec)
256{
257    struct client_light cl = { .fd = { .fd = fd } };
258    return __uh_raw_recv((struct client *)&cl, buf, len, sec,
259                         uh_tcp_recv_lowlevel);
260}
261
262int uh_tcp_recv(struct client *cl, char *buf, int len)
263{
264    int seconds = cl->server->conf->network_timeout;
265#ifdef HAVE_TLS
266    if (cl->tls)
267        return __uh_raw_recv(cl, buf, len, seconds,
268                             cl->server->conf->tls_recv);
269#endif
270    return __uh_raw_recv(cl, buf, len, seconds, uh_tcp_recv_lowlevel);
271}
272
273
274int uh_http_sendhf(struct client *cl, int code, const char *summary,
275                   const char *fmt, ...)
276{
277    va_list ap;
278
279    char buffer[UH_LIMIT_MSGHEAD];
280    int len;
281
282    len = snprintf(buffer, sizeof(buffer),
283        "HTTP/1.1 %03i %s\r\n"
284        "Connection: close\r\n"
285        "Content-Type: text/plain\r\n"
286        "Transfer-Encoding: chunked\r\n\r\n",
287            code, summary
288    );
289
290    ensure_ret(uh_tcp_send(cl, buffer, len));
291
292    va_start(ap, fmt);
293    len = vsnprintf(buffer, sizeof(buffer), fmt, ap);
294    va_end(ap);
295
296    ensure_ret(uh_http_sendc(cl, buffer, len));
297    ensure_ret(uh_http_sendc(cl, NULL, 0));
298
299    return 0;
300}
301
302
303int uh_http_sendc(struct client *cl, const char *data, int len)
304{
305    char chunk[8];
306    int clen;
307
308    if (len == -1)
309        len = strlen(data);
310
311    if (len > 0)
312    {
313        clen = snprintf(chunk, sizeof(chunk), "%X\r\n", len);
314        ensure_ret(uh_tcp_send(cl, chunk, clen));
315        ensure_ret(uh_tcp_send(cl, data, len));
316        ensure_ret(uh_tcp_send(cl, "\r\n", 2));
317    }
318    else
319    {
320        ensure_ret(uh_tcp_send(cl, "0\r\n\r\n", 5));
321    }
322
323    return 0;
324}
325
326int uh_http_sendf(struct client *cl, struct http_request *req,
327                  const char *fmt, ...)
328{
329    va_list ap;
330    char buffer[UH_LIMIT_MSGHEAD];
331    int len;
332
333    va_start(ap, fmt);
334    len = vsnprintf(buffer, sizeof(buffer), fmt, ap);
335    va_end(ap);
336
337    if ((req != NULL) && (req->version > UH_HTTP_VER_1_0))
338        ensure_ret(uh_http_sendc(cl, buffer, len));
339    else if (len > 0)
340        ensure_ret(uh_tcp_send(cl, buffer, len));
341
342    return 0;
343}
344
345int uh_http_send(struct client *cl, struct http_request *req,
346                 const char *buf, int len)
347{
348    if (len < 0)
349        len = strlen(buf);
350
351    if ((req != NULL) && (req->version > UH_HTTP_VER_1_0))
352        ensure_ret(uh_http_sendc(cl, buf, len));
353    else if (len > 0)
354        ensure_ret(uh_tcp_send(cl, buf, len));
355
356    return 0;
357}
358
359
360/* blen is the size of buf; slen is the length of src. The input-string need
361** not be, and the output string will not be, null-terminated. Returns the
362** length of the decoded string, -1 on buffer overflow, -2 on malformed string. */
363int uh_urldecode(char *buf, int blen, const char *src, int slen)
364{
365    int i;
366    int len = 0;
367
368#define hex(x) \
369    (((x) <= '9') ? ((x) - '0') : \
370        (((x) <= 'F') ? ((x) - 'A' + 10) : \
371            ((x) - 'a' + 10)))
372
373    for (i = 0; (i < slen) && (len < blen); i++)
374    {
375        if (src[i] == '%')
376        {
377            if (((i+2) < slen) && isxdigit(src[i+1]) && isxdigit(src[i+2]))
378            {
379                buf[len++] = (char)(16 * hex(src[i+1]) + hex(src[i+2]));
380                i += 2;
381            }
382            else
383            {
384                /* Encoding error: it's hard to think of a
385                ** scenario in which returning an incorrect
386                ** 'decoding' of the malformed string is
387                ** preferable to signaling an error condition. */
388                #if 0 /* WORSE_IS_BETTER */
389                    buf[len++] = '%';
390                #else
391                    return -2;
392                #endif
393            }
394        }
395        else
396        {
397            buf[len++] = src[i];
398        }
399    }
400
401    return (i == slen) ? len : -1;
402}
403
404/* blen is the size of buf; slen is the length of src. The input-string need
405** not be, and the output string will not be, null-terminated. Returns the
406** length of the encoded string, or -1 on error (buffer overflow) */
407int uh_urlencode(char *buf, int blen, const char *src, int slen)
408{
409    int i;
410    int len = 0;
411    const char hex[] = "0123456789abcdef";
412
413    for (i = 0; (i < slen) && (len < blen); i++)
414    {
415        if( isalnum(src[i]) || (src[i] == '-') || (src[i] == '_') ||
416            (src[i] == '.') || (src[i] == '~') )
417        {
418            buf[len++] = src[i];
419        }
420        else if ((len+3) <= blen)
421        {
422            buf[len++] = '%';
423            buf[len++] = hex[(src[i] >> 4) & 15];
424            buf[len++] = hex[ src[i] & 15];
425        }
426        else
427        {
428            len = -1;
429            break;
430        }
431    }
432
433    return (i == slen) ? len : -1;
434}
435
436int uh_b64decode(char *buf, int blen, const unsigned char *src, int slen)
437{
438    int i = 0;
439    int len = 0;
440
441    unsigned int cin = 0;
442    unsigned int cout = 0;
443
444
445    for (i = 0; (i <= slen) && (src[i] != 0); i++)
446    {
447        cin = src[i];
448
449        if ((cin >= '0') && (cin <= '9'))
450            cin = cin - '0' + 52;
451        else if ((cin >= 'A') && (cin <= 'Z'))
452            cin = cin - 'A';
453        else if ((cin >= 'a') && (cin <= 'z'))
454            cin = cin - 'a' + 26;
455        else if (cin == '+')
456            cin = 62;
457        else if (cin == '/')
458            cin = 63;
459        else if (cin == '=')
460            cin = 0;
461        else
462            continue;
463
464        cout = (cout << 6) | cin;
465
466        if ((i % 4) == 3)
467        {
468            if ((len + 3) < blen)
469            {
470                buf[len++] = (char)(cout >> 16);
471                buf[len++] = (char)(cout >> 8);
472                buf[len++] = (char)(cout);
473            }
474            else
475            {
476                break;
477            }
478        }
479    }
480
481    buf[len++] = 0;
482    return len;
483}
484
485static char * canonpath(const char *path, char *path_resolved)
486{
487    char path_copy[PATH_MAX];
488    char *path_cpy = path_copy;
489    char *path_res = path_resolved;
490
491    struct stat s;
492
493
494    /* relative -> absolute */
495    if (*path != '/')
496    {
497        getcwd(path_copy, PATH_MAX);
498        strncat(path_copy, "/", PATH_MAX - strlen(path_copy));
499        strncat(path_copy, path, PATH_MAX - strlen(path_copy));
500    }
501    else
502    {
503        strncpy(path_copy, path, PATH_MAX);
504    }
505
506    /* normalize */
507    while ((*path_cpy != '\0') && (path_cpy < (path_copy + PATH_MAX - 2)))
508    {
509        if (*path_cpy == '/')
510        {
511            /* skip repeating / */
512            if (path_cpy[1] == '/')
513            {
514                path_cpy++;
515                continue;
516            }
517
518            /* /./ or /../ */
519            else if (path_cpy[1] == '.')
520            {
521                /* skip /./ */
522                if ((path_cpy[2] == '/') || (path_cpy[2] == '\0'))
523                {
524                    path_cpy += 2;
525                    continue;
526                }
527
528                /* collapse /x/../ */
529                else if ((path_cpy[2] == '.') &&
530                         ((path_cpy[3] == '/') || (path_cpy[3] == '\0')))
531                {
532                    while ((path_res > path_resolved) && (*--path_res != '/'))
533                        ;
534
535                    path_cpy += 3;
536                    continue;
537                }
538            }
539        }
540
541        *path_res++ = *path_cpy++;
542    }
543
544    /* remove trailing slash if not root / */
545    if ((path_res > (path_resolved+1)) && (path_res[-1] == '/'))
546        path_res--;
547    else if (path_res == path_resolved)
548        *path_res++ = '/';
549
550    *path_res = '\0';
551
552    /* test access */
553    if (!stat(path_resolved, &s) && (s.st_mode & S_IROTH))
554        return path_resolved;
555
556    return NULL;
557}
558
559/* Returns NULL on error.
560** NB: improperly encoded URL should give client 400 [Bad Syntax]; returning
561** NULL here causes 404 [Not Found], but that's not too unreasonable. */
562struct path_info * uh_path_lookup(struct client *cl, const char *url)
563{
564    static char path_phys[PATH_MAX];
565    static char path_info[PATH_MAX];
566    static struct path_info p;
567
568    char buffer[UH_LIMIT_MSGHEAD];
569    char *docroot = cl->server->conf->docroot;
570    char *pathptr = NULL;
571
572    int slash = 0;
573    int no_sym = cl->server->conf->no_symlinks;
574    int i = 0;
575    struct stat s;
576
577    /* back out early if url is undefined */
578    if (url == NULL)
579        return NULL;
580
581    memset(path_phys, 0, sizeof(path_phys));
582    memset(path_info, 0, sizeof(path_info));
583    memset(buffer, 0, sizeof(buffer));
584    memset(&p, 0, sizeof(p));
585
586    /* copy docroot */
587    memcpy(buffer, docroot,
588           min(strlen(docroot), sizeof(buffer) - 1));
589
590    /* separate query string from url */
591    if ((pathptr = strchr(url, '?')) != NULL)
592    {
593        p.query = pathptr[1] ? pathptr + 1 : NULL;
594
595        /* urldecode component w/o query */
596        if (pathptr > url)
597        {
598            if (uh_urldecode(&buffer[strlen(docroot)],
599                             sizeof(buffer) - strlen(docroot) - 1,
600                             url, pathptr - url ) < 0)
601            {
602                return NULL; /* bad URL */
603            }
604        }
605    }
606
607    /* no query string, decode all of url */
608    else
609    {
610        if (uh_urldecode(&buffer[strlen(docroot)],
611                         sizeof(buffer) - strlen(docroot) - 1,
612                         url, strlen(url) ) < 0)
613        {
614            return NULL; /* bad URL */
615        }
616    }
617
618    /* create canon path */
619    for (i = strlen(buffer), slash = (buffer[max(0, i-1)] == '/'); i >= 0; i--)
620    {
621        if ((buffer[i] == 0) || (buffer[i] == '/'))
622        {
623            memset(path_info, 0, sizeof(path_info));
624            memcpy(path_info, buffer, min(i + 1, sizeof(path_info) - 1));
625
626            if (no_sym ? realpath(path_info, path_phys)
627                       : canonpath(path_info, path_phys))
628            {
629                memset(path_info, 0, sizeof(path_info));
630                memcpy(path_info, &buffer[i],
631                       min(strlen(buffer) - i, sizeof(path_info) - 1));
632
633                break;
634            }
635        }
636    }
637
638    /* check whether found path is within docroot */
639    if (strncmp(path_phys, docroot, strlen(docroot)) ||
640        ((path_phys[strlen(docroot)] != 0) &&
641         (path_phys[strlen(docroot)] != '/')))
642    {
643        return NULL;
644    }
645
646    /* test current path */
647    if (!stat(path_phys, &p.stat))
648    {
649        /* is a regular file */
650        if (p.stat.st_mode & S_IFREG)
651        {
652            p.root = docroot;
653            p.phys = path_phys;
654            p.name = &path_phys[strlen(docroot)];
655            p.info = path_info[0] ? path_info : NULL;
656        }
657
658        /* is a directory */
659        else if ((p.stat.st_mode & S_IFDIR) && !strlen(path_info))
660        {
661            /* ensure trailing slash */
662            if (path_phys[strlen(path_phys)-1] != '/')
663                path_phys[strlen(path_phys)] = '/';
664
665            /* try to locate index file */
666            memset(buffer, 0, sizeof(buffer));
667            memcpy(buffer, path_phys, sizeof(buffer));
668            pathptr = &buffer[strlen(buffer)];
669
670            /* if requested url resolves to a directory and a trailing slash
671               is missing in the request url, redirect the client to the same
672               url with trailing slash appended */
673            if (!slash)
674            {
675                uh_http_sendf(cl, NULL,
676                    "HTTP/1.1 302 Found\r\n"
677                    "Location: %s%s%s\r\n"
678                    "Connection: close\r\n\r\n",
679                        &path_phys[strlen(docroot)],
680                        p.query ? "?" : "",
681                        p.query ? p.query : ""
682                );
683
684                p.redirected = 1;
685            }
686            else if (cl->server->conf->index_file)
687            {
688                strncat(buffer, cl->server->conf->index_file, sizeof(buffer));
689
690                if (!stat(buffer, &s) && (s.st_mode & S_IFREG))
691                {
692                    memcpy(path_phys, buffer, sizeof(path_phys));
693                    memcpy(&p.stat, &s, sizeof(p.stat));
694                }
695            }
696            else
697            {
698                for (i = 0; i < array_size(uh_index_files); i++)
699                {
700                    strncat(buffer, uh_index_files[i], sizeof(buffer));
701
702                    if (!stat(buffer, &s) && (s.st_mode & S_IFREG))
703                    {
704                        memcpy(path_phys, buffer, sizeof(path_phys));
705                        memcpy(&p.stat, &s, sizeof(p.stat));
706                        break;
707                    }
708
709                    *pathptr = 0;
710                }
711            }
712
713            p.root = docroot;
714            p.phys = path_phys;
715            p.name = &path_phys[strlen(docroot)];
716        }
717    }
718
719    return p.phys ? &p : NULL;
720}
721
722
723static struct auth_realm *uh_realms = NULL;
724
725struct auth_realm * uh_auth_add(char *path, char *user, char *pass)
726{
727    struct auth_realm *new = NULL;
728    struct passwd *pwd;
729
730#ifdef HAVE_SHADOW
731    struct spwd *spwd;
732#endif
733
734    if((new = (struct auth_realm *)malloc(sizeof(struct auth_realm))) != NULL)
735    {
736        memset(new, 0, sizeof(struct auth_realm));
737
738        memcpy(new->path, path,
739               min(strlen(path), sizeof(new->path) - 1));
740
741        memcpy(new->user, user,
742               min(strlen(user), sizeof(new->user) - 1));
743
744        /* given password refers to a passwd entry */
745        if ((strlen(pass) > 3) && !strncmp(pass, "$p$", 3))
746        {
747#ifdef HAVE_SHADOW
748            /* try to resolve shadow entry */
749            if (((spwd = getspnam(&pass[3])) != NULL) && spwd->sp_pwdp)
750            {
751                memcpy(new->pass, spwd->sp_pwdp,
752                       min(strlen(spwd->sp_pwdp), sizeof(new->pass) - 1));
753            }
754
755            else
756#endif
757
758            /* try to resolve passwd entry */
759            if (((pwd = getpwnam(&pass[3])) != NULL) && pwd->pw_passwd &&
760                (pwd->pw_passwd[0] != '!') && (pwd->pw_passwd[0] != 0))
761            {
762                memcpy(new->pass, pwd->pw_passwd,
763                       min(strlen(pwd->pw_passwd), sizeof(new->pass) - 1));
764            }
765        }
766
767        /* ordinary pwd */
768        else
769        {
770            memcpy(new->pass, pass,
771                min(strlen(pass), sizeof(new->pass) - 1));
772        }
773
774        if (new->pass[0])
775        {
776            new->next = uh_realms;
777            uh_realms = new;
778
779            return new;
780        }
781
782        free(new);
783    }
784
785    return NULL;
786}
787
788int uh_auth_check(struct client *cl, struct http_request *req,
789                  struct path_info *pi)
790{
791    int i, plen, rlen, protected;
792    char buffer[UH_LIMIT_MSGHEAD];
793    char *user = NULL;
794    char *pass = NULL;
795
796    struct auth_realm *realm = NULL;
797
798    plen = strlen(pi->name);
799    protected = 0;
800
801    /* check whether at least one realm covers the requested url */
802    for (realm = uh_realms; realm; realm = realm->next)
803    {
804        rlen = strlen(realm->path);
805
806        if ((plen >= rlen) && !strncasecmp(pi->name, realm->path, rlen))
807        {
808            req->realm = realm;
809            protected = 1;
810            break;
811        }
812    }
813
814    /* requested resource is covered by a realm */
815    if (protected)
816    {
817        /* try to get client auth info */
818        foreach_header(i, req->headers)
819        {
820            if (!strcasecmp(req->headers[i], "Authorization") &&
821                (strlen(req->headers[i+1]) > 6) &&
822                !strncasecmp(req->headers[i+1], "Basic ", 6))
823            {
824                memset(buffer, 0, sizeof(buffer));
825                uh_b64decode(buffer, sizeof(buffer) - 1,
826                    (unsigned char *) &req->headers[i+1][6],
827                    strlen(req->headers[i+1]) - 6);
828
829                if ((pass = strchr(buffer, ':')) != NULL)
830                {
831                    user = buffer;
832                    *pass++ = 0;
833                }
834
835                break;
836            }
837        }
838
839        /* have client auth */
840        if (user && pass)
841        {
842            /* find matching realm */
843            for (realm = uh_realms; realm; realm = realm->next)
844            {
845                rlen = strlen(realm->path);
846
847                if ((plen >= rlen) &&
848                    !strncasecmp(pi->name, realm->path, rlen) &&
849                    !strcmp(user, realm->user))
850                {
851                    req->realm = realm;
852                    break;
853                }
854            }
855
856            /* found a realm matching the username */
857            if (realm)
858            {
859                /* check user pass */
860                if (!strcmp(pass, realm->pass) ||
861                    !strcmp(crypt(pass, realm->pass), realm->pass))
862                    return 1;
863            }
864        }
865
866        /* 401 */
867        uh_http_sendf(cl, NULL,
868                      "%s 401 Authorization Required\r\n"
869                      "WWW-Authenticate: Basic realm=\"%s\"\r\n"
870                      "Content-Type: text/plain\r\n"
871                      "Content-Length: 23\r\n\r\n"
872                      "Authorization Required\n",
873                      http_versions[req->version],
874                      cl->server->conf->realm);
875
876        return 0;
877    }
878
879    return 1;
880}
881
882
883static struct listener *uh_listeners = NULL;
884static struct client *uh_clients = NULL;
885
886struct listener * uh_listener_add(int sock, struct config *conf)
887{
888    struct listener *new = NULL;
889    socklen_t sl;
890
891    if ((new = (struct listener *)malloc(sizeof(struct listener))) != NULL)
892    {
893        memset(new, 0, sizeof(struct listener));
894
895        new->fd.fd = sock;
896        new->conf = conf;
897
898
899        /* get local endpoint addr */
900        sl = sizeof(struct sockaddr_in6);
901        memset(&(new->addr), 0, sl);
902        getsockname(sock, (struct sockaddr *) &(new->addr), &sl);
903
904        new->next = uh_listeners;
905        uh_listeners = new;
906
907        return new;
908    }
909
910    return NULL;
911}
912
913struct listener * uh_listener_lookup(int sock)
914{
915    struct listener *cur = NULL;
916
917    for (cur = uh_listeners; cur; cur = cur->next)
918        if (cur->fd.fd == sock)
919            return cur;
920
921    return NULL;
922}
923
924
925struct client * uh_client_add(int sock, struct listener *serv,
926                              struct sockaddr_in6 *peer)
927{
928    struct client *new = NULL;
929    socklen_t sl;
930
931    if ((new = (struct client *)malloc(sizeof(struct client))) != NULL)
932    {
933        memset(new, 0, sizeof(struct client));
934        memcpy(&new->peeraddr, peer, sizeof(new->peeraddr));
935
936        new->fd.fd = sock;
937        new->server = serv;
938
939        new->rpipe.fd = -1;
940        new->wpipe.fd = -1;
941
942        /* get local endpoint addr */
943        sl = sizeof(struct sockaddr_in6);
944        getsockname(sock, (struct sockaddr *) &(new->servaddr), &sl);
945
946        new->next = uh_clients;
947        uh_clients = new;
948
949        serv->n_clients++;
950
951        D("IO: Client(%d) allocated\n", new->fd.fd);
952    }
953
954    return new;
955}
956
957struct client * uh_client_lookup(int sock)
958{
959    struct client *cur = NULL;
960
961    for (cur = uh_clients; cur; cur = cur->next)
962        if (cur->fd.fd == sock)
963            return cur;
964
965    return NULL;
966}
967
968void uh_client_shutdown(struct client *cl)
969{
970#ifdef HAVE_TLS
971    /* free client tls context */
972    if (cl->server && cl->server->conf->tls)
973        cl->server->conf->tls_close(cl);
974#endif
975
976    /* remove from global client list */
977    uh_client_remove(cl);
978}
979
980void uh_client_remove(struct client *cl)
981{
982    struct client *cur = NULL;
983    struct client *prv = NULL;
984
985    for (cur = uh_clients; cur; prv = cur, cur = cur->next)
986    {
987        if (cur == cl)
988        {
989            if (prv)
990                prv->next = cur->next;
991            else
992                uh_clients = cur->next;
993
994            if (cur->timeout.pending)
995                uloop_timeout_cancel(&cur->timeout);
996
997            if (cur->proc.pid)
998                uloop_process_delete(&cur->proc);
999
1000            D("IO: Client(%d) freeing\n", cur->fd.fd);
1001
1002            uh_ufd_remove(&cur->rpipe);
1003            uh_ufd_remove(&cur->wpipe);
1004            uh_ufd_remove(&cur->fd);
1005
1006            cur->server->n_clients--;
1007
1008            free(cur);
1009            break;
1010        }
1011    }
1012}
1013
1014
1015void uh_ufd_add(struct uloop_fd *u, uloop_fd_handler h, unsigned int ev)
1016{
1017    if (h != NULL)
1018    {
1019        u->cb = h;
1020        uloop_fd_add(u, ev);
1021        D("IO: FD(%d) added to uloop\n", u->fd);
1022    }
1023}
1024
1025void uh_ufd_remove(struct uloop_fd *u)
1026{
1027    if (u->cb != NULL)
1028    {
1029        uloop_fd_delete(u);
1030        D("IO: FD(%d) removed from uloop\n", u->fd);
1031        u->cb = NULL;
1032    }
1033
1034    if (u->fd > -1)
1035    {
1036        close(u->fd);
1037        D("IO: FD(%d) closed\n", u->fd);
1038        u->fd = -1;
1039    }
1040}
1041
1042
1043#ifdef HAVE_CGI
1044static struct interpreter *uh_interpreters = NULL;
1045
1046struct interpreter * uh_interpreter_add(const char *extn, const char *path)
1047{
1048    struct interpreter *new = NULL;
1049
1050    if ((new = (struct interpreter *)malloc(sizeof(struct interpreter))) != NULL)
1051    {
1052        memset(new, 0, sizeof(struct interpreter));
1053
1054        memcpy(new->extn, extn, min(strlen(extn), sizeof(new->extn)-1));
1055        memcpy(new->path, path, min(strlen(path), sizeof(new->path)-1));
1056
1057        new->next = uh_interpreters;
1058        uh_interpreters = new;
1059
1060        return new;
1061    }
1062
1063    return NULL;
1064}
1065
1066struct interpreter * uh_interpreter_lookup(const char *path)
1067{
1068    struct interpreter *cur = NULL;
1069    const char *e;
1070
1071    for (cur = uh_interpreters; cur; cur = cur->next)
1072    {
1073        e = &path[max(strlen(path) - strlen(cur->extn), 0)];
1074
1075        if (!strcmp(e, cur->extn))
1076            return cur;
1077    }
1078
1079    return NULL;
1080}
1081#endif
1082

Archive Download this file



interactive