"Fossies" - the Fresh Open Source Software Archive

Member "pure-ftpd-1.0.49/src/pure-certd.c" (2 Apr 2019, 10110 Bytes) of package /linux/misc/pure-ftpd-1.0.49.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "pure-certd.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 1.0.48_vs_1.0.49.

    1 #include <config.h>
    2 
    3 #ifndef WITH_TLS
    4 #include <stdio.h>
    5 
    6 int main(void)
    7 {
    8     puts("Please compile the server with --with-tls to use this feature.\n"
    9          "Thank you.");
   10 
   11     return 0;
   12 }
   13 #else
   14 
   15 #include "ftpd.h"
   16 #include "tls_extcert.h"
   17 #include "pure-certd_p.h"
   18 #include "safe_rw.h"
   19 
   20 #ifdef WITH_DMALLOC
   21 # include <dmalloc.h>
   22 #endif
   23 
   24 static void setcloexec(const int fd)
   25 {
   26     fcntl(fd, F_SETFD, FD_CLOEXEC);
   27 }
   28 
   29 static int closedesc_all(const int closestdin)
   30 {
   31     int fodder;
   32 
   33     if (closestdin != 0) {
   34         (void) close(0);
   35         if ((fodder = open("/dev/null", O_RDONLY)) == -1) {
   36             return -1;
   37         }
   38         (void) dup2(fodder, 0);
   39         if (fodder > 0) {
   40             (void) close(fodder);
   41         }
   42     }
   43     if ((fodder = open("/dev/null", O_WRONLY)) == -1) {
   44         return -1;
   45     }
   46     (void) dup2(fodder, 1);
   47     (void) dup2(1, 2);
   48     if (fodder > 2) {
   49         (void) close(fodder);
   50     }
   51     return 0;
   52 }
   53 
   54 static void dodaemonize(void)
   55 {
   56     pid_t child;
   57 
   58     if (daemonize != 0) {
   59         if ((child = fork()) == (pid_t) -1) {
   60             perror("Daemonization failed - fork");
   61             return;
   62         } else if (child != (pid_t) 0) {
   63             _exit(EXIT_SUCCESS);
   64         } else if (setsid() == (pid_t) -1) {
   65             perror("Daemonization failed : setsid");
   66         }
   67         (void) chdir("/");
   68 #ifdef HAVE_CLOSEFROM
   69         (void) closefrom(3);
   70 #endif
   71         (void) closedesc_all(1);
   72     }
   73 }
   74 
   75 static int init(void)
   76 {
   77 #ifndef NON_ROOT_FTP
   78     if (geteuid() != (uid_t) 0) {
   79         fprintf(stderr,
   80         "Sorry, but you have to be root to run this program\n");
   81         return -1;
   82     }
   83 #endif
   84 
   85     return 0;
   86 }
   87 
   88 static void usage(void)
   89 {
   90 #ifndef NO_GETOPT_LONG
   91     const struct option *options = long_options;
   92 
   93     do {
   94         printf("-%c\t--%s\t%s\n", options->val, options->name,
   95                options->has_arg ? "<opt>" : "");
   96         options++;
   97     } while (options->name != NULL);
   98 #endif
   99     exit(EXIT_SUCCESS);
  100 }
  101 
  102 static int parseoptions(int argc, char *argv[])
  103 {
  104 #ifndef NO_GETOPT_LONG
  105     int option_index = 0;
  106 #endif
  107     int fodder;
  108 
  109     while ((fodder =
  110 #ifndef NO_GETOPT_LONG
  111             getopt_long(argc, argv, GETOPT_OPTIONS, long_options,
  112             &option_index)
  113 #else
  114             getopt(argc, argv, GETOPT_OPTIONS)
  115 #endif
  116             ) != -1) {
  117         switch (fodder) {
  118         case 'B': {
  119             daemonize = 1;
  120             break;
  121         }
  122         case 'g': {
  123             const char *nptr;
  124             char *endptr;
  125 
  126             nptr = optarg;
  127             endptr = NULL;
  128             gid = (gid_t) strtoul(nptr, &endptr, 10);
  129             if (!nptr || !*nptr || !endptr || *endptr) {
  130                 perror("Illegal GID - Must be a number\n");
  131             }
  132             break;
  133         }
  134         case 'p': {
  135             if ((certd_pid_file = strdup(optarg)) == NULL) {
  136                 perror("Oh no ! More memory !");
  137             }
  138             break;
  139         }
  140 #ifndef NO_GETOPT_LONG
  141         case 'h': {
  142             usage();
  143         }
  144 #endif
  145         case 'r': {
  146             if (script == NULL && (script = strdup(optarg)) == NULL) {
  147                 perror("Oh no ! More memory !");
  148             }
  149             break;
  150         }
  151         case 's': {
  152             if (socketpath == NULL && (socketpath = strdup(optarg)) == NULL) {
  153                 perror("Oh no ! More memory !");
  154             }
  155             break;
  156         }
  157         case 'u': {
  158             const char *nptr;
  159             char *endptr;
  160 
  161             nptr = optarg;
  162             endptr = NULL;
  163             uid = (uid_t) strtoul(nptr, &endptr, 10);
  164             if (!*nptr || !endptr || *endptr) {
  165                 perror("Illegal UID - Must be a number\n");
  166             }
  167             break;
  168         }
  169         default:
  170             usage();
  171         }
  172     }
  173     return 0;
  174 }
  175 
  176 static int changeuidgid(void)
  177 {
  178 #ifndef NON_ROOT_FTP
  179     if (
  180 # ifdef HAVE_SETGROUPS
  181         setgroups(1U, &gid) ||
  182 # endif
  183         setgid(gid) || setegid(gid) ||
  184         setuid(uid) || seteuid(uid) || chdir("/")) {
  185         return -1;
  186     }
  187 #endif
  188     return 0;
  189 }
  190 
  191 static void newenv_str(const char * const var, const char * const str)
  192 {
  193     size_t s;
  194     char *v;
  195 
  196     if (str == NULL || *str == 0) {
  197         return;
  198     }
  199     s = strlen(var) + strlen(str) + (size_t) 2U;
  200     if ((v = malloc(s)) == NULL) {
  201         return;
  202     }
  203     if (SNCHECK(snprintf(v, s, "%s=%s", var, str), s)) {
  204         free(v);
  205         return;
  206     }
  207 #ifdef HAVE_PUTENV
  208     putenv(v);
  209 #endif
  210 }
  211 
  212 static void updatepidfile(void)
  213 {
  214     int fd;
  215     char buf[42];
  216     size_t buf_len;
  217 
  218     if (SNCHECK(snprintf(buf, sizeof buf, "%lu\n",
  219                          (unsigned long) getpid()), sizeof buf)) {
  220         return;
  221     }
  222     if (unlink(certd_pid_file) != 0 && errno != ENOENT) {
  223         return;
  224     }
  225     if ((fd = open(certd_pid_file, O_CREAT | O_WRONLY | O_TRUNC |
  226                    O_NOFOLLOW, (mode_t) 0644)) == -1) {
  227         return;
  228     }
  229     buf_len = strlen(buf);
  230     if (safe_write(fd, buf, buf_len, -1) != (ssize_t) buf_len) {
  231         ftruncate(fd, (off_t) 0);
  232     }
  233     close(fd);
  234 }
  235 
  236 static void callback_client_sni_name(const char *str)
  237 {
  238     newenv_str(ENV_CERTD_SNI_NAME, str);
  239 }
  240 
  241 static void callback_client_end(const char *str)
  242 {
  243     (void) str;
  244     ended = 1;
  245 }
  246 
  247 static void process(const int clientfd)
  248 {
  249     ssize_t readnb;
  250     char *linepnt;
  251     char *crpoint;
  252     pid_t pid;
  253     int pfds[2];
  254     char line[4096];
  255 
  256     while ((readnb = read(clientfd, line, sizeof line - 1U)) < (ssize_t) 0 &&
  257            (errno == EINTR || errno == EIO));
  258     if (readnb <= (ssize_t) 0) {
  259         return;
  260     }
  261     line[readnb] = 0;
  262     if (pipe(pfds) != 0) {
  263         return;
  264     }
  265     pid = fork();
  266     if (pid == (pid_t) -1) {
  267         close(pfds[0]);
  268         close(pfds[1]);
  269         return;
  270     }
  271     if (pid != (pid_t) 0) {
  272         close(pfds[1]);         /* close the output side of the pipe */
  273         if ((readnb = safe_read(pfds[0], line,
  274                                 sizeof line - 1U)) > (ssize_t) 0) {
  275             (void) safe_write(clientfd, line, readnb, -1);
  276         }
  277 #ifdef HAVE_WAITPID
  278         (void) waitpid(pid, NULL, 0);
  279 #else
  280         while (wait3(NULL, 0, NULL) != pid);
  281 #endif
  282         close(pfds[0]);
  283         return;
  284     }
  285     /* now, we are in the child */
  286     close(clientfd);
  287     close(kindy);
  288     close(pfds[0]);                    /* close the input side of the pipe */
  289     closedesc_all(1);
  290     linepnt = line;
  291     while ((crpoint = strchr(linepnt, '\n')) != NULL) {
  292         const CertdCallBack *scanned;
  293         size_t keyword_len;
  294 
  295         *crpoint = 0;
  296         scanned = certd_callbacks;
  297         while (scanned->keyword != NULL) {
  298             keyword_len = strlen(scanned->keyword);
  299             if (strncmp(scanned->keyword, linepnt, keyword_len) == 0) {
  300                 scanned->func(linepnt + keyword_len);
  301                 break;
  302             }
  303             scanned++;
  304         }
  305         linepnt = crpoint + 1;
  306     }
  307     if (ended == 0) {
  308         close(pfds[1]);
  309         _exit(EXIT_FAILURE);
  310     }
  311     if (dup2(pfds[1], 1) == -1) {
  312         close(pfds[1]);
  313         _exit(EXIT_FAILURE);
  314     }
  315     close(pfds[1]);
  316 #ifdef DO_CERTD_TIMEOUT
  317     (void) alarm(CERTD_SCRIPT_TIMEOUT);
  318 #endif
  319     (void) execl(script, script, (char *) NULL);
  320 
  321     _exit(EXIT_SUCCESS);
  322 }
  323 
  324 int listencnx(void)
  325 {
  326     struct sockaddr_un *saddr;
  327     int clientfd;
  328     int ret = -1;
  329     const size_t socketpath_len = strlen(socketpath);
  330 
  331     if ((saddr = malloc(sizeof(*saddr) + socketpath_len +
  332                         (size_t) 1U)) == NULL) {
  333         perror("No more memory to listen to anything");
  334         goto bye;
  335     }
  336     memcpy(saddr->sun_path, socketpath, socketpath_len + (size_t) 1U);
  337     saddr->sun_family = AF_UNIX;
  338     (void) unlink(socketpath);
  339     (void) umask(077);
  340     if ((kindy = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
  341         perror("Unable to create a local socket");
  342         goto bye;
  343     }
  344     setcloexec(kindy);
  345     if (bind(kindy, (struct sockaddr *) saddr, SUN_LEN(saddr)) != 0) {
  346         perror("Unable to bind a local socket");
  347         goto bye;
  348     }
  349     if (chmod(socketpath, 0600) != 0) {
  350         perror("Unable to change perms on the local socket");
  351         goto bye;
  352     }
  353     if (listen(kindy, CERTD_BACKLOG) != 0) {
  354         perror("Unable to listen the local socket");
  355         goto bye;
  356     }
  357     if (changeuidgid() < 0) {
  358         perror("Identity change");
  359         goto bye;
  360     }
  361     do {
  362         if ((clientfd = accept(kindy, NULL, NULL)) == -1) {
  363             if (exit_certd != 0) {
  364                 break;
  365             }
  366             (void) sleep(1);
  367             continue;
  368         }
  369         setcloexec(clientfd);
  370         process(clientfd);
  371         close(clientfd);
  372     } while (exit_certd == 0);
  373     ret = 0;
  374 
  375     bye:
  376     if (kindy != -1) {
  377         close(kindy);
  378         kindy = -1;
  379     }
  380     (void) unlink(socketpath);
  381     free(saddr);
  382 
  383     return ret;
  384 }
  385 
  386 static RETSIGTYPE sigterm(int sig)
  387 {
  388     (void) sig;
  389 
  390     exit_certd = 1;
  391     if (kindy != -1) {
  392         close(kindy);
  393         kindy = -1;
  394     }
  395 }
  396 
  397 int main(int argc, char *argv[])
  398 {
  399     int err;
  400 
  401 #ifdef HAVE_SETLOCALE
  402 # ifdef LC_MESSAGES
  403     (void) setlocale(LC_MESSAGES, "");
  404 # endif
  405 # ifdef LC_CTYPE
  406     (void) setlocale(LC_CTYPE, "");
  407 # endif
  408 # ifdef LC_COLLATE
  409     (void) setlocale(LC_COLLATE, "");
  410 # endif
  411 #endif
  412     if (init() < 0) {
  413         return -1;
  414     }
  415     (void) signal(SIGTERM, sigterm);
  416     (void) signal(SIGQUIT, sigterm);
  417     (void) signal(SIGINT, sigterm);
  418 #ifdef SIGXCPU
  419     (void) signal(SIGXCPU, sigterm);
  420 #endif
  421     if (parseoptions(argc, argv) < 0) {
  422         return -1;
  423     }
  424     if (script == NULL || *script != '/') {
  425         fprintf(stderr, "You must give -r /path/to/cert/program\n");
  426         return -2;
  427     }
  428     if (socketpath == NULL || *socketpath == 0) {
  429         fprintf(stderr, "You must give -s /path/to/socket\n");
  430         return -2;
  431     }
  432     if (daemonize != 0) {
  433         dodaemonize();
  434     }
  435     updatepidfile();
  436 #ifdef SIGPIPE
  437     signal(SIGPIPE, SIG_IGN);
  438 #endif
  439 #ifdef SIGCHLD
  440     signal(SIGCHLD, SIG_DFL);
  441 #endif
  442     err = listencnx();
  443     (void) unlink(certd_pid_file);
  444 
  445     return err;
  446 }
  447 
  448 #endif