=== modified file 'plugins.d/mandos-client.c' --- plugins.d/mandos-client.c 2016-02-28 20:34:59 +0000 +++ plugins.d/mandos-client.c 2016-02-28 20:38:55 +0000 @@ -57,12 +57,16 @@ #include /* socket(), struct sockaddr_in6, inet_pton(), connect(), getnameinfo() */ -#include /* open(), unlinkat() */ +#include /* open(), unlinkat(), AT_REMOVEDIR */ #include /* opendir(), struct dirent, readdir() */ #include /* PRIu16, PRIdMAX, intmax_t, strtoimax() */ -#include /* perror(), errno, +#include /* perror(), errno, EINTR, EINVAL, + EAI_SYSTEM, ENETUNREACH, + EHOSTUNREACH, ECONNREFUSED, EPROTO, + EIO, ENOENT, ENXIO, ENOMEM, EISDIR, + ENOTEMPTY, program_invocation_short_name */ #include /* nanosleep(), time(), sleep() */ #include /* ioctl, ifreq, SIOCGIFFLAGS, IFF_UP, @@ -3024,41 +3028,65 @@ free(interfaces_to_take_down); free(interfaces_hooks); + void clean_dir_at(int base, const char * const dirname, + uintmax_t level){ + struct dirent **direntries = NULL; + int dret; + int dir_fd = (int)TEMP_FAILURE_RETRY(openat(base, dirname, + O_RDONLY + | O_NOFOLLOW + | O_DIRECTORY + | O_PATH)); + if(dir_fd == -1){ + perror_plus("open"); + } + int numentries = scandirat(dir_fd, ".", &direntries, + notdotentries, alphasort); + if(numentries >= 0){ + for(int i = 0; i < numentries; i++){ + if(debug){ + fprintf_plus(stderr, "Unlinking \"%s/%s\"\n", + dirname, direntries[i]->d_name); + } + dret = unlinkat(dir_fd, direntries[i]->d_name, 0); + if(dret == -1){ + if(errno == EISDIR){ + dret = unlinkat(dir_fd, direntries[i]->d_name, + AT_REMOVEDIR); + } + if((dret == -1) and (errno == ENOTEMPTY) + and (strcmp(direntries[i]->d_name, "private-keys-v1.d") + == 0) and (level == 0)){ + /* Recurse only in this special case */ + clean_dir_at(dir_fd, direntries[i]->d_name, level+1); + dret = 0; + } + if(dret == -1){ + fprintf_plus(stderr, "unlink(\"%s/%s\"): %s\n", dirname, + direntries[i]->d_name, strerror(errno)); + } + } + free(direntries[i]); + } + + /* need to clean even if 0 because man page doesn't specify */ + free(direntries); + if(numentries == -1){ + perror_plus("scandirat"); + } + dret = unlinkat(base, dirname, AT_REMOVEDIR); + if(dret == -1 and errno != ENOENT){ + perror_plus("rmdir"); + } + } else { + perror_plus("scandirat"); + } + close(dir_fd); + } + /* Removes the GPGME temp directory and all files inside */ if(tempdir != NULL){ - struct dirent **direntries = NULL; - int tempdir_fd = (int)TEMP_FAILURE_RETRY(open(tempdir, O_RDONLY - | O_NOFOLLOW - | O_DIRECTORY - | O_PATH)); - if(tempdir_fd == -1){ - perror_plus("open"); - } else { - int numentries = scandirat(tempdir_fd, ".", &direntries, - notdotentries, alphasort); - if(numentries >= 0){ - for(int i = 0; i < numentries; i++){ - ret = unlinkat(tempdir_fd, direntries[i]->d_name, 0); - if(ret == -1){ - fprintf_plus(stderr, "unlinkat(open(\"%s\", O_RDONLY)," - " \"%s\", 0): %s\n", tempdir, - direntries[i]->d_name, strerror(errno)); - } - free(direntries[i]); - } - - /* need to clean even if 0 because man page doesn't specify */ - free(direntries); - if(numentries == -1){ - perror_plus("scandir"); - } - ret = rmdir(tempdir); - if(ret == -1 and errno != ENOENT){ - perror_plus("rmdir"); - } - } - close(tempdir_fd); - } + clean_dir_at(-1, tempdir, 0); } if(quit_now){