summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog7
-rw-r--r--readconf.c18
-rw-r--r--readconf.h7
-rw-r--r--servconf.c19
-rw-r--r--servconf.h6
-rw-r--r--session.c52
-rw-r--r--session.h7
-rw-r--r--ssh.c41
-rw-r--r--ssh_config.523
-rw-r--r--sshd_config.525
10 files changed, 194 insertions, 11 deletions
diff --git a/ChangeLog b/ChangeLog
index 3457022c2..52c9eabdd 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -4,6 +4,11 @@
4 [moduli.c] 4 [moduli.c]
5 Bugzilla #850: Sophie Germain is the correct name of the French 5 Bugzilla #850: Sophie Germain is the correct name of the French
6 mathematician, "Sophie Germaine" isn't; from Luc.Maisonobe@c-s.fr 6 mathematician, "Sophie Germaine" isn't; from Luc.Maisonobe@c-s.fr
7 - djm@cvs.openbsd.org 2004/04/27 09:46:37
8 [readconf.c readconf.h servconf.c servconf.h session.c session.h ssh.c
9 ssh_config.5 sshd_config.5]
10 bz #815: implement ability to pass specified environment variables from
11 the client to the server; ok markus@
7 12
820040423 1320040423
9 - (dtucker) [configure.ac openbsd-compat/getrrsetbyname.c] Declare h_errno 14 - (dtucker) [configure.ac openbsd-compat/getrrsetbyname.c] Declare h_errno
@@ -1045,4 +1050,4 @@
1045 - (djm) Trim deprecated options from INSTALL. Mention UsePAM 1050 - (djm) Trim deprecated options from INSTALL. Mention UsePAM
1046 - (djm) Fix quote handling in sftp; Patch from admorten AT umich.edu 1051 - (djm) Fix quote handling in sftp; Patch from admorten AT umich.edu
1047 1052
1048$Id: ChangeLog,v 1.3333 2004/05/02 12:09:00 dtucker Exp $ 1053$Id: ChangeLog,v 1.3334 2004/05/02 12:11:30 dtucker Exp $
diff --git a/readconf.c b/readconf.c
index 096d1a71b..f4710e833 100644
--- a/readconf.c
+++ b/readconf.c
@@ -12,7 +12,7 @@
12 */ 12 */
13 13
14#include "includes.h" 14#include "includes.h"
15RCSID("$OpenBSD: readconf.c,v 1.129 2004/04/18 23:10:26 djm Exp $"); 15RCSID("$OpenBSD: readconf.c,v 1.130 2004/04/27 09:46:36 djm Exp $");
16 16
17#include "ssh.h" 17#include "ssh.h"
18#include "xmalloc.h" 18#include "xmalloc.h"
@@ -106,6 +106,7 @@ typedef enum {
106 oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout, 106 oEnableSSHKeysign, oRekeyLimit, oVerifyHostKeyDNS, oConnectTimeout,
107 oAddressFamily, oGssAuthentication, oGssDelegateCreds, 107 oAddressFamily, oGssAuthentication, oGssDelegateCreds,
108 oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly, 108 oServerAliveInterval, oServerAliveCountMax, oIdentitiesOnly,
109 oSendEnv,
109 oDeprecated, oUnsupported 110 oDeprecated, oUnsupported
110} OpCodes; 111} OpCodes;
111 112
@@ -193,6 +194,7 @@ static struct {
193 { "addressfamily", oAddressFamily }, 194 { "addressfamily", oAddressFamily },
194 { "serveraliveinterval", oServerAliveInterval }, 195 { "serveraliveinterval", oServerAliveInterval },
195 { "serveralivecountmax", oServerAliveCountMax }, 196 { "serveralivecountmax", oServerAliveCountMax },
197 { "sendenv", oSendEnv },
196 { NULL, oBadOption } 198 { NULL, oBadOption }
197}; 199};
198 200
@@ -749,6 +751,19 @@ parse_int:
749 intptr = &options->server_alive_count_max; 751 intptr = &options->server_alive_count_max;
750 goto parse_int; 752 goto parse_int;
751 753
754 case oSendEnv:
755 while ((arg = strdelim(&s)) != NULL && *arg != '\0') {
756 if (strchr(arg, '=') != NULL)
757 fatal("%s line %d: Invalid environment name.",
758 filename, linenum);
759 if (options->num_send_env >= MAX_SEND_ENV)
760 fatal("%s line %d: too many send env.",
761 filename, linenum);
762 options->send_env[options->num_send_env++] =
763 xstrdup(arg);
764 }
765 break;
766
752 case oDeprecated: 767 case oDeprecated:
753 debug("%s line %d: Deprecated option \"%s\"", 768 debug("%s line %d: Deprecated option \"%s\"",
754 filename, linenum, keyword); 769 filename, linenum, keyword);
@@ -894,6 +909,7 @@ initialize_options(Options * options)
894 options->verify_host_key_dns = -1; 909 options->verify_host_key_dns = -1;
895 options->server_alive_interval = -1; 910 options->server_alive_interval = -1;
896 options->server_alive_count_max = -1; 911 options->server_alive_count_max = -1;
912 options->num_send_env = 0;
897} 913}
898 914
899/* 915/*
diff --git a/readconf.h b/readconf.h
index 9d70fee67..668055943 100644
--- a/readconf.h
+++ b/readconf.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: readconf.h,v 1.61 2004/04/18 23:10:26 djm Exp $ */ 1/* $OpenBSD: readconf.h,v 1.62 2004/04/27 09:46:37 djm Exp $ */
2 2
3/* 3/*
4 * Author: Tatu Ylonen <ylo@cs.hut.fi> 4 * Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -27,6 +27,8 @@ typedef struct {
27} Forward; 27} Forward;
28/* Data structure for representing option data. */ 28/* Data structure for representing option data. */
29 29
30#define MAX_SEND_ENV 256
31
30typedef struct { 32typedef struct {
31 int forward_agent; /* Forward authentication agent. */ 33 int forward_agent; /* Forward authentication agent. */
32 int forward_x11; /* Forward X11 display. */ 34 int forward_x11; /* Forward X11 display. */
@@ -103,6 +105,9 @@ typedef struct {
103 int identities_only; 105 int identities_only;
104 int server_alive_interval; 106 int server_alive_interval;
105 int server_alive_count_max; 107 int server_alive_count_max;
108
109 int num_send_env;
110 char *send_env[MAX_SEND_ENV];
106} Options; 111} Options;
107 112
108 113
diff --git a/servconf.c b/servconf.c
index a72246b6c..ae380f522 100644
--- a/servconf.c
+++ b/servconf.c
@@ -10,7 +10,7 @@
10 */ 10 */
11 11
12#include "includes.h" 12#include "includes.h"
13RCSID("$OpenBSD: servconf.c,v 1.130 2003/12/23 16:12:10 jakob Exp $"); 13RCSID("$OpenBSD: servconf.c,v 1.131 2004/04/27 09:46:37 djm Exp $");
14 14
15#include "ssh.h" 15#include "ssh.h"
16#include "log.h" 16#include "log.h"
@@ -101,6 +101,7 @@ initialize_server_options(ServerOptions *options)
101 options->client_alive_count_max = -1; 101 options->client_alive_count_max = -1;
102 options->authorized_keys_file = NULL; 102 options->authorized_keys_file = NULL;
103 options->authorized_keys_file2 = NULL; 103 options->authorized_keys_file2 = NULL;
104 options->num_accept_env = 0;
104 105
105 /* Needs to be accessable in many places */ 106 /* Needs to be accessable in many places */
106 use_privsep = -1; 107 use_privsep = -1;
@@ -266,7 +267,7 @@ typedef enum {
266 sBanner, sUseDNS, sHostbasedAuthentication, 267 sBanner, sUseDNS, sHostbasedAuthentication,
267 sHostbasedUsesNameFromPacketOnly, sClientAliveInterval, 268 sHostbasedUsesNameFromPacketOnly, sClientAliveInterval,
268 sClientAliveCountMax, sAuthorizedKeysFile, sAuthorizedKeysFile2, 269 sClientAliveCountMax, sAuthorizedKeysFile, sAuthorizedKeysFile2,
269 sGssAuthentication, sGssCleanupCreds, 270 sGssAuthentication, sGssCleanupCreds, sAcceptEnv,
270 sUsePrivilegeSeparation, 271 sUsePrivilegeSeparation,
271 sDeprecated, sUnsupported 272 sDeprecated, sUnsupported
272} ServerOpCodes; 273} ServerOpCodes;
@@ -366,6 +367,7 @@ static struct {
366 { "authorizedkeysfile", sAuthorizedKeysFile }, 367 { "authorizedkeysfile", sAuthorizedKeysFile },
367 { "authorizedkeysfile2", sAuthorizedKeysFile2 }, 368 { "authorizedkeysfile2", sAuthorizedKeysFile2 },
368 { "useprivilegeseparation", sUsePrivilegeSeparation}, 369 { "useprivilegeseparation", sUsePrivilegeSeparation},
370 { "acceptenv", sAcceptEnv },
369 { NULL, sBadOption } 371 { NULL, sBadOption }
370}; 372};
371 373
@@ -892,6 +894,19 @@ parse_flag:
892 intptr = &options->client_alive_count_max; 894 intptr = &options->client_alive_count_max;
893 goto parse_int; 895 goto parse_int;
894 896
897 case sAcceptEnv:
898 while ((arg = strdelim(&cp)) && *arg != '\0') {
899 if (strchr(arg, '=') != NULL)
900 fatal("%s line %d: Invalid environment name.",
901 filename, linenum);
902 if (options->num_accept_env >= MAX_ACCEPT_ENV)
903 fatal("%s line %d: too many allow env.",
904 filename, linenum);
905 options->accept_env[options->num_accept_env++] =
906 xstrdup(arg);
907 }
908 break;
909
895 case sDeprecated: 910 case sDeprecated:
896 logit("%s line %d: Deprecated option %s", 911 logit("%s line %d: Deprecated option %s",
897 filename, linenum, arg); 912 filename, linenum, arg);
diff --git a/servconf.h b/servconf.h
index 57c7e5fab..1c6296acc 100644
--- a/servconf.h
+++ b/servconf.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: servconf.h,v 1.67 2003/12/23 16:12:10 jakob Exp $ */ 1/* $OpenBSD: servconf.h,v 1.68 2004/04/27 09:46:37 djm Exp $ */
2 2
3/* 3/*
4 * Author: Tatu Ylonen <ylo@cs.hut.fi> 4 * Author: Tatu Ylonen <ylo@cs.hut.fi>
@@ -24,6 +24,7 @@
24#define MAX_DENY_GROUPS 256 /* Max # groups on deny list. */ 24#define MAX_DENY_GROUPS 256 /* Max # groups on deny list. */
25#define MAX_SUBSYSTEMS 256 /* Max # subsystems. */ 25#define MAX_SUBSYSTEMS 256 /* Max # subsystems. */
26#define MAX_HOSTKEYS 256 /* Max # hostkeys. */ 26#define MAX_HOSTKEYS 256 /* Max # hostkeys. */
27#define MAX_ACCEPT_ENV 256 /* Max # of env vars. */
27 28
28/* permit_root_login */ 29/* permit_root_login */
29#define PERMIT_NOT_SET -1 30#define PERMIT_NOT_SET -1
@@ -107,6 +108,9 @@ typedef struct {
107 char *subsystem_name[MAX_SUBSYSTEMS]; 108 char *subsystem_name[MAX_SUBSYSTEMS];
108 char *subsystem_command[MAX_SUBSYSTEMS]; 109 char *subsystem_command[MAX_SUBSYSTEMS];
109 110
111 u_int num_accept_env;
112 char *accept_env[MAX_ACCEPT_ENV];
113
110 int max_startups_begin; 114 int max_startups_begin;
111 int max_startups_rate; 115 int max_startups_rate;
112 int max_startups; 116 int max_startups;
diff --git a/session.c b/session.c
index 55db2ffd2..da11e5549 100644
--- a/session.c
+++ b/session.c
@@ -33,7 +33,7 @@
33 */ 33 */
34 34
35#include "includes.h" 35#include "includes.h"
36RCSID("$OpenBSD: session.c,v 1.172 2004/01/30 09:48:57 markus Exp $"); 36RCSID("$OpenBSD: session.c,v 1.173 2004/04/27 09:46:37 djm Exp $");
37 37
38#include "ssh.h" 38#include "ssh.h"
39#include "ssh1.h" 39#include "ssh1.h"
@@ -42,6 +42,7 @@ RCSID("$OpenBSD: session.c,v 1.172 2004/01/30 09:48:57 markus Exp $");
42#include "sshpty.h" 42#include "sshpty.h"
43#include "packet.h" 43#include "packet.h"
44#include "buffer.h" 44#include "buffer.h"
45#include "match.h"
45#include "mpaux.h" 46#include "mpaux.h"
46#include "uidswap.h" 47#include "uidswap.h"
47#include "compat.h" 48#include "compat.h"
@@ -996,6 +997,10 @@ do_setup_env(Session *s, const char *shell)
996 997
997 if (!options.use_login) { 998 if (!options.use_login) {
998 /* Set basic environment. */ 999 /* Set basic environment. */
1000 for (i = 0; i < s->num_env; i++)
1001 child_set_env(&env, &envsize, s->env[i].name,
1002 s->env[i].val);
1003
999 child_set_env(&env, &envsize, "USER", pw->pw_name); 1004 child_set_env(&env, &envsize, "USER", pw->pw_name);
1000 child_set_env(&env, &envsize, "LOGNAME", pw->pw_name); 1005 child_set_env(&env, &envsize, "LOGNAME", pw->pw_name);
1001#ifdef _AIX 1006#ifdef _AIX
@@ -1832,6 +1837,41 @@ session_break_req(Session *s)
1832} 1837}
1833 1838
1834static int 1839static int
1840session_env_req(Session *s)
1841{
1842 char *name, *val;
1843 u_int name_len, val_len, i;
1844
1845 name = packet_get_string(&name_len);
1846 val = packet_get_string(&val_len);
1847 packet_check_eom();
1848
1849 /* Don't set too many environment variables */
1850 if (s->num_env > 128) {
1851 debug2("Ignoring env request %s: too many env vars", name);
1852 goto fail;
1853 }
1854
1855 for (i = 0; i < options.num_accept_env; i++) {
1856 if (match_pattern(name, options.accept_env[i])) {
1857 debug2("Setting env %d: %s=%s", s->num_env, name, val);
1858 s->env = xrealloc(s->env, sizeof(*s->env) *
1859 (s->num_env + 1));
1860 s->env[s->num_env].name = name;
1861 s->env[s->num_env].val = val;
1862 s->num_env++;
1863 return (1);
1864 }
1865 }
1866 debug2("Ignoring env request %s: disallowed name", name);
1867
1868 fail:
1869 xfree(name);
1870 xfree(val);
1871 return (0);
1872}
1873
1874static int
1835session_auth_agent_req(Session *s) 1875session_auth_agent_req(Session *s)
1836{ 1876{
1837 static int called = 0; 1877 static int called = 0;
@@ -1880,6 +1920,8 @@ session_input_channel_req(Channel *c, const char *rtype)
1880 success = session_subsystem_req(s); 1920 success = session_subsystem_req(s);
1881 } else if (strcmp(rtype, "break") == 0) { 1921 } else if (strcmp(rtype, "break") == 0) {
1882 success = session_break_req(s); 1922 success = session_break_req(s);
1923 } else if (strcmp(rtype, "env") == 0) {
1924 success = session_env_req(s);
1883 } 1925 }
1884 } 1926 }
1885 if (strcmp(rtype, "window-change") == 0) { 1927 if (strcmp(rtype, "window-change") == 0) {
@@ -2017,6 +2059,8 @@ session_exit_message(Session *s, int status)
2017void 2059void
2018session_close(Session *s) 2060session_close(Session *s)
2019{ 2061{
2062 int i;
2063
2020 debug("session_close: session %d pid %ld", s->self, (long)s->pid); 2064 debug("session_close: session %d pid %ld", s->self, (long)s->pid);
2021 if (s->ttyfd != -1) 2065 if (s->ttyfd != -1)
2022 session_pty_cleanup(s); 2066 session_pty_cleanup(s);
@@ -2031,6 +2075,12 @@ session_close(Session *s)
2031 if (s->auth_proto) 2075 if (s->auth_proto)
2032 xfree(s->auth_proto); 2076 xfree(s->auth_proto);
2033 s->used = 0; 2077 s->used = 0;
2078 for (i = 0; i < s->num_env; i++) {
2079 xfree(s->env[i].name);
2080 xfree(s->env[i].val);
2081 }
2082 if (s->env != NULL)
2083 xfree(s->env);
2034 session_proctitle(s); 2084 session_proctitle(s);
2035} 2085}
2036 2086
diff --git a/session.h b/session.h
index 405b8fe8a..e52506652 100644
--- a/session.h
+++ b/session.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: session.h,v 1.21 2003/09/23 20:17:11 markus Exp $ */ 1/* $OpenBSD: session.h,v 1.22 2004/04/27 09:46:37 djm Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. 4 * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
@@ -53,6 +53,11 @@ struct Session {
53 /* proto 2 */ 53 /* proto 2 */
54 int chanid; 54 int chanid;
55 int is_subsystem; 55 int is_subsystem;
56 int num_env;
57 struct {
58 char *name;
59 char *val;
60 } *env;
56}; 61};
57 62
58void do_authenticated(Authctxt *); 63void do_authenticated(Authctxt *);
diff --git a/ssh.c b/ssh.c
index 9658e4afc..df3b64b1c 100644
--- a/ssh.c
+++ b/ssh.c
@@ -40,7 +40,7 @@
40 */ 40 */
41 41
42#include "includes.h" 42#include "includes.h"
43RCSID("$OpenBSD: ssh.c,v 1.211 2004/04/19 21:51:49 djm Exp $"); 43RCSID("$OpenBSD: ssh.c,v 1.212 2004/04/27 09:46:37 djm Exp $");
44 44
45#include <openssl/evp.h> 45#include <openssl/evp.h>
46#include <openssl/err.h> 46#include <openssl/err.h>
@@ -68,6 +68,7 @@ RCSID("$OpenBSD: ssh.c,v 1.211 2004/04/19 21:51:49 djm Exp $");
68#include "kex.h" 68#include "kex.h"
69#include "mac.h" 69#include "mac.h"
70#include "sshtty.h" 70#include "sshtty.h"
71#include "match.h"
71 72
72#ifdef SMARTCARD 73#ifdef SMARTCARD
73#include "scard.h" 74#include "scard.h"
@@ -1057,6 +1058,44 @@ ssh_session2_setup(int id, void *arg)
1057 packet_send(); 1058 packet_send();
1058 } 1059 }
1059 1060
1061 /* Transfer any environment variables from client to server */
1062 if (options.num_send_env != 0) {
1063 int i, j, matched;
1064 extern char **environ;
1065 char *name, *val;
1066
1067 debug("Sending environment.");
1068 for (i = 0; environ && environ[i] != NULL; i++) {
1069 /* Split */
1070 name = xstrdup(environ[i]);
1071 if ((val = strchr(name, '=')) == NULL) {
1072 free(name);
1073 continue;
1074 }
1075 *val++ = '\0';
1076
1077 matched = 0;
1078 for (j = 0; j < options.num_send_env; j++) {
1079 if (match_pattern(name, options.send_env[j])) {
1080 matched = 1;
1081 break;
1082 }
1083 }
1084 if (!matched) {
1085 debug3("Ignored env %s", name);
1086 free(name);
1087 continue;
1088 }
1089
1090 debug("Sending env %s = %s", name, val);
1091 channel_request_start(id, "env", 0);
1092 packet_put_cstring(name);
1093 packet_put_cstring(val);
1094 packet_send();
1095 free(name);
1096 }
1097 }
1098
1060 len = buffer_len(&command); 1099 len = buffer_len(&command);
1061 if (len > 0) { 1100 if (len > 0) {
1062 if (len > 900) 1101 if (len > 900)
diff --git a/ssh_config.5 b/ssh_config.5
index df479c63a..fbe8c657d 100644
--- a/ssh_config.5
+++ b/ssh_config.5
@@ -34,7 +34,7 @@
34.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 34.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
35.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36.\" 36.\"
37.\" $OpenBSD: ssh_config.5,v 1.31 2004/04/19 16:12:14 jmc Exp $ 37.\" $OpenBSD: ssh_config.5,v 1.32 2004/04/27 09:46:37 djm Exp $
38.Dd September 25, 1999 38.Dd September 25, 1999
39.Dt SSH_CONFIG 5 39.Dt SSH_CONFIG 5
40.Os 40.Os
@@ -570,6 +570,27 @@ running.
570The default is 570The default is
571.Dq yes . 571.Dq yes .
572Note that this option applies to protocol version 1 only. 572Note that this option applies to protocol version 1 only.
573.It Cm SendEnv
574Specifies what variables from the local
575.Xr environ 7
576should be sent to the server.
577Note that environment passing is only supported for protocol 2, the
578server must also support it and must be configured to accept these
579enviornment variables.
580Refer to
581.Cm AcceptEnv
582in
583.Xr sshd_config 5
584for how to configure the server.
585Variables are specified by name, which may contain the wildcard characters
586.Ql \&*
587and
588.Ql \&? .
589Multiple environment variables may be seperated by whitespace or spread
590across multiple
591.Cm SendEnv
592directives.
593The default is not to send any environment variables.
573.It Cm ServerAliveInterval 594.It Cm ServerAliveInterval
574Sets a timeout interval in seconds after which if no data has been received 595Sets a timeout interval in seconds after which if no data has been received
575from the server, 596from the server,
diff --git a/sshd_config.5 b/sshd_config.5
index e15a225f2..b702e5ad4 100644
--- a/sshd_config.5
+++ b/sshd_config.5
@@ -34,7 +34,7 @@
34.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 34.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
35.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 35.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36.\" 36.\"
37.\" $OpenBSD: sshd_config.5,v 1.29 2004/03/08 10:18:57 dtucker Exp $ 37.\" $OpenBSD: sshd_config.5,v 1.30 2004/04/27 09:46:37 djm Exp $
38.Dd September 25, 1999 38.Dd September 25, 1999
39.Dt SSHD_CONFIG 5 39.Dt SSHD_CONFIG 5
40.Os 40.Os
@@ -61,6 +61,29 @@ The possible
61keywords and their meanings are as follows (note that 61keywords and their meanings are as follows (note that
62keywords are case-insensitive and arguments are case-sensitive): 62keywords are case-insensitive and arguments are case-sensitive):
63.Bl -tag -width Ds 63.Bl -tag -width Ds
64.It Cm AcceptEnv
65Specifies what environment variables sent by the client will be copied into
66the session's
67.Xr environ 7 .
68See
69.Cm SendEnv
70in
71.Xr ssh_config 5
72for how to configure the client.
73Note that environment passingis only supported for protocol 2.
74Variables are specified by name, which may contain the wildcard characters
75.Ql \&*
76and
77.Ql \&? .
78Multiple environment variables may be seperated by whitespace or spread
79across multiple
80.Cm AcceptEnv
81directives.
82Be warned that some enviornment variables could be used to bypass restricted
83user environments.
84For this reason, care should be taken in the use of this directive.
85The default is not to accept any environment variables.
86.Pp
64.It Cm AllowGroups 87.It Cm AllowGroups
65This keyword can be followed by a list of group name patterns, separated 88This keyword can be followed by a list of group name patterns, separated
66by spaces. 89by spaces.