diff options
author | Noriko Hosoi <nhosoi@redhat.com> | 2006-01-10 23:53:08 +0000 |
---|---|---|
committer | Noriko Hosoi <nhosoi@redhat.com> | 2006-01-10 23:53:08 +0000 |
commit | 67385d898398f60886047b9239d027cf997f9433 (patch) | |
tree | c7f9daeed093bdef2afa6f809c13cdfb457a94c7 /ldap/servers/slapd/util.c | |
parent | 4120eda907e600d7d4b7c3b54e747db8284b4037 (diff) | |
download | ds-67385d898398f60886047b9239d027cf997f9433.tar.gz ds-67385d898398f60886047b9239d027cf997f9433.tar.xz ds-67385d898398f60886047b9239d027cf997f9433.zip |
[174776] Multiple restores from a non-existant directory could wipe out database
If the specified backup dir does not exist, does not contain necessary files
(including the directory is not accessible), is not a directory, or is
identical to the path to the db dir, issues an error and stops restoring before
wiping out the database.
Diffstat (limited to 'ldap/servers/slapd/util.c')
-rw-r--r-- | ldap/servers/slapd/util.c | 159 |
1 files changed, 123 insertions, 36 deletions
diff --git a/ldap/servers/slapd/util.c b/ldap/servers/slapd/util.c index a129c6cc..a531e94c 100644 --- a/ldap/servers/slapd/util.c +++ b/ldap/servers/slapd/util.c @@ -44,6 +44,7 @@ #include <unistd.h> #include <pwd.h> #endif +#include <libgen.h> #include <pk11func.h> #include "slap.h" #include "prtime.h" @@ -53,6 +54,14 @@ #define UTIL_ESCAPE_HEX 1 #define UTIL_ESCAPE_BACKSLASH 2 +#if defined( _WIN32 ) +#define _PSEP "\\" +#define _CSEP '\\' +#else +#define _PSEP "/" +#define _CSEP '/' +#endif + static int special_np(unsigned char c) { if(c < 32 || c > 126) { @@ -383,6 +392,60 @@ is_abspath(const char *path) return 0; /* not an abs path */ } +static void +clean_path(char **norm_path) +{ + char **np; + + for (np = norm_path; np && *np; np++) + slapi_ch_free((void **)np); + slapi_ch_free((void **)&norm_path); +} + +static char ** +normalize_path(char *path) +{ + char *dname = slapi_ch_strdup(path); + char *dnamep = dname; + char *bnamep = NULL; + char **dirs = (char **)slapi_ch_calloc(strlen(path), 1); + char **rdirs = (char **)slapi_ch_calloc(strlen(path), 1); + char **dp = dirs; + char **rdp; + do { + bnamep = basename(dnamep); + if (0 != strcmp(bnamep, ".")) { + *dp++ = slapi_ch_strdup(bnamep); /* remove "/./" in the path */ + } + dnamep = dirname(dnamep); + } while (strcmp(dnamep, _PSEP) && + !(0 == strcmp(dnamep, ".") && 0 == strcmp(bnamep, "."))); + + /* remove "xxx/.." in the path */ + for (dp = dirs, rdp = rdirs; dp && *dp; dp++) { + while (*dp && 0 == strcmp(*dp, "..")) { + dp++; + if (rdp > rdirs) + rdp--; + } + if (*dp) + *rdp++ = slapi_ch_strdup(*dp); + } + for (--dp, rdp = rdirs; dp >= dirs; dp--) { + while (*dp && 0 == strcmp(*dp, "..")) { + dp--; + if (rdp > rdirs) + rdp--; + } + if (*dp) + *rdp++ = slapi_ch_strdup(*dp); + } + + clean_path(dirs); + slapi_ch_free_string(&dname); + + return rdirs; +} /* * Take "relpath" and prepend the current working directory to it @@ -399,13 +462,10 @@ rel2abspath( char *relpath ) CHAR szDir[_MAX_DIR]; CHAR szFname[_MAX_FNAME]; CHAR szExt[_MAX_EXT]; -#define _PSEP "\\" -#else -#define _PSEP "/" #endif if ( relpath == NULL ) { - return NULL; + return NULL; } #if defined( _WIN32 ) @@ -413,41 +473,51 @@ rel2abspath( char *relpath ) memset (&szDir, 0, sizeof (szDir)); memset (&szFname, 0, sizeof (szFname)); memset (&szExt, 0, sizeof (szExt)); - _splitpath( relpath, szDrive, szDir, szFname, szExt ); - if( szDrive[0] && szDir[0] ) - return( slapi_ch_strdup( relpath )); - if ( relpath[ 0 ] == '/' || relpath[ 0 ] == '\\' ) { - return( slapi_ch_strdup( relpath )); -#else - if ( relpath[ 0 ] == '/' ) { - return( slapi_ch_strdup( relpath )); - } + _splitpath( relpath, szDrive, szDir, szFname, szExt ); + if( szDrive[0] && szDir[0] ) + return( slapi_ch_strdup( relpath )); #endif - - if ( getcwd( abspath, MAXPATHLEN ) == NULL ) { - perror( "getcwd" ); - LDAPDebug( LDAP_DEBUG_ANY, "Cannot determine current directory\n", - 0, 0, 0 ); - exit( 1 ); - } - - if ( strlen( relpath ) + strlen( abspath ) + 1 > MAXPATHLEN ) { - LDAPDebug( LDAP_DEBUG_ANY, "Pathname \"%s" _PSEP "%s\" too long\n", - abspath, relpath, 0 ); - exit( 1 ); + if ( relpath[ 0 ] == _CSEP ) { /* absolute path */ + PR_snprintf(abspath, sizeof(abspath), "%s", relpath); + } else { /* relative path */ + if ( getcwd( abspath, MAXPATHLEN ) == NULL ) { + perror( "getcwd" ); + LDAPDebug( LDAP_DEBUG_ANY, "Cannot determine current directory\n", + 0, 0, 0 ); + exit( 1 ); + } + + if ( strlen( relpath ) + strlen( abspath ) + 1 > MAXPATHLEN ) { + LDAPDebug( LDAP_DEBUG_ANY, "Pathname \"%s" _PSEP "%s\" too long\n", + abspath, relpath, 0 ); + exit( 1 ); + } + + if ( strcmp( relpath, "." )) { + if ( abspath[ 0 ] != '\0' && + abspath[ strlen( abspath ) - 1 ] != _CSEP ) + { + PL_strcatn( abspath, sizeof(abspath), "/" ); + } + PL_strcatn( abspath, sizeof(abspath), relpath ); + } } - - if ( strcmp( relpath, "." )) { -#if defined( _WIN32 ) - if ( abspath[ 0 ] != '\0' && abspath[ strlen( abspath ) - 1 ] != '/' && abspath[ strlen( abspath ) - 1 ] != '\\' ) -#else - if ( abspath[ 0 ] != '\0' && abspath[ strlen( abspath ) - 1 ] != '/' ) { -#endif - PL_strcatn( abspath, sizeof(abspath), "/" ); - } - PL_strcatn( abspath, sizeof(abspath), relpath ); + { + char **norm_path = normalize_path(abspath); + char *retpath = slapi_ch_strdup(abspath); /* size is long enough */ + char **np, *rp; + int pathlen = strlen(abspath) + 1; + int usedlen = 0; + for (np = norm_path, rp = retpath; np && *np; np++) { + int thislen = strlen(*np) + 1; + if (0 != strcmp(*np, _PSEP)) + PR_snprintf(rp, pathlen - usedlen, "%c%s", _CSEP, *np); + rp += thislen; + usedlen += thislen; + } + clean_path(norm_path); + return retpath; } - return( slapi_ch_strdup( abspath )); } @@ -658,3 +728,20 @@ slapd_chown_if_not_owner(const char *filename, uid_t uid, gid_t gid) return result; } +/* + * Compare 2 pathes + * Paths could contain ".", "..", "//" in the path, thus normalize them first. + * One or two of the paths could be a relative path. + */ +int +slapd_comp_path(char *p0, char *p1) +{ + int rval = 0; + char *norm_p0 = rel2abspath(p0); + char *norm_p1 = rel2abspath(p1); + + rval = strcmp(norm_p0, norm_p1); + slapi_ch_free_string(&norm_p0); + slapi_ch_free_string(&norm_p1); + return rval; +} |