summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--auth-rhosts.c6
-rw-r--r--auth.c9
-rw-r--r--misc.c69
-rw-r--r--misc.h2
-rw-r--r--platform.c16
-rw-r--r--readconf.c5
-rw-r--r--ssh.12
-rw-r--r--ssh_config.52
8 files changed, 82 insertions, 29 deletions
diff --git a/auth-rhosts.c b/auth-rhosts.c
index 06ae7f0b9..f20278797 100644
--- a/auth-rhosts.c
+++ b/auth-rhosts.c
@@ -256,8 +256,7 @@ auth_rhosts2_raw(struct passwd *pw, const char *client_user, const char *hostnam
256 return 0; 256 return 0;
257 } 257 }
258 if (options.strict_modes && 258 if (options.strict_modes &&
259 ((st.st_uid != 0 && st.st_uid != pw->pw_uid) || 259 !secure_permissions(&st, pw->pw_uid)) {
260 (st.st_mode & 022) != 0)) {
261 logit("Rhosts authentication refused for %.100s: " 260 logit("Rhosts authentication refused for %.100s: "
262 "bad ownership or modes for home directory.", pw->pw_name); 261 "bad ownership or modes for home directory.", pw->pw_name);
263 auth_debug_add("Rhosts authentication refused for %.100s: " 262 auth_debug_add("Rhosts authentication refused for %.100s: "
@@ -283,8 +282,7 @@ auth_rhosts2_raw(struct passwd *pw, const char *client_user, const char *hostnam
283 * allowing access to their account by anyone. 282 * allowing access to their account by anyone.
284 */ 283 */
285 if (options.strict_modes && 284 if (options.strict_modes &&
286 ((st.st_uid != 0 && st.st_uid != pw->pw_uid) || 285 !secure_permissions(&st, pw->pw_uid)) {
287 (st.st_mode & 022) != 0)) {
288 logit("Rhosts authentication refused for %.100s: bad modes for %.200s", 286 logit("Rhosts authentication refused for %.100s: bad modes for %.200s",
289 pw->pw_name, buf); 287 pw->pw_name, buf);
290 auth_debug_add("Bad file modes for %.200s", buf); 288 auth_debug_add("Bad file modes for %.200s", buf);
diff --git a/auth.c b/auth.c
index 9a36f1dac..0c45f0954 100644
--- a/auth.c
+++ b/auth.c
@@ -407,8 +407,7 @@ check_key_in_hostfiles(struct passwd *pw, Key *key, const char *host,
407 user_hostfile = tilde_expand_filename(userfile, pw->pw_uid); 407 user_hostfile = tilde_expand_filename(userfile, pw->pw_uid);
408 if (options.strict_modes && 408 if (options.strict_modes &&
409 (stat(user_hostfile, &st) == 0) && 409 (stat(user_hostfile, &st) == 0) &&
410 ((st.st_uid != 0 && st.st_uid != pw->pw_uid) || 410 !secure_permissions(&st, pw->pw_uid)) {
411 (st.st_mode & 022) != 0)) {
412 logit("Authentication refused for %.100s: " 411 logit("Authentication refused for %.100s: "
413 "bad owner or modes for %.200s", 412 "bad owner or modes for %.200s",
414 pw->pw_name, user_hostfile); 413 pw->pw_name, user_hostfile);
@@ -470,8 +469,7 @@ auth_secure_path(const char *name, struct stat *stp, const char *pw_dir,
470 snprintf(err, errlen, "%s is not a regular file", buf); 469 snprintf(err, errlen, "%s is not a regular file", buf);
471 return -1; 470 return -1;
472 } 471 }
473 if ((!platform_sys_dir_uid(stp->st_uid) && stp->st_uid != uid) || 472 if (!secure_permissions(stp, uid)) {
474 (stp->st_mode & 022) != 0) {
475 snprintf(err, errlen, "bad ownership or modes for file %s", 473 snprintf(err, errlen, "bad ownership or modes for file %s",
476 buf); 474 buf);
477 return -1; 475 return -1;
@@ -486,8 +484,7 @@ auth_secure_path(const char *name, struct stat *stp, const char *pw_dir,
486 strlcpy(buf, cp, sizeof(buf)); 484 strlcpy(buf, cp, sizeof(buf));
487 485
488 if (stat(buf, &st) < 0 || 486 if (stat(buf, &st) < 0 ||
489 (!platform_sys_dir_uid(st.st_uid) && st.st_uid != uid) || 487 !secure_permissions(&st, uid)) {
490 (st.st_mode & 022) != 0) {
491 snprintf(err, errlen, 488 snprintf(err, errlen,
492 "bad ownership or modes for directory %s", buf); 489 "bad ownership or modes for directory %s", buf);
493 return -1; 490 return -1;
diff --git a/misc.c b/misc.c
index e4c8c3238..4e756b04b 100644
--- a/misc.c
+++ b/misc.c
@@ -49,8 +49,9 @@
49#include <netdb.h> 49#include <netdb.h>
50#ifdef HAVE_PATHS_H 50#ifdef HAVE_PATHS_H
51# include <paths.h> 51# include <paths.h>
52#include <pwd.h>
53#endif 52#endif
53#include <pwd.h>
54#include <grp.h>
54#ifdef SSH_TUN_OPENBSD 55#ifdef SSH_TUN_OPENBSD
55#include <net/if.h> 56#include <net/if.h>
56#endif 57#endif
@@ -59,6 +60,7 @@
59#include "misc.h" 60#include "misc.h"
60#include "log.h" 61#include "log.h"
61#include "ssh.h" 62#include "ssh.h"
63#include "platform.h"
62 64
63/* remove newline at end of string */ 65/* remove newline at end of string */
64char * 66char *
@@ -643,6 +645,71 @@ read_keyfile_line(FILE *f, const char *filename, char *buf, size_t bufsz,
643 return -1; 645 return -1;
644} 646}
645 647
648/*
649 * return 1 if the specified uid is a uid that may own a system directory
650 * otherwise 0.
651 */
652int
653platform_sys_dir_uid(uid_t uid)
654{
655 if (uid == 0)
656 return 1;
657#ifdef PLATFORM_SYS_DIR_UID
658 if (uid == PLATFORM_SYS_DIR_UID)
659 return 1;
660#endif
661 return 0;
662}
663
664int
665secure_permissions(struct stat *st, uid_t uid)
666{
667 if (!platform_sys_dir_uid(st->st_uid) && st->st_uid != uid)
668 return 0;
669 if ((st->st_mode & 002) != 0)
670 return 0;
671 if ((st->st_mode & 020) != 0) {
672 /* If the file is group-writable, the group in question must
673 * have exactly one member, namely the file's owner.
674 * (Zero-member groups are typically used by setgid
675 * binaries, and are unlikely to be suitable.)
676 */
677 struct passwd *pw;
678 struct group *gr;
679 int members = 0;
680
681 gr = getgrgid(st->st_gid);
682 if (!gr)
683 return 0;
684
685 /* Check primary group memberships. */
686 while ((pw = getpwent()) != NULL) {
687 if (pw->pw_gid == gr->gr_gid) {
688 ++members;
689 if (pw->pw_uid != uid)
690 return 0;
691 }
692 }
693 endpwent();
694
695 pw = getpwuid(st->st_uid);
696 if (!pw)
697 return 0;
698
699 /* Check supplementary group memberships. */
700 if (gr->gr_mem[0]) {
701 ++members;
702 if (strcmp(pw->pw_name, gr->gr_mem[0]) ||
703 gr->gr_mem[1])
704 return 0;
705 }
706
707 if (!members)
708 return 0;
709 }
710 return 1;
711}
712
646int 713int
647tun_open(int tun, int mode) 714tun_open(int tun, int mode)
648{ 715{
diff --git a/misc.h b/misc.h
index d4df619cd..ceb173bda 100644
--- a/misc.h
+++ b/misc.h
@@ -106,4 +106,6 @@ char *read_passphrase(const char *, int);
106int ask_permission(const char *, ...) __attribute__((format(printf, 1, 2))); 106int ask_permission(const char *, ...) __attribute__((format(printf, 1, 2)));
107int read_keyfile_line(FILE *, const char *, char *, size_t, u_long *); 107int read_keyfile_line(FILE *, const char *, char *, size_t, u_long *);
108 108
109int secure_permissions(struct stat *st, uid_t uid);
110
109#endif /* _MISC_H */ 111#endif /* _MISC_H */
diff --git a/platform.c b/platform.c
index 4aab9a9cd..f99de7fab 100644
--- a/platform.c
+++ b/platform.c
@@ -196,19 +196,3 @@ platform_krb5_get_principal_name(const char *pw_name)
196 return NULL; 196 return NULL;
197#endif 197#endif
198} 198}
199
200/*
201 * return 1 if the specified uid is a uid that may own a system directory
202 * otherwise 0.
203 */
204int
205platform_sys_dir_uid(uid_t uid)
206{
207 if (uid == 0)
208 return 1;
209#ifdef PLATFORM_SYS_DIR_UID
210 if (uid == PLATFORM_SYS_DIR_UID)
211 return 1;
212#endif
213 return 0;
214}
diff --git a/readconf.c b/readconf.c
index e79e355dc..273552d7c 100644
--- a/readconf.c
+++ b/readconf.c
@@ -36,6 +36,8 @@
36#include <stdio.h> 36#include <stdio.h>
37#include <string.h> 37#include <string.h>
38#include <unistd.h> 38#include <unistd.h>
39#include <pwd.h>
40#include <grp.h>
39#ifdef HAVE_UTIL_H 41#ifdef HAVE_UTIL_H
40#include <util.h> 42#include <util.h>
41#endif 43#endif
@@ -1475,8 +1477,7 @@ read_config_file(const char *filename, struct passwd *pw, const char *host,
1475 1477
1476 if (fstat(fileno(f), &sb) == -1) 1478 if (fstat(fileno(f), &sb) == -1)
1477 fatal("fstat %s: %s", filename, strerror(errno)); 1479 fatal("fstat %s: %s", filename, strerror(errno));
1478 if (((sb.st_uid != 0 && sb.st_uid != getuid()) || 1480 if (!secure_permissions(&sb, getuid()))
1479 (sb.st_mode & 022) != 0))
1480 fatal("Bad owner or permissions on %s", filename); 1481 fatal("Bad owner or permissions on %s", filename);
1481 } 1482 }
1482 1483
diff --git a/ssh.1 b/ssh.1
index 27794e2d0..ff5e6acab 100644
--- a/ssh.1
+++ b/ssh.1
@@ -1352,6 +1352,8 @@ The file format and configuration options are described in
1352.Xr ssh_config 5 . 1352.Xr ssh_config 5 .
1353Because of the potential for abuse, this file must have strict permissions: 1353Because of the potential for abuse, this file must have strict permissions:
1354read/write for the user, and not writable by others. 1354read/write for the user, and not writable by others.
1355It may be group-writable provided that the group in question contains only
1356the user.
1355.Pp 1357.Pp
1356.It Pa ~/.ssh/environment 1358.It Pa ~/.ssh/environment
1357Contains additional definitions for environment variables; see 1359Contains additional definitions for environment variables; see
diff --git a/ssh_config.5 b/ssh_config.5
index b3c5dc614..3c6b9d4d2 100644
--- a/ssh_config.5
+++ b/ssh_config.5
@@ -1523,6 +1523,8 @@ The format of this file is described above.
1523This file is used by the SSH client. 1523This file is used by the SSH client.
1524Because of the potential for abuse, this file must have strict permissions: 1524Because of the potential for abuse, this file must have strict permissions:
1525read/write for the user, and not accessible by others. 1525read/write for the user, and not accessible by others.
1526It may be group-writable provided that the group in question contains only
1527the user.
1526.It Pa /etc/ssh/ssh_config 1528.It Pa /etc/ssh/ssh_config
1527Systemwide configuration file. 1529Systemwide configuration file.
1528This file provides defaults for those 1530This file provides defaults for those