From 3d9f9fb9249a2179d792ce9042cebbffeb4088f3 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Mon, 28 Oct 2013 16:59:20 -0700 Subject: [PATCH 1/2] Fix bug #10229 - No access check verification on stream files. 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. Back-ported for 4.0.x. Signed-off-by: Jeremy Allison Reviewed-by: Stefan Metzmacher Reviewed-by: David Disseldorp (Based on master commit 60f922bf1bd8816eacbb32c24793ad1f97a1d9f2) --- source3/smbd/open.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) diff --git a/source3/smbd/open.c b/source3/smbd/open.c index a1b4e43..0282722 100644 --- a/source3/smbd/open.c +++ b/source3/smbd/open.c @@ -300,6 +300,44 @@ 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, + 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, + access_mask); +} + +/**************************************************************************** fd support routines - attempt to do a dos_open. ****************************************************************************/ @@ -3749,6 +3787,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. */ -- 1.8.1.2 From a6d1dffee24c80852c8f0dffd65fd2c83ab06b1a Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Tue, 29 Oct 2013 15:57:01 -0700 Subject: [PATCH 2/2] Add regression test for bug #10229 - No access check verification on stream files. Checks against a file with attribute READONLY, and a security descriptor denying WRITE_DATA access. Signed-off-by: Jeremy Allison Reviewed-by: Stefan Metzmacher Reviewed-by: David Disseldorp Autobuild-User(master): Jeremy Allison Autobuild-Date(master): Mon Nov 4 23:10:10 CET 2013 on sn-devel-104 (cherry picked from commit 65882152cc7ccaba0e7903862b99ca93594ed080) --- selftest/knownfail | 1 + source4/torture/raw/streams.c | 181 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 182 insertions(+) diff --git a/selftest/knownfail b/selftest/knownfail index d249a25..e393635 100644 --- a/selftest/knownfail +++ b/selftest/knownfail @@ -128,6 +128,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/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. */ + ZERO_STRUCT(sfinfo); + sfinfo.generic.level = RAW_SFILEINFO_SETATTR; + sfinfo.generic.in.file.path = fname; + sfinfo.setattr.in.attrib = FILE_ATTRIBUTE_READONLY; + + status = smb_raw_setpathinfo(cli->tree, &sfinfo); + CHECK_STATUS(status, NT_STATUS_OK); + + /* Try and open the stream name for WRITE_DATA. Should + fail with ACCESS_DENIED. */ + + ZERO_STRUCT(io); + io.generic.level = RAW_OPEN_NTCREATEX; + io.ntcreatex.in.root_fid.fnum = 0; + io.ntcreatex.in.flags = 0; + io.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA; + io.ntcreatex.in.create_options = 0; + io.ntcreatex.in.file_attr = 0; + io.ntcreatex.in.share_access = 0; + io.ntcreatex.in.alloc_size = 0; + io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN; + io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS; + io.ntcreatex.in.security_flags = 0; + io.ntcreatex.in.fname = fname_stream; + + status = smb_raw_open(cli->tree, tctx, &io); + CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED); + + /* Change the attributes on the base file back. */ + ZERO_STRUCT(sfinfo); + sfinfo.generic.level = RAW_SFILEINFO_SETATTR; + sfinfo.generic.in.file.path = fname; + sfinfo.setattr.in.attrib = 0; + + status = smb_raw_setpathinfo(cli->tree, &sfinfo); + CHECK_STATUS(status, NT_STATUS_OK); + + /* Re-open the file name. */ + + ZERO_STRUCT(io); + io.generic.level = RAW_OPEN_NTCREATEX; + io.ntcreatex.in.root_fid.fnum = 0; + io.ntcreatex.in.flags = 0; + io.ntcreatex.in.access_mask = (SEC_FILE_READ_DATA|SEC_FILE_WRITE_DATA| + SEC_STD_READ_CONTROL|SEC_STD_WRITE_DAC| + SEC_FILE_WRITE_ATTRIBUTE); + io.ntcreatex.in.create_options = 0; + io.ntcreatex.in.file_attr = 0; + io.ntcreatex.in.share_access = 0; + io.ntcreatex.in.alloc_size = 0; + io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN; + io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS; + io.ntcreatex.in.security_flags = 0; + io.ntcreatex.in.fname = fname; + + status = smb_raw_open(cli->tree, tctx, &io); + CHECK_STATUS(status, NT_STATUS_OK); + + fnum = io.ntcreatex.out.file.fnum; + + /* Get the existing security descriptor. */ + ZERO_STRUCT(q); + q.query_secdesc.level = RAW_FILEINFO_SEC_DESC; + q.query_secdesc.in.file.fnum = fnum; + q.query_secdesc.in.secinfo_flags = + SECINFO_OWNER | + SECINFO_GROUP | + SECINFO_DACL; + status = smb_raw_fileinfo(cli->tree, tctx, &q); + CHECK_STATUS(status, NT_STATUS_OK); + sd = q.query_secdesc.out.sd; + + /* Now add a DENY WRITE security descriptor for Everyone. */ + torture_comment(tctx, "add a new ACE to the DACL\n"); + + ace.type = SEC_ACE_TYPE_ACCESS_DENIED; + ace.flags = 0; + ace.access_mask = SEC_FILE_WRITE_DATA; + ace.trustee = *dom_sid_parse_talloc(tctx, SID_WORLD); + + status = security_descriptor_dacl_add(sd, &ace); + CHECK_STATUS(status, NT_STATUS_OK); + + /* security_descriptor_dacl_add adds to the *end* of + the ace array, we need it at the start. Swap.. */ + ace = sd->dacl->aces[0]; + sd->dacl->aces[0] = sd->dacl->aces[sd->dacl->num_aces-1]; + sd->dacl->aces[sd->dacl->num_aces-1] = ace; + + ZERO_STRUCT(set); + set.set_secdesc.level = RAW_SFILEINFO_SEC_DESC; + set.set_secdesc.in.file.fnum = fnum; + set.set_secdesc.in.secinfo_flags = SECINFO_DACL; + set.set_secdesc.in.sd = sd; + + status = smb_raw_setfileinfo(cli->tree, &set); + CHECK_STATUS(status, NT_STATUS_OK); + + smbcli_close(cli->tree, fnum); + fnum = -1; + + /* Try and open the stream name for WRITE_DATA. Should + fail with ACCESS_DENIED. */ + + ZERO_STRUCT(io); + io.generic.level = RAW_OPEN_NTCREATEX; + io.ntcreatex.in.root_fid.fnum = 0; + io.ntcreatex.in.flags = 0; + io.ntcreatex.in.access_mask = SEC_FILE_WRITE_DATA; + io.ntcreatex.in.create_options = 0; + io.ntcreatex.in.file_attr = 0; + io.ntcreatex.in.share_access = 0; + io.ntcreatex.in.alloc_size = 0; + io.ntcreatex.in.open_disposition = NTCREATEX_DISP_OPEN; + io.ntcreatex.in.impersonation = NTCREATEX_IMPERSONATION_ANONYMOUS; + io.ntcreatex.in.security_flags = 0; + io.ntcreatex.in.fname = fname_stream; + + status = smb_raw_open(cli->tree, tctx, &io); + CHECK_STATUS(status, NT_STATUS_ACCESS_DENIED); + + done: + + if (fnum != -1) { + smbcli_close(cli->tree, fnum); + } + smbcli_unlink(cli->tree, fname); + + smbcli_deltree(cli->tree, BASEDIR); + return ret; +} + /* basic testing of streams calls */ @@ -1905,6 +2085,7 @@ struct torture_suite *torture_raw_streams(TALLOC_CTX *tctx) test_stream_create_disposition); torture_suite_add_1smb_test(suite, "attr", test_stream_attributes); torture_suite_add_1smb_test(suite, "sumtab", test_stream_summary_tab); + torture_suite_add_1smb_test(suite, "perms", test_stream_permissions); #if 0 torture_suite_add_1smb_test(suite, "LARGESTREAMINFO", -- 1.8.1.2 From 414c543bd8263a97e10421063938ce17fb27c24d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Baumbach?= Date: Tue, 29 Oct 2013 17:43:17 +0100 Subject: [PATCH 1/6] CVE-2013-4476: lib-util: add file_check_permissions() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bug: https://bugzilla.samba.org/show_bug.cgi?id=10234 Signed-off-by: Björn Baumbach Reviewed-by: Stefan Metzmacher --- lib/util/samba_util.h | 9 +++++++++ lib/util/util.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 0 deletions(-) diff --git a/lib/util/samba_util.h b/lib/util/samba_util.h index 4a6dd3b..677a220 100644 --- a/lib/util/samba_util.h +++ b/lib/util/samba_util.h @@ -623,6 +623,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 b50d28a..f63720c 100644 --- a/lib/util/util.c +++ b/lib/util/util.c @@ -119,6 +119,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. **/ -- 1.7.3.4 From eb2fb47fdfc2bdf7a50fa76a816005640525ea6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Baumbach?= Date: Tue, 29 Oct 2013 17:48:11 +0100 Subject: [PATCH 2/6] CVE-2013-4476: lib-util: split out file_save_mode() from file_save() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit file_save_mode() writes files with specified mode. Bug: https://bugzilla.samba.org/show_bug.cgi?id=10234 Signed-off-by: Björn Baumbach Reviewed-by: Stefan Metzmacher --- lib/util/samba_util.h | 2 ++ lib/util/util_file.c | 16 +++++++++++----- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/lib/util/samba_util.h b/lib/util/samba_util.h index 677a220..311e99d 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 */ 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; -- 1.7.3.4 From aea107c660fa9013078580b5f05c0502a524fb6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Baumbach?= Date: Tue, 29 Oct 2013 17:49:55 +0100 Subject: [PATCH 3/6] CVE-2013-4476: samba-tool provision: create ${private_dir}/tls with mode 0700 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bug: https://bugzilla.samba.org/show_bug.cgi?id=10234 Signed-off-by: Björn Baumbach Reviewed-by: Stefan Metzmacher --- python/samba/provision/__init__.py | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) diff --git a/python/samba/provision/__init__.py b/python/samba/provision/__init__.py index e0b3d22..0a54af8 100644 --- a/python/samba/provision/__init__.py +++ b/python/samba/provision/__init__.py @@ -2014,7 +2014,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) -- 1.7.3.4 From b4991492fe4659892eb0b6abafd8a44c07b71636 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 30 Oct 2013 14:48:36 +0100 Subject: [PATCH 4/6] CVE-2013-4476: selftest/Samba4: use umask 0077 within mk_keyblobs() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We should generate private keys with 0600. Bug: https://bugzilla.samba.org/show_bug.cgi?id=10234 Pair-Programmed-With: Björn Baumbach Signed-off-by: Stefan Metzmacher Signed-off-by: Björn Baumbach Reviewed-by: Stefan Metzmacher --- selftest/target/Samba4.pm | 6 +++++- 1 files changed, 5 insertions(+), 1 deletions(-) diff --git a/selftest/target/Samba4.pm b/selftest/target/Samba4.pm index 9fd2d40..0e798ba 100644 --- a/selftest/target/Samba4.pm +++ b/selftest/target/Samba4.pm @@ -227,7 +227,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"); @@ -418,6 +420,8 @@ Zd7J9s//rNFNa7waklFkDaY56+QWTFtdvxfE+KoHaqt6X8u6pqi7p3M4wDKQox+9Dx8yWFyq Wfz/8alZ5aMezCQzXJyIaJsCLeKABosSwHcpAFmxlQ== -----END CERTIFICATE----- EOF + + umask $oldumask; } sub provision_raw_prepare($$$$$$$$$$) -- 1.7.3.4 From 0d98d56bf8ce876f44550a34d2da817568914f24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Baumbach?= Date: Tue, 29 Oct 2013 17:52:39 +0100 Subject: [PATCH 5/6] CVE-2013-4476: s4:libtls: Create tls private key file (key.pem) with mode 0600 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bug: https://bugzilla.samba.org/show_bug.cgi?id=10234 Signed-off-by: Björn Baumbach Reviewed-by: Stefan Metzmacher --- source4/lib/tls/tlscert.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-) 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; } -- 1.7.3.4 From 005571a42403b5f11ccbf225b42dc904b6519524 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Baumbach?= Date: Tue, 29 Oct 2013 17:53:59 +0100 Subject: [PATCH 6/6] CVE-2013-4476: s4:libtls: check for safe permissions of tls private key file (key.pem) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If the tls key is not owned by root or has not mode 0600 samba will not start up. Bug: https://bugzilla.samba.org/show_bug.cgi?id=10234 Pair-Programmed-With: Stefan Metzmacher Signed-off-by: Björn Baumbach Signed-off-by: Stefan Metzmacher Reviewed-by: Stefan Metzmacher --- source4/lib/tls/tls.c | 17 +++++++++++++++++ source4/lib/tls/tls_tstream.c | 16 ++++++++++++++++ 2 files changed, 33 insertions(+), 0 deletions(-) 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))); -- 1.7.3.4