From 6180d760a005346e40908d07e618bd93efa51ffd Mon Sep 17 00:00:00 2001 From: octo Date: Wed, 21 Dec 2005 09:57:13 +0000 Subject: [PATCH] Added the functions `strjoin' and `escape_slashes' to `common.c'. Changed `check_create_dir' so it can recursively create directories. Documented `strsplit', `strjoin' and `escape_slashes' in `common.h'. --- src/common.c | 164 +++++++++++++++++++++++++++++++++++++++++++++++---- src/common.h | 64 ++++++++++++++++++++ 2 files changed, 216 insertions(+), 12 deletions(-) diff --git a/src/common.c b/src/common.c index 1eec286a..db8fce1a 100644 --- a/src/common.c +++ b/src/common.c @@ -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); } diff --git a/src/common.h b/src/common.h index a3fe5fde..59984b18 100644 --- a/src/common.h +++ b/src/common.h @@ -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); -- 2.30.2