Added the functions `strjoin' and `escape_slashes' to `common.c'.
authorocto <octo>
Wed, 21 Dec 2005 09:57:13 +0000 (09:57 +0000)
committerocto <octo>
Wed, 21 Dec 2005 09:57:13 +0000 (09:57 +0000)
Changed `check_create_dir' so it can recursively create directories.
Documented `strsplit', `strjoin' and `escape_slashes' in `common.h'.

src/common.c
src/common.h

index 1eec286..db8fce1 100644 (file)
@@ -94,32 +94,172 @@ int strsplit (char *string, char **fields, size_t size)
        return (i);
 }
 
+int strjoin (char *dst, size_t dst_len,
+               char **fields, size_t fields_num,
+               const char *sep)
+{
+       int field_len;
+       int sep_len;
+       int i;
+
+       memset (dst, '\0', dst_len);
+
+       if (fields_num <= 0)
+               return (-1);
+
+       sep_len = 0;
+       if (sep != NULL)
+               sep_len = strlen (sep);
+
+       for (i = 0; i < fields_num; i++)
+       {
+               if ((i > 0) && (sep_len > 0))
+               {
+                       if (dst_len <= sep_len)
+                               return (-1);
+
+                       strncat (dst, sep, dst_len);
+                       dst_len -= sep_len;
+               }
+
+               field_len = strlen (fields[i]);
+
+               if (dst_len <= field_len)
+                       return (-1);
+
+               strncat (dst, fields[i], dst_len);
+               dst_len -= field_len;
+       }
+
+       return (strlen (dst));
+}
+
+int escape_slashes (char *buf, int buf_len)
+{
+       int i;
+
+       if (strcmp (buf, "/") == 0)
+       {
+               if (buf_len < 5)
+                       return (-1);
+
+               strncpy (buf, "root", buf_len);
+               return (0);
+       }
+
+       /* Move one to the left */
+       memmove (buf, buf + 1, buf_len - 1);
+
+       for (i = 0; i < buf_len - 1; i++)
+       {
+               if (buf[i] == '\0')
+                       break;
+               else if (buf[i] == '/')
+                       buf[i] = '_';
+       }
+       buf[i] = '\0';
+
+       return (0);
+}
+
 #ifdef HAVE_LIBRRD
-int check_create_dir (char *dir)
+int check_create_dir (const char *file_orig)
 {
        struct stat statbuf;
 
-       if (stat (dir, &statbuf) == -1)
+       char  file_copy[512];
+       char  dir[512];
+       int   dir_len = 512;
+       char *fields[16];
+       int   fields_num;
+       char *ptr;
+       int   last_is_file = 1;
+       int   len;
+       int   i;
+
+       /*
+        * Sanity checks first
+        */
+       if (file_orig == NULL)
+               return (-1);
+
+       if ((len = strlen (file_orig)) < 1)
+               return (-1);
+       else if (len >= 512)
+               return (-1);
+
+       /*
+        * If `file_orig' ends in a slash the last component is a directory,
+        * otherwise it's a file. Act accordingly..
+        */
+       if (file_orig[len - 1] == '/')
+               last_is_file = 0;
+
+       /*
+        * Create a copy for `strtok' to destroy
+        */
+       strncpy (file_copy, file_orig, 512);
+       file_copy[511] = '\0';
+
+       /*
+        * Break into components. This will eat up several slashes in a row and
+        * remove leading and trailing slashes..
+        */
+       ptr = file_copy;
+       fields_num = 0;
+       while ((fields[fields_num] = strtok (ptr, "/")) != NULL)
        {
-               if (errno == ENOENT)
+               ptr = NULL;
+               fields_num++;
+
+               if (fields_num >= 16)
+                       break;
+       }
+
+       /*
+        * For each component, do..
+        */
+       for (i = 0; i < (fields_num - last_is_file); i++)
+       {
+               /*
+                * Join the components together again
+                */
+               if (strjoin (dir, dir_len, fields, i + 1, "/") < 0)
+                       return (-1);
+
+               /*
+                * Do not create directories that start with a dot. This
+                * prevents `../../' attacks and other likely malicious
+                * behavior.
+                */
+               if (fields[i][0] == '.')
+               {
+                       syslog (LOG_ERR, "Cowardly refusing to create a directory that begins with a `.' (dot): `%s'", dir);
+                       return (-2);
+               }
+
+               if (stat (dir, &statbuf) == -1)
                {
-                       if (mkdir (dir, 0755) == -1)
+                       if (errno == ENOENT)
+                       {
+                               if (mkdir (dir, 0755) == -1)
+                               {
+                                       syslog (LOG_ERR, "mkdir (%s): %s", dir, strerror (errno));
+                                       return (-1);
+                               }
+                       }
+                       else
                        {
-                               syslog (LOG_ERR, "mkdir (%s): %s", dir, strerror (errno));
+                               syslog (LOG_ERR, "stat (%s): %s", dir, strerror (errno));
                                return (-1);
                        }
                }
-               else
+               else if (!S_ISDIR (statbuf.st_mode))
                {
-                       syslog (LOG_ERR, "stat (%s): %s", dir, strerror (errno));
+                       syslog (LOG_ERR, "stat (%s): Not a directory!", dir);
                        return (-1);
                }
        }
-       else if (!S_ISDIR (statbuf.st_mode))
-       {
-               syslog (LOG_ERR, "stat %s: Not a directory!", dir);
-               return (-1);
-       }
 
        return (0);
 }
index a3fe5fd..59984b1 100644 (file)
@@ -37,8 +37,72 @@ void sstrncpy(char *d, const char *s, int len);
 char *sstrdup(const char *s);
 void *smalloc(size_t size);
 
+/*
+ * NAME
+ *   strsplit
+ *
+ * DESCRIPTION
+ *   Splits a string into parts and stores pointers to the parts in `fields'.
+ *   The characters split at are ` ' (space) and "\t" (tab).
+ *
+ * PARAMETERS
+ *   `string'      String to split. This string will be modified. `fields' will
+ *                 contain pointers to parts of this string, so free'ing it
+ *                 will destroy `fields' as well.
+ *   `fields'      Array of strings where pointers to the parts will be stored.
+ *   `size'        Number of elements in the array. No more than `size'
+ *                 pointers will be stored in `fields'.
+ *
+ * RETURN VALUE
+ *    Returns the number of parts stored in `fields'.
+ */
 int strsplit (char *string, char **fields, size_t size);
 
+/*
+ * NAME
+ *   strjoin
+ *
+ * DESCRIPTION
+ *   Joins together several parts of a string using `sep' as a seperator. This
+ *   is equipollent to the perl buildin `join'.
+ *
+ * PARAMETERS
+ *   `dst'         Buffer where the result is stored.
+ *   `dst_len'     Length of the destination buffer. No more than this many
+ *                 bytes will be written to the memory pointed to by `dst',
+ *                 including the trailing null-byte.
+ *   `fields'      Array of strings to be joined.
+ *   `fields_num'  Number of elements in the `fields' array.
+ *   `sep'         String to be inserted between any two elements of `fields'.
+ *                 This string is neither prepended nor appended to the result.
+ *                 Instead of passing "" (empty string) one can pass NULL.
+ *
+ * RETURN VALUE
+ *   Returns the number of characters in `dst', NOT including the trailing
+ *   null-byte. If an error occured (empty array or `dst' too small) a value
+ *   smaller than zero will be returned.
+ */
+int strjoin (char *dst, size_t dst_len, char **fields, size_t fields_num, const char *sep);
+
+/*
+ * NAME
+ *   escape_slashes
+ *
+ * DESCRIPTION
+ *   Removes slashes from the string `buf' and substitutes them with something
+ *   appropriate. This function should be used whenever a path is to be used as
+ *   (part of) an instance.
+ *
+ * PARAMETERS
+ *   `buf'         String to be escaped.
+ *   `buf_len'     Length of the buffer. No more then this many bytes will be
+ *   written to `buf', including the trailing null-byte.
+ *
+ * RETURN VALUE
+ *   Returns zero upon success and a value smaller than zero upon failure.
+ */
+int escape_slashes (char *buf, int buf_len);
+
 int rrd_update_file (char *host, char *file, char *values, char **ds_def,
                int ds_num);