r23779: Change from v2 or later to v3 or later.
[ira/wip.git] / source3 / rpc_client / cli_pipe.c
index 7965aee8074fad093918687a133dfa2ba4e0d17d..a659785896b1653863e8e3fe31212aec0df15f28 100644 (file)
@@ -5,7 +5,7 @@
  *  
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
+ *  the Free Software Foundation; either version 3 of the License, or
  *  (at your option) any later version.
  *  
  *  This program is distributed in the hope that it will be useful,
@@ -619,7 +619,7 @@ static NTSTATUS cli_pipe_validate_current_pdu(struct rpc_pipe_client *cli, RPC_H
 
                        DEBUG(1, ("cli_pipe_validate_current_pdu: RPC fault code %s received from remote machine %s "
                                "pipe %s fnum 0x%x!\n",
-                               nt_errstr(fault_resp.status),
+                               dcerpc_errstr(NT_STATUS_V(fault_resp.status)),
                                cli->cli->desthost,
                                cli->pipe_name,
                                (unsigned int)cli->fnum));
@@ -744,8 +744,8 @@ static NTSTATUS rpc_api_pipe(struct rpc_pipe_client *cli,
        char *rparam = NULL;
        uint32 rparam_len = 0;
        uint16 setup[2];
-       char *pdata = data ? prs_data_p(data) : NULL;
-       uint32 data_len = data ? prs_offset(data) : 0;
+       char *pdata = prs_data_p(data);
+       uint32 data_len = prs_offset(data);
        char *prdata = NULL;
        uint32 rdata_len = 0;
        uint32 max_data = cli->max_xmit_frag ? cli->max_xmit_frag : RPC_MAX_PDU_FRAG_LEN;
@@ -789,6 +789,8 @@ static NTSTATUS rpc_api_pipe(struct rpc_pipe_client *cli,
                        (unsigned int)cli->fnum,
                        cli_errstr(cli->cli)));
                ret = cli_get_nt_error(cli->cli);
+               SAFE_FREE(rparam);
+               SAFE_FREE(prdata);
                goto err;
        }
 
@@ -913,8 +915,8 @@ static NTSTATUS create_krb5_auth_bind_req( struct rpc_pipe_client *cli,
 #ifdef HAVE_KRB5
        int ret;
        struct kerberos_auth_struct *a = cli->auth.a_u.kerberos_auth;
-       DATA_BLOB tkt = data_blob(NULL, 0);
-       DATA_BLOB tkt_wrapped = data_blob(NULL, 0);
+       DATA_BLOB tkt = data_blob_null;
+       DATA_BLOB tkt_wrapped = data_blob_null;
 
        /* We may change the pad length before marshalling. */
        init_rpc_hdr_auth(pauth_out, RPC_KRB5_AUTH_TYPE, (int)auth_level, 0, 1);
@@ -925,7 +927,7 @@ static NTSTATUS create_krb5_auth_bind_req( struct rpc_pipe_client *cli,
        /* Create the ticket for the service principal and return it in a gss-api wrapped blob. */
 
        ret = cli_krb5_get_ticket(a->service_principal, 0, &tkt,
-                       &a->session_key, (uint32)AP_OPTS_MUTUAL_REQUIRED);
+                       &a->session_key, (uint32)AP_OPTS_MUTUAL_REQUIRED, NULL, NULL);
 
        if (ret) {
                DEBUG(1,("create_krb5_auth_bind_req: cli_krb5_get_ticket for principal %s "
@@ -951,7 +953,7 @@ static NTSTATUS create_krb5_auth_bind_req( struct rpc_pipe_client *cli,
        }
 
        DEBUG(5, ("create_krb5_auth_bind_req: Created krb5 GSS blob :\n"));
-       dump_data(5, (const char *)tkt_wrapped.data, tkt_wrapped.length);
+       dump_data(5, tkt_wrapped.data, tkt_wrapped.length);
 
        data_blob_free(&tkt_wrapped);
        return NT_STATUS_OK;
@@ -970,9 +972,9 @@ static NTSTATUS create_spnego_ntlmssp_auth_rpc_bind_req( struct rpc_pipe_client
                                                prs_struct *auth_data)
 {
        NTSTATUS nt_status;
-       DATA_BLOB null_blob = data_blob(NULL, 0);
-       DATA_BLOB request = data_blob(NULL, 0);
-       DATA_BLOB spnego_msg = data_blob(NULL, 0);
+       DATA_BLOB null_blob = data_blob_null;
+       DATA_BLOB request = data_blob_null;
+       DATA_BLOB spnego_msg = data_blob_null;
 
        /* We may change the pad length before marshalling. */
        init_rpc_hdr_auth(pauth_out, RPC_SPNEGO_AUTH_TYPE, (int)auth_level, 0, 1);
@@ -1001,7 +1003,7 @@ static NTSTATUS create_spnego_ntlmssp_auth_rpc_bind_req( struct rpc_pipe_client
        }
 
        DEBUG(5, ("create_spnego_ntlmssp_auth_rpc_bind_req: NTLMSSP Negotiate:\n"));
-       dump_data(5, (const char *)spnego_msg.data, spnego_msg.length);
+       dump_data(5, spnego_msg.data, spnego_msg.length);
 
        data_blob_free(&spnego_msg);
        return NT_STATUS_OK;
@@ -1017,8 +1019,8 @@ static NTSTATUS create_ntlmssp_auth_rpc_bind_req( struct rpc_pipe_client *cli,
                                                prs_struct *auth_data)
 {
        NTSTATUS nt_status;
-       DATA_BLOB null_blob = data_blob(NULL, 0);
-       DATA_BLOB request = data_blob(NULL, 0);
+       DATA_BLOB null_blob = data_blob_null;
+       DATA_BLOB request = data_blob_null;
 
        /* We may change the pad length before marshalling. */
        init_rpc_hdr_auth(pauth_out, RPC_NTLMSSP_AUTH_TYPE, (int)auth_level, 0, 1);
@@ -1042,7 +1044,7 @@ static NTSTATUS create_ntlmssp_auth_rpc_bind_req( struct rpc_pipe_client *cli,
        }
 
        DEBUG(5, ("create_ntlmssp_auth_rpc_bind_req: NTLMSSP Negotiate:\n"));
-       dump_data(5, (const char *)request.data, request.length);
+       dump_data(5, request.data, request.length);
 
        data_blob_free(&request);
        return NT_STATUS_OK;
@@ -1088,7 +1090,7 @@ static NTSTATUS create_schannel_auth_rpc_bind_req( struct rpc_pipe_client *cli,
  Creates the internals of a DCE/RPC bind request or alter context PDU.
  ********************************************************************/
 
-static NTSTATUS create_bind_or_alt_ctx_internal(uint8 pkt_type,
+static NTSTATUS create_bind_or_alt_ctx_internal(enum RPC_PKT_TYPE pkt_type,
                                                prs_struct *rpc_out, 
                                                uint32 rpc_call_id,
                                                RPC_IFACE *abstract,
@@ -1248,7 +1250,7 @@ static NTSTATUS add_ntlmssp_auth_footer(struct rpc_pipe_client *cli,
 {
        RPC_HDR_AUTH auth_info;
        NTSTATUS status;
-       DATA_BLOB auth_blob = data_blob(NULL, 0);
+       DATA_BLOB auth_blob = data_blob_null;
        uint16 data_and_pad_len = prs_offset(outgoing_pdu) - RPC_HEADER_LEN - RPC_HDR_RESP_LEN;
 
        if (!cli->auth.a_u.ntlmssp_state) {
@@ -1643,10 +1645,10 @@ static BOOL valid_pipe_name(const int pipe_idx, RPC_IFACE *abstract, RPC_IFACE *
        }
 
        DEBUG(5,("Bind Abstract Syntax: "));    
-       dump_data(5, (char*)&pipe_names[pipe_idx].abstr_syntax, 
+       dump_data(5, (uint8 *)&pipe_names[pipe_idx].abstr_syntax, 
                  sizeof(pipe_names[pipe_idx].abstr_syntax));
        DEBUG(5,("Bind Transfer Syntax: "));
-       dump_data(5, (char*)&pipe_names[pipe_idx].trans_syntax,
+       dump_data(5, (uint8 *)&pipe_names[pipe_idx].trans_syntax,
                  sizeof(pipe_names[pipe_idx].trans_syntax));
 
        /* copy the required syntaxes out so we can do the right bind */
@@ -1773,8 +1775,8 @@ static NTSTATUS rpc_finish_auth3_bind(struct rpc_pipe_client *cli,
                                enum pipe_auth_type auth_type,
                                enum pipe_auth_level auth_level)
 {
-       DATA_BLOB server_response = data_blob(NULL,0);
-       DATA_BLOB client_reply = data_blob(NULL,0);
+       DATA_BLOB server_response = data_blob_null;
+       DATA_BLOB client_reply = data_blob_null;
        RPC_HDR_AUTH hdr_auth;
        NTSTATUS nt_status;
        prs_struct rpc_out;
@@ -1898,10 +1900,10 @@ static NTSTATUS rpc_finish_spnego_ntlmssp_bind(struct rpc_pipe_client *cli,
                                 enum pipe_auth_type auth_type,
                                 enum pipe_auth_level auth_level)
 {
-       DATA_BLOB server_spnego_response = data_blob(NULL,0);
-       DATA_BLOB server_ntlm_response = data_blob(NULL,0);
-       DATA_BLOB client_reply = data_blob(NULL,0);
-       DATA_BLOB tmp_blob = data_blob(NULL, 0);
+       DATA_BLOB server_spnego_response = data_blob_null;
+       DATA_BLOB server_ntlm_response = data_blob_null;
+       DATA_BLOB client_reply = data_blob_null;
+       DATA_BLOB tmp_blob = data_blob_null;
        RPC_HDR_AUTH hdr_auth;
        NTSTATUS nt_status;
        prs_struct rpc_out;
@@ -1951,7 +1953,7 @@ static NTSTATUS rpc_finish_spnego_ntlmssp_bind(struct rpc_pipe_client *cli,
        tmp_blob = spnego_gen_auth(client_reply);
        data_blob_free(&client_reply);
        client_reply = tmp_blob;
-       tmp_blob = data_blob(NULL,0); /* Ensure it's safe to free this just in case. */
+       tmp_blob = data_blob_null; /* Ensure it's safe to free this just in case. */
 
        /* Now prepare the alter context pdu. */
        prs_init(&rpc_out, 0, prs_get_mem_context(rbuf), MARSHALL);
@@ -2000,7 +2002,7 @@ static NTSTATUS rpc_finish_spnego_ntlmssp_bind(struct rpc_pipe_client *cli,
        prs_copy_data_out((char *)server_spnego_response.data, rbuf, phdr->auth_len);
 
        /* Check we got a valid auth response. */
-       if (!spnego_parse_auth_response(server_spnego_response, NT_STATUS_OK, &tmp_blob)) {
+       if (!spnego_parse_auth_response(server_spnego_response, NT_STATUS_OK, OID_NTLMSSP, &tmp_blob)) {
                data_blob_free(&server_spnego_response);
                data_blob_free(&tmp_blob);
                return NT_STATUS_INVALID_PARAMETER;
@@ -2139,6 +2141,24 @@ static NTSTATUS rpc_pipe_bind(struct rpc_pipe_client *cli,
                        return NT_STATUS_INVALID_INFO_CLASS;
        }
 
+       /* For NTLMSSP ensure the server gave us the auth_level we wanted. */
+       if (auth_type == PIPE_AUTH_TYPE_NTLMSSP || auth_type == PIPE_AUTH_TYPE_SPNEGO_NTLMSSP) {
+               if (auth_level == PIPE_AUTH_LEVEL_INTEGRITY) {
+                       if (!(cli->auth.a_u.ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SIGN)) {
+                               DEBUG(0,("cli_finish_bind_auth: requested NTLMSSSP signing and server refused.\n"));
+                               prs_mem_free(&rbuf);
+                               return NT_STATUS_INVALID_PARAMETER;
+                       }
+               }
+               if (auth_level == PIPE_AUTH_LEVEL_INTEGRITY) {
+                       if (!(cli->auth.a_u.ntlmssp_state->neg_flags & NTLMSSP_NEGOTIATE_SEAL)) {
+                               DEBUG(0,("cli_finish_bind_auth: requested NTLMSSSP sealing and server refused.\n"));
+                               prs_mem_free(&rbuf);
+                               return NT_STATUS_INVALID_PARAMETER;
+                       }
+               }
+       }
+
        /* Pipe is bound - set up auth_type and auth_level data. */
 
        cli->auth.auth_type = auth_type;
@@ -2150,6 +2170,15 @@ static NTSTATUS rpc_pipe_bind(struct rpc_pipe_client *cli,
 
 /****************************************************************************
  Open a named pipe over SMB to a remote server.
+ *
+ * CAVEAT CALLER OF THIS FUNCTION:
+ *    The returned rpc_pipe_client saves a copy of the cli_state cli pointer,
+ *    so be sure that this function is called AFTER any structure (vs pointer)
+ *    assignment of the cli.  In particular, libsmbclient does structure
+ *    assignments of cli, which invalidates the data in the returned
+ *    rpc_pipe_client if this function is called before the structure assignment
+ *    of cli.
+ * 
  ****************************************************************************/
 
 static struct rpc_pipe_client *cli_rpc_pipe_open(struct cli_state *cli, int pipe_idx, NTSTATUS *perr)
@@ -2160,6 +2189,13 @@ static struct rpc_pipe_client *cli_rpc_pipe_open(struct cli_state *cli, int pipe
 
        *perr = NT_STATUS_NO_MEMORY;
 
+       /* sanity check to protect against crashes */
+
+       if ( !cli ) {
+               *perr = NT_STATUS_INVALID_HANDLE;
+               return NULL;
+       }
+
        /* The pipe name index must fall within our array */
        SMB_ASSERT((pipe_idx >= 0) && (pipe_idx < PI_MAX_PIPES));
 
@@ -2180,7 +2216,7 @@ static struct rpc_pipe_client *cli_rpc_pipe_open(struct cli_state *cli, int pipe
        fnum = cli_nt_create(cli, result->pipe_name, DESIRED_ACCESS_PIPE);
 
        if (fnum == -1) {
-               DEBUG(0,("cli_rpc_pipe_open: cli_nt_create failed on pipe %s "
+               DEBUG(1,("cli_rpc_pipe_open: cli_nt_create failed on pipe %s "
                         "to machine %s.  Error was %s\n",
                         result->pipe_name, cli->desthost,
                         cli_errstr(cli)));
@@ -2225,7 +2261,13 @@ struct rpc_pipe_client *cli_rpc_pipe_open_noauth(struct cli_state *cli, int pipe
 
        *perr = rpc_pipe_bind(result, PIPE_AUTH_TYPE_NONE, PIPE_AUTH_LEVEL_NONE);
        if (!NT_STATUS_IS_OK(*perr)) {
-               DEBUG(0, ("cli_rpc_pipe_open_noauth: rpc_pipe_bind for pipe %s failed with error %s\n",
+               int lvl = 0;
+               if (pipe_idx == PI_LSARPC_DS) {
+                       /* non AD domains just don't have this pipe, avoid
+                        * level 0 statement in that case - gd */
+                       lvl = 3;
+               }
+               DEBUG(lvl, ("cli_rpc_pipe_open_noauth: rpc_pipe_bind for pipe %s failed with error %s\n",
                        cli_get_pipe_name(pipe_idx), nt_errstr(*perr) ));
                cli_rpc_pipe_close(result);
                return NULL;
@@ -2382,13 +2424,14 @@ struct rpc_pipe_client *cli_rpc_pipe_open_spnego_ntlmssp(struct cli_state *cli,
 
 /****************************************************************************
  Open a netlogon pipe and get the schannel session key.
+ Now exposed to external callers.
  ****************************************************************************/
 
-static struct rpc_pipe_client *get_schannel_session_key(struct cli_state *cli,
+struct rpc_pipe_client *get_schannel_session_key(struct cli_state *cli,
                                                        const char *domain,
+                                                       uint32 *pneg_flags,
                                                        NTSTATUS *perr)
 {
-       uint32 neg_flags = NETLOGON_NEG_AUTH2_FLAGS|NETLOGON_NEG_SCHANNEL;
        struct rpc_pipe_client *netlogon_pipe = NULL;
        uint32 sec_chan_type = 0;
        unsigned char machine_pwd[16];
@@ -2409,15 +2452,18 @@ static struct rpc_pipe_client *get_schannel_session_key(struct cli_state *cli,
                return NULL;
        }
 
+       /* A DC should use DOMAIN$ as its account name.
+          A member server can only use it's machine name since it
+          does not have an account in a trusted domain.
+
+          We don't check the domain against lp_workgroup() here since
+          'net ads join' has to continue to work with only the realm
+          specified in smb.conf.  -- jerry */
+
         if ( IS_DC && !strequal(domain, lp_workgroup()) && lp_allow_trusted_domains()) {
                fstrcpy( machine_account, lp_workgroup() );
         } else {
-                /* Hmmm. Is this correct for trusted domains when we're a member server ? JRA. */
-                if (strequal(domain, lp_workgroup())) {
-                        fstrcpy(machine_account, global_myname());
-                } else {
-                        fstrcpy(machine_account, domain);
-                }
+               fstrcpy(machine_account, global_myname());
         }
 
        *perr = rpccli_netlogon_setup_creds(netlogon_pipe,
@@ -2427,7 +2473,7 @@ static struct rpc_pipe_client *get_schannel_session_key(struct cli_state *cli,
                                        machine_account, /* machine account name */
                                        machine_pwd,
                                        sec_chan_type,
-                                       &neg_flags);
+                                       pneg_flags);
 
        if (!NT_STATUS_IS_OK(*perr)) {
                DEBUG(3,("get_schannel_session_key: rpccli_netlogon_setup_creds "
@@ -2437,7 +2483,7 @@ static struct rpc_pipe_client *get_schannel_session_key(struct cli_state *cli,
                return NULL;
        }
 
-       if ((neg_flags & NETLOGON_NEG_SCHANNEL) == 0) {
+       if (((*pneg_flags) & NETLOGON_NEG_SCHANNEL) == 0) {
                DEBUG(3, ("get_schannel_session_key: Server %s did not offer schannel\n",
                        cli->desthost));
                cli_rpc_pipe_close(netlogon_pipe);
@@ -2509,9 +2555,9 @@ static struct rpc_pipe_client *get_schannel_session_key_auth_ntlmssp(struct cli_
                                                        const char *domain,
                                                        const char *username,
                                                        const char *password,
+                                                       uint32 *pneg_flags,
                                                        NTSTATUS *perr)
 {
-       uint32 neg_flags = NETLOGON_NEG_AUTH2_FLAGS|NETLOGON_NEG_SCHANNEL;
        struct rpc_pipe_client *netlogon_pipe = NULL;
        uint32 sec_chan_type = 0;
        unsigned char machine_pwd[16];
@@ -2553,7 +2599,7 @@ static struct rpc_pipe_client *get_schannel_session_key_auth_ntlmssp(struct cli_
                                        machine_account,   /* machine account name */
                                        machine_pwd,
                                        sec_chan_type,
-                                       &neg_flags);
+                                       pneg_flags);
 
        if (!NT_STATUS_IS_OK(*perr)) {
                DEBUG(3,("get_schannel_session_key_auth_ntlmssp: rpccli_netlogon_setup_creds "
@@ -2563,7 +2609,7 @@ static struct rpc_pipe_client *get_schannel_session_key_auth_ntlmssp(struct cli_
                return NULL;
        }
 
-       if ((neg_flags & NETLOGON_NEG_SCHANNEL) == 0) {
+       if (((*pneg_flags) & NETLOGON_NEG_SCHANNEL) == 0) {
                DEBUG(3, ("get_schannel_session_key_auth_ntlmssp: Server %s did not offer schannel\n",
                        cli->desthost));
                cli_rpc_pipe_close(netlogon_pipe);
@@ -2588,10 +2634,12 @@ struct rpc_pipe_client *cli_rpc_pipe_open_ntlmssp_auth_schannel(struct cli_state
                                                const char *password,
                                                NTSTATUS *perr)
 {
+       uint32 neg_flags = NETLOGON_NEG_AUTH2_FLAGS|NETLOGON_NEG_SCHANNEL;
        struct rpc_pipe_client *netlogon_pipe = NULL;
        struct rpc_pipe_client *result = NULL;
 
-       netlogon_pipe = get_schannel_session_key_auth_ntlmssp(cli, domain, username, password, perr);
+       netlogon_pipe = get_schannel_session_key_auth_ntlmssp(cli, domain, username,
+                                                       password, &neg_flags, perr);
        if (!netlogon_pipe) {
                DEBUG(0,("cli_rpc_pipe_open_ntlmssp_auth_schannel: failed to get schannel session "
                        "key from server %s for domain %s.\n",
@@ -2620,10 +2668,11 @@ struct rpc_pipe_client *cli_rpc_pipe_open_schannel(struct cli_state *cli,
                                                 const char *domain,
                                                NTSTATUS *perr)
 {
+       uint32 neg_flags = NETLOGON_NEG_AUTH2_FLAGS|NETLOGON_NEG_SCHANNEL;
        struct rpc_pipe_client *netlogon_pipe = NULL;
        struct rpc_pipe_client *result = NULL;
 
-       netlogon_pipe = get_schannel_session_key(cli, domain, perr);
+       netlogon_pipe = get_schannel_session_key(cli, domain, &neg_flags, perr);
        if (!netlogon_pipe) {
                DEBUG(0,("cli_rpc_pipe_open_schannel: failed to get schannel session "
                        "key from server %s for domain %s.\n",
@@ -2676,9 +2725,9 @@ struct rpc_pipe_client *cli_rpc_pipe_open_krb5(struct cli_state *cli,
                return NULL;
        }
 
-       /* Default service principal is "host/server@realm" */
+       /* Default service principal is "desthost$@realm" */
        if (!service_princ) {
-               service_princ = talloc_asprintf(result->mem_ctx, "host/%s@%s",
+               service_princ = talloc_asprintf(result->mem_ctx, "%s$@%s",
                        cli->desthost, lp_realm() );
                if (!service_princ) {
                        cli_rpc_pipe_close(result);
@@ -2688,7 +2737,7 @@ struct rpc_pipe_client *cli_rpc_pipe_open_krb5(struct cli_state *cli,
 
        /* Only get a new TGT if username/password are given. */
        if (username && password) {
-               int ret = kerberos_kinit_password(username, password, 0, NULL, NULL);
+               int ret = kerberos_kinit_password(username, password, 0, NULL);
                if (ret) {
                        cli_rpc_pipe_close(result);
                        return NULL;
@@ -2726,7 +2775,7 @@ struct rpc_pipe_client *cli_rpc_pipe_open_krb5(struct cli_state *cli,
  Close an open named pipe over SMB. Free any authentication data.
  ****************************************************************************/
 
-void cli_rpc_pipe_close(struct rpc_pipe_client *cli)
+ void cli_rpc_pipe_close(struct rpc_pipe_client *cli)
 {
        if (!cli_close(cli->cli, cli->fnum)) {
                DEBUG(0,("cli_rpc_pipe_close: cli_close failed on pipe %s "