From ee2b10d63b6714cb851e0f5e68cf005c864fcb27 Mon Sep 17 00:00:00 2001
From: Nathan Bossart <nathandbossart@gmail.com>
Date: Wed, 18 May 2022 14:33:48 -0700
Subject: [PATCH v1 3/3] Allow building only trusted or untrusted PL/Tcl.

Presently, when the --with-tcl configuration option is used, both
trusted and untrusted PL/Tcl are built.  However, some users may
only want to build one or the other.  This change introduces an
optional argument that can be used to do so.  If
--with-tcl='trusted' is specified, only trusted PL/Tcl is built.
If --with-tcl='untrusted' is specified, only untrusted PL/Tcl is
built.  If --with-tcl is given without an argument, both trusted
and untrusted PL/Tcl are built.
---
 configure                      | 47 +++++++++++++++++++++++++++++++---
 configure.ac                   | 32 ++++++++++++++++++++++-
 doc/src/sgml/installation.sgml | 23 ++++++++++++++++-
 src/Makefile.global.in         |  2 ++
 src/include/pg_config.h.in     |  6 +++++
 src/pl/tcl/Makefile            | 12 ++++++---
 src/pl/tcl/pltcl.c             | 16 ++++++++++--
 7 files changed, 126 insertions(+), 12 deletions(-)

diff --git a/configure b/configure
index faa8b1a2e3..046fc4dcf0 100755
--- a/configure
+++ b/configure
@@ -726,6 +726,8 @@ with_python
 PERL_UNTRUSTED
 PERL_TRUSTED
 with_perl
+TCL_UNTRUSTED
+TCL_TRUSTED
 with_tcl
 ICU_LIBS
 ICU_CFLAGS
@@ -1563,7 +1565,8 @@ Optional Packages:
   --with-CC=CMD           set compiler (deprecated)
   --with-llvm             build with LLVM based JIT support
   --with-icu              build with ICU support
-  --with-tcl              build Tcl modules (PL/Tcl)
+  --with-tcl[=TRUSTWORTHINESS]
+                          build Tcl modules (PL/Tcl)
   --with-tclconfig=DIR    tclConfig.sh is in DIR
   --with-perl[=TRUSTWORTHINESS]
                           build Perl modules (PL/Perl)
@@ -8097,26 +8100,62 @@ if test "${with_tcl+set}" = set; then :
   withval=$with_tcl;
   case $withval in
     yes)
-      :
+
+  TCL_TRUSTED=yes
+  TCL_UNTRUSTED=yes
+
       ;;
     no)
       :
       ;;
     *)
-      as_fn_error $? "no argument expected for --with-tcl option" "$LINENO" 5
+      with_tcl=yes
+
+  if test "$withval" = trusted ; then
+    TCL_TRUSTED=yes
+    TCL_UNTRUSTED=no
+  elif test "$withval" = untrusted ; then
+    TCL_TRUSTED=no
+    TCL_UNTRUSTED=yes
+  else
+    as_fn_error $? "invalid --with-tcl value: argument must be omitted or specified as 'trusted' or 'untrusted'" "$LINENO" 5
+  fi
+
       ;;
   esac
 
 else
   with_tcl=no
-
 fi
 
 
+
+if test "$with_tcl" = yes; then
+
+  if test "$TCL_TRUSTED" = yes ; then
+
+$as_echo "#define USE_TCL 1" >>confdefs.h
+
+  fi
+  if test "$TCL_UNTRUSTED" = yes ; then
+
+$as_echo "#define USE_TCLU 1" >>confdefs.h
+
+  fi
+
+else
+
+  TCL_TRUSTED=no
+  TCL_UNTRUSTED=no
+
+fi
+
 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_tcl" >&5
 $as_echo "$with_tcl" >&6; }
 
 
+
+
 # We see if the path to the Tcl/Tk configuration scripts is specified.
 # This will override the use of tclsh to find the paths to search.
 
diff --git a/configure.ac b/configure.ac
index 0dd440131b..8e7d96a6fe 100644
--- a/configure.ac
+++ b/configure.ac
@@ -810,9 +810,39 @@ fi
 # Optionally build Tcl modules (PL/Tcl)
 #
 AC_MSG_CHECKING([whether to build with Tcl])
-PGAC_ARG_BOOL(with, tcl, no, [build Tcl modules (PL/Tcl)])
+PGAC_ARG_OPTARG(with, tcl,
+[TRUSTWORTHINESS], [build Tcl modules (PL/Tcl)],
+[
+  TCL_TRUSTED=yes
+  TCL_UNTRUSTED=yes
+],
+[
+  if test "$withval" = trusted ; then
+    TCL_TRUSTED=yes
+    TCL_UNTRUSTED=no
+  elif test "$withval" = untrusted ; then
+    TCL_TRUSTED=no
+    TCL_UNTRUSTED=yes
+  else
+    AC_MSG_ERROR([invalid --with-tcl value: argument must be omitted or specified as 'trusted' or 'untrusted'])
+  fi
+],
+[
+  if test "$TCL_TRUSTED" = yes ; then
+    AC_DEFINE([USE_TCL], 1, [Define to 1 to build with trusted Tcl support. (--with-tcl='trusted')])
+  fi
+  if test "$TCL_UNTRUSTED" = yes ; then
+    AC_DEFINE([USE_TCLU], 1, [Define to 1 to build with untrusted Tcl support. (--with-tcl='untrusted')])
+  fi
+],
+[
+  TCL_TRUSTED=no
+  TCL_UNTRUSTED=no
+])
 AC_MSG_RESULT([$with_tcl])
 AC_SUBST([with_tcl])
+AC_SUBST(TCL_TRUSTED)
+AC_SUBST(TCL_UNTRUSTED)
 
 # We see if the path to the Tcl/Tk configuration scripts is specified.
 # This will override the use of tclsh to find the paths to search.
diff --git a/doc/src/sgml/installation.sgml b/doc/src/sgml/installation.sgml
index 4377e9d51a..8d96152dd2 100644
--- a/doc/src/sgml/installation.sgml
+++ b/doc/src/sgml/installation.sgml
@@ -912,10 +912,31 @@ build-postgresql:
       </varlistentry>
 
       <varlistentry>
-       <term><option>--with-tcl</option></term>
+       <term><option>--with_tcl<optional>=<replaceable>TRUSTWORTHINESS</replaceable></optional></option></term>
        <listitem>
         <para>
          Build the <application>PL/Tcl</application> server-side language.
+         <replaceable>TRUSTWORTHINESS</replaceable> is an optional argument and,
+         if provided, must be one of:
+        </para>
+        <itemizedlist>
+         <listitem>
+          <para>
+           <option>trusted</option> to build only trusted
+           <application>PL/Tcl</application>
+          </para>
+         </listitem>
+         <listitem>
+          <para>
+           <option>untrusted</option> to build only untrusted
+           <application>PL/Tcl</application>
+           (<application>PL/TclU</application>)
+          </para>
+         </listitem>
+        </itemizedlist>
+        <para>
+         If <replaceable>TRUSTWORTHINESS</replaceable> is not specified, both
+         trusted and untrusted <application>PL/Tcl</application> will be built.
         </para>
        </listitem>
       </varlistentry>
diff --git a/src/Makefile.global.in b/src/Makefile.global.in
index 53f367ca7a..0262ee6d96 100644
--- a/src/Makefile.global.in
+++ b/src/Makefile.global.in
@@ -528,6 +528,8 @@ DEF_PGPORT = @default_port@
 WANTED_LANGUAGES = @WANTED_LANGUAGES@
 PERL_TRUSTED = @PERL_TRUSTED@
 PERL_UNTRUSTED = @PERL_UNTRUSTED@
+TCL_TRUSTED = @TCL_TRUSTED@
+TCL_UNTRUSTED = @TCL_UNTRUSTED@
 
 
 ##########################################################################
diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in
index 2779f5f671..c7eb244050 100644
--- a/src/include/pg_config.h.in
+++ b/src/include/pg_config.h.in
@@ -955,6 +955,12 @@
 /* Define to select SysV-style shared memory. */
 #undef USE_SYSV_SHARED_MEMORY
 
+/* Define to 1 to build with trusted Tcl support. (--with-tcl='trusted') */
+#undef USE_TCL
+
+/* Define to 1 to build with untrusted Tcl support. (--with-tcl='untrusted') */
+#undef USE_TCLU
+
 /* Define to select unnamed POSIX semaphores. */
 #undef USE_UNNAMED_POSIX_SEMAPHORES
 
diff --git a/src/pl/tcl/Makefile b/src/pl/tcl/Makefile
index 25e65189b6..842d425969 100644
--- a/src/pl/tcl/Makefile
+++ b/src/pl/tcl/Makefile
@@ -26,11 +26,15 @@ OBJS = \
 	$(WIN32RES) \
 	pltcl.o
 
-DATA = pltcl.control pltcl--1.0.sql \
-       pltclu.control pltclu--1.0.sql
+ifeq ($(TCL_TRUSTED), yes)
+	DATA += pltcl.control pltcl--1.0.sql
+	REGRESS_OPTS = --dbname=$(PL_TESTDB) --load-extension=pltcl
+	REGRESS = pltcl_setup pltcl_queries pltcl_trigger pltcl_call pltcl_start_proc pltcl_subxact pltcl_unicode pltcl_transaction
+endif
 
-REGRESS_OPTS = --dbname=$(PL_TESTDB) --load-extension=pltcl
-REGRESS = pltcl_setup pltcl_queries pltcl_trigger pltcl_call pltcl_start_proc pltcl_subxact pltcl_unicode pltcl_transaction
+ifeq ($(TCL_UNTRUSTED), yes)
+	DATA += pltclu.control pltclu--1.0.sql
+endif
 
 # Tcl on win32 ships with import libraries only for Microsoft Visual C++,
 # which are not compatible with mingw gcc. Therefore we need to build a
diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c
index 0dd6d8ab2c..57c5fc79fb 100644
--- a/src/pl/tcl/pltcl.c
+++ b/src/pl/tcl/pltcl.c
@@ -459,6 +459,7 @@ _PG_init(void)
 	/************************************************************
 	 * Define PL/Tcl's custom GUCs
 	 ************************************************************/
+#ifdef USE_TCL
 	DefineCustomStringVariable("pltcl.start_proc",
 							   gettext_noop("PL/Tcl function to call once when pltcl is first used."),
 							   NULL,
@@ -466,6 +467,10 @@ _PG_init(void)
 							   NULL,
 							   PGC_SUSET, 0,
 							   NULL, NULL, NULL);
+	MarkGUCPrefixReserved("pltcl");
+#endif	/* USE_TCL */
+
+#ifdef USE_TCLU
 	DefineCustomStringVariable("pltclu.start_proc",
 							   gettext_noop("PL/TclU function to call once when pltclu is first used."),
 							   NULL,
@@ -473,9 +478,8 @@ _PG_init(void)
 							   NULL,
 							   PGC_SUSET, 0,
 							   NULL, NULL, NULL);
-
-	MarkGUCPrefixReserved("pltcl");
 	MarkGUCPrefixReserved("pltclu");
+#endif	/* USE_TCLU */
 
 	pltcl_pm_init_done = true;
 }
@@ -690,6 +694,8 @@ start_proc_error_callback(void *arg)
  *				  call this function for execution of
  *				  PL/Tcl procedures.
  **********************************************************************/
+#ifdef USE_TCL
+
 PG_FUNCTION_INFO_V1(pltcl_call_handler);
 
 /* keep non-static */
@@ -699,6 +705,10 @@ pltcl_call_handler(PG_FUNCTION_ARGS)
 	return pltcl_handler(fcinfo, true);
 }
 
+#endif /* USE_TCL */
+
+#ifdef USE_TCLU
+
 /*
  * Alternative handler for unsafe functions
  */
@@ -711,6 +721,8 @@ pltclu_call_handler(PG_FUNCTION_ARGS)
 	return pltcl_handler(fcinfo, false);
 }
 
+#endif	/* USE_TCLU */
+
 
 /**********************************************************************
  * pltcl_handler()		- Handler for function and trigger calls, for
-- 
2.25.1

