Bug 1217346

Summary: FreeIPA trusts to AD broken due to Samba 4.2 failure to run LSARPC pipe externally
Product: [Fedora] Fedora Reporter: Alexander Bokovoy <abokovoy>
Component: sambaAssignee: Guenther Deschner <gdeschner>
Status: CLOSED ERRATA QA Contact: Fedora Extras Quality Assurance <extras-qa>
Severity: unspecified Docs Contact:
Priority: unspecified    
Version: 22CC: abokovoy, asn, gdeschner, jlayton, madam, sbose, ssorce
Target Milestone: ---   
Target Release: ---   
Hardware: Unspecified   
OS: Unspecified   
Whiteboard:
Fixed In Version: samba-4.2.1-7.fc22 Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: 2015-05-03 17:20:08 UTC Type: Bug
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:

Description Alexander Bokovoy 2015-04-30 08:01:12 UTC
With Samba 4.2.1 I'm unable to even initiate trust to AD with FreeIPA because Samba cannot start lsasd daemon with external LSARPC pipe (and other pipes too).

On FreeIPA's python code trying to establish connection to lsarpc pipe, I'm getting:

[2015/04/30 10:26:46.527638,  2, pid=1257, effective(1981400000, 1981400000), real(1981400000, 0), class=rpc_srv] ../source3/rpc_server/rpc_ncacn_np.c:773(make_external_rpc_pipe)
tstream_npa_connect_recv  to /run/samba/ncalrpc/np for pipe lsarpc and user F22\admin failed: No such file or directory
..
NT error packet at ../source3/smbd/nttrans.c(299) cmd=162 (SMBntcreateX) NT_STATUS_OBJECT_NAME_NOT_FOUND


When Samba starts, it forks out an lsasd daemon off smbd. That daemon creates TCP sockets and forks out handlers for specific pipes. However, it looks like the socket setup succeeds and then a failure is returned by dcerpc_binding_vector_add_port() which causes rpc_create_tcpip_sockets() to bail out and return to lsasd initialization code, causing it to exit.

Using a modified systemd unit for smb.service I was able to catch strace what is happening:
write(14, "  bind succeeded on port 1024\n", 30) = 30
stat("/etc/localtime", {st_mode=S_IFREG|0644, st_size=127, ...}) = 0
getgid()                                = 0
getuid()                                = 0
getegid()                               = 0
geteuid()                               = 0
geteuid()                               = 0
write(14, "[2015/04/29 18:46:36.028567, 10, pid=1331, effective(0, 0), real(0, 0)] ../source3/rpc_server/rpc_server.c:628(create_tcpip_socket)\n", 132) = 132
geteuid()                               = 0
write(14, "  Opened tcpip socket fd 16 for port 1024\n", 42) = 42
socket(PF_INET, SOCK_STREAM, IPPROTO_IP) = 38
setsockopt(38, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0
setsockopt(38, SOL_SOCKET, SO_REUSEPORT, [1], 4) = 0
bind(38, {sa_family=AF_INET, sin_port=htons(1024), sin_addr=inet_addr("0.0.0.0")}, 16) = 0
stat("/etc/localtime", {st_mode=S_IFREG|0644, st_size=127, ...}) = 0
getgid()                                = 0
getuid()                                = 0
getegid()                               = 0
geteuid()                               = 0
geteuid()                               = 0
write(14, "[2015/04/29 18:46:36.029143, 10, pid=1331, effective(0, 0), real(0, 0)] ../source3/lib/util_sock.c:531(open_socket_in)\n", 119) = 119
geteuid()                               = 0
write(14, "  bind succeeded on port 1024\n", 30) = 30
stat("/etc/localtime", {st_mode=S_IFREG|0644, st_size=127, ...}) = 0
getgid()                                = 0
getuid()                                = 0
getegid()                               = 0
geteuid()                               = 0
geteuid()                               = 0
write(14, "[2015/04/29 18:46:36.029404, 10, pid=1331, effective(0, 0), real(0, 0)] ../source3/rpc_server/rpc_server.c:628(create_tcpip_socket)\n", 132) = 132
geteuid()                               = 0
write(14, "  Opened tcpip socket fd 38 for port 1024\n", 42) = 42
close(38)                               = 0
close(35)                               = 0
close(3)                                = 0
close(31)                               = 0
exit_group(1)                           = ?
+++ exited with 1 +++

As you can see, socket is created and then closed/exited.

The code is roughly here:
in start_lsasd():
        ok = lsasd_create_sockets(ev_ctx, msg_ctx, listen_fd, &listen_fd_size);
        if (!ok) {
                exit(1);
        }

in lsasd_create_sockets():
        /* Create only one tcpip listener for all services */
        status = rpc_create_tcpip_sockets(&ndr_table_lsarpc,
                                          v_orig,
                                          0,
                                          listen_fd,
                                          listen_fd_size);
        if (!NT_STATUS_IS_OK(status)) {
                goto done;
        }


in rpc_create_tcpip_sockets():
                for (sock_ptr = sock_addr;
                     next_token_talloc(talloc_tos(), &sock_ptr, &sock_tok, " \t,");
                    ) {
                        struct sockaddr_storage ss;
                        int fd;

                        /* open an incoming socket */
                        if (!interpret_string_addr(&ss,
                                                   sock_tok,
                                                   AI_NUMERICHOST|AI_PASSIVE)) {
                                continue;
                        }

                        fd = create_tcpip_socket(&ss, &p);
                        if (fd < 0 || p == 0) {
                                status = NT_STATUS_UNSUCCESSFUL;
                                if (fd != -1) {
                                        close(fd);
                                }
                                goto done;
                        }
                        listen_fd[*listen_fd_size] = fd;
                        (*listen_fd_size)++;

                        if (bvec != NULL) {
                                status = dcerpc_binding_vector_add_port(iface,
                                                                        bvec,
                                                                        sock_ptr,
                                                                        p);
                                if (!NT_STATUS_IS_OK(status)) {
                                        close(fd);
                                        goto done;
                                }
                        }
                }

the way I interpret the strace output is that dcerpc_binding_vector_add_port() fails. It looks like the code in commit 52ccd28ca75bef4f7ac2489389a5aebf5db2b34a may be responsible here.

Commit 52ccd28ca75bef4f7ac2489389a5aebf5db2b34a
s3:dcerpc_ep: make use of dcerpc_binding helper functions
We should not dereference 'struct dcerpc_binding'.

$ git tag --contains 52ccd28ca75bef4f7ac2489389a5aebf5db2b34a |grep samba
samba-4.2.0
samba-4.2.0rc1
samba-4.2.0rc2
samba-4.2.0rc3
samba-4.2.0rc4
samba-4.2.0rc5
samba-4.2.1

Comment 1 Alexander Bokovoy 2015-04-30 10:00:53 UTC
Guenther and I found actual issue -- rpc_create_tcpip_sockets() passed empty string (non-NULL, '') to dcerpc_binding_vector_add_port() and then dcerpc_binding_vector_add_port() tried to set binding's option 'host' to this string.

With the commit 017338a1 which is also 4.2 only, setting empty string to special properties of the binding is not possible:

+               if (value[0] == '\0') {
+                       return NT_STATUS_INVALID_PARAMETER_MIX;
+               }
+

Following patch fixed the issue for us:
commit 1ff9ffea061e4bdecea65749d8d0e3c082e25d77
Author:     Günther Deschner <gd>
AuthorDate: Thu Apr 30 11:20:58 2015 +0200
Commit:     Günther Deschner <gd>
CommitDate: Thu Apr 30 11:22:26 2015 +0200

    s3-rpc_server: fix rpc_create_tcpip_sockets() processing of interfaces.
    
    We were supplying an empty value for the "host" binding string option, causing
    dcerpc_binding_vector_add_port() call to fail.
    
    Guenther
    
    Signed-off-by: Günther Deschner <gd>
    Pair-Programmed-With: Alexander Bokovoy <ab>
---
 source3/rpc_server/rpc_sock_helper.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/source3/rpc_server/rpc_sock_helper.c b/source3/rpc_server/rpc_sock_helper.c
index 8f371b8..7aced63 100644
--- a/source3/rpc_server/rpc_sock_helper.c
+++ b/source3/rpc_server/rpc_sock_helper.c
@@ -138,7 +138,7 @@ NTSTATUS rpc_create_tcpip_sockets(const struct ndr_interface_table *iface,
 			if (bvec != NULL) {
 				status = dcerpc_binding_vector_add_port(iface,
 									bvec,
-									sock_ptr,
+									sock_tok,
 									p);
 				if (!NT_STATUS_IS_OK(status)) {
 					close(fd);

Comment 2 Alexander Bokovoy 2015-04-30 10:06:27 UTC
Cloned bug to Samba bugzilla.

Comment 3 Fedora Update System 2015-04-30 11:58:58 UTC
samba-4.2.1-7.fc22 has been submitted as an update for Fedora 22.
https://admin.fedoraproject.org/updates/samba-4.2.1-7.fc22

Comment 4 Fedora Update System 2015-05-01 16:43:13 UTC
Package samba-4.2.1-7.fc22:
* should fix your issue,
* was pushed to the Fedora 22 testing repository,
* should be available at your local mirror within two days.
Update it with:
# su -c 'yum update --enablerepo=updates-testing samba-4.2.1-7.fc22'
as soon as you are able to.
Please go to the following url:
https://admin.fedoraproject.org/updates/FEDORA-2015-7318/samba-4.2.1-7.fc22
then log in and leave karma (feedback).

Comment 5 Fedora Update System 2015-05-03 17:20:08 UTC
samba-4.2.1-7.fc22 has been pushed to the Fedora 22 stable repository.  If problems still persist, please make note of it in this bug report.