From 3ef1fec92e9e8a76bb3ed531b6d9a961ea1e40dd Mon Sep 17 00:00:00 2001 From: mdw Date: Fri, 6 May 2005 20:31:51 +0000 Subject: [PATCH] Check the proposed socket directory before trusting its contents. --- noip.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 58 insertions(+), 17 deletions(-) diff --git a/noip.c b/noip.c index 61d4a62..e674bed 100644 --- a/noip.c +++ b/noip.c @@ -105,7 +105,7 @@ static void *xmalloc(size_t n) { void *p; if (!n) return (0); - if ((p = malloc(n)) == 0) { perror("malloc"); exit(1); } + if ((p = malloc(n)) == 0) { perror("malloc"); exit(127); } return (p); } @@ -117,7 +117,7 @@ static char *xstrdup(const char *p) return (q); } -static int unix_socket_status(struct sockaddr_un *sun, int quick_p) +static int unix_socket_status(struct sockaddr_un *sun, int quickp) { struct stat st; FILE *fp = 0; @@ -125,13 +125,11 @@ static int unix_socket_status(struct sockaddr_un *sun, int quick_p) int rc; char buf[256]; - rc = UNUSED; - if (stat(sun->sun_path, &st) && errno == ENOENT) - goto done; + if (stat(sun->sun_path, &st)) + return (errno == ENOENT ? UNUSED : USED); + if (!S_ISSOCK(st.st_mode) || !quickp) + return (USED); rc = USED; - if (quick_p) - goto done; - if ((fp = fopen("/proc/net/unix", "r")) == 0) goto done; fgets(buf, sizeof(buf), fp); /* skip header */ @@ -237,7 +235,7 @@ static int encode_inet_addr(struct sockaddr_un *sun, int want) { int i; - int desperate_p = 0; + int desperatep = 0; char buf[INET_ADDRSTRLEN]; int rc; @@ -264,12 +262,12 @@ static int encode_inet_addr(struct sockaddr_un *sun, randrange(minautoport, maxautoport)); if (unix_socket_status(sun, 1) == UNUSED) goto found; } - for (desperate_p = 0; desperate_p < 2; desperate_p++) { + for (desperatep = 0; desperatep < 2; desperatep++) { for (i = minautoport; i <= maxautoport; i++) { snprintf(sun->sun_path, sizeof(sun->sun_path), "%s/%s:%u", sockdir, inet_ntop(AF_INET, &sin->sin_addr, buf, sizeof(buf)), (unsigned)i); - rc = unix_socket_status(sun, !desperate_p); + rc = unix_socket_status(sun, !desperatep); switch (rc) { case STALE: unlink(sun->sun_path); case UNUSED: goto found; @@ -452,9 +450,13 @@ static char *home(void) char *p; struct passwd *pw; - if ((p = getenv("HOME")) != 0) return (p); - else if ((pw = getpwuid(uid)) != 0) return (pw->pw_dir); - else return "/notexist"; + if (getuid() == uid && + (p = getenv("HOME")) != 0) + return (p); + else if ((pw = getpwuid(uid)) != 0) + return (pw->pw_dir); + else + return "/notexist"; } static char *tmpdir(void) @@ -703,7 +705,7 @@ done: snprintf(buf, sizeof(buf), "%s/noip-%s", tmpdir(), user()); sockdir = xstrdup(buf); } - D( fprintf(stderr, "noip: sockdir: %s\n", sockdir); + D( fprintf(stderr, "noip: socketdir: %s\n", sockdir); fprintf(stderr, "noip: autoports: %u-%u\n", minautoport, maxautoport); fprintf(stderr, "noip: realbind acl:\n"); @@ -908,7 +910,9 @@ static void cleanup_sockdir(void) { DIR *dir; struct dirent *d; + struct sockaddr_in sin; struct sockaddr_un sun; + struct stat st; if ((dir = opendir(sockdir)) == 0) return; @@ -916,6 +920,10 @@ static void cleanup_sockdir(void) if (d->d_name[0] == '.') continue; snprintf(sun.sun_path, sizeof(sun.sun_path), "%s/%s", sockdir, d->d_name); + if (decode_inet_addr(&sin, &sun, SUN_LEN(&sun)) || + stat(sun.sun_path, &st) || + !S_ISSOCK(st.st_mode)) + continue; if (unix_socket_status(&sun, 0) == STALE) { D( fprintf(stderr, "noip: clearing away stale socket %s\n", d->d_name); ) @@ -950,18 +958,51 @@ static void get_local_ipaddrs(void) close(sk); } +static void printerr(const char *p) { write(STDERR_FILENO, p, strlen(p)); } + +static void create_sockdir(void) +{ + struct stat st; + + if (stat(sockdir, &st)) { + if (errno == ENOENT) { + if (mkdir(sockdir, 0700)) { + perror("noip: creating socketdir"); + exit(127); + } + if (!stat(sockdir, &st)) + goto check; + } + perror("noip: checking socketdir"); + exit(127); + } +check: + if (!S_ISDIR(st.st_mode)) { + printerr("noip: bad socketdir: not a directory\n"); + exit(127); + } + if (st.st_uid != uid) { + printerr("noip: bad socketdir: not owner\n"); + exit(127); + } + if (st.st_mode & 077) { + printerr("noip: bad socketdir: not private\n"); + exit(127); + } +} + static void setup(void) { PRESERVING_ERRNO({ char *p; import(); - uid = getuid(); + uid = geteuid(); if ((p = getenv("NOIP_DEBUG")) && atoi(p)) debug = 1; get_local_ipaddrs(); readconfig(); - mkdir(sockdir, 0700); + create_sockdir(); cleanup_sockdir(); }); } -- 2.11.0