⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 secsave.c

📁 一个很有名的浏览器
💻 C
字号:
/* Secure file saving handling *//* $Id: secsave.c,v 1.41.2.4 2005/05/01 22:03:23 jonas Exp $ */#ifdef HAVE_CONFIG_H#include "config.h"#endif#include <errno.h>#include <stdarg.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/types.h>#include <sys/stat.h> /* OS/2 needs this after sys/types.h */#ifdef HAVE_UNISTD_H#include <unistd.h>#endif#include "elinks.h"#include "config/options.h"#include "osdep/osdep.h" /* Needed for mkstemp() on win32 */#include "util/memory.h"#include "util/secsave.h"#include "util/string.h"/* If infofiles.secure_save is set: * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * * A call to secure_open("/home/me/.elinks/filename", mask) will open a file * named "filename.tmp_XXXXXX" in /home/me/.elinks/ and return a pointer to a * structure secure_save_info on success or NULL on error. * * filename.tmp_XXXXXX can't conflict with any file since it's created using * mkstemp(). XXXXXX is a random string. * * Subsequent write operations are done using returned secure_save_info FILE * * field named fp. * * If an error is encountered, secure_save_info int field named err is set * (automatically if using secure_fp*() functions or by programmer) * * When secure_close() is called, "filename.tmp_XXXXXX" is flushed and closed, * and if secure_save_info err field has a value of zero, "filename.tmp_XXXXXX" * is renamed to "filename". If this succeeded, then secure_close() returns 0. * * WARNING: since rename() is used, any symlink called "filename" may be * replaced by a regular file. If destination file isn't a regular file, * then secsave is disabled for that file. * * If infofiles.secure_save is unset: * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * * No temporary file is created, "filename" is truncated, all operations are * done on it, no rename nor flush occur, symlinks are preserved. * * In both cases: * ~~~~~~~~~~~~~ * * Access rights are affected by secure_open() mask parameter. *//* FIXME: locking system on files about to be rewritten ? *//* FIXME: Low risk race conditions about ssi->file_name. */enum secsave_errno secsave_errno = SS_ERR_NONE;/* Open a file for writing in a secure way. It returns a pointer to a structure * secure_save_info on success, or NULL on failure. */struct secure_save_info *secure_open(unsigned char *file_name, mode_t mask){	mode_t saved_mask;	struct stat st;	struct secure_save_info *ssi;	secsave_errno = SS_ERR_NONE;	/* XXX: This is inherently evil and has no place in util/, which	 * should be independent on such stuff. What do we do, except blaming	 * Jonas for noticing it? --pasky */	if ((get_cmd_opt_bool("no-connect")	     || get_cmd_opt_int("session-ring"))	    && !get_cmd_opt_bool("touch-files")) {		secsave_errno = SS_ERR_DISABLED;		return NULL;	}	ssi = mem_calloc(1, sizeof(*ssi));	if (!ssi) {		secsave_errno = SS_ERR_OUT_OF_MEM;		goto end;	}	ssi->secure_save = get_opt_bool("infofiles.secure_save");	ssi->file_name = stracpy(file_name);	if (!ssi->file_name) {		secsave_errno = SS_ERR_OUT_OF_MEM;		goto free_f;	}	/* Check properties of final file. */#ifdef FS_UNIX_SOFTLINKS	if (lstat(ssi->file_name, &st)) {#else	if (stat(ssi->file_name, &st)) {#endif		/* We ignore error caused by file inexistence. */		if (errno != ENOENT) {			/* lstat() error. */			ssi->err = errno;			secsave_errno = SS_ERR_STAT;			goto free_file_name;		}	} else {		if (!S_ISREG(st.st_mode)) {			/* Not a regular file, secure_save is disabled. */			ssi->secure_save = 0;		} else {#ifdef HAVE_ACCESS			/* XXX: access() do not work with setuid programs. */			if (access(ssi->file_name, R_OK | W_OK) < 0) {				ssi->err = errno;				secsave_errno = SS_ERR_ACCESS;				goto free_file_name;			}#else			FILE *f1;			/* We still have a race condition here between			 * [l]stat() and fopen() */			f1 = fopen(ssi->file_name, "rb+");			if (f1) {				fclose(f1);			} else {				ssi->err = errno;				secsave_errno = SS_ERR_OPEN_READ;				goto free_file_name;			}#endif		}	}	saved_mask = umask(mask);	if (ssi->secure_save) {		/* We use a random name for temporary file, mkstemp() opens		 * the file and return a file descriptor named fd, which is		 * then converted to FILE * using fdopen().		 */		int fd;		unsigned char *randname = straconcat(ssi->file_name,						     ".tmp_XXXXXX", NULL);		if (!randname) {			secsave_errno = SS_ERR_OUT_OF_MEM;			goto free_file_name;		}		/* No need to use safe_mkstemp() here. --Zas */		fd = mkstemp(randname);		if (fd == -1) {			secsave_errno = SS_ERR_MKSTEMP;			mem_free(randname);			goto free_file_name;		}		ssi->fp = fdopen(fd, "w");		if (!ssi->fp) {			secsave_errno = SS_ERR_OPEN_WRITE;			ssi->err = errno;			mem_free(randname);			goto free_file_name;		}		ssi->tmp_file_name = randname;	} else {		/* No need to create a temporary file here. */		ssi->fp = fopen(ssi->file_name, "wb");		if (!ssi->fp) {			secsave_errno = SS_ERR_OPEN_WRITE;			ssi->err = errno;			goto free_file_name;		}	}	umask(saved_mask);	return ssi;free_file_name:	mem_free(ssi->file_name);	ssi->file_name = NULL;free_f:	mem_free(ssi);	ssi = NULL;end:	return NULL;}/* Close a file opened with secure_open, and return 0 on success, errno * or -1 on failure. */intsecure_close(struct secure_save_info *ssi){	int ret = -1;	if (!ssi) return ret;	if (!ssi->fp) goto free;	if (ssi->err) {	/* Keep previous errno. */		ret = ssi->err;		fclose(ssi->fp); /* Close file */		goto free;	}	/* Ensure data is effectively written to disk, we first flush libc buffers	 * using fflush(), then fsync() to flush kernel buffers, and finally call	 * fclose() (which call fflush() again, but the first one is needed since	 * it doesn't make much sense to flush kernel buffers and then libc buffers,	 * while closing file releases file descriptor we need to call fsync(). */#if defined(HAVE_FFLUSH) || defined(HAVE_FSYNC)	if (ssi->secure_save) {		int fail = 0;#ifdef HAVE_FFLUSH		fail = (fflush(ssi->fp) == EOF);#endif#ifdef HAVE_FSYNC		if (!fail && get_opt_bool("infofiles.secure_save_fsync"))			fail = fsync(fileno(ssi->fp));#endif		if (fail) {			ret = errno;			secsave_errno = SS_ERR_OTHER;			fclose(ssi->fp); /* Close file, ignore errors. */			goto free;		}	}#endif	/* Close file. */	if (fclose(ssi->fp) == EOF) {		ret = errno;		secsave_errno = SS_ERR_OTHER;		goto free;	}	if (ssi->secure_save && ssi->file_name && ssi->tmp_file_name) {#ifdef CONFIG_OS2		/* OS/2 needs this, however it breaks atomicity on		 * UN*X. */		unlink(ssi->file_name);#endif		/* FIXME: Race condition on ssi->file_name. The file		 * named ssi->file_name may have changed since		 * secure_open() call (where we stat() file and		 * more..).  */		if (rename(ssi->tmp_file_name, ssi->file_name) == -1) {			ret = errno;			secsave_errno = SS_ERR_RENAME;			goto free;		}	}	ret = 0;	/* Success. */free:	mem_free_if(ssi->tmp_file_name);	mem_free_if(ssi->file_name);	mem_free_if(ssi);	return ret;}/* fputs() wrapper, set ssi->err to errno on error. If ssi->err is set when * called, it immediatly returns EOF. */intsecure_fputs(struct secure_save_info *ssi, const char *s){	int ret;	if (!ssi || !ssi->fp || ssi->err) return EOF;	ret = fputs(s, ssi->fp);	if (ret == EOF) {		secsave_errno = SS_ERR_OTHER;		ssi->err = errno;	}	return ret;}/* fputc() wrapper, set ssi->err to errno on error. If ssi->err is set when * called, it immediatly returns EOF. */intsecure_fputc(struct secure_save_info *ssi, int c){	int ret;	if (!ssi || !ssi->fp || ssi->err) return EOF;	ret = fputc(c, ssi->fp);	if (ret == EOF) {		ssi->err = errno;		secsave_errno = SS_ERR_OTHER;	}	return ret;}/* fprintf() wrapper, set ssi->err to errno on error and return a negative * value. If ssi->err is set when called, it immediatly returns -1. */intsecure_fprintf(struct secure_save_info *ssi, const char *format, ...){	va_list ap;	int ret;	if (!ssi || !ssi->fp || ssi->err) return -1;	va_start(ap, format);	ret = vfprintf(ssi->fp, format, ap);	if (ret < 0) ssi->err = errno;	va_end(ap);	return ret;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -