+#if !(defined(HAVE_CYGWIN) || defined(HAVE_MINGW))
+ char *p;
+ const char *f;
+ char x;
+ struct stat s;
+ char l[MAXBUFSIZE];
+
+ if(*file != '/') {
+ logger(LOG_ERR, _("`%s' is not an absolute path"), file);
+ return false;
+ }
+
+ p = strrchr(file, '/');
+
+ if(p == file) /* It's in the root */
+ p++;
+
+ x = *p;
+ *p = '\0';
+
+ f = file;
+
+check1:
+ if(lstat(f, &s) < 0) {
+ logger(LOG_ERR, _("Couldn't stat `%s': %s"), f, strerror(errno));
+ return false;
+ }
+
+ if(s.st_uid != geteuid()) {
+ logger(LOG_ERR, _("`%s' is owned by UID %d instead of %d"),
+ f, s.st_uid, geteuid());
+ return false;
+ }
+
+ if(S_ISLNK(s.st_mode)) {
+ logger(LOG_WARNING, _("Warning: `%s' is a symlink"), f);
+
+ if(readlink(f, l, MAXBUFSIZE) < 0) {
+ logger(LOG_ERR, _("Unable to read symbolic link `%s': %s"), f,
+ strerror(errno));
+ return false;
+ }
+
+ f = l;
+ goto check1;
+ }
+
+ *p = x;
+ f = file;
+
+check2:
+ if(lstat(f, &s) < 0 && errno != ENOENT) {
+ logger(LOG_ERR, _("Couldn't stat `%s': %s"), f, strerror(errno));
+ return false;
+ }
+
+ if(errno == ENOENT)
+ return true;
+
+ if(s.st_uid != geteuid()) {
+ logger(LOG_ERR, _("`%s' is owned by UID %d instead of %d"),
+ f, s.st_uid, geteuid());
+ return false;
+ }
+
+ if(S_ISLNK(s.st_mode)) {
+ logger(LOG_WARNING, _("Warning: `%s' is a symlink"), f);
+
+ if(readlink(f, l, MAXBUFSIZE) < 0) {
+ logger(LOG_ERR, _("Unable to read symbolic link `%s': %s"), f,
+ strerror(errno));
+ return false;
+ }
+
+ f = l;
+ goto check2;
+ }
+
+ if(s.st_mode & 0007) {
+ /* Accessible by others */
+ logger(LOG_ERR, _("`%s' has unsecure permissions"), f);
+ return false;
+ }
+#endif
+
+ return true;
+}
+
+FILE *ask_and_safe_open(const char *filename, const char *what, bool safe, const char *mode)
+{
+ FILE *r;
+ char *directory;
+ char *fn;
+
+ /* Check stdin and stdout */
+ if(!isatty(0) || !isatty(1)) {
+ /* Argh, they are running us from a script or something. Write
+ the files to the current directory and let them burn in hell
+ for ever. */
+ fn = xstrdup(filename);
+ } else {
+ /* Ask for a file and/or directory name. */
+ fprintf(stdout, _("Please enter a file to save %s to [%s]: "),
+ what, filename);
+ fflush(stdout);
+
+ fn = readline(stdin, NULL, NULL);
+
+ if(!fn) {
+ fprintf(stderr, _("Error while reading stdin: %s\n"),
+ strerror(errno));
+ return NULL;
+ }
+
+ if(!strlen(fn))
+ /* User just pressed enter. */
+ fn = xstrdup(filename);
+ }
+
+ if(!strchr(fn, '/') || fn[0] != '/') {
+ /* The directory is a relative path or a filename. */
+ char *p;
+
+ directory = get_current_dir_name();
+ asprintf(&p, "%s/%s", directory, fn);
+ free(fn);
+ free(directory);
+ fn = p;
+ }
+
+ umask(0077); /* Disallow everything for group and other */
+
+ /* Open it first to keep the inode busy */
+
+ r = fopen(fn, mode);
+
+ if(!r) {
+ fprintf(stderr, _("Error opening file `%s': %s\n"),
+ fn, strerror(errno));
+ free(fn);
+ return NULL;
+ }
+
+ /* Then check the file for nasty attacks */
+ if(safe) {
+ if(!is_safe_path(fn)) { /* Do not permit any directories that are readable or writeable by other users. */
+ fprintf(stderr, _("The file `%s' (or any of the leading directories) has unsafe permissions.\n"
+ "I will not create or overwrite this file.\n"), fn);
+ fclose(r);
+ free(fn);
+ return NULL;
+ }
+ }
+
+ free(fn);
+
+ return r;