root/handler.c

Revision afa113a315cc3a8540fbd86ca2667b9be278dd0b, 18.3 kB (checked in by D.J. Capelis <dev@…>, 23 months ago)

This is the version of fived that was used in the testing for CMPS232 at UCSC.

An important bug is fixed in this commit that allows for fived to
actually work correctly when there's a bunch of data heading at it.
Fived incorrect assumed at one point that a read would read the entire
range.

  • Property mode set to 100644
Line 
1#include"main.h"
2
3#define MAX_NAME_LEN 256
4#define BUFFER 4*1024
5
6void * handle(void * args)
7{
8    char * getbuffer = calloc(MAX_NAME_LEN, sizeof(char));
9    char * buffer = calloc(MAX_NAME_LEN*2, sizeof(char));
10    char * netbuffer = calloc(BUFFER, sizeof(char));
11    size_t size = 0;
12    size_t offset = 0;
13    int mode = 0;       // 1 is connection established
14    struct service * service = NULL;
15    struct service * listservice = NULL;
16    int i = 0;
17    int outsock = 0;
18    int waiting = 0;
19    char * response;
20    struct epoll_event ev, *events; //For epoll()
21    int len;
22    char * check = calloc(BUFFER, sizeof(char));
23
24    struct session * s = calloc(1, sizeof(struct session));
25    s->sock = (int) args;
26    s->ssl = NULL;     // If this is set, we need to use SSL
27    s->contxt = NULL;
28    s->multiplex = 0;
29    s->multiplex_xtra = 0;
30    //s->header[16];
31    s->ptr = (unsigned int *) &s->header;
32    s->user = NULL;
33    s->host = "main";
34
35    /* Epoll Initialization */
36    int epfd = epoll_create(16);
37    events = calloc(16, sizeof(struct epoll_event));
38    ev.events = EPOLLIN;
39    ev.data.fd = s->sock;
40    epoll_ctl(epfd, EPOLL_CTL_ADD, s->sock, &ev);
41
42    while(1)
43    {
44        if(mode == 0)
45        {
46incoming:
47            if(!s->ssl)  //TODO: re-write everything here to use gettalk()
48            {
49                if(!s->multiplex)
50                    size = read(s->sock, getbuffer, MAX_NAME_LEN);
51                else
52                {
53                    if(len > MAX_NAME_LEN)
54                    {
55                        size = read(s->sock, getbuffer, MAX_NAME_LEN);
56                        read(s->sock, netbuffer, len - MAX_NAME_LEN); //TODO: check overflow
57                    }
58                    size = read(s->sock, getbuffer, len);
59                }
60            }
61            else
62            {
63                if(!s->multiplex)
64                    size = SSL_read(s->ssl, getbuffer, MAX_NAME_LEN);
65                else
66                {
67                    if(len > MAX_NAME_LEN)
68                    {
69                        size = SSL_read(s->ssl, getbuffer, MAX_NAME_LEN);
70                        SSL_read(s->ssl, netbuffer, len - MAX_NAME_LEN); //TODO: check overflow
71                    }
72                    size = SSL_read(s->ssl, getbuffer, len);
73                }
74            }
75        }
76
77       
78        if(size < 1)
79        {
80kill:
81            if(s->ssl)
82            {
83                SSL_shutdown(s->ssl);
84                SSL_free(s->ssl);
85                SSL_CTX_free(s->contxt);
86            }
87            close(s->sock);
88            close(outsock);
89            close(epfd);
90            free(getbuffer);
91            free(buffer);
92            free(netbuffer);
93            free(events);
94            free(check);
95            printf("Client disconnected\n");
96            return NULL;
97        }
98
99        printf("Parsing\n");
100        service = parse(&offset, &size, getbuffer, buffer, s);
101
102        if(service == (void *) -1)
103            continue;
104
105        /* Catch all and access denied */
106        if(service == NULL)
107        {
108            talkback(s, "- No Such Service\r\n");
109            if(mode)
110                goto process;
111            else
112                continue;
113        }
114
115        if(service->service_type == HELP_SERVICE || service->service_type == LIST_SERVICE)
116        {
117            i = 0;
118            response = calloc(BUFFER, sizeof(char));
119            listservice = servicelist;
120            while(listservice)
121            {
122                if((listservice->service_type == HELP_SERVICE || listservice->service_type == LIST_SERVICE))
123                {
124                    listservice = listservice->next;
125                    continue;
126                }
127                if((listservice->service_type == SSL_SERVICE && s->ssl) || (listservice->service_type == MULTIPLEX_SERVICE && s->multiplex))
128                {
129                    listservice = listservice->next;
130                    continue;
131                }
132                if(listservice->restrict_user != NULL)
133                {
134                    if(s->user == NULL || listservice->restrict_user == NULL)
135                    {
136                        listservice = listservice->next;
137                        continue;
138                    }
139                    if(strcmp(s->user, listservice->restrict_user))
140                    {
141                        listservice = listservice->next;
142                        continue;
143                    }
144                }
145                if(listservice->restrict_host != NULL)
146                {
147                    if(s->host == NULL || listservice->restrict_host == NULL)
148                    {
149                        listservice = listservice->next;
150                        continue;
151                    }
152                    if(strcmp(s->host, listservice->restrict_host))
153                    {
154                        listservice = listservice->next;
155                        continue;
156                    }
157                }
158                i += strlen(listservice->name) + 2;
159                if(i > BUFFER)
160                    response = realloc(response, i);
161                strcat(response+i-(strlen(listservice->name)+2), listservice->name);
162                response[i-1] = '\n';
163                response[i-2] = '\r';
164                listservice = listservice->next;
165            }
166            talkback_len(s, response, i);
167            free(response);
168            if(service->service_type == HELP_SERVICE)
169                goto kill;
170            if(mode)
171                goto process;
172            else
173                continue;
174        }
175
176        if(service->service_type == MULTIPLEX_SERVICE)
177        {
178            if(s->multiplex)
179            {
180                talkback(s, "- No Such Service\r\n");
181                if(mode)
182                    goto process;
183                else
184                    continue;
185            }
186            talkback(s, "+ Success\r\n");
187            s->multiplex = 1;
188            mode = 1;
189            /* Go into multiplex mode */
190            send_header(s, 0, NEW_PLEX, 0);
191        }
192
193        if(service->service_type == SSL_SERVICE)
194        {
195            //TODO: OpenSSL is not re-entrant, care about that.
196            if(s->ssl)
197            {
198                talkback(s, "- No Such Service\r\n");
199                if(mode)
200                    goto process;
201                else
202                    continue;
203            }
204            talkback(s, "+ Success\r\n");
205
206            s->contxt = SSL_CTX_new(SSLv23_server_method());
207            if(!s->contxt)
208                printf("SSL_CTX_new failed\n");
209
210            i = SSL_CTX_use_RSAPrivateKey_file(s->contxt, "/home/djc/projects/fived/fived_key.pem", SSL_FILETYPE_PEM);
211            if(!i)
212                printf("RSA Key Load Failed\n");
213
214            i = SSL_CTX_use_certificate_file(s->contxt, "/home/djc/projects/fived/fived_cert.pem", SSL_FILETYPE_PEM);
215            if(!i)
216                printf("Cert Load Failed\n");
217
218            SSL_CTX_set_quiet_shutdown(s->contxt, 1);
219
220            s->ssl = SSL_new(s->contxt);
221            if(!s->ssl)
222                printf("SSL_new failed\n");
223
224            i = SSL_set_fd(s->ssl, s->sock);
225            if(!i)
226                printf("SSL_set_fd failed\n");
227
228            SSL_set_accept_state(s->ssl);
229            i = SSL_accept(s->ssl);
230            if(i < 1)
231            {
232                printf("SSL_accept failed\n");
233                switch(SSL_get_error(s->ssl, i))
234                {
235                    case SSL_ERROR_NONE:
236                        printf("no error\n");
237                        break;
238                    case SSL_ERROR_WANT_X509_LOOKUP:
239                        printf("X509 error\n");
240                        break;
241                    case SSL_ERROR_SSL:
242                        printf("You did something wrong\n");
243                        break;
244                    case SSL_ERROR_SYSCALL:
245                        printf("Someone else did something wrong (syscall)\n");
246                        break;
247                    default:
248                        printf("Idunnolol\n");
249                        break;
250                }
251            }
252        }
253
254        /* Imagine the most minimalistic demo-driven auth service you could think of... this is a hair below that */
255        if(service->service_type == AUTH_SERVICE)
256        {
257            talkback(s, "+ Success\r\nEnter Username: ");
258            gettalk(s, check, 0); // username (TODO: unsafe)
259            talkback(s, "Enter Password: ");
260            gettalk(s, check, 0); // password (TODO: unsafe)
261            if(!strncmp("demopass", check, 8))
262            {
263                s->user = "demo";
264                talkback(s, "Authentication as demo successful\r\n");
265            }
266            else
267            {
268                talkback(s, "Authentication failed\r\n");
269            }
270        }
271
272        if(service->service_type == HOST_SERVICE)
273        {
274            talkback(s, "+ Success\r\nWhich VHOST? ");
275            gettalk(s, check, 0); // host (TODO: unsafe);
276            if(!strncmp(check, "toys", 4))
277            {
278                s->host = "toys";
279                talkback(s, "+ Success: Host changed to toys\r\n");
280            }
281            else if(!strncmp(check, "main", 4))
282            {
283                s->host = "main";
284                talkback(s, "+ Success: Host changed to main\r\n");
285            }
286            else
287            {
288                talkback(s, "- Invalid hostname\r\n");
289            }
290        }
291
292        if(service->service_type == CUSTOM_SERVICE)
293        {
294            // TODO: access control
295            outsock = socket(PF_INET6, SOCK_STREAM, 0);
296            error(outsock);
297            i = connect(outsock, (const struct sockaddr *) service->info, sizeof(struct sockaddr_in6));
298            error(i);
299
300            /* Add to epoll() */
301            ev.data.fd = outsock;
302            i = epoll_ctl(epfd, EPOLL_CTL_ADD, outsock, &ev);
303            error(i);
304            printf("Adding fd %d to epoll\n", outsock);
305
306            /* For multiplexing, or not */
307            if(mode != 2)
308                mode = 1;
309           
310            talkback(s, "+ Success\r\n");
311
312            //TODO: Much more interesting things happen here during multiplexing
313            if(s->multiplex)
314                send_header(s, outsock, NEW_PLEX, 0);
315        }
316
317        goto deny;  //get rid of unused label warnings.
318deny:
319        /* Catch all and access denied */
320        if(service == NULL)
321            talkback(s, "- No Such Service\r\n");
322
323process:
324        if(mode == 1)
325        {
326            len = 0;
327            while(1)
328            {
329                waiting = epoll_wait(epfd, events, 16, -1);
330                error(waiting);
331                for(i=0;i<waiting;i++)
332                {
333                    if(s->multiplex)
334                    {
335                        //printf("fd %d has an event\n", events[i].data.fd);
336                        if(events[i].data.fd != s->sock)
337                        {
338                            len = read(events[i].data.fd, netbuffer, BUFFER);
339                            if(len < 1)
340                            {
341                                send_header(s, events[i].data.fd, DEL_PLEX, 0);
342                                epoll_ctl(epfd, EPOLL_CTL_DEL, events[i].data.fd, NULL);
343                                continue;
344                            }
345                            send_header(s, events[i].data.fd, 0, len);
346                            if(!s->ssl)
347                                write(s->sock, netbuffer, len);
348                            else
349                                SSL_write(s->ssl, netbuffer, len);
350                            continue;
351                        }
352                        if(!s->ssl)
353                            len = read(s->sock, &s->header, 16);
354                        else
355                            len = SSL_read(s->ssl, &s->header, 16);
356                        //printf("%x | %x | %x | %x\n", ntohl(s->ptr[0]), ntohl(s->ptr[1]), ntohl(s->ptr[2]), ntohl(s->ptr[3]));
357                        //if(len < 1)
358                        if(len != 16)
359                            goto kill;
360                        s->multiplex_xtra = ntohl(s->ptr[3]);
361                        if(ntohl(s->ptr[1]) == 0 && ntohl(s->ptr[3]) != 0) //They're talking to tcpmux
362                        {
363                            if(ntohl(s->ptr[2]) != 0)
364                                printf("Client is sending flags about id 0, something is wrong\n");
365                            len = s->multiplex_xtra;
366                            s->multiplex_xtra = 0; //TODO: revise this when you refactor the incoming module
367                            goto incoming;
368                        }
369                        if(ntohl(s->ptr[2]) == DEL_PLEX)
370                        {
371                            close(ntohl(s->ptr[1])); //TODO: Yeah, we should actually have our own table and be verifying
372                            continue;
373                        }
374                        while(s->multiplex_xtra != 0)
375                        {
376                            if(s->multiplex_xtra > BUFFER)
377                                len = BUFFER;
378                            else
379                                len = s->multiplex_xtra;
380                            if(!s->ssl)
381                                len = read(s->sock, netbuffer, len);
382                            else
383                                len = SSL_read(s->ssl, netbuffer, len);
384                            chk_error(write(ntohl(s->ptr[1]), netbuffer, len) != len);
385                            //printf("Wrote %d bytes to fd %d\n", len, ntohl(s->ptr[1]));
386                            s->multiplex_xtra -= len;
387                        }
388                        continue;
389                    }
390                    if(!s->ssl || events[i].data.fd != s->sock)
391                        len = read(events[i].data.fd, netbuffer, BUFFER);
392                    else
393                        len = SSL_read(s->ssl, netbuffer, BUFFER);
394                    if(len < 1)
395                        goto kill;
396                    if(events[i].data.fd == s->sock)
397                        write(outsock, netbuffer, len);
398                    else
399                    {
400                        if(!s->ssl)
401                            write(s->sock, netbuffer, len);
402                        else
403                            SSL_write(s->ssl, netbuffer, len);
404                    }
405                }
406            }
407        }
408    }
409
410err:
411    perror("Error");
412
413    return NULL;
414}
415
416struct service * parse(size_t * offset, size_t * size, char * getbuffer, char * buffer, struct session * s)
417{
418    unsigned int i = 0;
419    char * name;
420    memcpy(buffer+(*offset), getbuffer, *size);
421    *size += *offset;
422    for(i = 0; i < *size; ++i)
423    {
424        if(buffer[i] == '\r' || buffer[i] == '\n')
425            break;
426    }
427   
428    /* So there's no newline in the entire message */
429    if(i == *size)
430    {
431        *offset += *size - *offset;
432        if(*offset > MAX_NAME_LEN)
433            *offset = 0;
434        return (struct service *) -1;  //Presumably not a value a pointer can have.
435    }
436
437    /* There's a valid name of some sort */
438    name = calloc(i+1, sizeof(char));
439    memcpy(name, buffer, i+1);
440    name[i] = '\0'; //Replace \n or \r with null terminator
441    if(i == *size - 1 || (i == *size - 2 && buffer[i+1] == '\n'))
442        *offset = 0;
443    else //There is remaining data left to parse.
444    {
445        if(i != *size-1)
446        {
447            if(buffer[i] == '\r' && buffer[i+1] == '\n')
448            {
449                *offset = i+2;
450                memmove(buffer, buffer + i+2, *size - i+2);
451            }
452            else
453            {
454                *offset = i+1;
455                memmove(buffer, buffer + i+1, *size - i+1);
456            }
457        }
458        else
459        {
460            *offset = i+1;
461            memmove(buffer, buffer + i+1, *size - i+1);
462        }
463    }
464
465    //TODO, make syslog "attempt to request service x"
466    printf("Service name is %s\n", name);
467
468    struct service * current = servicelist;
469    while(current)
470    {
471        if(current ->restrict_user != NULL)
472        {
473            if(s->user == NULL || current->restrict_user == NULL)
474            {
475                current = current->next;
476                continue;
477            }
478            if(strcmp(s->user, current->restrict_user))
479            {
480                current = current->next;
481                continue;
482            }
483        }
484        if(current->restrict_host != NULL)
485        {
486            if(s->host == NULL || current->restrict_host == NULL)
487            {
488                current = current->next;
489                continue;
490            }
491            if(strcmp(s->host, current->restrict_host))
492            {
493                current = current->next;
494                continue;
495            }
496        }
497        if(strncmp(current->name,name,MAX_NAME_LEN) == 0)
498            return current;
499        current = current->next;
500    }
501
502    return NULL;
503}
504
505void send_header(struct session * s, int id, int flags, int len)
506{
507    //printf("Sending to id %d len %d with flags %d\n", id, len, flags);
508    char header[16];
509    int * ptr = (int *) &header;
510    ptr[0] = htonl(0);      //Version 0
511    ptr[1] = htonl(id);     //Id
512    ptr[2] = htonl(flags);  //Flags (1 for new, 2 for del, 0 for normal)  Rest reserved.
513    ptr[3] = htonl(len);    //Next header
514    if(s->ssl)
515        SSL_write(s->ssl, &header, 16);
516    else
517        write(s->sock, &header, 16);
518}
519
520void talkback_len(struct session * s, char * msg, int length)
521{
522    if(s->multiplex)
523        send_header(s, 0, 0, length);
524    if(!s->ssl)
525        write(s->sock, msg, length);
526    else
527        SSL_write(s->ssl, msg, length);
528}
529
530void talkback(struct session * s, char * msg)
531{
532    talkback_len(s, msg, strlen(msg));
533}
534
535int gettalk(struct session * s, char * buffer, int length)
536{
537    int len = 0;
538    if(length == 0 || length > BUFFER)
539        len = BUFFER;
540    else
541        len = length;
542
543    if(s->multiplex && !s->multiplex_xtra)
544    {
545        if(!s->ssl)
546        {
547            chk_error(read(s->sock, &s->header, 16) != 16);
548        }
549        else
550        {
551            chk_error(SSL_read(s->ssl, &s->header, 16) != 16);
552        }
553        s->multiplex_xtra = ntohl(s->ptr[3]);
554        if(s->multiplex_xtra <= len)
555        {
556            len = s->multiplex_xtra;
557            s->multiplex_xtra = 0;
558        }
559        else
560            s->multiplex_xtra = s->multiplex_xtra - len;
561    }
562    if(s->ssl)
563        return SSL_read(s->ssl, buffer, len);
564    else
565        return read(s->sock, buffer, len);
566
567err:
568    printf("Failed get multiplexing header");
569    return -1;
570}
Note: See TracBrowser for help on using the browser.