Blame SOURCES/0001-patch-8.1.0881-can-execute-shell-commands-in-rvim-th.patch

3ed64d
diff --git a/runtime/doc/starting.txt b/runtime/doc/starting.txt
3ed64d
index 8256152..8320039 100644
3ed64d
--- a/runtime/doc/starting.txt
3ed64d
+++ b/runtime/doc/starting.txt
3ed64d
@@ -247,12 +247,18 @@ a slash.  Thus "-R" means recovery and "-/R" readonly.
3ed64d
 		changes and writing.
3ed64d
 		{not in Vi}
3ed64d
 
3ed64d
-						*-Z* *restricted-mode* *E145*
3ed64d
+					*-Z* *restricted-mode* *E145* *E981*
3ed64d
 -Z		Restricted mode.  All commands that make use of an external
3ed64d
 		shell are disabled.  This includes suspending with CTRL-Z,
3ed64d
-		":sh", filtering, the system() function, backtick expansion,
3ed64d
-		delete(), rename(), mkdir(), writefile(), libcall(),
3ed64d
-		job_start(), etc.
3ed64d
+		":sh", filtering, the system() function, backtick expansion
3ed64d
+		and libcall().
3ed64d
+		Also disallowed are delete(), rename(), mkdir(), job_start(),
3ed64d
+		etc.
3ed64d
+		Interfaces, such as Python, Ruby and Lua, are also disabled,
3ed64d
+		since they could be used to execute shell commands.  Perl uses
3ed64d
+		the Safe module.
3ed64d
+		Note that the user may still find a loophole to execute a
3ed64d
+		shell command, it has only been made difficult.
3ed64d
 		{not in Vi}
3ed64d
 
3ed64d
 							*-g*
3ed64d
diff --git a/src/evalfunc.c b/src/evalfunc.c
3ed64d
index dd4462d..3cc305a 100644
3ed64d
--- a/src/evalfunc.c
3ed64d
+++ b/src/evalfunc.c
3ed64d
@@ -6446,7 +6446,7 @@ f_histadd(typval_T *argvars UNUSED, typval_T *rettv)
3ed64d
 #endif
3ed64d
 
3ed64d
     rettv->vval.v_number = FALSE;
3ed64d
-    if (check_restricted() || check_secure())
3ed64d
+    if (check_secure())
3ed64d
 	return;
3ed64d
 #ifdef FEAT_CMDHIST
3ed64d
     str = get_tv_string_chk(&argvars[0]);	/* NULL on type error */
3ed64d
@@ -7456,6 +7456,9 @@ f_luaeval(typval_T *argvars, typval_T *rettv)
3ed64d
     char_u	*str;
3ed64d
     char_u	buf[NUMBUFLEN];
3ed64d
 
3ed64d
+    if (check_restricted() || check_secure())
3ed64d
+	return;
3ed64d
+
3ed64d
     str = get_tv_string_buf(&argvars[0], buf);
3ed64d
     do_luaeval(str, argvars + 1, rettv);
3ed64d
 }
3ed64d
@@ -8188,6 +8191,8 @@ f_mzeval(typval_T *argvars, typval_T *rettv)
3ed64d
     char_u	*str;
3ed64d
     char_u	buf[NUMBUFLEN];
3ed64d
 
3ed64d
+    if (check_restricted() || check_secure())
3ed64d
+	return;
3ed64d
     str = get_tv_string_buf(&argvars[0], buf);
3ed64d
     do_mzeval(str, rettv);
3ed64d
 }
3ed64d
@@ -8398,6 +8403,9 @@ f_py3eval(typval_T *argvars, typval_T *rettv)
3ed64d
     char_u	*str;
3ed64d
     char_u	buf[NUMBUFLEN];
3ed64d
 
3ed64d
+    if (check_restricted() || check_secure())
3ed64d
+	return;
3ed64d
+
3ed64d
     if (p_pyx == 0)
3ed64d
 	p_pyx = 3;
3ed64d
 
3ed64d
@@ -8416,6 +8424,9 @@ f_pyeval(typval_T *argvars, typval_T *rettv)
3ed64d
     char_u	*str;
3ed64d
     char_u	buf[NUMBUFLEN];
3ed64d
 
3ed64d
+    if (check_restricted() || check_secure())
3ed64d
+	return;
3ed64d
+
3ed64d
     if (p_pyx == 0)
3ed64d
 	p_pyx = 2;
3ed64d
 
3ed64d
@@ -8431,6 +8442,9 @@ f_pyeval(typval_T *argvars, typval_T *rettv)
3ed64d
     static void
3ed64d
 f_pyxeval(typval_T *argvars, typval_T *rettv)
3ed64d
 {
3ed64d
+    if (check_restricted() || check_secure())
3ed64d
+	return;
3ed64d
+
3ed64d
 # if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
3ed64d
     init_pyxversion();
3ed64d
     if (p_pyx == 2)
3ed64d
@@ -10272,7 +10286,7 @@ f_setbufvar(typval_T *argvars, typval_T *rettv UNUSED)
3ed64d
     typval_T	*varp;
3ed64d
     char_u	nbuf[NUMBUFLEN];
3ed64d
 
3ed64d
-    if (check_restricted() || check_secure())
3ed64d
+    if (check_secure())
3ed64d
 	return;
3ed64d
     (void)get_tv_number(&argvars[0]);	    /* issue errmsg if type error */
3ed64d
     varname = get_tv_string_chk(&argvars[1]);
3ed64d
@@ -10792,7 +10806,7 @@ f_settabvar(typval_T *argvars, typval_T *rettv)
3ed64d
 
3ed64d
     rettv->vval.v_number = 0;
3ed64d
 
3ed64d
-    if (check_restricted() || check_secure())
3ed64d
+    if (check_secure())
3ed64d
 	return;
3ed64d
 
3ed64d
     tp = find_tabpage((int)get_tv_number_chk(&argvars[0], NULL));
3ed64d
@@ -13674,7 +13688,7 @@ f_writefile(typval_T *argvars, typval_T *rettv)
3ed64d
     list_T	*list;
3ed64d
 
3ed64d
     rettv->vval.v_number = -1;
3ed64d
-    if (check_restricted() || check_secure())
3ed64d
+    if (check_secure())
3ed64d
 	return;
3ed64d
 
3ed64d
     if (argvars[0].v_type != VAR_LIST)
3ed64d
diff --git a/src/ex_cmds.c b/src/ex_cmds.c
3ed64d
index 111fe01..1827fec 100644
3ed64d
--- a/src/ex_cmds.c
3ed64d
+++ b/src/ex_cmds.c
3ed64d
@@ -4693,7 +4693,7 @@ check_restricted(void)
3ed64d
 {
3ed64d
     if (restricted)
3ed64d
     {
3ed64d
-	EMSG(_("E145: Shell commands not allowed in rvim"));
3ed64d
+	EMSG(_("E145: Shell commands and some functionality not allowed in rvim"));
3ed64d
 	return TRUE;
3ed64d
     }
3ed64d
     return FALSE;
3ed64d
diff --git a/src/ex_cmds.h b/src/ex_cmds.h
3ed64d
index 48b0253..82d6e29 100644
3ed64d
--- a/src/ex_cmds.h
3ed64d
+++ b/src/ex_cmds.h
3ed64d
@@ -56,6 +56,7 @@
3ed64d
 				 * curbuf_lock is set */
3ed64d
 #define MODIFY       0x200000L	/* forbidden in non-'modifiable' buffer */
3ed64d
 #define EXFLAGS      0x400000L	/* allow flags after count in argument */
3ed64d
+#define RESTRICT     0x800000L	/* forbidden in restricted mode */
3ed64d
 #define FILES	(XFILE | EXTRA)	/* multiple extra files allowed */
3ed64d
 #define WORD1	(EXTRA | NOSPC)	/* one extra word allowed */
3ed64d
 #define FILE1	(FILES | NOSPC)	/* 1 file allowed, defaults to current file */
3ed64d
@@ -860,13 +861,13 @@ EX(CMD_lunmap,		"lunmap",	ex_unmap,
3ed64d
 			EXTRA|TRLBAR|NOTRLCOM|USECTRLV|CMDWIN,
3ed64d
 			ADDR_LINES),
3ed64d
 EX(CMD_lua,		"lua",		ex_lua,
3ed64d
-			RANGE|EXTRA|NEEDARG|CMDWIN,
3ed64d
+			RANGE|EXTRA|NEEDARG|CMDWIN|RESTRICT,
3ed64d
 			ADDR_LINES),
3ed64d
 EX(CMD_luado,		"luado",	ex_luado,
3ed64d
-			RANGE|DFLALL|EXTRA|NEEDARG|CMDWIN,
3ed64d
+			RANGE|DFLALL|EXTRA|NEEDARG|CMDWIN|RESTRICT,
3ed64d
 			ADDR_LINES),
3ed64d
 EX(CMD_luafile,		"luafile",	ex_luafile,
3ed64d
-			RANGE|FILE1|NEEDARG|CMDWIN,
3ed64d
+			RANGE|FILE1|NEEDARG|CMDWIN|RESTRICT,
3ed64d
 			ADDR_LINES),
3ed64d
 EX(CMD_lvimgrep,	"lvimgrep",	ex_vimgrep,
3ed64d
 			RANGE|NOTADR|BANG|NEEDARG|EXTRA|NOTRLCOM|TRLBAR|XFILE,
3ed64d
@@ -929,10 +930,10 @@ EX(CMD_mode,		"mode",		ex_mode,
3ed64d
 			WORD1|TRLBAR|CMDWIN,
3ed64d
 			ADDR_LINES),
3ed64d
 EX(CMD_mzscheme,	"mzscheme",	ex_mzscheme,
3ed64d
-			RANGE|EXTRA|DFLALL|NEEDARG|CMDWIN|SBOXOK,
3ed64d
+			RANGE|EXTRA|DFLALL|NEEDARG|CMDWIN|SBOXOK|RESTRICT,
3ed64d
 			ADDR_LINES),
3ed64d
 EX(CMD_mzfile,		"mzfile",	ex_mzfile,
3ed64d
-			RANGE|FILE1|NEEDARG|CMDWIN,
3ed64d
+			RANGE|FILE1|NEEDARG|CMDWIN|RESTRICT,
3ed64d
 			ADDR_LINES),
3ed64d
 EX(CMD_next,		"next",		ex_next,
3ed64d
 			RANGE|NOTADR|BANG|FILES|EDITCMD|ARGOPT|TRLBAR,
3ed64d
@@ -1115,37 +1116,37 @@ EX(CMD_pwd,		"pwd",		ex_pwd,
3ed64d
 			TRLBAR|CMDWIN,
3ed64d
 			ADDR_LINES),
3ed64d
 EX(CMD_python,		"python",	ex_python,
3ed64d
-			RANGE|EXTRA|NEEDARG|CMDWIN,
3ed64d
+			RANGE|EXTRA|NEEDARG|CMDWIN|RESTRICT,
3ed64d
 			ADDR_LINES),
3ed64d
 EX(CMD_pydo,		"pydo",		ex_pydo,
3ed64d
-			RANGE|DFLALL|EXTRA|NEEDARG|CMDWIN,
3ed64d
+			RANGE|DFLALL|EXTRA|NEEDARG|CMDWIN|RESTRICT,
3ed64d
 			ADDR_LINES),
3ed64d
 EX(CMD_pyfile,		"pyfile",	ex_pyfile,
3ed64d
-			RANGE|FILE1|NEEDARG|CMDWIN,
3ed64d
+			RANGE|FILE1|NEEDARG|CMDWIN|RESTRICT,
3ed64d
 			ADDR_LINES),
3ed64d
 EX(CMD_py3,		"py3",		ex_py3,
3ed64d
-			RANGE|EXTRA|NEEDARG|CMDWIN,
3ed64d
+			RANGE|EXTRA|NEEDARG|CMDWIN|RESTRICT,
3ed64d
 			ADDR_LINES),
3ed64d
 EX(CMD_py3do,		"py3do",	ex_py3do,
3ed64d
-			RANGE|DFLALL|EXTRA|NEEDARG|CMDWIN,
3ed64d
+			RANGE|DFLALL|EXTRA|NEEDARG|CMDWIN|RESTRICT,
3ed64d
 			ADDR_LINES),
3ed64d
 EX(CMD_python3,		"python3",	ex_py3,
3ed64d
-			RANGE|EXTRA|NEEDARG|CMDWIN,
3ed64d
+			RANGE|EXTRA|NEEDARG|CMDWIN|RESTRICT,
3ed64d
 			ADDR_LINES),
3ed64d
 EX(CMD_py3file,		"py3file",	ex_py3file,
3ed64d
-			RANGE|FILE1|NEEDARG|CMDWIN,
3ed64d
+			RANGE|FILE1|NEEDARG|CMDWIN|RESTRICT,
3ed64d
 			ADDR_LINES),
3ed64d
 EX(CMD_pyx,		"pyx",		ex_pyx,
3ed64d
-			RANGE|EXTRA|NEEDARG|CMDWIN,
3ed64d
+			RANGE|EXTRA|NEEDARG|CMDWIN|RESTRICT,
3ed64d
 			ADDR_LINES),
3ed64d
 EX(CMD_pyxdo,		"pyxdo",	ex_pyxdo,
3ed64d
-			RANGE|DFLALL|EXTRA|NEEDARG|CMDWIN,
3ed64d
+			RANGE|DFLALL|EXTRA|NEEDARG|CMDWIN|RESTRICT,
3ed64d
 			ADDR_LINES),
3ed64d
 EX(CMD_pythonx,		"pythonx",	ex_pyx,
3ed64d
-			RANGE|EXTRA|NEEDARG|CMDWIN,
3ed64d
+			RANGE|EXTRA|NEEDARG|CMDWIN|RESTRICT,
3ed64d
 			ADDR_LINES),
3ed64d
 EX(CMD_pyxfile,		"pyxfile",	ex_pyxfile,
3ed64d
-			RANGE|FILE1|NEEDARG|CMDWIN,
3ed64d
+			RANGE|FILE1|NEEDARG|CMDWIN|RESTRICT,
3ed64d
 			ADDR_LINES),
3ed64d
 EX(CMD_quit,		"quit",		ex_quit,
3ed64d
 			BANG|RANGE|COUNT|NOTADR|TRLBAR|CMDWIN,
3ed64d
@@ -1199,13 +1200,13 @@ EX(CMD_runtime,		"runtime",	ex_runtime,
3ed64d
 			BANG|NEEDARG|FILES|TRLBAR|SBOXOK|CMDWIN,
3ed64d
 			ADDR_LINES),
3ed64d
 EX(CMD_ruby,		"ruby",		ex_ruby,
3ed64d
-			RANGE|EXTRA|NEEDARG|CMDWIN,
3ed64d
+			RANGE|EXTRA|NEEDARG|CMDWIN|RESTRICT,
3ed64d
 			ADDR_LINES),
3ed64d
 EX(CMD_rubydo,		"rubydo",	ex_rubydo,
3ed64d
-			RANGE|DFLALL|EXTRA|NEEDARG|CMDWIN,
3ed64d
+			RANGE|DFLALL|EXTRA|NEEDARG|CMDWIN|RESTRICT,
3ed64d
 			ADDR_LINES),
3ed64d
 EX(CMD_rubyfile,	"rubyfile",	ex_rubyfile,
3ed64d
-			RANGE|FILE1|NEEDARG|CMDWIN,
3ed64d
+			RANGE|FILE1|NEEDARG|CMDWIN|RESTRICT,
3ed64d
 			ADDR_LINES),
3ed64d
 EX(CMD_rundo,		"rundo",	ex_rundo,
3ed64d
 			NEEDARG|FILE1,
3ed64d
@@ -1472,13 +1473,13 @@ EX(CMD_tabs,		"tabs",		ex_tabs,
3ed64d
 			TRLBAR|CMDWIN,
3ed64d
 			ADDR_TABS),
3ed64d
 EX(CMD_tcl,		"tcl",		ex_tcl,
3ed64d
-			RANGE|EXTRA|NEEDARG|CMDWIN,
3ed64d
+			RANGE|EXTRA|NEEDARG|CMDWIN|RESTRICT,
3ed64d
 			ADDR_LINES),
3ed64d
 EX(CMD_tcldo,		"tcldo",	ex_tcldo,
3ed64d
-			RANGE|DFLALL|EXTRA|NEEDARG|CMDWIN,
3ed64d
+			RANGE|DFLALL|EXTRA|NEEDARG|CMDWIN|RESTRICT,
3ed64d
 			ADDR_LINES),
3ed64d
 EX(CMD_tclfile,		"tclfile",	ex_tclfile,
3ed64d
-			RANGE|FILE1|NEEDARG|CMDWIN,
3ed64d
+			RANGE|FILE1|NEEDARG|CMDWIN|RESTRICT,
3ed64d
 			ADDR_LINES),
3ed64d
 EX(CMD_tearoff,		"tearoff",	ex_tearoff,
3ed64d
 			NEEDARG|EXTRA|TRLBAR|NOTRLCOM|CMDWIN,
3ed64d
diff --git a/src/ex_docmd.c b/src/ex_docmd.c
3ed64d
index ef86fc8..aaf2f9d 100644
3ed64d
--- a/src/ex_docmd.c
3ed64d
+++ b/src/ex_docmd.c
3ed64d
@@ -2372,11 +2372,16 @@ do_one_cmd(
3ed64d
 #ifdef HAVE_SANDBOX
3ed64d
 	if (sandbox != 0 && !(ea.argt & SBOXOK))
3ed64d
 	{
3ed64d
-	    /* Command not allowed in sandbox. */
3ed64d
+	    // Command not allowed in sandbox.
3ed64d
 	    errormsg = (char_u *)_(e_sandbox);
3ed64d
 	    goto doend;
3ed64d
 	}
3ed64d
 #endif
3ed64d
+	if (restricted != 0 && (ea.argt & RESTRICT))
3ed64d
+	{
3ed64d
+	    errormsg = (char_u *)_("E981: Command not allowed in rvim");
3ed64d
+	    goto doend;
3ed64d
+	}
3ed64d
 	if (!curbuf->b_p_ma && (ea.argt & MODIFY))
3ed64d
 	{
3ed64d
 	    /* Command not allowed in non-'modifiable' buffer */
3ed64d
diff --git a/src/if_perl.xs b/src/if_perl.xs
3ed64d
index 7b45033..fc8d613 100644
3ed64d
--- a/src/if_perl.xs
3ed64d
+++ b/src/if_perl.xs
3ed64d
@@ -930,6 +930,7 @@ VIM_init(void)
3ed64d
 #ifdef DYNAMIC_PERL
3ed64d
 static char *e_noperl = N_("Sorry, this command is disabled: the Perl library could not be loaded.");
3ed64d
 #endif
3ed64d
+static char *e_perlsandbox = N_("E299: Perl evaluation forbidden in sandbox without the Safe module");
3ed64d
 
3ed64d
 /*
3ed64d
  * ":perl"
3ed64d
@@ -978,13 +979,12 @@ ex_perl(exarg_T *eap)
3ed64d
 	vim_free(script);
3ed64d
     }
3ed64d
 
3ed64d
-#ifdef HAVE_SANDBOX
3ed64d
-    if (sandbox)
3ed64d
+    if (sandbox || secure)
3ed64d
     {
3ed64d
 	safe = perl_get_sv("VIM::safe", FALSE);
3ed64d
 # ifndef MAKE_TEST  /* avoid a warning for unreachable code */
3ed64d
 	if (safe == NULL || !SvTRUE(safe))
3ed64d
-	    EMSG(_("E299: Perl evaluation forbidden in sandbox without the Safe module"));
3ed64d
+	    EMSG(_(e_perlsandbox));
3ed64d
 	else
3ed64d
 # endif
3ed64d
 	{
3ed64d
@@ -996,7 +996,6 @@ ex_perl(exarg_T *eap)
3ed64d
 	}
3ed64d
     }
3ed64d
     else
3ed64d
-#endif
3ed64d
 	perl_eval_sv(sv, G_DISCARD | G_NOARGS);
3ed64d
 
3ed64d
     SvREFCNT_dec(sv);
3ed64d
@@ -1259,13 +1258,12 @@ do_perleval(char_u *str, typval_T *rettv)
3ed64d
 	ENTER;
3ed64d
 	SAVETMPS;
3ed64d
 
3ed64d
-#ifdef HAVE_SANDBOX
3ed64d
-	if (sandbox)
3ed64d
+	if (sandbox || secure)
3ed64d
 	{
3ed64d
 	    safe = get_sv("VIM::safe", FALSE);
3ed64d
 # ifndef MAKE_TEST  /* avoid a warning for unreachable code */
3ed64d
 	    if (safe == NULL || !SvTRUE(safe))
3ed64d
-		EMSG(_("E299: Perl evaluation forbidden in sandbox without the Safe module"));
3ed64d
+		EMSG(_(e_perlsandbox));
3ed64d
 	    else
3ed64d
 # endif
3ed64d
 	    {
3ed64d
@@ -1281,7 +1279,6 @@ do_perleval(char_u *str, typval_T *rettv)
3ed64d
 	    }
3ed64d
 	}
3ed64d
 	else
3ed64d
-#endif /* HAVE_SANDBOX */
3ed64d
 	    sv = eval_pv((char *)str, 0);
3ed64d
 
3ed64d
 	if (sv) {
3ed64d
diff --git a/src/testdir/Make_all.mak b/src/testdir/Make_all.mak
3ed64d
index e36089a..5f1c38c 100644
3ed64d
--- a/src/testdir/Make_all.mak
3ed64d
+++ b/src/testdir/Make_all.mak
3ed64d
@@ -156,6 +156,7 @@ NEW_TESTS = test_arabic.res \
3ed64d
 	    test_quotestar.res \
3ed64d
 	    test_regex_char_classes.res \
3ed64d
 	    test_registers.res \
3ed64d
+	    test_restricted.res \
3ed64d
 	    test_retab.res \
3ed64d
 	    test_ruby.res \
3ed64d
 	    test_scrollbind.res \
3ed64d
diff --git a/src/testdir/test_restricted.vim b/src/testdir/test_restricted.vim
3ed64d
new file mode 100644
3ed64d
index 0000000..9dd937c
3ed64d
--- /dev/null
3ed64d
+++ b/src/testdir/test_restricted.vim
3ed64d
@@ -0,0 +1,107 @@
3ed64d
+" Test for "rvim" or "vim -Z"
3ed64d
+
3ed64d
+source shared.vim
3ed64d
+
3ed64d
+func Test_restricted()
3ed64d
+  let cmd = GetVimCommand('Xrestricted')
3ed64d
+  if cmd == ''
3ed64d
+    return
3ed64d
+  endif
3ed64d
+
3ed64d
+  call writefile([
3ed64d
+	\ "silent !ls",
3ed64d
+	\ "call writefile([v:errmsg], 'Xrestrout')",
3ed64d
+	\ "qa!",
3ed64d
+	\ ], 'Xrestricted')
3ed64d
+  call system(cmd . ' -Z')
3ed64d
+  call assert_match('E145:', join(readfile('Xrestrout')))
3ed64d
+
3ed64d
+  call delete('Xrestricted')
3ed64d
+  call delete('Xrestrout')
3ed64d
+endfunc
3ed64d
+
3ed64d
+func Run_restricted_test(ex_cmd, error)
3ed64d
+  let cmd = GetVimCommand('Xrestricted')
3ed64d
+  if cmd == ''
3ed64d
+    return
3ed64d
+  endif
3ed64d
+
3ed64d
+  call writefile([
3ed64d
+	\ a:ex_cmd,
3ed64d
+	\ "call writefile([v:errmsg], 'Xrestrout')",
3ed64d
+	\ "qa!",
3ed64d
+	\ ], 'Xrestricted')
3ed64d
+  call system(cmd . ' -Z')
3ed64d
+  call assert_match(a:error, join(readfile('Xrestrout')))
3ed64d
+
3ed64d
+  call delete('Xrestricted')
3ed64d
+  call delete('Xrestrout')
3ed64d
+endfunc
3ed64d
+
3ed64d
+func Test_restricted_lua()
3ed64d
+  if !has('lua')
3ed64d
+    throw 'Skipped: Lua is not supported'
3ed64d
+  endif
3ed64d
+  call Run_restricted_test('lua print("Hello, Vim!")', 'E981:')
3ed64d
+  call Run_restricted_test('luado return "hello"', 'E981:')
3ed64d
+  call Run_restricted_test('luafile somefile', 'E981:')
3ed64d
+  call Run_restricted_test('call luaeval("expression")', 'E145:')
3ed64d
+endfunc
3ed64d
+
3ed64d
+func Test_restricted_mzscheme()
3ed64d
+  if !has('mzscheme')
3ed64d
+    throw 'Skipped: MzScheme is not supported'
3ed64d
+  endif
3ed64d
+  call Run_restricted_test('mzscheme statement', 'E981:')
3ed64d
+  call Run_restricted_test('mzfile somefile', 'E981:')
3ed64d
+  call Run_restricted_test('call mzeval("expression")', 'E145:')
3ed64d
+endfunc
3ed64d
+
3ed64d
+func Test_restricted_perl()
3ed64d
+  if !has('perl')
3ed64d
+    throw 'Skipped: Perl is not supported'
3ed64d
+  endif
3ed64d
+  " TODO: how to make Safe mode fail?
3ed64d
+  " call Run_restricted_test('perl system("ls")', 'E981:')
3ed64d
+  " call Run_restricted_test('perldo system("hello")', 'E981:')
3ed64d
+  " call Run_restricted_test('perlfile somefile', 'E981:')
3ed64d
+  " call Run_restricted_test('call perleval("system(\"ls\")")', 'E145:')
3ed64d
+endfunc
3ed64d
+
3ed64d
+func Test_restricted_python()
3ed64d
+  if !has('python')
3ed64d
+    throw 'Skipped: Python is not supported'
3ed64d
+  endif
3ed64d
+  call Run_restricted_test('python print "hello"', 'E981:')
3ed64d
+  call Run_restricted_test('pydo return "hello"', 'E981:')
3ed64d
+  call Run_restricted_test('pyfile somefile', 'E981:')
3ed64d
+  call Run_restricted_test('call pyeval("expression")', 'E145:')
3ed64d
+endfunc
3ed64d
+
3ed64d
+func Test_restricted_python3()
3ed64d
+  if !has('python3')
3ed64d
+    throw 'Skipped: Python3 is not supported'
3ed64d
+  endif
3ed64d
+  call Run_restricted_test('py3 print "hello"', 'E981:')
3ed64d
+  call Run_restricted_test('py3do return "hello"', 'E981:')
3ed64d
+  call Run_restricted_test('py3file somefile', 'E981:')
3ed64d
+  call Run_restricted_test('call py3eval("expression")', 'E145:')
3ed64d
+endfunc
3ed64d
+
3ed64d
+func Test_restricted_ruby()
3ed64d
+  if !has('ruby')
3ed64d
+    throw 'Skipped: Ruby is not supported'
3ed64d
+  endif
3ed64d
+  call Run_restricted_test('ruby print "Hello"', 'E981:')
3ed64d
+  call Run_restricted_test('rubydo print "Hello"', 'E981:')
3ed64d
+  call Run_restricted_test('rubyfile somefile', 'E981:')
3ed64d
+endfunc
3ed64d
+
3ed64d
+func Test_restricted_tcl()
3ed64d
+  if !has('tcl')
3ed64d
+    throw 'Skipped: Tcl is not supported'
3ed64d
+  endif
3ed64d
+  call Run_restricted_test('tcl puts "Hello"', 'E981:')
3ed64d
+  call Run_restricted_test('tcldo puts "Hello"', 'E981:')
3ed64d
+  call Run_restricted_test('tclfile somefile', 'E981:')
3ed64d
+endfunc