"Fossies" - the Fresh Open Source Software Archive

Member "pure-ftpd-1.0.49/src/pure-authd.c" (2 Apr 2019, 10800 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-authd.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_EXTAUTH
    4 #include <stdio.h>
    5 
    6 int main(void)
    7 {
    8     puts("Please compile the server with --with-extauth to use this feature.\n"
    9          "Thank you.");
   10 
   11     return 0;
   12 }
   13 #else
   14 
   15 #include "ftpd.h"
   16 #include "log_extauth.h"
   17 #include "pure-authd_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 ((authd_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(authd_pid_file) != 0 && errno != ENOENT) {
  223         return;
  224     }
  225     if ((fd = open(authd_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_account(const char *str)
  237 {
  238     newenv_str(ENV_AUTHD_ACCOUNT, str);
  239 }
  240 
  241 static void callback_client_password(const char *str)
  242 {
  243     newenv_str(ENV_AUTHD_PASSWORD, str);
  244 }
  245 
  246 static void callback_client_sa_host(const char *str)
  247 {
  248     newenv_str(ENV_AUTHD_SA_HOST, str);
  249 }
  250 
  251 static void callback_client_sa_port(const char *str)
  252 {
  253     newenv_str(ENV_AUTHD_SA_PORT, str);
  254 }
  255 
  256 static void callback_client_peer_host(const char *str)
  257 {
  258     newenv_str(ENV_AUTHD_PEER_HOST, str);
  259 }
  260 
  261 static void callback_client_encrypted(const char *str)
  262 {
  263     newenv_str(ENV_AUTHD_ENCRYPTED, str);
  264 }
  265 
  266 static void callback_client_sni_name(const char *str)
  267 {
  268     if (*str != 0) {
  269         newenv_str(ENV_AUTHD_CLIENT_SNI_NAME, str);
  270     }
  271 }
  272 
  273 static void callback_client_end(const char *str)
  274 {
  275     (void) str;
  276     ended = 1;
  277 }
  278 
  279 static void process(const int clientfd)
  280 {
  281     ssize_t readnb;
  282     char *linepnt;
  283     char *crpoint;
  284     pid_t pid;
  285     int pfds[2];
  286     char line[4096];
  287 
  288     while ((readnb = read(clientfd, line, sizeof line - 1U)) < (ssize_t) 0 &&
  289            (errno == EINTR || errno == EIO));
  290     if (readnb <= (ssize_t) 0) {
  291         return;
  292     }
  293     line[readnb] = 0;
  294     if (pipe(pfds) != 0) {
  295         return;
  296     }
  297     pid = fork();
  298     if (pid == (pid_t) -1) {
  299         close(pfds[0]);
  300         close(pfds[1]);
  301         return;
  302     }
  303     if (pid != (pid_t) 0) {
  304         close(pfds[1]);         /* close the output side of the pipe */
  305         if ((readnb = safe_read(pfds[0], line,
  306                                 sizeof line - 1U)) > (ssize_t) 0) {
  307             (void) safe_write(clientfd, line, readnb, -1);
  308         }
  309 #ifdef HAVE_WAITPID
  310         (void) waitpid(pid, NULL, 0);
  311 #else
  312         while (wait3(NULL, 0, NULL) != pid);
  313 #endif
  314         close(pfds[0]);
  315         return;
  316     }
  317     /* now, we are in the child */
  318     close(clientfd);
  319     close(kindy);
  320     close(pfds[0]);                    /* close the input side of the pipe */
  321     closedesc_all(1);
  322     linepnt = line;
  323     while ((crpoint = strchr(linepnt, '\n')) != NULL) {
  324         const ExtauthdCallBack *scanned;
  325         size_t keyword_len;
  326 
  327         *crpoint = 0;
  328         scanned = extauthd_callbacks;
  329         while (scanned->keyword != NULL) {
  330             keyword_len = strlen(scanned->keyword);
  331             if (strncmp(scanned->keyword, linepnt, keyword_len) == 0) {
  332                 scanned->func(linepnt + keyword_len);
  333                 break;
  334             }
  335             scanned++;
  336         }
  337         linepnt = crpoint + 1;
  338     }
  339     if (ended == 0) {
  340         close(pfds[1]);
  341         _exit(EXIT_FAILURE);
  342     }
  343     if (dup2(pfds[1], 1) == -1) {
  344         close(pfds[1]);
  345         _exit(EXIT_FAILURE);
  346     }
  347     close(pfds[1]);
  348 #ifdef DO_AUTHD_TIMEOUT
  349     (void) alarm(AUTHD_SCRIPT_TIMEOUT);
  350 #endif
  351     (void) execl(script, script, (char *) NULL);
  352 
  353     _exit(EXIT_SUCCESS);
  354 }
  355 
  356 int listencnx(void)
  357 {
  358     struct sockaddr_un *saddr;
  359     int clientfd;
  360     int ret = -1;
  361     const size_t socketpath_len = strlen(socketpath);
  362 
  363     if ((saddr = malloc(sizeof(*saddr) + socketpath_len +
  364                         (size_t) 1U)) == NULL) {
  365         perror("No more memory to listen to anything");
  366         goto bye;
  367     }
  368     memcpy(saddr->sun_path, socketpath, socketpath_len + (size_t) 1U);
  369     saddr->sun_family = AF_UNIX;
  370     (void) unlink(socketpath);
  371     (void) umask(077);
  372     if ((kindy = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
  373         perror("Unable to create a local socket");
  374         goto bye;
  375     }
  376     setcloexec(kindy);
  377     if (bind(kindy, (struct sockaddr *) saddr, SUN_LEN(saddr)) != 0) {
  378         perror("Unable to bind a local socket");
  379         goto bye;
  380     }
  381     if (chmod(socketpath, 0600) != 0) {
  382         perror("Unable to change perms on the local socket");
  383         goto bye;
  384     }
  385     if (listen(kindy, AUTHD_BACKLOG) != 0) {
  386         perror("Unable to listen the local socket");
  387         goto bye;
  388     }
  389     if (changeuidgid() < 0) {
  390         perror("Identity change");
  391         (void) unlink(authd_pid_file);
  392         return -1;
  393     }
  394     do {
  395         if ((clientfd = accept(kindy, NULL, NULL)) == -1) {
  396             if (exit_authd != 0) {
  397                 break;
  398             }
  399             (void) sleep(1);
  400             continue;
  401         }
  402         setcloexec(clientfd);
  403         process(clientfd);
  404         close(clientfd);
  405     } while (exit_authd == 0);
  406     ret = 0;
  407 
  408     bye:
  409     if (kindy != -1) {
  410         close(kindy);
  411         kindy = -1;
  412     }
  413     (void) unlink(socketpath);
  414     free(saddr);
  415 
  416     return ret;
  417 }
  418 
  419 static RETSIGTYPE sigterm(int sig)
  420 {
  421     (void) sig;
  422 
  423     exit_authd = 1;
  424     if (kindy != -1) {
  425         close(kindy);
  426         kindy = -1;
  427     }
  428 }
  429 
  430 int main(int argc, char *argv[])
  431 {
  432     int err;
  433 
  434 #ifdef HAVE_SETLOCALE
  435 # ifdef LC_MESSAGES
  436     (void) setlocale(LC_MESSAGES, "");
  437 # endif
  438 # ifdef LC_CTYPE
  439     (void) setlocale(LC_CTYPE, "");
  440 # endif
  441 # ifdef LC_COLLATE
  442     (void) setlocale(LC_COLLATE, "");
  443 # endif
  444 #endif
  445     if (init() < 0) {
  446         return -1;
  447     }
  448     (void) signal(SIGTERM, sigterm);
  449     (void) signal(SIGQUIT, sigterm);
  450     (void) signal(SIGINT, sigterm);
  451 #ifdef SIGXCPU
  452     (void) signal(SIGXCPU, sigterm);
  453 #endif
  454     if (parseoptions(argc, argv) < 0) {
  455         return -1;
  456     }
  457     if (script == NULL || *script != '/') {
  458         fprintf(stderr, "You must give -r /path/to/auth/program\n");
  459         return -2;
  460     }
  461     if (socketpath == NULL || *socketpath == 0) {
  462         fprintf(stderr, "You must give -s /path/to/socket\n");
  463         return -2;
  464     }
  465     if (daemonize != 0) {
  466         dodaemonize();
  467     }
  468     updatepidfile();
  469 #ifdef SIGPIPE
  470     signal(SIGPIPE, SIG_IGN);
  471 #endif
  472 #ifdef SIGCHLD
  473     signal(SIGCHLD, SIG_DFL);
  474 #endif
  475     err = listencnx();
  476     (void) unlink(authd_pid_file);
  477 
  478     return err;
  479 }
  480 
  481 #endif