From b6c8d90ab1686e30f646950636ad64fe9985b662 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. Signed-off-by: Jeremy Allison Reviewed-by: Stefan Metzmacher Reviewed-by: David Disseldorp (cherry picked from commit 60f922bf1bd8816eacbb32c24793ad1f97a1d9f2) --- source3/smbd/open.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) 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. */ -- 1.7.10.4 From ebb92082c74b82eccae0f108048edddcf99a5f96 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 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/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.7.10.4 From 58edc505a22c4f7e79ee1e2ba5da2bb1150839e4 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 89aa9aa..f98cf60 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 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. **/ -- 1.7.3.4 From e6819553ee04bcf2106f4d2777ae95fabbf93f03 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 f98cf60..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 */ 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 d1536768f8f85b84712545817a3911970ff61483 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 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) -- 1.7.3.4 From a9aebd7d26eb173bccf200b9a0ef484b51d53cc9 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 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($$$$$$$$$$) -- 1.7.3.4 From 8073ac5add6e85b42f336eacabf7cfcaa8a7930d 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 48b33b22e2ae297ea3639436ed186c84921bac30 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