Advertisement
Guest User

Untitled

a guest
May 20th, 2017
108
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 20.69 KB | None | 0 0
  1. /**
  2.  * @file ftpd.c
  3.  * @date 04/09/10
  4.  * @version 1.0
  5.  
  6.  * @brief A simple ftpd server in C
  7.  *
  8.  * @author Josip Djolonga (jdjolonga), j.djolonga@jacobs-university.de
  9.  *
  10.  * Note that simultaneous connections are supported.
  11.  *
  12.  */
  13.  
  14. #define _REETRANT
  15.  
  16. #include <dirent.h>
  17. #include <errno.h>
  18. #include <grp.h>
  19. #include <pwd.h>
  20. #include <signal.h>
  21. #define _GNU_SOURCE
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <string.h>
  25. #include <time.h>
  26. #include <getopt.h>
  27. #include <libgen.h>
  28.  
  29. #include <sys/stat.h>
  30. #include <sys/socket.h>
  31. #include <sys/wait.h>
  32. #include <sys/types.h>
  33. #include <netdb.h>
  34.  
  35. #include <unistd.h>
  36.  
  37. /* maximum pending connections */
  38. #define MAX_PENDING 50
  39.  
  40. #define DEBUG
  41.  
  42. struct ftp_user {
  43.     char * name;
  44.     char * pass;
  45.     char * dir;
  46. };
  47.  
  48. struct ftp_user * users;
  49. unsigned users_num = 0;
  50.  
  51. static void parse_conf() {
  52.     static const char * conf_file_path = "myftpd.conf";
  53.     char * line;
  54.     size_t line_len;
  55.  
  56.     int n;
  57.     char c, last_c = '\0';
  58.     int i;
  59.     char * token;
  60.  
  61.     FILE * conf = fopen(conf_file_path, "r");
  62.     if(conf == NULL) {
  63.         perror("fopen");
  64.         exit(EXIT_FAILURE);
  65.     }
  66.  
  67.     n = 0;
  68.     while((c = fgetc(conf)) != EOF) {
  69.         if(c == '\n') {
  70.             n++;
  71.         }
  72.         last_c = c;
  73.     }
  74.  
  75.     /* some editors might leave a '\n' on the last line, ignore it */
  76.     if(last_c != '\n') {
  77.         n++;
  78.     }
  79.  
  80.     fseek(conf, 0, SEEK_SET);
  81.  
  82.     users = malloc(sizeof(*users)*n);
  83.     if(users == NULL) {
  84.         perror("malloc");
  85.         exit(EXIT_FAILURE);
  86.     }
  87.  
  88.    for(i=0; i<n; i++) {
  89.         line = NULL;
  90.         line_len = 0;
  91.  
  92.         if(getline(&line, &line_len, conf) == -1) {
  93.             fputs("ill formed configuration file\n", stderr);
  94.             exit(2);
  95.         };
  96.  
  97.         token = strtok(line, "\n:");
  98.         if(token == NULL) {
  99.             fputs("ill formed configuration file\n", stderr);
  100.             exit(2);
  101.         }
  102.         users[i].name = token;
  103.  
  104.         token = strtok(NULL, "\n:");
  105.         if(token == NULL) {
  106.             fputs("ill formed configuration file\n", stderr);
  107.             exit(2);
  108.         }
  109.         users[i].pass = token;
  110.  
  111.         token = strtok(NULL, "\n:");
  112.         if(token == NULL) {
  113.             fputs("ill formed configuration file\n", stderr);
  114.             exit(2);
  115.         }
  116.         users[i].dir = token;
  117.  
  118.        if(strtok(NULL, "\n:") != NULL) {
  119.             fputs("ill formed configuration file\n", stderr);
  120.             exit(2);
  121.         }
  122.  
  123.     }
  124.  
  125.     users_num = n;
  126. }
  127.  
  128.  
  129. static void print_usage() {
  130.     static const char * usage_str1 =
  131.     "usage: ftpd [options]                                                   \n"
  132.     "                                                                        \n"
  133.     "description:                                                            \n"
  134.     "    This program runs an FTP server on the given port. Multiple         \n"
  135.     "simultaneous connections are supported. If the port is not specified    \n";
  136.     static const char * usage_str2 =
  137.     "it defaults to 21.                                                      \n"
  138.     "                                                                        \n"
  139.     "options:                                                                \n"
  140.     "   -h,--help                   print this message                       \n"
  141.     "   -p port,--port port         run the server on the given port         \n";
  142.  
  143.     /* splitted into two because the string is greater than the
  144.      * max size compilers have to support according to the standard */
  145.     fputs(usage_str1, stderr);
  146.     fputs(usage_str2, stderr);
  147. }
  148.  
  149. static void sock_safe_send(int fd, const char * data, ssize_t size) {
  150.     int s, bytes;
  151.  
  152.     bytes = 0;
  153.     while(bytes < size) {
  154.         s = write(fd, data+bytes, size-bytes);
  155.         if(s == -1) {
  156.             perror("write");
  157.             exit(EXIT_FAILURE);
  158.         } else {
  159.             bytes += s;
  160.         }
  161.     }
  162. }
  163.  
  164. static void sock_putc(int fd, char c) {
  165.     int s=0;
  166.  
  167.     while((s = write(fd, &c, 1)) == 0) {
  168.     }
  169.  
  170.     if(s == -1) {
  171.         perror("write");
  172.         exit(EXIT_FAILURE);
  173.     }
  174.  
  175. }
  176.  
  177. static void sock_puts(int fd, const char * str) {
  178.     sock_safe_send(fd, str, strlen(str));
  179. }
  180.  
  181. static char * cwd_str() {
  182.     char * path;
  183.     int size = 1024;
  184.  
  185.     path = malloc(size);
  186.     if(path == NULL) {
  187.         perror("malloc");
  188.         exit(EXIT_FAILURE);
  189.     }
  190.  
  191.     while(getcwd(path, size) == NULL) {
  192.         if(errno == ERANGE) {
  193.             size += 512;
  194.             if(realloc(path, size) == NULL) {
  195.                 perror("realloc");
  196.                 exit(EXIT_FAILURE);
  197.             }
  198.         } else {
  199.             perror("getcwd");
  200.             exit(EXIT_FAILURE);
  201.         }
  202.     }
  203.  
  204.     return path;
  205. }
  206.  
  207. #define sock_printf(fd, buf, fmt, ...) \
  208.             snprintf((buf), (sizeof(buf)), (fmt), __VA_ARGS__); \
  209.             sock_puts((fd), (buf));
  210.  
  211. /* the show_* functions are based on the implementation provided in the
  212.  * course homepage */
  213. static void
  214. show_mode(int fd, mode_t mode)
  215. {
  216.     char c;
  217.  
  218.     if (S_ISDIR(mode)) {
  219.         c = 'd';
  220.     } else if (S_ISREG(mode)) {
  221.         c = '-';
  222.     } else if (S_ISCHR(mode)) {
  223.         c = 'c';
  224.     } else if (S_ISBLK(mode)) {
  225.         c = 'b';
  226. #ifdef S_ISSOCK
  227.     } else if (S_ISSOCK(mode)) {
  228.         c = 's';
  229. #endif
  230.     } else if (S_ISFIFO(mode)) {
  231.         c = 'f';
  232.     } else {
  233.         c = 'c';
  234.     }
  235.  
  236.     sock_putc(fd, (mode & S_IRUSR) ? 'r' : '-');
  237.     sock_putc(fd, (mode & S_IWUSR) ? 'w' : '-');
  238.     sock_putc(fd, (mode & S_IXUSR) ? 'x' : '-');
  239.     sock_putc(fd, (mode & S_IRGRP) ? 'r' : '-');
  240.     sock_putc(fd, (mode & S_IWGRP) ? 'w' : '-');
  241.     sock_putc(fd, (mode & S_IXGRP) ? 'x' : '-');
  242.     sock_putc(fd, (mode & S_IROTH) ? 'r' : '-');
  243.     sock_putc(fd, (mode & S_IWOTH) ? 'w' : '-');
  244.     sock_putc(fd, (mode & S_IXOTH) ? 'x' : '-');
  245. }
  246.  
  247. static void show_user(int fd, uid_t uid)
  248. {
  249.     struct passwd *pwd;
  250.     static char buf[8];
  251.  
  252.     pwd = getpwuid(uid);
  253.     if (pwd) {
  254.         sock_printf(fd, buf, " %6s", pwd->pw_name);
  255.     } else {
  256.         sock_printf(fd, buf, " %6u", uid);
  257.     }
  258. }
  259.  
  260. static void
  261. show_group(int fd, gid_t gid)
  262. {
  263.     struct group *grp;
  264.     static char buf[8];
  265.  
  266.  
  267.     grp = getgrgid(gid);
  268.     if (grp) {
  269.         sock_printf(fd, buf, " %6s", grp->gr_name);
  270.     } else {
  271.         sock_printf(fd, buf, " %6u", gid);
  272.     }
  273. }
  274.  
  275. static void
  276. show_time(int fd, time_t t, time_t now)
  277. {
  278.     struct tm *tm;
  279.     char buf[14];
  280.     char buf_out[14];
  281.     const time_t delta = 7905600;       /* 366/2 * 12 * 3600 seconds */
  282.     size_t n = 0;
  283.  
  284.     tm = localtime(&t);
  285.     if (now != (time_t) -1 && t < now - delta) {
  286.         n = strftime(buf, sizeof(buf), "%b %d  %Y", tm);
  287.     } else {
  288.         n = strftime(buf, sizeof(buf), "%b %d %H:%M", tm);
  289.     }
  290.     if (n) {
  291.         sock_printf(fd, buf_out, " %12s", buf);
  292.     } else {
  293.         sock_printf(fd, buf_out, " %12lu", (unsigned long) t);
  294.     }
  295. }
  296.  
  297.  
  298. /* global variables, the state of the FTP transaction */
  299. int log_in_progress = 0;
  300. int logged_in = 0;
  301. static char user[1024];
  302. struct ftp_user * cur_user = NULL;
  303.  
  304. int path_is_safe(const char * path) {
  305.     char * abspath;
  306.     int ret;
  307.  
  308.     abspath = realpath(path, NULL);
  309.     if(abspath == NULL) {
  310.         perror("realpath");
  311.         ret = -1;
  312.     } else {
  313.         ret = (strstr(abspath, cur_user->dir) == abspath);
  314.     }
  315.  
  316.     free(abspath);
  317.     return ret;
  318. }
  319.  
  320. static void cmd_user(int fd, char *params) {
  321.     unsigned i;
  322.  
  323.     if(params == NULL) {
  324.             sock_puts(fd, "501 Invalid number of arguments.\r\n");
  325.             return;
  326.     }
  327.  
  328.     for(i=0; i<strlen(params); i++) {
  329.         if(params[i] == ' ') {
  330.             sock_puts(fd, "501 Invalid number of arguments.\r\n");
  331.             return;
  332.         }
  333.     }
  334.  
  335.     logged_in = 0;
  336.     log_in_progress = 1;
  337.  
  338.     cur_user = NULL;
  339.     memset(user, 0, sizeof(user));
  340.     strncpy(user, params, sizeof(user));
  341.  
  342.     sock_puts(fd, "331 Please specify the password.\r\n");
  343. }
  344.  
  345. static void cmd_pass(int fd, char *params) {
  346.     unsigned i;
  347.  
  348.     if(params == NULL) {
  349.             sock_puts(fd, "501 Invalid number of arguments.\r\n");
  350.             return;
  351.     }
  352.  
  353.     for(i=0; i<strlen(params); i++) {
  354.         if(params[i] == ' ') {
  355.             sock_puts(fd, "501 Invalid number of arguments.\r\n");
  356.             return;
  357.         }
  358.     }
  359.  
  360.     if(!log_in_progress) {
  361.         sock_puts(fd, "503 Login with USER first.\r\n");
  362.         return;
  363.     }
  364.  
  365.     for(i=0; i<users_num; i++) {
  366.             if(strcmp(users[i].name, user) == 0 &&
  367.                strcmp(users[i].pass, params) == 0) {
  368.             cur_user = &users[i];
  369.             logged_in = 1;
  370.             log_in_progress = 0;
  371.             if(chdir(users[i].dir) != 0) {
  372.                 perror("chdir");
  373.                 exit(EXIT_FAILURE);
  374.             }
  375.             sock_puts(fd, "230 Login successful.\r\n");
  376.             return;
  377.         }
  378.     }
  379.  
  380.     logged_in = 0;
  381.     log_in_progress = 0;
  382.     sock_puts(fd, "530 Invalid user or password, try again.\r\n");
  383. }
  384.  
  385. static void cmd_help(int fd, char *params) {
  386.     static const char * commands = "214-The following commands are recognized,\r\n"
  387.                                    " USER PASS HELP CWD PWD \r\n"
  388.                                    " MKD RMD QUIT           \r\n"
  389.                                    "214 End of command list.\r\n";
  390.     if(params == NULL) {
  391.         sock_puts(fd, commands);
  392.     } else {
  393.         sock_puts(fd, "501 Invalid number of arguments.\r\n");
  394.     }
  395. }
  396.  
  397. static void cmd_cwd(int fd, char *params) {
  398.     unsigned i;
  399.     char * old_path;
  400.     int status;
  401.  
  402.     if(params == NULL) {
  403.             sock_puts(fd, "501 Invalid number of arguments.\r\n");
  404.             return;
  405.     }
  406.  
  407.     for(i=0; i<strlen(params); i++) {
  408.         if(params[i] == ' ') {
  409.             sock_puts(fd, "501 Invalid number of arguments.\r\n");
  410.             return;
  411.         }
  412.     }
  413.  
  414.     if(!logged_in) {
  415.         sock_puts(fd, "530 Please login with USER and PASS.\r\n");
  416.         return;
  417.     }
  418.  
  419.     old_path = cwd_str();
  420.     status = path_is_safe(params);
  421.     if(status == 1) {
  422.             if(chdir(params) != 0) {
  423.                 sock_puts(fd, "550 Failed to change directory.\r\n");
  424.                 perror("chdir");
  425.             } else {
  426.                 sock_puts(fd, "250 Directory successfully changed.\r\n");
  427.             }
  428.     } else if(status == 0) {
  429.         sock_puts(fd, "550 Permission denied.\r\n");
  430.     } else {
  431.         sock_puts(fd, "550 Failed to change directory.\r\n");
  432.     }
  433.     free(old_path);
  434. }
  435.  
  436. static void cmd_pwd(int fd, char *params) {
  437.     char * path;
  438.     char buf[128];
  439.  
  440.     if(params != NULL) {
  441.             sock_puts(fd, "501 Invalid number of arguments.\r\n");
  442.             return;
  443.     }
  444.  
  445.     if(!logged_in) {
  446.         sock_puts(fd, "530 Please login with USER and PASS.\n");
  447.         return;
  448.     }
  449.  
  450.     path = cwd_str();
  451.     sock_printf(fd, buf, "257 \"%s\"\r\n", path);
  452.     free(path);
  453. }
  454.  
  455. static void cmd_mkd(int fd, char *params) {
  456.     unsigned i;
  457.     int ret;
  458.     char * parent_dir;
  459.  
  460.     if(params == NULL) {
  461.             sock_puts(fd, "501 Invalid number of arguments.\r\n");
  462.             return;
  463.     }
  464.  
  465.     for(i=0; i<strlen(params); i++) {
  466.             sock_puts(fd, "501 Invalid number of arguments.\r\n");
  467.             return;
  468.     }
  469.  
  470.     if(!logged_in) {
  471.         sock_puts(fd, "530 Please login with USER and PASS.\n");
  472.         return;
  473.     }
  474.  
  475.     /* copy needed of params as dirname might modify it */
  476.     parent_dir = malloc(strlen(params));
  477.     if(parent_dir == NULL) {
  478.         perror("malloc");
  479.         exit(EXIT_FAILURE);
  480.     }
  481.  
  482.     strncpy(parent_dir, params, strlen(params));
  483.     ret = path_is_safe(dirname(parent_dir));
  484.  
  485.     free(parent_dir);
  486.  
  487.     if(ret == 1) {
  488.         if(mkdir(params, 0755) == 0) {
  489.             sock_puts(fd, "220 Created\r\n");
  490.         } else {
  491.             sock_puts(fd, "550 Failed to create directory\r\n");
  492.             perror("mkdir");
  493.         }
  494.     } else if(ret == -1) {
  495.         sock_puts(fd, "550 Failed to create directory\r\n");
  496.     } else {
  497.         sock_puts(fd, "550 Permission denied\r\n");
  498.     }
  499. }
  500.  
  501. static void cmd_rmd(int fd, char *params) {
  502.      unsigned i;
  503.      int ret;
  504.  
  505.     if(params == NULL) {
  506.             sock_puts(fd, "501 Invalid number of arguments.\r\n");
  507.             return;
  508.     }
  509.  
  510.     for(i=0; i<strlen(params); i++) {
  511.         if(params[i] == ' ') {
  512.             sock_puts(fd, "501 Invalid number of arguments.\r\n");
  513.             return;
  514.         }
  515.     }
  516.  
  517.     if(!logged_in) {
  518.         sock_puts(fd, "530 Please login with USER and PASS.\n");
  519.         return;
  520.     }
  521.  
  522.     ret = path_is_safe(params);
  523.     if(ret == 1) {
  524.         if(rmdir(params) == 0) {
  525.             sock_puts(fd, "220 Removed\r\n");
  526.         } else {
  527.             sock_puts(fd, "550 Failed to remove directory\r\n");
  528.             perror("rmdir");
  529.         }
  530.     } else if(ret == -1) {
  531.         sock_puts(fd, "550 Failed to remove directory\r\n");
  532.     } else {
  533.         sock_puts(fd, "550 Permission denied\r\n");
  534.     }
  535. }
  536.  
  537. static void cmd_stat(int fd, char *params) {
  538.     DIR * dir;
  539.     struct dirent * dir_ent;
  540.     int status;
  541.     struct stat info;
  542.     char * old_path;
  543.     char buf[128];
  544.  
  545.      if(!logged_in) {
  546.         sock_puts(fd, "530 Please login with USER and PASS.\n");
  547.         return;
  548.     }
  549.  
  550.     if(params == NULL) {
  551.         sock_puts  (fd, "211-FTP server status: \r\n");
  552.         sock_puts  (fd, "    Status: Ready\r\n");
  553.         sock_printf(fd, buf, "    Logged in as %s\r\n", user);
  554.         sock_puts  (fd, "    Type: ASCII\r\n");
  555.         sock_puts  (fd, "211 End of status\r\n");
  556.     } else {
  557.         status = path_is_safe(params);
  558.  
  559.         if(status == 1) {
  560.             dir = opendir(params);
  561.             /* no need to error check, if the directory is invalid,  *
  562.              * print an empty list (like in proftpd)                 */
  563.  
  564.             old_path = cwd_str();
  565.             if(chdir(params) != 0) {
  566.                 free(old_path);
  567.                 sock_puts(fd, "550 Can not list the directory\r\n");
  568.                 return;
  569.             }
  570.  
  571.             sock_puts (fd, "213-Status follows\r\n");
  572.             while((dir_ent = readdir(dir)) != NULL) {
  573.                 sock_puts(fd, " ");
  574.                 if(stat(dir_ent->d_name,  &info) == 0) {
  575.                     show_mode(fd, info.st_mode);
  576.                     show_user(fd, info.st_uid);
  577.                     show_group(fd, info.st_gid);
  578. #ifdef FS_SIZE_64_BIT
  579.                     sock_printf(fd, buf, " %9llu", info.st_size);
  580. #else
  581.                     sock_printf(fd, buf, " %9lu", info.st_size);
  582. #endif
  583.                     show_time(fd, info.st_mtime, time(NULL));
  584.                 }
  585.  
  586.                 sock_printf(fd, buf, " %s\r\n",  dir_ent->d_name);
  587.             }
  588.             sock_puts (fd, "213 End of status\r\n");
  589.  
  590.             if(chdir(old_path) != 0) {
  591.                 perror("chdir");
  592.                 exit(EXIT_FAILURE);
  593.             }
  594.         } else if(status == 0) {
  595.             sock_puts(fd, "550 Permission denied.\r\n");
  596.         } else {
  597.             sock_puts(fd, "550 No such directory.\r\n");
  598.         }
  599.     }
  600. }
  601.  
  602. static void cmd_quit(int fd, char *params) {
  603.     if(params != NULL) {
  604.         sock_puts(fd, "501 Invalid number of arguments.\r\n");
  605.     } else {
  606.         sock_puts(fd, "221 Goodbye.\r\n");
  607.         close(fd);
  608.         exit(EXIT_SUCCESS);
  609.     }
  610. }
  611.  
  612. struct command {
  613.     const char * name;
  614.     void (*handler)(int fd, char * params);
  615. };
  616.  
  617. static struct command commands[] = {
  618.     {"USER" ,   cmd_user    },
  619.     {"PASS" ,   cmd_pass    },
  620.     {"HELP" ,   cmd_help    },
  621.     {"CWD"  ,   cmd_cwd     },
  622.     {"PWD"  ,   cmd_pwd     },
  623.     {"MKD"  ,   cmd_mkd     },
  624.     {"RMD"  ,   cmd_rmd     },
  625.     {"STAT" ,   cmd_stat    },
  626.     {"QUIT" ,   cmd_quit    }
  627. };
  628.  
  629. static int serve_client(int clifd) {
  630.     static char buf[512];
  631.     unsigned i;
  632.     int j;
  633.     int s;
  634.     char * cmd, * params;
  635.     int found = 0;
  636.  
  637.     sock_puts(clifd, "220 wtftpd 1.0 - the server is ready to serve you!\r\n");
  638.  
  639.     while(1) {
  640.         s = read(clifd, buf, sizeof(buf)-1);
  641.         if(s == -1) {
  642.             perror("read");
  643.             exit(EXIT_FAILURE);
  644.         }
  645.  
  646.         if(s > 0 && buf[s-1] == '\n') {
  647.             buf[s-1] = '\0';
  648.         }
  649.  
  650.         if(s > 1 && buf[s-2] == '\r') {
  651.             buf[s-2] = '\0';
  652.         }
  653.  
  654.         params = NULL;
  655.         cmd = buf;
  656.         for(j=0; j<s; j++) {
  657.             if(buf[j] == ' ') {
  658.                 /* split the command here */
  659.                 params = &buf[j+1];
  660.                 break;
  661.             }
  662.         }
  663.         buf[j] = '\0'; /* null terminate the command */
  664.  
  665.         found = 0;
  666.         for(i=0; i<sizeof(commands)/sizeof(*commands); i++) {
  667.             if(strcasecmp(commands[i].name, cmd) == 0) {
  668.                 found = 1;
  669.                 commands[i].handler(clifd, params);
  670.             }
  671.         }
  672.  
  673.         if(!found) {
  674.             sock_puts(clifd, "500 Unknown command.\r\n");
  675.         }
  676.     }
  677.  
  678.     if(close(clifd) < 0) {
  679.         fputs("Can not close the connection", stderr);
  680.         perror("close");
  681.         return EXIT_FAILURE;
  682.     }
  683. }
  684.  
  685. /**
  686.  * SIGCHLD handler, reaps the zombies
  687.  **/
  688. static void reap_zombies(int sig) {
  689.     /*  KILL 'EM ALL */
  690.     while(waitpid(-1, NULL,  WNOHANG) > 0) { }
  691. }
  692.  
  693. int main(int argc, char * argv[]) {
  694.     int sockfd, clifd, c;
  695.     struct sigaction sig_chld;
  696.     char * port = "21";
  697.     int help = 0;
  698.     int status;
  699.     int opt_len = -1;
  700.     socklen_t addr_len;
  701.  
  702.     struct addrinfo ai_hints, *ai_result, *ai;
  703.     struct sockaddr cli_addr;
  704.  
  705.     pid_t pid;
  706.  
  707.     static struct option opts[] = {
  708.         {"help", 0, 0, 'h'},
  709.         {"port", 1, 0, 'p'}
  710.     };
  711.  
  712.     while((c  = getopt_long(argc, argv, "hp:", opts, NULL)) != -1) {
  713.         switch(c) {
  714.             case 'h':
  715.                 help = 1;
  716.                 break;
  717.  
  718.             case 'p':
  719.                 if(atoi(optarg) <= 0) {
  720.                     fputs("invalid port number\n", stderr);
  721.                     return EXIT_FAILURE;
  722.                 }
  723.  
  724.                 opt_len = strlen(optarg);
  725.                 port = malloc(opt_len);
  726.                 if(port == NULL) {
  727.                     perror("malloc");
  728.                     return EXIT_FAILURE;
  729.                 }
  730.                 strncpy(port, optarg, opt_len);
  731.  
  732.                 break;
  733.  
  734.             case '?':
  735.                 fputs("use the --help to see how the program can be used\n",
  736.                       stderr);
  737.                 return EXIT_FAILURE;
  738.                 break;
  739.         }
  740.     }
  741.  
  742.     if(help == 1) {
  743.         print_usage();
  744.         return EXIT_SUCCESS;
  745.     }
  746.  
  747.     if(optind != argc) {
  748.         fputs("too many arguments, use --help too see all options\n", stderr);
  749.         return EXIT_FAILURE;
  750.     }
  751.  
  752.     parse_conf();
  753.  
  754.     /* set up the zombie reaper */
  755.     memset(&sig_chld, 0, sizeof(sig_chld));
  756.     sig_chld.sa_handler = reap_zombies;
  757.  
  758.     if(sigaction(SIGCHLD, &sig_chld, NULL) != 0) {
  759.         perror("sigaction");
  760.         return EXIT_FAILURE;
  761.     }
  762.  
  763.     memset(&ai_hints, 0, sizeof(ai_hints));
  764.     ai_hints.ai_family = AF_UNSPEC;
  765.     ai_hints.ai_socktype = SOCK_STREAM;
  766.     ai_hints.ai_flags = AI_PASSIVE;
  767.  
  768.     if((status = getaddrinfo(NULL, port, &ai_hints, &ai_result)) != 0) {
  769.         fprintf(stderr, "getaddrinfo error: %s\n", gai_strerror(status));
  770.         return EXIT_FAILURE;
  771.     }
  772.  
  773.     if(opt_len != -1) {
  774.         free(port);
  775.     }
  776.  
  777.     for(ai = ai_result; ai != NULL; ai = ai->ai_next) {
  778.         sockfd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
  779.         if(sockfd < 0) {
  780.             perror("socket");
  781.         } else {
  782.             break;
  783.         }
  784.     }
  785.  
  786.     if(sockfd < 0) {
  787.         fputs("can not create a socket\n", stderr);
  788.         perror("socket");
  789.         return EXIT_FAILURE;
  790.     }
  791.  
  792.     if(bind(sockfd, ai->ai_addr, ai->ai_addrlen) != 0) {
  793.         fputs("can not bind\n", stderr);
  794.         perror("bind");
  795.         return EXIT_FAILURE;
  796.     }
  797.  
  798.     if(listen(sockfd, MAX_PENDING) != 0) {
  799.         perror("listen");
  800.         return EXIT_FAILURE;
  801.     }
  802.  
  803.     memset(user, 0, sizeof(user));
  804.  
  805.     while(1) {
  806.         addr_len = sizeof(cli_addr);
  807.         clifd = accept(sockfd, &cli_addr, &addr_len);
  808.         if(clifd == -1) {
  809.             /* probably a SIGCHLD */
  810.             if(errno == EINTR) {
  811.                 continue;
  812.             } else {
  813.                 perror("accept");
  814.                 return EXIT_FAILURE;
  815.             }
  816.         }
  817.  
  818.         pid = fork();
  819.  
  820.         if(pid == 0) {
  821.             close(sockfd);
  822.             serve_client(clifd);
  823.             /* this is never executed */
  824.         } else {
  825.             close(clifd);
  826.         }
  827.     }
  828.  
  829.     return EXIT_SUCCESS;
  830. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement