summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--runtime/compiler/perl.vim2
-rw-r--r--runtime/doc/editing.txt3
-rw-r--r--runtime/doc/todo.txt3
-rw-r--r--runtime/doc/undo.txt3
-rw-r--r--runtime/indent/tf.vim4
-rw-r--r--src/fileio.c167
-rw-r--r--src/proto/fileio.pro4
-rw-r--r--src/testdir/test72.in49
-rw-r--r--src/testdir/test72.ok8
-rw-r--r--src/undo.c67
10 files changed, 260 insertions, 50 deletions
diff --git a/runtime/compiler/perl.vim b/runtime/compiler/perl.vim
index 2b7c94a89a..583c6c3787 100644
--- a/runtime/compiler/perl.vim
+++ b/runtime/compiler/perl.vim
@@ -1,6 +1,6 @@
" Vim Compiler File
" Compiler: Perl syntax checks (perl -Wc)
-" Maintainer: Christian J. Robinson <infynity@onewest.net>
+" Maintainer: Christian J. Robinson <heptite@gmail.com>
" Last Change: 2006 Aug 13
if exists("current_compiler")
diff --git a/runtime/doc/editing.txt b/runtime/doc/editing.txt
index 11f5748a5c..32848ac4e2 100644
--- a/runtime/doc/editing.txt
+++ b/runtime/doc/editing.txt
@@ -1366,6 +1366,9 @@ this before writing the file. When reading an encrypted file it will be set
automatically to the method used when that file was written. You can change
'cryptmethod' before writing that file to change the method.
+When writing an undo file, the same key and method will be used for the text
+in the undo file. |persistent-undo|.
+
*E817* *E818* *E819* *E820*
When encryption does not work properly, you would be able to write your text
to a file and never be able to read it back. Therefore a test is performed to
diff --git a/runtime/doc/todo.txt b/runtime/doc/todo.txt
index 7210961fdc..0bd8d6700f 100644
--- a/runtime/doc/todo.txt
+++ b/runtime/doc/todo.txt
@@ -1085,9 +1085,6 @@ Vim 7.3:
- using NSIS 2.46: install on Windows 7 works, but no "Edit with Vim" menu.
Use register_shell_extension()? (George Reilly, 2010 May 26)
Ron's version: http://dev.ronware.org/p/vim/finfo?name=gvim.nsi
-- Persistent undo bugs / fixes:
- - Need to check all values for evil manipulation.
-- Also crypt the undo file.
- Also crypt the swap file, each block separately. Change mf_write() and
mf_read(). How to get b_p_key to these functions?
- Do profiling on sha256 code to find obvious bottlenecks.
diff --git a/runtime/doc/undo.txt b/runtime/doc/undo.txt
index 96ff96a9ee..e8fed4f067 100644
--- a/runtime/doc/undo.txt
+++ b/runtime/doc/undo.txt
@@ -225,6 +225,9 @@ after the undo file was written, to prevent corruption.
Undo files are normally saved in the same directory as the file. This can be
changed with the 'undodir' option.
+When the file is encrypted, the text in the undo file is also crypted. The
+same key and method is used. |encryption|
+
You can also save and restore undo histories by using ":wundo" and ":rundo"
respectively:
*:wundo* *:rundo*
diff --git a/runtime/indent/tf.vim b/runtime/indent/tf.vim
index 61cebc3a67..17597734b8 100644
--- a/runtime/indent/tf.vim
+++ b/runtime/indent/tf.vim
@@ -1,7 +1,7 @@
" Vim indent file
" Language: tf (TinyFugue)
-" Maintainer: Christian J. Robinson <infynity@onewest.net>
-" URL: http://www.infynity.spodzone.com/vim/indent/tf.vim
+" Maintainer: Christian J. Robinson <heptite@gmail.com>
+" URL: http://christianrobinson.name/vim/indent/tf.vim
" Last Change: 2002 May 29
" Only load this indent file when no other was loaded.
diff --git a/src/fileio.c b/src/fileio.c
index 101c804de8..ff21783ffe 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -2827,7 +2827,7 @@ check_marks_read()
}
#endif
-#ifdef FEAT_CRYPT
+#if defined(FEAT_CRYPT) || defined(PROTO)
/*
* Get the crypt method used for a file from "ptr[len]", the magic text at the
* start of the file.
@@ -2926,7 +2926,129 @@ check_for_cryptkey(cryptkey, ptr, sizep, filesizep, newfile, did_ask)
return cryptkey;
}
-#endif
+
+/*
+ * Check for magic number used for encryption. Applies to the current buffer.
+ * If found and decryption is possible returns OK;
+ */
+ int
+prepare_crypt_read(fp)
+ FILE *fp;
+{
+ int method;
+ char_u buffer[CRYPT_MAGIC_LEN + CRYPT_SEED_LEN_MAX + 2];
+
+ if (fread(buffer, CRYPT_MAGIC_LEN, 1, fp) != 1)
+ return FAIL;
+ method = get_crypt_method((char *)buffer,
+ CRYPT_MAGIC_LEN + CRYPT_SEED_LEN_MAX);
+ if (method < 0 || method != curbuf->b_p_cm)
+ return FAIL;
+
+ if (method == 0)
+ crypt_init_keys(curbuf->b_p_key);
+ else
+ {
+ int seed_len = crypt_seed_len[method];
+
+ if (fread(buffer, seed_len, 1, fp) != 1)
+ return FAIL;
+ bf_key_init(curbuf->b_p_key);
+ bf_ofb_init(buffer, seed_len);
+ }
+ return OK;
+}
+
+/*
+ * Prepare for writing encrypted bytes for buffer "buf".
+ * Returns a pointer to an allocated header of length "*lenp".
+ */
+ char_u *
+prepare_crypt_write(buf, lenp)
+ buf_T *buf;
+ int *lenp;
+{
+ char_u *header;
+ int seed_len = crypt_seed_len[buf->b_p_cm];
+
+ header = alloc_clear(CRYPT_MAGIC_LEN + CRYPT_SEED_LEN_MAX + 2);
+ if (header != NULL)
+ {
+ use_crypt_method = buf->b_p_cm; /* select pkzip or blowfish */
+ vim_strncpy(header, (char_u *)crypt_magic[use_crypt_method],
+ CRYPT_MAGIC_LEN);
+ if (buf->b_p_cm == 0)
+ crypt_init_keys(buf->b_p_key);
+ else
+ {
+ /* Using blowfish, add seed. */
+ sha2_seed(header + CRYPT_MAGIC_LEN, seed_len); /* create iv */
+ bf_ofb_init(header + CRYPT_MAGIC_LEN, seed_len);
+ bf_key_init(buf->b_p_key);
+ }
+ }
+ *lenp = CRYPT_MAGIC_LEN + seed_len;
+ return header;
+}
+
+/*
+ * Like fwrite() but crypt the bytes when 'key' is set.
+ * Returns 1 if successful.
+ */
+ size_t
+fwrite_crypt(buf, ptr, len, fp)
+ buf_T *buf;
+ char_u *ptr;
+ size_t len;
+ FILE *fp;
+{
+ char_u *copy;
+ char_u small_buf[100];
+ int ztemp, t;
+ size_t i;
+
+ if (*buf->b_p_key == NUL)
+ return fwrite(ptr, len, (size_t)1, fp);
+ if (len < 100)
+ copy = small_buf; /* no malloc()/free() for short strings */
+ else
+ {
+ copy = lalloc(len, FALSE);
+ if (copy == NULL)
+ return 0;
+ }
+ for (i = 0; i < len; ++i)
+ {
+ ztemp = ptr[i];
+ copy[i] = ZENCODE(ztemp, t);
+ }
+ i = fwrite(copy, len, (size_t)1, fp);
+ if (copy != small_buf)
+ vim_free(copy);
+ return i;
+}
+
+/*
+ * Read a string of length "len" from "fd".
+ * When 'key' is set decrypt the bytes.
+ */
+ char_u *
+read_string_decrypt(buf, fd, len)
+ buf_T *buf;
+ FILE *fd;
+ int len;
+{
+ char_u *ptr;
+ char_u *p;
+
+ ptr = read_string(fd, len);
+ if (ptr != NULL || *buf->b_p_key != NUL)
+ for (p = ptr; p < ptr + len; ++p)
+ ZDECODE(*p);
+ return ptr;
+}
+
+#endif /* FEAT_CRYPT */
#ifdef UNIX
static void
@@ -4323,34 +4445,25 @@ restore_backup:
#ifdef FEAT_CRYPT
if (*buf->b_p_key && !filtering)
{
- char_u header[CRYPT_MAGIC_LEN + CRYPT_SEED_LEN_MAX + 2];
- int seed_len = crypt_seed_len[buf->b_p_cm];
-
- use_crypt_method = buf->b_p_cm; /* select pkzip or blowfish */
+ char_u *header;
+ int header_len;
- vim_memset(header, 0, sizeof(header));
- vim_strncpy(header, (char_u *)crypt_magic[use_crypt_method],
- CRYPT_MAGIC_LEN);
-
- if (buf->b_p_cm == 0)
- crypt_init_keys(buf->b_p_key);
+ header = prepare_crypt_write(buf, &header_len);
+ if (header == NULL)
+ end = 0;
else
{
- /* Using blowfish, add seed. */
- sha2_seed(header + CRYPT_MAGIC_LEN, seed_len); /* create iv */
- bf_ofb_init(header + CRYPT_MAGIC_LEN, seed_len);
- bf_key_init(buf->b_p_key);
+ /* Write magic number, so that Vim knows that this file is
+ * encrypted when reading it again. This also undergoes utf-8 to
+ * ucs-2/4 conversion when needed. */
+ write_info.bw_buf = header;
+ write_info.bw_len = header_len;
+ write_info.bw_flags = FIO_NOCONVERT;
+ if (buf_write_bytes(&write_info) == FAIL)
+ end = 0;
+ wb_flags |= FIO_ENCRYPTED;
+ vim_free(header);
}
-
- /* Write magic number, so that Vim knows that this file is
- * encrypted when reading it again. This also undergoes utf-8 to
- * ucs-2/4 conversion when needed. */
- write_info.bw_buf = (char_u *)header;
- write_info.bw_len = CRYPT_MAGIC_LEN + seed_len;
- write_info.bw_flags = FIO_NOCONVERT;
- if (buf_write_bytes(&write_info) == FAIL)
- end = 0;
- wb_flags |= FIO_ENCRYPTED;
}
#endif
@@ -5558,7 +5671,7 @@ buf_write_bytes(ip)
for (i = 0; i < len; i++)
{
- ztemp = buf[i];
+ ztemp = buf[i];
buf[i] = ZENCODE(ztemp, t);
}
}
diff --git a/src/proto/fileio.pro b/src/proto/fileio.pro
index e5a1b284ae..32e3045523 100644
--- a/src/proto/fileio.pro
+++ b/src/proto/fileio.pro
@@ -2,6 +2,10 @@
void filemess __ARGS((buf_T *buf, char_u *name, char_u *s, int attr));
int readfile __ARGS((char_u *fname, char_u *sfname, linenr_T from, linenr_T lines_to_skip, linenr_T lines_to_read, exarg_T *eap, int flags));
int prep_exarg __ARGS((exarg_T *eap, buf_T *buf));
+int prepare_crypt_read __ARGS((FILE *fp));
+char_u *prepare_crypt_write __ARGS((buf_T *buf, int *lenp));
+size_t fwrite_crypt __ARGS((buf_T *buf, char_u *ptr, size_t len, FILE *fp));
+char_u *read_string_decrypt __ARGS((buf_T *buf, FILE *fd, int len));
int check_file_readonly __ARGS((char_u *fname, int perm));
int buf_write __ARGS((buf_T *buf, char_u *fname, char_u *sfname, linenr_T start, linenr_T end, exarg_T *eap, int append, int forceit, int reset_changed, int filtering));
void msg_add_fname __ARGS((buf_T *buf, char_u *fname));
diff --git a/src/testdir/test72.in b/src/testdir/test72.in
index a5674b5272..b6c6bfab3c 100644
--- a/src/testdir/test72.in
+++ b/src/testdir/test72.in
@@ -49,6 +49,55 @@ dd:set ul=100
:e Xtestfile
uuu:w >>test.out
:"
+:" And now with encryption, cryptmethod=0
+:e! Xtestfile
+:set undofile cm=0
+ggdG
+imonday
+tuesday
+wednesday
+thursday
+friday:set ul=100
+kkkdd:set ul=100
+dd:set ul=100
+dd:set ul=100
+:X
+foobar
+foobar
+:w!
+:bwipe!
+:e Xtestfile
+foobar
+:set key=
+uu:w >>test.out
+:"
+:"
+:" With encryption, cryptmethod=1
+:e! Xtestfile
+:set undofile cm=1
+ggdG
+ijan
+feb
+mar
+apr
+jun:set ul=100
+kk0ifoo :set ul=100
+dd:set ul=100
+ibar :set ul=100
+:X
+foobar
+foobar
+:w!
+:bwipe!
+:e Xtestfile
+foobar
+:set key=
+/bar
+:.w >>test.out
+u:.w >>test.out
+u:.w >>test.out
+u:.w >>test.out
+:"
:" Rename the undo file so that it gets cleaned up.
:call rename(".Xtestfile.un~", "Xtestundo")
:qa!
diff --git a/src/testdir/test72.ok b/src/testdir/test72.ok
index 66e7250df6..44210c942a 100644
--- a/src/testdir/test72.ok
+++ b/src/testdir/test72.ok
@@ -7,3 +7,11 @@ seven
eight
nine
ten
+monday
+wednesday
+thursday
+friday
+bar apr
+apr
+foo mar
+mar
diff --git a/src/undo.c b/src/undo.c
index 35b66c3db1..86a4d1753f 100644
--- a/src/undo.c
+++ b/src/undo.c
@@ -103,9 +103,9 @@ static void u_freeentry __ARGS((u_entry_T *, long));
static void corruption_error __ARGS((char *msg, char_u *file_name));
static void u_free_uhp __ARGS((u_header_T *uhp));
static int serialize_header __ARGS((FILE *fp, buf_T *buf, char_u *hash));
-static int serialize_uhp __ARGS((FILE *fp, u_header_T *uhp));
+static int serialize_uhp __ARGS((FILE *fp, buf_T *buf, u_header_T *uhp));
static u_header_T *unserialize_uhp __ARGS((FILE *fp, char_u *file_name));
-static int serialize_uep __ARGS((u_entry_T *uep, FILE *fp));
+static int serialize_uep __ARGS((FILE *fp, buf_T *buf, u_entry_T *uep));
static u_entry_T *unserialize_uep __ARGS((FILE *fp, int *error, char_u *file_name));
static void serialize_pos __ARGS((pos_T pos, FILE *fp));
static void unserialize_pos __ARGS((pos_T *pos, FILE *fp));
@@ -670,6 +670,7 @@ nomem:
# define UF_ENTRY_MAGIC 0xf518 /* magic at start of entry */
# define UF_ENTRY_END_MAGIC 0x3581 /* magic after last entry */
# define UF_VERSION 1 /* 2-byte undofile version number */
+# define UF_VERSION_CRYPT 0x8001 /* idem, encrypted */
static char_u e_not_open[] = N_("E828: Cannot open undo file for writing: %s");
@@ -811,7 +812,28 @@ serialize_header(fp, buf, hash)
/* Start writing, first the magic marker and undo info version. */
if (fwrite(UF_START_MAGIC, (size_t)UF_START_MAGIC_LEN, (size_t)1, fp) != 1)
return FAIL;
- put_bytes(fp, (long_u)UF_VERSION, 2);
+
+ /* If the buffer is encrypted then all text bytes following will be
+ * encrypted. Numbers and other info is not crypted. */
+#ifdef FEAT_CRYPT
+ if (*buf->b_p_key)
+ {
+ char_u *header;
+ int header_len;
+
+ put_bytes(fp, (long_u)UF_VERSION_CRYPT, 2);
+ header = prepare_crypt_write(buf, &header_len);
+ if (header == NULL)
+ return FAIL;
+ len = fwrite(header, (size_t)header_len, (size_t)1, fp);
+ vim_free(header);
+ if (len != 1)
+ return FAIL;
+ }
+ else
+#endif
+ put_bytes(fp, (long_u)UF_VERSION, 2);
+
/* Write a hash of the buffer text, so that we can verify it is still the
* same when reading the buffer text. */
@@ -822,7 +844,7 @@ serialize_header(fp, buf, hash)
put_bytes(fp, (long_u)buf->b_ml.ml_line_count, 4);
len = buf->b_u_line_ptr != NULL ? (int)STRLEN(buf->b_u_line_ptr) : 0;
put_bytes(fp, (long_u)len, 4);
- if (len > 0 && fwrite(buf->b_u_line_ptr, (size_t)len, (size_t)1, fp) != 1)
+ if (len > 0 && fwrite_crypt(buf, buf->b_u_line_ptr, (size_t)len, fp) != 1)
return FAIL;
put_bytes(fp, (long_u)buf->b_u_line_lnum, 4);
put_bytes(fp, (long_u)buf->b_u_line_colnr, 4);
@@ -841,8 +863,9 @@ serialize_header(fp, buf, hash)
}
static int
-serialize_uhp(fp, uhp)
+serialize_uhp(fp, buf, uhp)
FILE *fp;
+ buf_T *buf;
u_header_T *uhp;
{
int i;
@@ -882,7 +905,7 @@ serialize_uhp(fp, uhp)
for (uep = uhp->uh_entry; uep != NULL; uep = uep->ue_next)
{
put_bytes(fp, (long_u)UF_ENTRY_MAGIC, 2);
- if (serialize_uep(uep, fp) == FAIL)
+ if (serialize_uep(fp, buf, uep) == FAIL)
return FAIL;
}
put_bytes(fp, (long_u)UF_ENTRY_END_MAGIC, 2);
@@ -971,9 +994,10 @@ unserialize_uhp(fp, file_name)
* Serialize "uep" to "fp".
*/
static int
-serialize_uep(uep, fp)
- u_entry_T *uep;
+serialize_uep(fp, buf, uep)
FILE *fp;
+ buf_T *buf;
+ u_entry_T *uep;
{
int i;
size_t len;
@@ -987,7 +1011,7 @@ serialize_uep(uep, fp)
len = STRLEN(uep->ue_array[i]);
if (put_bytes(fp, (long_u)len, 4) == FAIL)
return FAIL;
- if (len > 0 && fwrite(uep->ue_array[i], len, (size_t)1, fp) != 1)
+ if (len > 0 && fwrite_crypt(buf, uep->ue_array[i], len, fp) != 1)
return FAIL;
}
return OK;
@@ -1034,7 +1058,7 @@ unserialize_uep(fp, error, file_name)
{
line_len = get4c(fp);
if (line_len >= 0)
- line = read_string(fp, line_len);
+ line = read_string_decrypt(curbuf, fp, line_len);
else
{
line = NULL;
@@ -1333,7 +1357,7 @@ u_write_undo(name, forceit, buf, hash)
#ifdef U_DEBUG
++headers_written;
#endif
- if (serialize_uhp(fp, uhp) == FAIL)
+ if (serialize_uhp(fp, buf, uhp) == FAIL)
goto write_error;
}
@@ -1478,7 +1502,20 @@ u_read_undo(name, hash, orig_name)
goto error;
}
version = get2c(fp);
- if (version != UF_VERSION)
+ if (version == UF_VERSION_CRYPT)
+ {
+#ifdef FEAT_CRYPT
+ if (prepare_crypt_read(fp) == FAIL)
+ {
+ EMSG2(_("E826: Undo file decryption failed: %s"), file_name);
+ goto error;
+ }
+#else
+ EMSG2(_("E826: Undo file is encrypted: %s"), file_name);
+ goto error;
+#endif
+ }
+ else if (version != UF_VERSION)
{
EMSG2(_("E824: Incompatible undo file: %s"), file_name);
goto error;
@@ -1510,7 +1547,7 @@ u_read_undo(name, hash, orig_name)
if (str_len < 0)
goto error;
if (str_len > 0)
- line_ptr = read_string(fp, str_len);
+ line_ptr = read_string_decrypt(curbuf, fp, str_len);
line_lnum = (linenr_T)get4c(fp);
line_colnr = (colnr_T)get4c(fp);
if (line_lnum < 0 || line_colnr < 0)
@@ -1634,10 +1671,6 @@ u_read_undo(name, hash, orig_name)
curbuf->b_u_oldhead = old_idx < 0 ? NULL : uhp_table[old_idx];
curbuf->b_u_newhead = new_idx < 0 ? NULL : uhp_table[new_idx];
curbuf->b_u_curhead = cur_idx < 0 ? NULL : uhp_table[cur_idx];
-#ifdef U_DEBUG
- if (curbuf->b_u_curhead != NULL)
- corruption_error("curhead not NULL", file_name);
-#endif
curbuf->b_u_line_ptr = line_ptr;
curbuf->b_u_line_lnum = line_lnum;
curbuf->b_u_line_colnr = line_colnr;