The branch, v4-1-test has been updated via a52afc3 VERSION: Bump version number up to 4.1.2... via 5e64b07 Merge tag 'samba-4.1.1' into v4-1-test via 32d78c8 VERSION: Disable git snapshots for the 4.1.1 release. via 07be799 WHATSNEW: Add release notes for Samba 4.1.1. via e737fc7 CVE-2013-4476: s4:libtls: check for safe permissions of tls private key file (key.pem) via 2ca3eae CVE-2013-4476: s4:libtls: Create tls private key file (key.pem) with mode 0600 via bc067d0 CVE-2013-4476: selftest/Samba4: use umask 0077 within mk_keyblobs() via d6988a1 CVE-2013-4476: samba-tool provision: create ${private_dir}/tls with mode 0700 via 7fc2f97 CVE-2013-4476: lib-util: split out file_save_mode() from file_save() via 81e5048 CVE-2013-4476: lib-util: add file_check_permissions() via afe7ffd Add regression test for bug #10229 - No access check verification on stream files. via a2c4c0e Fix bug #10229 - No access check verification on stream files. from 6207530 s4-dns: dlz_bind9: Create dns-HOSTNAME account disabled
http://gitweb.samba.org/?p=samba.git;a=shortlog;h=v4-1-test - Log ----------------------------------------------------------------- commit a52afc34d992c7a201c0b35d9d8df1ba25260787 Author: Karolin Seeger <ksee...@samba.org> Date: Mon Nov 11 11:40:49 2013 +0100 VERSION: Bump version number up to 4.1.2... and re-enable git snapshots. Signed-off-by: Karolin Seeger <ksee...@samba.org> commit 5e64b0718f56181b6d70623e285f5e74096fe4af Merge: 62075301713602612fe3eae92ce4b23e14ab8fa8 32d78c867eb259960736121146c7152934f3e6b3 Author: Karolin Seeger <ksee...@samba.org> Date: Mon Nov 11 11:39:35 2013 +0100 Merge tag 'samba-4.1.1' into v4-1-test samba: tag release samba-4.1.1 ----------------------------------------------------------------------- Summary of changes: VERSION | 2 +- WHATSNEW.txt | 73 +++++++++++++++ lib/util/samba_util.h | 11 ++ lib/util/util.c | 44 +++++++++ lib/util/util_file.c | 16 ++- python/samba/provision/__init__.py | 2 +- selftest/knownfail | 1 + selftest/target/Samba4.pm | 6 +- source3/smbd/open.c | 59 ++++++++++++ source4/lib/tls/tls.c | 17 ++++ source4/lib/tls/tls_tstream.c | 16 +++ source4/lib/tls/tlscert.c | 2 +- source4/torture/raw/streams.c | 181 ++++++++++++++++++++++++++++++++++++ 13 files changed, 421 insertions(+), 9 deletions(-) Changeset truncated at 500 lines: diff --git a/VERSION b/VERSION index 9394c6f..28fdecb 100644 --- a/VERSION +++ b/VERSION @@ -25,7 +25,7 @@ ######################################################## SAMBA_VERSION_MAJOR=4 SAMBA_VERSION_MINOR=1 -SAMBA_VERSION_RELEASE=1 +SAMBA_VERSION_RELEASE=2 ######################################################## # If a official release has a serious bug # diff --git a/WHATSNEW.txt b/WHATSNEW.txt index 857a7ce..4c96f34 100644 --- a/WHATSNEW.txt +++ b/WHATSNEW.txt @@ -1,4 +1,77 @@ ============================= + Release Notes for Samba 4.1.1 + November 11, 2013 + ============================= + + +This is a security release in order to address +CVE-2013-4475 (ACLs are not checked on opening an alternate +data stream on a file or directory) and +CVE-2013-4476 (Private key in key.pem world readable). + +o CVE-2013-4475: + Samba versions 3.2.0 and above (all versions of 3.2.x, 3.3.x, + 3.4.x, 3.5.x, 3.6.x, 4.0.x and 4.1.x) do not check the underlying + file or directory ACL when opening an alternate data stream. + + According to the SMB1 and SMB2+ protocols the ACL on an underlying + file or directory should control what access is allowed to alternate + data streams that are associated with the file or directory. + + By default no version of Samba supports alternate data streams + on files or directories. + + Samba can be configured to support alternate data streams by loading + either one of two virtual file system modues (VFS) vfs_streams_depot or + vfs_streams_xattr supplied with Samba, so this bug only affects Samba + servers configured this way. + + To determine if your server is vulnerable, check for the strings + "streams_depot" or "streams_xattr" inside your smb.conf configuration + file. + +o CVE-2013-4476: + In setups which provide ldap(s) and/or https services, the private + key for SSL/TLS encryption might be world readable. This typically + happens in active directory domain controller setups. + + +Changes since 4.1.0: +-------------------- + +o Jeremy Allison <j...@samba.org> + * BUGs 10234 + 10229: CVE-2013-4475: Fix access check verification on stream + files. + + +o Björn Baumbach <b...@sernet.de> + * BUG 10234: CVE-2013-4476: Private key in key.pem world readable. + + +####################################### +Reporting bugs & Development Discussion +####################################### + +Please discuss this release on the samba-technical mailing list or by +joining the #samba-technical IRC channel on irc.freenode.net. + +If you do report problems then please try to send high quality +feedback. If you don't provide vital information to help us track down +the problem then you will probably be ignored. All bug reports should +be filed under the Samba 4.1 product in the project's Bugzilla +database (https://bugzilla.samba.org/). + + +====================================================================== +== Our Code, Our Bugs, Our Responsibility. +== The Samba Team +====================================================================== + + +Release notes for older releases follow: +---------------------------------------- + + ============================= Release Notes for Samba 4.1.0 October 11, 2013 ============================= diff --git a/lib/util/samba_util.h b/lib/util/samba_util.h index 89aa9aa..243ed3e 100644 --- a/lib/util/samba_util.h +++ b/lib/util/samba_util.h @@ -580,6 +580,8 @@ a line **/ _PUBLIC_ void file_lines_slashcont(char **lines); +_PUBLIC_ bool file_save_mode(const char *fname, const void *packet, + size_t length, mode_t mode); /** save a lump of data into a file. Mostly used for debugging */ @@ -623,6 +625,15 @@ _PUBLIC_ time_t file_modtime(const char *fname); _PUBLIC_ bool directory_exist(const char *dname); /** + Check file permissions. +**/ +struct stat; +_PUBLIC_ bool file_check_permissions(const char *fname, + uid_t uid, + mode_t file_perms, + struct stat *pst); + +/** * Try to create the specified directory if it didn't exist. * * @retval true if the directory already existed and has the right permissions diff --git a/lib/util/util.c b/lib/util/util.c index f0ed7f6..3e9047c 100644 --- a/lib/util/util.c +++ b/lib/util/util.c @@ -122,6 +122,50 @@ _PUBLIC_ time_t file_modtime(const char *fname) } /** + Check file permissions. +**/ + +_PUBLIC_ bool file_check_permissions(const char *fname, + uid_t uid, + mode_t file_perms, + struct stat *pst) +{ + int ret; + struct stat st; + + if (pst == NULL) { + pst = &st; + } + + ZERO_STRUCTP(pst); + + ret = stat(fname, pst); + if (ret != 0) { + DEBUG(0, ("stat failed on file '%s': %s\n", + fname, strerror(errno))); + return false; + } + + if (pst->st_uid != uid && !uwrap_enabled()) { + DEBUG(0, ("invalid ownership of file '%s': " + "owned by uid %u, should be %u\n", + fname, (unsigned int)pst->st_uid, + (unsigned int)uid)); + return false; + } + + if ((pst->st_mode & 0777) != file_perms) { + DEBUG(0, ("invalid permissions on file " + "'%s': has 0%o should be 0%o\n", fname, + (unsigned int)(pst->st_mode & 0777), + (unsigned int)file_perms)); + return false; + } + + return true; +} + +/** Check if a directory exists. **/ diff --git a/lib/util/util_file.c b/lib/util/util_file.c index e031fc5..815cc2b 100644 --- a/lib/util/util_file.c +++ b/lib/util/util_file.c @@ -368,13 +368,11 @@ _PUBLIC_ void file_lines_slashcont(char **lines) } } -/** - save a lump of data into a file. Mostly used for debugging -*/ -_PUBLIC_ bool file_save(const char *fname, const void *packet, size_t length) +_PUBLIC_ bool file_save_mode(const char *fname, const void *packet, + size_t length, mode_t mode) { int fd; - fd = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0644); + fd = open(fname, O_WRONLY|O_CREAT|O_TRUNC, mode); if (fd == -1) { return false; } @@ -386,6 +384,14 @@ _PUBLIC_ bool file_save(const char *fname, const void *packet, size_t length) return true; } +/** + save a lump of data into a file. Mostly used for debugging +*/ +_PUBLIC_ bool file_save(const char *fname, const void *packet, size_t length) +{ + return file_save_mode(fname, packet, length, 0644); +} + _PUBLIC_ int vfdprintf(int fd, const char *format, va_list ap) { char *p; diff --git a/python/samba/provision/__init__.py b/python/samba/provision/__init__.py index 89f029a..4af6b69 100644 --- a/python/samba/provision/__init__.py +++ b/python/samba/provision/__init__.py @@ -2024,7 +2024,7 @@ def provision(logger, session_info, credentials, smbconf=None, if not os.path.exists(paths.private_dir): os.mkdir(paths.private_dir) if not os.path.exists(os.path.join(paths.private_dir, "tls")): - os.mkdir(os.path.join(paths.private_dir, "tls")) + os.makedirs(os.path.join(paths.private_dir, "tls"), 0700) if not os.path.exists(paths.state_dir): os.mkdir(paths.state_dir) diff --git a/selftest/knownfail b/selftest/knownfail index 0c501fa..2586947 100644 --- a/selftest/knownfail +++ b/selftest/knownfail @@ -144,6 +144,7 @@ ^samba4.raw.streams.*.delete ^samba4.raw.streams.*.createdisp ^samba4.raw.streams.*.sumtab +^samba4.raw.streams.*.perms ^samba4.raw.acls.INHERITFLAGS ^samba4.raw.acls.*.create_dir ^samba4.raw.acls.*.create_file diff --git a/selftest/target/Samba4.pm b/selftest/target/Samba4.pm index 37f7102..8a3f51d 100644 --- a/selftest/target/Samba4.pm +++ b/selftest/target/Samba4.pm @@ -246,7 +246,9 @@ sub mk_keyblobs($$) my $admincertfile = "$tlsdir/admincert.pem"; my $admincertupnfile = "$tlsdir/admincertupn.pem"; - mkdir($tlsdir, 0777); + mkdir($tlsdir, 0700); + my $oldumask = umask; + umask 0077; #This is specified here to avoid draining entropy on every run open(DHFILE, ">$dhfile"); @@ -437,6 +439,8 @@ Zd7J9s//rNFNa7waklFkDaY56+QWTFtdvxfE+KoHaqt6X8u6pqi7p3M4wDKQox+9Dx8yWFyq Wfz/8alZ5aMezCQzXJyIaJsCLeKABosSwHcpAFmxlQ== -----END CERTIFICATE----- EOF + + umask $oldumask; } sub provision_raw_prepare($$$$$$$$$$) diff --git a/source3/smbd/open.c b/source3/smbd/open.c index 10b04e7..cd1bb72 100644 --- a/source3/smbd/open.c +++ b/source3/smbd/open.c @@ -302,6 +302,46 @@ static NTSTATUS check_parent_access(struct connection_struct *conn, } /**************************************************************************** + Ensure when opening a base file for a stream open that we have permissions + to do so given the access mask on the base file. +****************************************************************************/ + +static NTSTATUS check_base_file_access(struct connection_struct *conn, + struct smb_filename *smb_fname, + uint32_t access_mask) +{ + NTSTATUS status; + + status = smbd_calculate_access_mask(conn, smb_fname, + false, + access_mask, + &access_mask); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(10, ("smbd_calculate_access_mask " + "on file %s returned %s\n", + smb_fname_str_dbg(smb_fname), + nt_errstr(status))); + return status; + } + + if (access_mask & (FILE_WRITE_DATA|FILE_APPEND_DATA)) { + uint32_t dosattrs; + if (!CAN_WRITE(conn)) { + return NT_STATUS_ACCESS_DENIED; + } + dosattrs = dos_mode(conn, smb_fname); + if (IS_DOS_READONLY(dosattrs)) { + return NT_STATUS_ACCESS_DENIED; + } + } + + return smbd_check_access_rights(conn, + smb_fname, + false, + access_mask); +} + +/**************************************************************************** fd support routines - attempt to do a dos_open. ****************************************************************************/ @@ -3764,6 +3804,25 @@ static NTSTATUS create_file_unixpath(connection_struct *conn, if (SMB_VFS_STAT(conn, smb_fname_base) == -1) { DEBUG(10, ("Unable to stat stream: %s\n", smb_fname_str_dbg(smb_fname_base))); + } else { + /* + * https://bugzilla.samba.org/show_bug.cgi?id=10229 + * We need to check if the requested access mask + * could be used to open the underlying file (if + * it existed), as we're passing in zero for the + * access mask to the base filename. + */ + status = check_base_file_access(conn, + smb_fname_base, + access_mask); + + if (!NT_STATUS_IS_OK(status)) { + DEBUG(10, ("Permission check " + "for base %s failed: " + "%s\n", smb_fname->base_name, + nt_errstr(status))); + goto fail; + } } /* Open the base file. */ diff --git a/source4/lib/tls/tls.c b/source4/lib/tls/tls.c index db6d1eb..9a3e610 100644 --- a/source4/lib/tls/tls.c +++ b/source4/lib/tls/tls.c @@ -22,6 +22,7 @@ */ #include "includes.h" +#include "system/filesys.h" #include "lib/events/events.h" #include "lib/socket/socket.h" #include "lib/tls/tls.h" @@ -369,6 +370,7 @@ struct tls_params *tls_initialise(TALLOC_CTX *mem_ctx, struct loadparm_context * { struct tls_params *params; int ret; + struct stat st; TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); const char *keyfile = lpcfg_tls_keyfile(tmp_ctx, lp_ctx); const char *certfile = lpcfg_tls_certfile(tmp_ctx, lp_ctx); @@ -399,6 +401,21 @@ struct tls_params *tls_initialise(TALLOC_CTX *mem_ctx, struct loadparm_context * talloc_free(hostname); } + if (file_exist(keyfile) && + !file_check_permissions(keyfile, geteuid(), 0600, &st)) + { + DEBUG(0, ("Invalid permissions on TLS private key file '%s':\n" + "owner uid %u should be %u, mode 0%o should be 0%o\n" + "This is known as CVE-2013-4476.\n" + "Removing all tls .pem files will cause an " + "auto-regeneration with the correct permissions.\n", + keyfile, + (unsigned int)st.st_uid, geteuid(), + (unsigned int)(st.st_mode & 0777), 0600)); + talloc_free(tmp_ctx); + return NULL; + } + ret = gnutls_global_init(); if (ret < 0) goto init_failed; diff --git a/source4/lib/tls/tls_tstream.c b/source4/lib/tls/tls_tstream.c index 6bb68fb..2cb75ed 100644 --- a/source4/lib/tls/tls_tstream.c +++ b/source4/lib/tls/tls_tstream.c @@ -19,6 +19,7 @@ #include "includes.h" #include "system/network.h" +#include "system/filesys.h" #include "../util/tevent_unix.h" #include "../lib/tsocket/tsocket.h" #include "../lib/tsocket/tsocket_internal.h" @@ -1083,6 +1084,7 @@ NTSTATUS tstream_tls_params_server(TALLOC_CTX *mem_ctx, struct tstream_tls_params *tlsp; #if ENABLE_GNUTLS int ret; + struct stat st; if (!enabled || key_file == NULL || *key_file == 0) { tlsp = talloc_zero(mem_ctx, struct tstream_tls_params); @@ -1110,6 +1112,20 @@ NTSTATUS tstream_tls_params_server(TALLOC_CTX *mem_ctx, key_file, cert_file, ca_file); } + if (file_exist(key_file) && + !file_check_permissions(key_file, geteuid(), 0600, &st)) + { + DEBUG(0, ("Invalid permissions on TLS private key file '%s':\n" + "owner uid %u should be %u, mode 0%o should be 0%o\n" + "This is known as CVE-2013-4476.\n" + "Removing all tls .pem files will cause an " + "auto-regeneration with the correct permissions.\n", + key_file, + (unsigned int)st.st_uid, geteuid(), + (unsigned int)(st.st_mode & 0777), 0600)); + return NT_STATUS_CANT_ACCESS_DOMAIN_INFO; + } + ret = gnutls_certificate_allocate_credentials(&tlsp->x509_cred); if (ret != GNUTLS_E_SUCCESS) { DEBUG(0,("TLS %s - %s\n", __location__, gnutls_strerror(ret))); diff --git a/source4/lib/tls/tlscert.c b/source4/lib/tls/tlscert.c index 0c780ea..8a19e0a 100644 --- a/source4/lib/tls/tlscert.c +++ b/source4/lib/tls/tlscert.c @@ -152,7 +152,7 @@ void tls_cert_generate(TALLOC_CTX *mem_ctx, bufsize = sizeof(buf); TLSCHECK(gnutls_x509_privkey_export(key, GNUTLS_X509_FMT_PEM, buf, &bufsize)); - if (!file_save(keyfile, buf, bufsize)) { + if (!file_save_mode(keyfile, buf, bufsize, 0600)) { DEBUG(0,("Unable to save privatekey in %s parent dir exists ?\n", keyfile)); goto failed; } diff --git a/source4/torture/raw/streams.c b/source4/torture/raw/streams.c index 1611c64..61852f5 100644 --- a/source4/torture/raw/streams.c +++ b/source4/torture/raw/streams.c @@ -23,6 +23,8 @@ #include "system/locale.h" #include "torture/torture.h" #include "libcli/raw/libcliraw.h" +#include "libcli/security/dom_sid.h" +#include "libcli/security/security_descriptor.h" #include "system/filesys.h" #include "libcli/libcli.h" #include "torture/util.h" @@ -1885,6 +1887,184 @@ static bool test_stream_summary_tab(struct torture_context *tctx, return ret; } +/* Test how streams interact with base file permissions */ +/* Regression test for bug: + https://bugzilla.samba.org/show_bug.cgi?id=10229 + bug #10229 - No access check verification on stream files. +*/ +static bool test_stream_permissions(struct torture_context *tctx, + struct smbcli_state *cli) +{ + NTSTATUS status; + bool ret = true; + union smb_open io; + const char *fname = BASEDIR "\\stream_permissions.txt"; + const char *stream = "Stream One:$DATA"; + const char *fname_stream; + union smb_fileinfo finfo; + union smb_setfileinfo sfinfo; + int fnum = -1; + union smb_fileinfo q; + union smb_setfileinfo set; + struct security_ace ace; + struct security_descriptor *sd; + + torture_assert(tctx, torture_setup_dir(cli, BASEDIR), + "Failed to setup up test directory: " BASEDIR); + + torture_comment(tctx, "(%s) testing permissions on streams\n", __location__); + + fname_stream = talloc_asprintf(tctx, "%s:%s", fname, stream); + + /* Create a file with a stream with attribute FILE_ATTRIBUTE_ARCHIVE. */ + ret = create_file_with_stream(tctx, cli, fname_stream); + if (!ret) { + goto done; + } + + ZERO_STRUCT(finfo); + finfo.generic.level = RAW_FILEINFO_BASIC_INFO; + finfo.generic.in.file.path = fname; + status = smb_raw_pathinfo(cli->tree, tctx, &finfo); + CHECK_STATUS(status, NT_STATUS_OK); + + torture_assert_int_equal_goto(tctx, + finfo.all_info.out.attrib & ~FILE_ATTRIBUTE_NONINDEXED, + FILE_ATTRIBUTE_ARCHIVE, ret, done, "attrib incorrect"); + + /* Change the attributes on the base file name. */ -- Samba Shared Repository