diff options
Diffstat (limited to 'src/lib/escape/escape_unistd.c')
-rw-r--r-- | src/lib/escape/escape_unistd.c | 186 |
1 files changed, 186 insertions, 0 deletions
diff --git a/src/lib/escape/escape_unistd.c b/src/lib/escape/escape_unistd.c new file mode 100644 index 0000000000..5dbbb18634 --- /dev/null +++ b/src/lib/escape/escape_unistd.c @@ -0,0 +1,186 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif /* HAVE_CONFIG_H */ + +#ifdef HAVE_ERRNO_H +#include <errno.h> +#endif /* HAVE_ERRNO_H */ + +#include <sys/types.h> /* See NOTES */ +#include <sys/socket.h> +#include <net/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <net/net.h> +#include <string.h> +#include <libiberty.h> +#include <sys/stat.h> + +#include "Escape.h" + +char * +escape_realpath(const char *path, char *resolved_path) +{ + char *real = lrealpath (path); + + if (real) + { + if (resolved_path) + { + memcpy (resolved_path, real, PATH_MAX); + free (real); + return resolved_path; + } + else + { + return real; + } + } + + return NULL; +} + +int +escape_access(const char *pathname, int mode) +{ + struct stat stat_buf; + + if (stat(pathname, &stat_buf) != 0) + return -1; + + if (mode == F_OK) + return 0; + if (mode == R_OK) + { + if (stat_buf.st_mode & S_IRUSR) + return 0; + errno = EACCES; + return -1; + } + if (mode == W_OK) + { + if (stat_buf.st_mode & S_IWUSR) + return 0; + errno = EROFS; + return -1; + } + if (mode == X_OK) + { + if (stat_buf.st_mode & S_IXUSR) + return 0; + errno = EACCES; + return -1; + } + + return 0; +} + +EAPI ssize_t +escape_readlink(const char *path, + char *buf, + size_t bufsize) +{ + errno = EINVAL; + return -1; +} + +EAPI int +escape_symlink(const char *path1, const char *path2) +{ + errno = EINVAL; + return -1; +} + +/* + * The code of the following functions has been kindly offered + * by Tor Lillqvist. + */ +int +escape_pipe(int *fds) +{ + struct sockaddr_in saddr; + int temp; + int socket1 = -1; + int socket2 = -1; + fd_set read_set; + fd_set write_set; + int len; + + temp = socket (AF_INET, SOCK_STREAM, 0); + + if (temp == -1) + goto out0; + + memset (&saddr, 0, sizeof (saddr)); + saddr.sin_family = AF_INET; + saddr.sin_port = 0; + saddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK); + + if (bind (temp, (struct sockaddr *)&saddr, sizeof (saddr))) + goto out0; + + if (listen (temp, 1) == -1) + goto out0; + + len = sizeof (saddr); + if (getsockname (temp, (struct sockaddr *)&saddr, &len)) + goto out0; + + socket1 = socket (AF_INET, SOCK_STREAM, 0); + + if (socket1 == -1) + goto out0; + + if ((connect (socket1, (struct sockaddr *)&saddr, len) == -1) && + (errno != EAGAIN)) + goto out1; + + FD_ZERO (&read_set); + FD_SET (temp, &read_set); + + if (select (0, &read_set, NULL, NULL, NULL) == -1) + goto out1; + + if (!FD_ISSET (temp, &read_set)) + goto out1; + + socket2 = accept (temp, (struct sockaddr *)&saddr, &len); + if (socket2 == -1) + goto out1; + + FD_ZERO (&write_set); + FD_SET (socket1, &write_set); + + if (select (0, NULL, &write_set, NULL, NULL) == -1) + goto out2; + + if (!FD_ISSET (socket1, &write_set)) + goto out2; + + fds[0] = socket1; + fds[1] = socket2; + + closesocket (temp); + + return 0; + +out2: + closesocket (socket2); +out1: + closesocket (socket1); +out0: + closesocket (temp); + + fds[0] = -1; + fds[1] = -1; + + return -1; +} + +#undef access +int +access(const char *pathname, int mode) +{ + return escape_access (pathname, mode); +} + |