diff options
author | Colin Watson <cjwatson@debian.org> | 2007-06-12 16:16:35 +0000 |
---|---|---|
committer | Colin Watson <cjwatson@debian.org> | 2007-06-12 16:16:35 +0000 |
commit | b7e40fa9da0b5491534a429dadb321eab5a77558 (patch) | |
tree | bed1da11e9f829925797aa093e379fc0b5868ecd /ssh.c | |
parent | 4f84beedf1005e44ff33c854abd6b711ffc0adb7 (diff) | |
parent | 086ea76990b1e6287c24b6db74adffd4605eb3b0 (diff) |
* New upstream release (closes: #395507, #397961, #420035). Important
changes not previously backported to 4.3p2:
- 4.4/4.4p1 (http://www.openssh.org/txt/release-4.4):
+ On portable OpenSSH, fix a GSSAPI authentication abort that could be
used to determine the validity of usernames on some platforms.
+ Implemented conditional configuration in sshd_config(5) using the
"Match" directive. This allows some configuration options to be
selectively overridden if specific criteria (based on user, group,
hostname and/or address) are met. So far a useful subset of
post-authentication options are supported and more are expected to
be added in future releases.
+ Add support for Diffie-Hellman group exchange key agreement with a
final hash of SHA256.
+ Added a "ForceCommand" directive to sshd_config(5). Similar to the
command="..." option accepted in ~/.ssh/authorized_keys, this forces
the execution of the specified command regardless of what the user
requested. This is very useful in conjunction with the new "Match"
option.
+ Add a "PermitOpen" directive to sshd_config(5). This mirrors the
permitopen="..." authorized_keys option, allowing fine-grained
control over the port-forwardings that a user is allowed to
establish.
+ Add optional logging of transactions to sftp-server(8).
+ ssh(1) will now record port numbers for hosts stored in
~/.ssh/known_hosts when a non-standard port has been requested
(closes: #50612).
+ Add an "ExitOnForwardFailure" option to cause ssh(1) to exit (with a
non-zero exit code) when requested port forwardings could not be
established.
+ Extend sshd_config(5) "SubSystem" declarations to allow the
specification of command-line arguments.
+ Replacement of all integer overflow susceptible invocations of
malloc(3) and realloc(3) with overflow-checking equivalents.
+ Many manpage fixes and improvements.
+ Add optional support for OpenSSL hardware accelerators (engines),
enabled using the --with-ssl-engine configure option.
+ Tokens in configuration files may be double-quoted in order to
contain spaces (closes: #319639).
+ Move a debug() call out of a SIGCHLD handler, fixing a hang when the
session exits very quickly (closes: #307890).
+ Fix some incorrect buffer allocation calculations (closes: #410599).
+ ssh-add doesn't ask for a passphrase if key file permissions are too
liberal (closes: #103677).
+ Likewise, ssh doesn't ask either (closes: #99675).
- 4.6/4.6p1 (http://www.openssh.org/txt/release-4.6):
+ sshd now allows the enabling and disabling of authentication methods
on a per user, group, host and network basis via the Match directive
in sshd_config.
+ Fixed an inconsistent check for a terminal when displaying scp
progress meter (closes: #257524).
+ Fix "hang on exit" when background processes are running at the time
of exit on a ttyful/login session (closes: #88337).
* Update to current GSSAPI patch from
http://www.sxw.org.uk/computing/patches/openssh-4.6p1-gsskex-20070312.patch;
install ChangeLog.gssapi.
Diffstat (limited to 'ssh.c')
-rw-r--r-- | ssh.c | 147 |
1 files changed, 102 insertions, 45 deletions
@@ -1,3 +1,4 @@ | |||
1 | /* $OpenBSD: ssh.c,v 1.295 2007/01/03 03:01:40 stevesk Exp $ */ | ||
1 | /* | 2 | /* |
2 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
3 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
@@ -40,20 +41,46 @@ | |||
40 | */ | 41 | */ |
41 | 42 | ||
42 | #include "includes.h" | 43 | #include "includes.h" |
43 | RCSID("$OpenBSD: ssh.c,v 1.257 2005/12/20 04:41:07 dtucker Exp $"); | 44 | |
45 | #include <sys/types.h> | ||
46 | #ifdef HAVE_SYS_STAT_H | ||
47 | # include <sys/stat.h> | ||
48 | #endif | ||
49 | #include <sys/resource.h> | ||
50 | #include <sys/ioctl.h> | ||
51 | #include <sys/socket.h> | ||
52 | #include <sys/un.h> | ||
53 | |||
54 | #include <ctype.h> | ||
55 | #include <errno.h> | ||
56 | #include <fcntl.h> | ||
57 | #include <netdb.h> | ||
58 | #ifdef HAVE_PATHS_H | ||
59 | #include <paths.h> | ||
60 | #endif | ||
61 | #include <pwd.h> | ||
62 | #include <signal.h> | ||
63 | #include <stdarg.h> | ||
64 | #include <stddef.h> | ||
65 | #include <stdio.h> | ||
66 | #include <stdlib.h> | ||
67 | #include <string.h> | ||
68 | #include <unistd.h> | ||
69 | |||
70 | #include <netinet/in.h> | ||
71 | #include <arpa/inet.h> | ||
44 | 72 | ||
45 | #include <openssl/evp.h> | 73 | #include <openssl/evp.h> |
46 | #include <openssl/err.h> | 74 | #include <openssl/err.h> |
47 | 75 | ||
76 | #include "xmalloc.h" | ||
48 | #include "ssh.h" | 77 | #include "ssh.h" |
49 | #include "ssh1.h" | 78 | #include "ssh1.h" |
50 | #include "ssh2.h" | 79 | #include "ssh2.h" |
51 | #include "compat.h" | 80 | #include "compat.h" |
52 | #include "cipher.h" | 81 | #include "cipher.h" |
53 | #include "xmalloc.h" | ||
54 | #include "packet.h" | 82 | #include "packet.h" |
55 | #include "buffer.h" | 83 | #include "buffer.h" |
56 | #include "bufaux.h" | ||
57 | #include "channels.h" | 84 | #include "channels.h" |
58 | #include "key.h" | 85 | #include "key.h" |
59 | #include "authfd.h" | 86 | #include "authfd.h" |
@@ -72,6 +99,7 @@ RCSID("$OpenBSD: ssh.c,v 1.257 2005/12/20 04:41:07 dtucker Exp $"); | |||
72 | #include "msg.h" | 99 | #include "msg.h" |
73 | #include "monitor_fdpass.h" | 100 | #include "monitor_fdpass.h" |
74 | #include "uidswap.h" | 101 | #include "uidswap.h" |
102 | #include "version.h" | ||
75 | 103 | ||
76 | #ifdef SMARTCARD | 104 | #ifdef SMARTCARD |
77 | #include "scard.h" | 105 | #include "scard.h" |
@@ -162,7 +190,7 @@ usage(void) | |||
162 | " [-i identity_file] [-L [bind_address:]port:host:hostport]\n" | 190 | " [-i identity_file] [-L [bind_address:]port:host:hostport]\n" |
163 | " [-l login_name] [-m mac_spec] [-O ctl_cmd] [-o option] [-p port]\n" | 191 | " [-l login_name] [-m mac_spec] [-O ctl_cmd] [-o option] [-p port]\n" |
164 | " [-R [bind_address:]port:host:hostport] [-S ctl_path]\n" | 192 | " [-R [bind_address:]port:host:hostport] [-S ctl_path]\n" |
165 | " [-w tunnel:tunnel] [user@]hostname [command]\n" | 193 | " [-w local_tun[:remote_tun]] [user@]hostname [command]\n" |
166 | ); | 194 | ); |
167 | exit(255); | 195 | exit(255); |
168 | } | 196 | } |
@@ -242,7 +270,7 @@ main(int ac, char **av) | |||
242 | /* Parse command-line arguments. */ | 270 | /* Parse command-line arguments. */ |
243 | host = NULL; | 271 | host = NULL; |
244 | 272 | ||
245 | again: | 273 | again: |
246 | while ((opt = getopt(ac, av, | 274 | while ((opt = getopt(ac, av, |
247 | "1246ab:c:e:fgi:kl:m:no:p:qstvxACD:F:I:KL:MNO:PR:S:TVw:XY")) != -1) { | 275 | "1246ab:c:e:fgi:kl:m:no:p:qstvxACD:F:I:KL:MNO:PR:S:TVw:XY")) != -1) { |
248 | switch (opt) { | 276 | switch (opt) { |
@@ -594,7 +622,7 @@ again: | |||
594 | if (!read_config_file(config, host, &options, 0)) | 622 | if (!read_config_file(config, host, &options, 0)) |
595 | fatal("Can't open user config file %.100s: " | 623 | fatal("Can't open user config file %.100s: " |
596 | "%.100s", config, strerror(errno)); | 624 | "%.100s", config, strerror(errno)); |
597 | } else { | 625 | } else { |
598 | snprintf(buf, sizeof buf, "%.100s/%.100s", pw->pw_dir, | 626 | snprintf(buf, sizeof buf, "%.100s/%.100s", pw->pw_dir, |
599 | _PATH_SSH_USER_CONFFILE); | 627 | _PATH_SSH_USER_CONFFILE); |
600 | (void)read_config_file(buf, host, &options, 1); | 628 | (void)read_config_file(buf, host, &options, 1); |
@@ -624,7 +652,7 @@ again: | |||
624 | if (options.host_key_alias != NULL) { | 652 | if (options.host_key_alias != NULL) { |
625 | for (p = options.host_key_alias; *p; p++) | 653 | for (p = options.host_key_alias; *p; p++) |
626 | if (isupper(*p)) | 654 | if (isupper(*p)) |
627 | *p = tolower(*p); | 655 | *p = (char)tolower(*p); |
628 | } | 656 | } |
629 | 657 | ||
630 | /* Get default port if port has not been set. */ | 658 | /* Get default port if port has not been set. */ |
@@ -641,11 +669,15 @@ again: | |||
641 | options.control_path = NULL; | 669 | options.control_path = NULL; |
642 | 670 | ||
643 | if (options.control_path != NULL) { | 671 | if (options.control_path != NULL) { |
672 | char thishost[NI_MAXHOST]; | ||
673 | |||
674 | if (gethostname(thishost, sizeof(thishost)) == -1) | ||
675 | fatal("gethostname: %s", strerror(errno)); | ||
644 | snprintf(buf, sizeof(buf), "%d", options.port); | 676 | snprintf(buf, sizeof(buf), "%d", options.port); |
645 | cp = tilde_expand_filename(options.control_path, | 677 | cp = tilde_expand_filename(options.control_path, |
646 | original_real_uid); | 678 | original_real_uid); |
647 | options.control_path = percent_expand(cp, "p", buf, "h", host, | 679 | options.control_path = percent_expand(cp, "p", buf, "h", host, |
648 | "r", options.user, (char *)NULL); | 680 | "r", options.user, "l", thishost, (char *)NULL); |
649 | xfree(cp); | 681 | xfree(cp); |
650 | } | 682 | } |
651 | if (mux_command != 0 && options.control_path == NULL) | 683 | if (mux_command != 0 && options.control_path == NULL) |
@@ -678,16 +710,16 @@ again: | |||
678 | if (options.rhosts_rsa_authentication || | 710 | if (options.rhosts_rsa_authentication || |
679 | options.hostbased_authentication) { | 711 | options.hostbased_authentication) { |
680 | sensitive_data.nkeys = 3; | 712 | sensitive_data.nkeys = 3; |
681 | sensitive_data.keys = xmalloc(sensitive_data.nkeys * | 713 | sensitive_data.keys = xcalloc(sensitive_data.nkeys, |
682 | sizeof(Key)); | 714 | sizeof(Key)); |
683 | 715 | ||
684 | PRIV_START; | 716 | PRIV_START; |
685 | sensitive_data.keys[0] = key_load_private_type(KEY_RSA1, | 717 | sensitive_data.keys[0] = key_load_private_type(KEY_RSA1, |
686 | _PATH_HOST_KEY_FILE, "", NULL); | 718 | _PATH_HOST_KEY_FILE, "", NULL, NULL); |
687 | sensitive_data.keys[1] = key_load_private_type(KEY_DSA, | 719 | sensitive_data.keys[1] = key_load_private_type(KEY_DSA, |
688 | _PATH_HOST_DSA_KEY_FILE, "", NULL); | 720 | _PATH_HOST_DSA_KEY_FILE, "", NULL, NULL); |
689 | sensitive_data.keys[2] = key_load_private_type(KEY_RSA, | 721 | sensitive_data.keys[2] = key_load_private_type(KEY_RSA, |
690 | _PATH_HOST_RSA_KEY_FILE, "", NULL); | 722 | _PATH_HOST_RSA_KEY_FILE, "", NULL, NULL); |
691 | PRIV_END; | 723 | PRIV_END; |
692 | 724 | ||
693 | if (options.hostbased_authentication == 1 && | 725 | if (options.hostbased_authentication == 1 && |
@@ -803,6 +835,8 @@ ssh_init_forwarding(void) | |||
803 | options.local_forwards[i].connect_port, | 835 | options.local_forwards[i].connect_port, |
804 | options.gateway_ports); | 836 | options.gateway_ports); |
805 | } | 837 | } |
838 | if (i > 0 && success != i && options.exit_on_forward_failure) | ||
839 | fatal("Could not request local forwarding."); | ||
806 | if (i > 0 && success == 0) | 840 | if (i > 0 && success == 0) |
807 | error("Could not request local forwarding."); | 841 | error("Could not request local forwarding."); |
808 | 842 | ||
@@ -815,11 +849,17 @@ ssh_init_forwarding(void) | |||
815 | options.remote_forwards[i].listen_port, | 849 | options.remote_forwards[i].listen_port, |
816 | options.remote_forwards[i].connect_host, | 850 | options.remote_forwards[i].connect_host, |
817 | options.remote_forwards[i].connect_port); | 851 | options.remote_forwards[i].connect_port); |
818 | channel_request_remote_forwarding( | 852 | if (channel_request_remote_forwarding( |
819 | options.remote_forwards[i].listen_host, | 853 | options.remote_forwards[i].listen_host, |
820 | options.remote_forwards[i].listen_port, | 854 | options.remote_forwards[i].listen_port, |
821 | options.remote_forwards[i].connect_host, | 855 | options.remote_forwards[i].connect_host, |
822 | options.remote_forwards[i].connect_port); | 856 | options.remote_forwards[i].connect_port) < 0) { |
857 | if (options.exit_on_forward_failure) | ||
858 | fatal("Could not request remote forwarding."); | ||
859 | else | ||
860 | logit("Warning: Could not request remote " | ||
861 | "forwarding."); | ||
862 | } | ||
823 | } | 863 | } |
824 | } | 864 | } |
825 | 865 | ||
@@ -880,10 +920,10 @@ ssh_session(void) | |||
880 | /* Store window size in the packet. */ | 920 | /* Store window size in the packet. */ |
881 | if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) < 0) | 921 | if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) < 0) |
882 | memset(&ws, 0, sizeof(ws)); | 922 | memset(&ws, 0, sizeof(ws)); |
883 | packet_put_int(ws.ws_row); | 923 | packet_put_int((u_int)ws.ws_row); |
884 | packet_put_int(ws.ws_col); | 924 | packet_put_int((u_int)ws.ws_col); |
885 | packet_put_int(ws.ws_xpixel); | 925 | packet_put_int((u_int)ws.ws_xpixel); |
886 | packet_put_int(ws.ws_ypixel); | 926 | packet_put_int((u_int)ws.ws_ypixel); |
887 | 927 | ||
888 | /* Store tty modes in the packet. */ | 928 | /* Store tty modes in the packet. */ |
889 | tty_make_modes(fileno(stdin), NULL); | 929 | tty_make_modes(fileno(stdin), NULL); |
@@ -1001,9 +1041,16 @@ client_global_request_reply_fwd(int type, u_int32_t seq, void *ctxt) | |||
1001 | options.remote_forwards[i].listen_port, | 1041 | options.remote_forwards[i].listen_port, |
1002 | options.remote_forwards[i].connect_host, | 1042 | options.remote_forwards[i].connect_host, |
1003 | options.remote_forwards[i].connect_port); | 1043 | options.remote_forwards[i].connect_port); |
1004 | if (type == SSH2_MSG_REQUEST_FAILURE) | 1044 | if (type == SSH2_MSG_REQUEST_FAILURE) { |
1005 | logit("Warning: remote port forwarding failed for listen " | 1045 | if (options.exit_on_forward_failure) |
1006 | "port %d", options.remote_forwards[i].listen_port); | 1046 | fatal("Error: remote port forwarding failed for " |
1047 | "listen port %d", | ||
1048 | options.remote_forwards[i].listen_port); | ||
1049 | else | ||
1050 | logit("Warning: remote port forwarding failed for " | ||
1051 | "listen port %d", | ||
1052 | options.remote_forwards[i].listen_port); | ||
1053 | } | ||
1007 | } | 1054 | } |
1008 | 1055 | ||
1009 | static void | 1056 | static void |
@@ -1032,7 +1079,7 @@ ssh_control_listener(void) | |||
1032 | fatal("%s socket(): %s", __func__, strerror(errno)); | 1079 | fatal("%s socket(): %s", __func__, strerror(errno)); |
1033 | 1080 | ||
1034 | old_umask = umask(0177); | 1081 | old_umask = umask(0177); |
1035 | if (bind(control_fd, (struct sockaddr*)&addr, addr_len) == -1) { | 1082 | if (bind(control_fd, (struct sockaddr *)&addr, addr_len) == -1) { |
1036 | control_fd = -1; | 1083 | control_fd = -1; |
1037 | if (errno == EINVAL || errno == EADDRINUSE) | 1084 | if (errno == EINVAL || errno == EADDRINUSE) |
1038 | fatal("ControlSocket %s already exists", | 1085 | fatal("ControlSocket %s already exists", |
@@ -1184,15 +1231,16 @@ ssh_session2(void) | |||
1184 | static void | 1231 | static void |
1185 | load_public_identity_files(void) | 1232 | load_public_identity_files(void) |
1186 | { | 1233 | { |
1187 | char *filename; | 1234 | char *filename, *cp, thishost[NI_MAXHOST]; |
1188 | int i = 0; | 1235 | int i = 0; |
1189 | Key *public; | 1236 | Key *public; |
1237 | struct passwd *pw; | ||
1190 | #ifdef SMARTCARD | 1238 | #ifdef SMARTCARD |
1191 | Key **keys; | 1239 | Key **keys; |
1192 | 1240 | ||
1193 | if (options.smartcard_device != NULL && | 1241 | if (options.smartcard_device != NULL && |
1194 | options.num_identity_files < SSH_MAX_IDENTITY_FILES && | 1242 | options.num_identity_files < SSH_MAX_IDENTITY_FILES && |
1195 | (keys = sc_get_keys(options.smartcard_device, NULL)) != NULL ) { | 1243 | (keys = sc_get_keys(options.smartcard_device, NULL)) != NULL) { |
1196 | int count = 0; | 1244 | int count = 0; |
1197 | for (i = 0; keys[i] != NULL; i++) { | 1245 | for (i = 0; keys[i] != NULL; i++) { |
1198 | count++; | 1246 | count++; |
@@ -1210,9 +1258,18 @@ load_public_identity_files(void) | |||
1210 | xfree(keys); | 1258 | xfree(keys); |
1211 | } | 1259 | } |
1212 | #endif /* SMARTCARD */ | 1260 | #endif /* SMARTCARD */ |
1261 | if ((pw = getpwuid(original_real_uid)) == NULL) | ||
1262 | fatal("load_public_identity_files: getpwuid failed"); | ||
1263 | if (gethostname(thishost, sizeof(thishost)) == -1) | ||
1264 | fatal("load_public_identity_files: gethostname: %s", | ||
1265 | strerror(errno)); | ||
1213 | for (; i < options.num_identity_files; i++) { | 1266 | for (; i < options.num_identity_files; i++) { |
1214 | filename = tilde_expand_filename(options.identity_files[i], | 1267 | cp = tilde_expand_filename(options.identity_files[i], |
1215 | original_real_uid); | 1268 | original_real_uid); |
1269 | filename = percent_expand(cp, "d", pw->pw_dir, | ||
1270 | "u", pw->pw_name, "l", thishost, "h", host, | ||
1271 | "r", options.user, (char *)NULL); | ||
1272 | xfree(cp); | ||
1216 | public = key_load_public(filename, NULL); | 1273 | public = key_load_public(filename, NULL); |
1217 | debug("identity file %s type %d", filename, | 1274 | debug("identity file %s type %d", filename, |
1218 | public ? public->type : -1); | 1275 | public ? public->type : -1); |
@@ -1238,14 +1295,14 @@ control_client_sigrelay(int signo) | |||
1238 | static int | 1295 | static int |
1239 | env_permitted(char *env) | 1296 | env_permitted(char *env) |
1240 | { | 1297 | { |
1241 | int i; | 1298 | int i, ret; |
1242 | char name[1024], *cp; | 1299 | char name[1024], *cp; |
1243 | 1300 | ||
1244 | strlcpy(name, env, sizeof(name)); | 1301 | if ((cp = strchr(env, '=')) == NULL || cp == env) |
1245 | if ((cp = strchr(name, '=')) == NULL) | ||
1246 | return (0); | 1302 | return (0); |
1247 | 1303 | ret = snprintf(name, sizeof(name), "%.*s", (int)(cp - env), env); | |
1248 | *cp = '\0'; | 1304 | if (ret <= 0 || (size_t)ret >= sizeof(name)) |
1305 | fatal("env_permitted: name '%.100s...' too long", env); | ||
1249 | 1306 | ||
1250 | for (i = 0; i < options.num_send_env; i++) | 1307 | for (i = 0; i < options.num_send_env; i++) |
1251 | if (match_pattern(name, options.send_env[i])) | 1308 | if (match_pattern(name, options.send_env[i])) |
@@ -1290,29 +1347,29 @@ control_client(const char *path) | |||
1290 | if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) | 1347 | if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) |
1291 | fatal("%s socket(): %s", __func__, strerror(errno)); | 1348 | fatal("%s socket(): %s", __func__, strerror(errno)); |
1292 | 1349 | ||
1293 | if (connect(sock, (struct sockaddr*)&addr, addr_len) == -1) { | 1350 | if (connect(sock, (struct sockaddr *)&addr, addr_len) == -1) { |
1294 | if (mux_command != SSHMUX_COMMAND_OPEN) { | 1351 | if (mux_command != SSHMUX_COMMAND_OPEN) { |
1295 | fatal("Control socket connect(%.100s): %s", path, | 1352 | fatal("Control socket connect(%.100s): %s", path, |
1296 | strerror(errno)); | 1353 | strerror(errno)); |
1297 | } | 1354 | } |
1298 | if (errno == ENOENT) | 1355 | if (errno == ENOENT) |
1299 | debug("Control socket \"%.100s\" does not exist", path); | 1356 | debug("Control socket \"%.100s\" does not exist", path); |
1300 | else { | 1357 | else { |
1301 | error("Control socket connect(%.100s): %s", path, | 1358 | error("Control socket connect(%.100s): %s", path, |
1302 | strerror(errno)); | 1359 | strerror(errno)); |
1303 | } | 1360 | } |
1304 | close(sock); | 1361 | close(sock); |
1305 | return; | 1362 | return; |
1306 | } | 1363 | } |
1307 | 1364 | ||
1308 | if (stdin_null_flag) { | 1365 | if (stdin_null_flag) { |
1309 | if ((fd = open(_PATH_DEVNULL, O_RDONLY)) == -1) | 1366 | if ((fd = open(_PATH_DEVNULL, O_RDONLY)) == -1) |
1310 | fatal("open(/dev/null): %s", strerror(errno)); | 1367 | fatal("open(/dev/null): %s", strerror(errno)); |
1311 | if (dup2(fd, STDIN_FILENO) == -1) | 1368 | if (dup2(fd, STDIN_FILENO) == -1) |
1312 | fatal("dup2: %s", strerror(errno)); | 1369 | fatal("dup2: %s", strerror(errno)); |
1313 | if (fd > STDERR_FILENO) | 1370 | if (fd > STDERR_FILENO) |
1314 | close(fd); | 1371 | close(fd); |
1315 | } | 1372 | } |
1316 | 1373 | ||
1317 | term = getenv("TERM"); | 1374 | term = getenv("TERM"); |
1318 | 1375 | ||