"Fossies" - the Fresh Open Source Software Archive

Member "darkstat-3.0.721/conv.c" (12 Jan 2022, 9354 Bytes) of package /linux/privat/darkstat-3.0.721.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 "conv.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 3.0.719_vs_3.0.721.

    1 /* darkstat 3
    2  * copyright (c) 2001-2014 Emil Mikulic.
    3  *
    4  * conv.c: convenience functions.
    5  *
    6  * Permission to use, copy, modify, and distribute this file for any
    7  * purpose with or without fee is hereby granted, provided that the above
    8  * copyright notice and this permission notice appear in all copies.
    9  *
   10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
   12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
   13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
   14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
   15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
   16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   17  */
   18 
   19 #include "conv.h"
   20 
   21 #include <sys/wait.h>
   22 #include <assert.h>
   23 #include <ctype.h>
   24 #include "err.h"
   25 #include <errno.h>
   26 #include <fcntl.h>
   27 #include <grp.h>
   28 #include <limits.h>
   29 #include <pwd.h>
   30 #include <stdio.h>
   31 #include <stdlib.h>
   32 #include <string.h>
   33 #include <time.h>
   34 #include <unistd.h>
   35 
   36 #define PATH_DEVNULL "/dev/null"
   37 
   38 /* malloc() that exits on failure. */
   39 void *
   40 xmalloc(const size_t size)
   41 {
   42    void *ptr = malloc(size);
   43 
   44    if (ptr == NULL)
   45       errx(1, "malloc(): out of memory");
   46    return (ptr);
   47 }
   48 
   49 /* calloc() that exits on failure. */
   50 void *
   51 xcalloc(const size_t num, const size_t size)
   52 {
   53    void *ptr = calloc(num, size);
   54 
   55    if (ptr == NULL)
   56       errx(1, "calloc(): out of memory");
   57    return (ptr);
   58 }
   59 
   60 /* realloc() that exits on failure. */
   61 void *
   62 xrealloc(void *original, const size_t size)
   63 {
   64     void *ptr = realloc(original, size);
   65 
   66     if (ptr == NULL)
   67       errx(1, "realloc(): out of memory");
   68     return (ptr);
   69 }
   70 
   71 /* strdup() that exits on failure. */
   72 char *
   73 xstrdup(const char *s)
   74 {
   75    char *tmp = strdup(s);
   76 
   77    if (tmp == NULL)
   78       errx(1, "strdup(): out of memory");
   79    return (tmp);
   80 }
   81 
   82 /* ---------------------------------------------------------------------------
   83  * Split string out of src with range [left:right-1]
   84  */
   85 char *
   86 split_string(const char *src, const size_t left, const size_t right)
   87 {
   88     char *dest;
   89     assert(left <= right);
   90     assert(left < strlen(src));   /* [left means must be smaller */
   91     assert(right <= strlen(src)); /* right) means can be equal or smaller */
   92 
   93     dest = xmalloc(right - left + 1);
   94     memcpy(dest, src+left, right-left);
   95     dest[right-left] = '\0';
   96     return (dest);
   97 }
   98 
   99 /* ---------------------------------------------------------------------------
  100  * Uppercasify all characters in a string of given length.
  101  */
  102 void
  103 strntoupper(char *str, const size_t length)
  104 {
  105     size_t i;
  106 
  107     for (i=0; i<length; i++)
  108         str[i] = toupper(str[i]);
  109 }
  110 
  111 /* ---------------------------------------------------------------------------
  112  * Returns non-zero if haystack starts with needle.
  113  */
  114 int
  115 str_starts_with(const char *haystack, const char *needle)
  116 {
  117    int i = 0;
  118 
  119    while (needle[i] != '\0') {
  120       if ((haystack[i] == '\0') || (haystack[i] != needle[i]))
  121          return (0);
  122       i++;
  123    }
  124    return (1);
  125 }
  126 
  127 /* split - splits a string by a delimiter character into an array of
  128  * string chunks.
  129  *
  130  * The chunks and the array are dynamically allocated using xmalloc() so
  131  * it will errx() if it runs out of memory.
  132  *
  133  *    int num_chunks;
  134  *    char **chunks = split('.', "..one...two....", &num_chunks);
  135  *
  136  *    num_chunks = 2, chunks = { "one", "two", NULL }
  137  */
  138 char **
  139 split(const char delimiter, const char *str, unsigned int *num_chunks)
  140 {
  141    unsigned int num = 0;
  142    char **chunks = NULL;
  143    size_t left, right = 0;
  144 
  145    #define PUSH(c) do { num++;  chunks = (char**) xrealloc(chunks, \
  146       sizeof(*chunks) * num);  chunks[num-1] = c; } while(0)
  147 
  148    for(;;) {
  149       /* find first non-delimiter */
  150       for (left = right; str[left] == delimiter; left++)
  151             ;
  152 
  153       if (str[left] == '\0')
  154          break; /* ran out of string */
  155 
  156       /* find first delimiter or end of string */
  157       for (right=left+1;
  158          str[right] != delimiter && str[right] != '\0';
  159          right++)
  160             ;
  161 
  162       /* split chunk out */
  163       PUSH( split_string(str, left, right) );
  164 
  165       if (str[right] == '\0')
  166          break; /* ran out of string */
  167       else
  168          right++;
  169    }
  170 
  171    /* return */
  172    PUSH(NULL);
  173    if (num_chunks != NULL)
  174       *num_chunks = num-1; /* NULL doesn't count */
  175    return (chunks);
  176    #undef PUSH
  177 }
  178 
  179 /* Given an HTTP query string and a key to search for, return the value
  180  * associated with it, or NULL if there is no such key or qs is NULL.
  181  * The returned string needs to be freed.
  182  *
  183  * e.g.:
  184  * qs = "sort=in&start=20";
  185  * qs_get(sq, "sort") returns "in"
  186  * qs_get(sq, "end") returns NULL
  187  */
  188 char *
  189 qs_get(const char *qs, const char *key)
  190 {
  191    size_t pos, qslen, keylen;
  192 
  193    if (qs == NULL) return NULL;
  194 
  195    qslen = strlen(qs);
  196    keylen = strlen(key);
  197    pos = 0;
  198    while (pos < qslen) {
  199       if (!(pos + keylen + 1 < qslen))
  200          /* not enough room for "key" + "=" */
  201          return NULL;
  202       else {
  203          if (str_starts_with(qs+pos, key) && qs[pos+keylen] == '=') {
  204             /* found key= */
  205             size_t start, end;
  206 
  207             start = pos + keylen + 1;
  208             for (end=start; end<qslen && qs[end] != '&'; end++)
  209                ;
  210             return split_string(qs, start, end);
  211          } else {
  212             /* didn't find key, skip to next & */
  213             do { pos++; } while ((pos < qslen) && (qs[pos] != '&'));
  214             pos++; /* skip the ampersand */
  215          }
  216       }
  217    }
  218    return NULL; /* not found */
  219 }
  220 
  221 static int lifeline[2] = { -1, -1 };
  222 static int fd_null = -1;
  223 
  224 void
  225 daemonize_start(void)
  226 {
  227    pid_t f, w;
  228 
  229    if (pipe(lifeline) == -1)
  230       err(1, "pipe(lifeline)");
  231 
  232    fd_null = open(PATH_DEVNULL, O_RDWR, 0);
  233    if (fd_null == -1)
  234       err(1, "open(" PATH_DEVNULL ")");
  235 
  236    f = fork();
  237    if (f == -1)
  238       err(1, "fork");
  239    else if (f != 0) {
  240       /* parent: wait for child */
  241       char tmp[1];
  242       int status;
  243 
  244       verbosef("parent waiting");
  245       if (close(lifeline[1]) == -1)
  246          warn("close lifeline in parent");
  247       if (read(lifeline[0], tmp, sizeof(tmp)) != 0) /* expecting EOF */
  248          err(1, "lifeline read() failed");
  249       verbosef("parent done reading, calling waitpid");
  250       w = waitpid(f, &status, WNOHANG);
  251       verbosef("waitpid ret %d, status is %d", w, status);
  252       if (w == -1)
  253          err(1, "waitpid");
  254       else if (w == 0)
  255          /* child is running happily */
  256          exit(EXIT_SUCCESS);
  257       else
  258          /* child init failed, pass on its exit status */
  259          exit(WEXITSTATUS(status));
  260    }
  261    /* else we are the child: continue initializing */
  262 }
  263 
  264 void
  265 daemonize_finish(void)
  266 {
  267    if (fd_null == -1)
  268       return; /* didn't daemonize_start(), i.e. we're not daemonizing */
  269 
  270    if (setsid() == -1)
  271       err(1, "setsid");
  272    if (close(lifeline[0]) == -1)
  273       warn("close read end of lifeline in child");
  274    if (close(lifeline[1]) == -1)
  275       warn("couldn't cut the lifeline");
  276 
  277    /* close all our std fds */
  278    if (dup2(fd_null, STDIN_FILENO) == -1)
  279       warn("dup2(stdin)");
  280    if (dup2(fd_null, STDOUT_FILENO) == -1)
  281       warn("dup2(stdout)");
  282    if (dup2(fd_null, STDERR_FILENO) == -1)
  283       warn("dup2(stderr)");
  284    if (fd_null > 2)
  285       close(fd_null);
  286 }
  287 
  288 /*
  289  * For security, chroot (optionally) and drop privileges.
  290  * Pass a NULL chroot_dir to disable chroot() behaviour.
  291  */
  292 void privdrop(const char *chroot_dir, const char *privdrop_user) {
  293    struct passwd *pw;
  294 
  295    errno = 0;
  296    pw = getpwnam(privdrop_user);
  297 
  298    if (pw == NULL) {
  299       if (errno == 0)
  300          errx(1, "getpwnam(\"%s\") failed: no such user", privdrop_user);
  301       else
  302          err(1, "getpwnam(\"%s\") failed", privdrop_user);
  303    }
  304    if (chroot_dir == NULL) {
  305       verbosef("no --chroot dir specified, darkstat will not chroot()");
  306    } else {
  307       /* Read /etc/localtime before we chroot. This works on FreeBSD but not
  308        * on Linux / with glibc (as of 2.22) */
  309       tzset();
  310       if (chroot(chroot_dir) == -1)
  311          err(1, "chroot(\"%s\") failed", chroot_dir);
  312       if (chdir("/") == -1)
  313          err(1, "chdir(\"/\") failed");
  314       verbosef("chrooted into: %s", chroot_dir);
  315    }
  316    {
  317       gid_t list[1];
  318       list[0] = pw->pw_gid;
  319       if (setgroups(1, list) == -1)
  320          err(1, "setgroups");
  321    }
  322    if (setgid(pw->pw_gid) == -1)
  323       err(1, "setgid");
  324    if (setuid(pw->pw_uid) == -1)
  325       err(1, "setuid");
  326    verbosef("set uid/gid to %d/%d", (int)pw->pw_uid, (int)pw->pw_gid);
  327 }
  328 
  329 /* Make the specified file descriptor non-blocking. */
  330 void
  331 fd_set_nonblock(const int fd)
  332 {
  333    int flags;
  334 
  335    if ((flags = fcntl(fd, F_GETFL, 0)) == -1)
  336       err(1, "fcntl(fd %d) to get flags", fd);
  337    flags |= O_NONBLOCK;
  338    if (fcntl(fd, F_SETFL, flags) == -1)
  339       err(1, "fcntl(fd %d) to set O_NONBLOCK", fd);
  340    assert( (fcntl(fd, F_GETFL, 0) & O_NONBLOCK ) == O_NONBLOCK );
  341 }
  342 
  343 /* Make the specified file descriptor blocking. */
  344 void
  345 fd_set_block(const int fd)
  346 {
  347    int flags;
  348 
  349    if ((flags = fcntl(fd, F_GETFL, 0)) == -1)
  350       err(1, "fcntl(fd %d) to get flags", fd);
  351    flags &= ~O_NONBLOCK;
  352    if (fcntl(fd, F_SETFL, flags) == -1)
  353       err(1, "fcntl(fd %d) to unset O_NONBLOCK", fd);
  354    assert( (fcntl(fd, F_GETFL, 0) & O_NONBLOCK ) == 0 );
  355 }
  356 
  357 /* vim:set ts=3 sw=3 tw=78 expandtab: */