Make path appear as if a chroot had occurred. This handles a leading * "/" (either removing it or expanding it) and any leading or embedded * ".." components that attempt to escape past the module's top dir. * * If dest is NULL, a buffer is allocated to hold the result. It is legal * to call with the dest and the path (p) pointing to the same buffer, but * rootdir will be ignored to avoid
| 1054 | * string up to "depth" deep). If the resulting name would be empty, |
| 1055 | * change it into a ".". */ |
| 1056 | char *sanitize_path(char *dest, const char *p, const char *rootdir, int depth, int flags) |
| 1057 | { |
| 1058 | char *start, *sanp; |
| 1059 | int rlen = 0, drop_dot_dirs = !relative_paths || !(flags & SP_KEEP_DOT_DIRS); |
| 1060 | |
| 1061 | if (dest != p) { |
| 1062 | int plen = strlen(p); /* the path len INCLUDING any separating slash */ |
| 1063 | if (*p == '/') { |
| 1064 | if (!rootdir) |
| 1065 | rootdir = module_dir; |
| 1066 | rlen = strlen(rootdir); |
| 1067 | depth = 0; |
| 1068 | p++; |
| 1069 | } |
| 1070 | if (!dest) |
| 1071 | dest = new_array(char, MAX(rlen + plen + 1, 2)); |
| 1072 | else if (rlen + plen + 1 >= MAXPATHLEN) |
| 1073 | return NULL; |
| 1074 | if (rlen) { /* only true if p previously started with a slash */ |
| 1075 | memcpy(dest, rootdir, rlen); |
| 1076 | if (rlen > 1) /* a rootdir of len 1 is "/", so this avoids a 2nd slash */ |
| 1077 | dest[rlen++] = '/'; |
| 1078 | } |
| 1079 | } |
| 1080 | |
| 1081 | if (drop_dot_dirs) { |
| 1082 | while (*p == '.' && p[1] == '/') |
| 1083 | p += 2; |
| 1084 | } |
| 1085 | |
| 1086 | start = sanp = dest + rlen; |
| 1087 | /* This loop iterates once per filename component in p, pointing at |
| 1088 | * the start of the name (past any prior slash) for each iteration. */ |
| 1089 | while (*p) { |
| 1090 | /* discard leading or extra slashes */ |
| 1091 | if (*p == '/') { |
| 1092 | p++; |
| 1093 | continue; |
| 1094 | } |
| 1095 | if (drop_dot_dirs) { |
| 1096 | if (*p == '.' && (p[1] == '/' || p[1] == '\0')) { |
| 1097 | /* skip "." component */ |
| 1098 | p++; |
| 1099 | continue; |
| 1100 | } |
| 1101 | } |
| 1102 | if (*p == '.' && p[1] == '.' && (p[2] == '/' || p[2] == '\0')) { |
| 1103 | /* ".." component followed by slash or end */ |
| 1104 | if (depth <= 0 || sanp != start) { |
| 1105 | p += 2; |
| 1106 | if (sanp != start) { |
| 1107 | /* back up sanp one level */ |
| 1108 | --sanp; /* now pointing at slash */ |
| 1109 | while (sanp > start && sanp[-1] != '/') |
| 1110 | sanp--; |
| 1111 | } |
| 1112 | continue; |
| 1113 | } |
no outgoing calls
no test coverage detected