r14182: Ensure we know that dom_sid cannot be null.
[kai/samba-autobuild/.git] / source / rpc_server / srv_netlog_nt.c
index fd78f954cc4e393f5166d9e5ebdf107eb3e76970..8dbd4ff33f33c49bc5dcbd28f0e17618874903a6 100644 (file)
@@ -206,7 +206,7 @@ static void init_net_r_srv_pwset(NET_R_SRV_PWSET *r_s,
 
 static BOOL get_md4pw(char *md4pw, char *mach_acct)
 {
-       SAM_ACCOUNT *sampass = NULL;
+       struct samu *sampass = NULL;
        const uint8 *pass;
        BOOL ret;
        uint32 acct_ctrl;
@@ -229,8 +229,9 @@ static BOOL get_md4pw(char *md4pw, char *mach_acct)
        }
 #endif /* 0 */
 
-       if(!NT_STATUS_IS_OK(pdb_init_sam(&sampass)))
+       if ( !(sampass = samu_new( NULL )) ) {
                return False;
+       }
 
        /* JRA. This is ok as it is only used for generating the challenge. */
        become_root();
@@ -239,7 +240,7 @@ static BOOL get_md4pw(char *md4pw, char *mach_acct)
  
        if (ret==False) {
                DEBUG(0,("get_md4pw: Workstation %s: no account in domain\n", mach_acct));
-               pdb_free_sam(&sampass);
+               TALLOC_FREE(sampass);
                return False;
        }
 
@@ -251,12 +252,12 @@ static BOOL get_md4pw(char *md4pw, char *mach_acct)
            ((pass=pdb_get_nt_passwd(sampass)) != NULL)) {
                memcpy(md4pw, pass, 16);
                dump_data(5, md4pw, 16);
-               pdb_free_sam(&sampass);
+               TALLOC_FREE(sampass);
                return True;
        }
        
        DEBUG(0,("get_md4pw: Workstation %s: no account in domain\n", mach_acct));
-       pdb_free_sam(&sampass);
+       TALLOC_FREE(sampass);
        return False;
 
 }
@@ -334,10 +335,11 @@ NTSTATUS _net_auth(pipes_struct *p, NET_Q_AUTH *q_u, NET_R_AUTH *r_u)
        }
 
        /* From the client / server challenges and md4 password, generate sess key */
-       creds_server_init(p->dc,
+       creds_server_init(0,                    /* No neg flags. */
+                       p->dc,
                        &p->dc->clnt_chal,      /* Stored client chal. */
                        &p->dc->srv_chal,       /* Stored server chal. */
-                       (const char *)p->dc->mach_pw,
+                       p->dc->mach_pw,
                        &srv_chal_out); 
 
        /* Check client credentials are valid. */
@@ -384,6 +386,8 @@ NTSTATUS _net_auth_2(pipes_struct *p, NET_Q_AUTH_2 *q_u, NET_R_AUTH_2 *r_u)
 
        rpcstr_pull(mach_acct, q_u->clnt_id.uni_acct_name.buffer,sizeof(fstring),
                                q_u->clnt_id.uni_acct_name.uni_str_len*2,0);
+
+       /* We use this as the key to store the creds. */
        rpcstr_pull(remote_machine, q_u->clnt_id.uni_comp_name.buffer,sizeof(fstring),
                                q_u->clnt_id.uni_comp_name.uni_str_len*2,0);
 
@@ -411,10 +415,11 @@ NTSTATUS _net_auth_2(pipes_struct *p, NET_Q_AUTH_2 *q_u, NET_R_AUTH_2 *r_u)
        }
 
        /* From the client / server challenges and md4 password, generate sess key */
-       creds_server_init(p->dc,
+       creds_server_init(q_u->clnt_flgs.neg_flags,
+                       p->dc,
                        &p->dc->clnt_chal,      /* Stored client chal. */
                        &p->dc->srv_chal,       /* Stored server chal. */
-                       (const char *)p->dc->mach_pw,
+                       p->dc->mach_pw,
                        &srv_chal_out); 
 
        /* Check client credentials are valid. */
@@ -442,7 +447,9 @@ NTSTATUS _net_auth_2(pipes_struct *p, NET_Q_AUTH_2 *q_u, NET_R_AUTH_2 *r_u)
 
        /* Store off the state so we can continue after client disconnect. */
        become_root();
-       secrets_store_schannel_session_info(p->mem_ctx, p->dc);
+       secrets_store_schannel_session_info(p->mem_ctx,
+                                       remote_machine,
+                                       p->dc);
        unbecome_root();
 
        return r_u->status;
@@ -455,8 +462,8 @@ NTSTATUS _net_auth_2(pipes_struct *p, NET_Q_AUTH_2 *q_u, NET_R_AUTH_2 *r_u)
 NTSTATUS _net_srv_pwset(pipes_struct *p, NET_Q_SRV_PWSET *q_u, NET_R_SRV_PWSET *r_u)
 {
        NTSTATUS status = NT_STATUS_ACCESS_DENIED;
-       fstring workstation;
-       SAM_ACCOUNT *sampass=NULL;
+       fstring remote_machine;
+       struct samu *sampass=NULL;
        BOOL ret = False;
        unsigned char pwd[16];
        int i;
@@ -464,32 +471,61 @@ NTSTATUS _net_srv_pwset(pipes_struct *p, NET_Q_SRV_PWSET *q_u, NET_R_SRV_PWSET *
        DOM_CRED cred_out;
        const uchar *old_pw;
 
+       DEBUG(5,("_net_srv_pwset: %d\n", __LINE__));
+
+       /* We need the remote machine name for the creds lookup. */
+       rpcstr_pull(remote_machine,q_u->clnt_id.login.uni_comp_name.buffer,
+                   sizeof(remote_machine),q_u->clnt_id.login.uni_comp_name.uni_str_len*2,0);
+
+       if ( (lp_server_schannel() == True) && (p->auth.auth_type != PIPE_AUTH_TYPE_SCHANNEL) ) {
+               /* 'server schannel = yes' should enforce use of
+                  schannel, the client did offer it in auth2, but
+                  obviously did not use it. */
+               DEBUG(0,("_net_srv_pwset: client %s not using schannel for netlogon\n",
+                       remote_machine ));
+               return NT_STATUS_ACCESS_DENIED;
+       }
+
+       if (!p->dc) {
+               /* Restore the saved state of the netlogon creds. */
+               become_root();
+               ret = secrets_restore_schannel_session_info(p->pipe_state_mem_ctx,
+                                                       remote_machine,
+                                                       &p->dc);
+               unbecome_root();
+               if (!ret) {
+                       return NT_STATUS_INVALID_HANDLE;
+               }
+       }
+
        if (!p->dc || !p->dc->authenticated) {
                return NT_STATUS_INVALID_HANDLE;
        }
 
+       DEBUG(3,("_net_srv_pwset: Server Password Set by remote machine:[%s] on account [%s]\n",
+                       remote_machine, p->dc->mach_acct));
+       
        /* Step the creds chain forward. */
        if (!creds_server_step(p->dc, &q_u->clnt_id.cred, &cred_out)) {
                DEBUG(2,("_net_srv_pwset: creds_server_step failed. Rejecting auth "
                        "request from client %s machine account %s\n",
-                       p->dc->remote_machine, p->dc->mach_acct ));
-               return NT_STATUS_ACCESS_DENIED;
+                       remote_machine, p->dc->mach_acct ));
+               return NT_STATUS_INVALID_PARAMETER;
        }
 
-       DEBUG(5,("_net_srv_pwset: %d\n", __LINE__));
-
-       rpcstr_pull(workstation,q_u->clnt_id.login.uni_comp_name.buffer,
-                   sizeof(workstation),q_u->clnt_id.login.uni_comp_name.uni_str_len*2,0);
-
-       DEBUG(3,("_net_srv_pwset: Server Password Set by Wksta:[%s] on account [%s]\n",
-                       workstation, p->dc->mach_acct));
-       
-       pdb_init_sam(&sampass);
-
+       /* We must store the creds state after an update. */
        become_root();
-       ret=pdb_getsampwnam(sampass, p->dc->mach_acct);
+       secrets_store_schannel_session_info(p->pipe_state_mem_ctx,
+                                               remote_machine,
+                                               p->dc);
+       if ( (sampass = samu_new( NULL )) != NULL ) {
+               ret = pdb_getsampwnam(sampass, p->dc->mach_acct);
+       }
        unbecome_root();
 
+       if ( !sampass ) 
+               return NT_STATUS_NO_MEMORY;
+
        /* Ensure the account exists and is a machine account. */
        
        acct_ctrl = pdb_get_acct_ctrl(sampass);
@@ -498,12 +534,12 @@ NTSTATUS _net_srv_pwset(pipes_struct *p, NET_Q_SRV_PWSET *q_u, NET_R_SRV_PWSET *
              && (acct_ctrl & ACB_WSTRUST ||
                      acct_ctrl & ACB_SVRTRUST ||
                      acct_ctrl & ACB_DOMTRUST))) {
-               pdb_free_sam(&sampass);
+               TALLOC_FREE(sampass);
                return NT_STATUS_NO_SUCH_USER;
        }
        
        if (pdb_get_acct_ctrl(sampass) & ACB_DISABLED) {
-               pdb_free_sam(&sampass);
+               TALLOC_FREE(sampass);
                return NT_STATUS_ACCOUNT_DISABLED;
        }
 
@@ -526,17 +562,17 @@ NTSTATUS _net_srv_pwset(pipes_struct *p, NET_Q_SRV_PWSET *q_u, NET_R_SRV_PWSET *
 
                /* LM password should be NULL for machines */
                if (!pdb_set_lanman_passwd(sampass, NULL, PDB_CHANGED)) {
-                       pdb_free_sam(&sampass);
+                       TALLOC_FREE(sampass);
                        return NT_STATUS_NO_MEMORY;
                }
                
                if (!pdb_set_nt_passwd(sampass, pwd, PDB_CHANGED)) {
-                       pdb_free_sam(&sampass);
+                       TALLOC_FREE(sampass);
                        return NT_STATUS_NO_MEMORY;
                }
                
                if (!pdb_set_pass_changed_now(sampass)) {
-                       pdb_free_sam(&sampass);
+                       TALLOC_FREE(sampass);
                        /* Not quite sure what this one qualifies as, but this will do */
                        return NT_STATUS_UNSUCCESSFUL; 
                }
@@ -549,7 +585,7 @@ NTSTATUS _net_srv_pwset(pipes_struct *p, NET_Q_SRV_PWSET *q_u, NET_R_SRV_PWSET *
        /* set up the LSA Server Password Set response */
        init_net_r_srv_pwset(r_u, &cred_out, status);
 
-       pdb_free_sam(&sampass);
+       TALLOC_FREE(sampass);
        return r_u->status;
 }
 
@@ -559,9 +595,39 @@ NTSTATUS _net_srv_pwset(pipes_struct *p, NET_Q_SRV_PWSET *q_u, NET_R_SRV_PWSET *
 
 NTSTATUS _net_sam_logoff(pipes_struct *p, NET_Q_SAM_LOGOFF *q_u, NET_R_SAM_LOGOFF *r_u)
 {
+       fstring remote_machine;
+
+       if ( (lp_server_schannel() == True) && (p->auth.auth_type != PIPE_AUTH_TYPE_SCHANNEL) ) {
+               /* 'server schannel = yes' should enforce use of
+                  schannel, the client did offer it in auth2, but
+                  obviously did not use it. */
+               DEBUG(0,("_net_sam_logoff: client %s not using schannel for netlogon\n",
+                       get_remote_machine_name() ));
+               return NT_STATUS_ACCESS_DENIED;
+       }
+
+
        if (!get_valid_user_struct(p->vuid))
                return NT_STATUS_NO_SUCH_USER;
 
+       /* Get the remote machine name for the creds store. */
+       rpcstr_pull(remote_machine,q_u->sam_id.client.login.uni_comp_name.buffer,
+                   sizeof(remote_machine),q_u->sam_id.client.login.uni_comp_name.uni_str_len*2,0);
+
+       if (!p->dc) {
+               /* Restore the saved state of the netlogon creds. */
+               BOOL ret;
+
+               become_root();
+               ret = secrets_restore_schannel_session_info(p->pipe_state_mem_ctx,
+                                               remote_machine,
+                                               &p->dc);
+               unbecome_root();
+               if (!ret) {
+                       return NT_STATUS_INVALID_HANDLE;
+               }
+       }
+
        if (!p->dc || !p->dc->authenticated) {
                return NT_STATUS_INVALID_HANDLE;
        }
@@ -572,18 +638,25 @@ NTSTATUS _net_sam_logoff(pipes_struct *p, NET_Q_SAM_LOGOFF *q_u, NET_R_SAM_LOGOF
        if (!creds_server_step(p->dc, &q_u->sam_id.client.cred, &r_u->srv_creds)) {
                DEBUG(2,("_net_sam_logoff: creds_server_step failed. Rejecting auth "
                        "request from client %s machine account %s\n",
-                       p->dc->remote_machine, p->dc->mach_acct ));
-               return NT_STATUS_ACCESS_DENIED;
+                       remote_machine, p->dc->mach_acct ));
+               return NT_STATUS_INVALID_PARAMETER;
        }
 
+       /* We must store the creds state after an update. */
+       become_root();
+       secrets_store_schannel_session_info(p->pipe_state_mem_ctx,
+                                       remote_machine,
+                                       p->dc);
+       unbecome_root();
+
        r_u->status = NT_STATUS_OK;
        return r_u->status;
 }
 
-
 /*******************************************************************
  gets a domain user's groups from their already-calculated NT_USER_TOKEN
  ********************************************************************/
+
 static NTSTATUS nt_token_to_group_list(TALLOC_CTX *mem_ctx,
                                       const DOM_SID *domain_sid,
                                       size_t num_sids,
@@ -614,7 +687,10 @@ static NTSTATUS nt_token_to_group_list(TALLOC_CTX *mem_ctx,
  _net_sam_logon
  *************************************************************************/
 
-NTSTATUS _net_sam_logon(pipes_struct *p, NET_Q_SAM_LOGON *q_u, NET_R_SAM_LOGON *r_u)
+static NTSTATUS _net_sam_logon_internal(pipes_struct *p,
+                                       NET_Q_SAM_LOGON *q_u,
+                                       NET_R_SAM_LOGON *r_u,
+                                       BOOL process_creds)
 {
        NTSTATUS status = NT_STATUS_OK;
        NET_USER_INFO_3 *usr_info = NULL;
@@ -625,48 +701,83 @@ NTSTATUS _net_sam_logon(pipes_struct *p, NET_Q_SAM_LOGON *q_u, NET_R_SAM_LOGON *
        fstring nt_username, nt_domain, nt_workstation;
        auth_usersupplied_info *user_info = NULL;
        auth_serversupplied_info *server_info = NULL;
-       SAM_ACCOUNT *sampw;
+       struct samu *sampw;
        struct auth_context *auth_context = NULL;
-               
+        
+       if ( (lp_server_schannel() == True) && (p->auth.auth_type != PIPE_AUTH_TYPE_SCHANNEL) ) {
+               /* 'server schannel = yes' should enforce use of
+                  schannel, the client did offer it in auth2, but
+                  obviously did not use it. */
+               DEBUG(0,("_net_sam_logon_internal: client %s not using schannel for netlogon\n",
+                       get_remote_machine_name() ));
+               return NT_STATUS_ACCESS_DENIED;
+       }
+
        usr_info = TALLOC_P(p->mem_ctx, NET_USER_INFO_3);
-       if (!usr_info)
+       if (!usr_info) {
                return NT_STATUS_NO_MEMORY;
+       }
 
        ZERO_STRUCTP(usr_info);
 
        /* store the user information, if there is any. */
        r_u->user = usr_info;
-       r_u->switch_value = 0; /* indicates no info */
        r_u->auth_resp = 1; /* authoritative response */
-       r_u->switch_value = 3; /* indicates type of validation user info */
+       if (q_u->validation_level != 2 && q_u->validation_level != 3) {
+               DEBUG(0,("_net_sam_logon: bad validation_level value %d.\n", (int)q_u->validation_level ));
+               return NT_STATUS_ACCESS_DENIED;
+       }
+       /* We handle the return of USER_INFO_2 instead of 3 in the parse return. Sucks, I know... */
+       r_u->switch_value = q_u->validation_level; /* indicates type of validation user info */
        r_u->buffer_creds = 1; /* Ensure we always return server creds. */
  
        if (!get_valid_user_struct(p->vuid))
                return NT_STATUS_NO_SUCH_USER;
 
-       if (!p->dc || !p->dc->authenticated) {
-               return NT_STATUS_INVALID_HANDLE;
-       }
+       if (process_creds) {
+               fstring remote_machine;
 
-       if ( (lp_server_schannel() == True) && (p->auth.auth_type != PIPE_AUTH_TYPE_SCHANNEL) ) {
-               /* 'server schannel = yes' should enforce use of
-                  schannel, the client did offer it in auth2, but
-                  obviously did not use it. */
-               DEBUG(0,("_net_sam_logon: client %s not using schannel for netlogon\n",
-                       p->dc->remote_machine ));
-               return NT_STATUS_ACCESS_DENIED;
-       }
+               /* Get the remote machine name for the creds store. */
+               /* Note this is the remote machine this request is coming from (member server),
+                  not neccessarily the workstation name the user is logging onto.
+               */
+               rpcstr_pull(remote_machine,q_u->sam_id.client.login.uni_comp_name.buffer,
+                   sizeof(remote_machine),q_u->sam_id.client.login.uni_comp_name.uni_str_len*2,0);
 
-       /* checks and updates credentials.  creates reply credentials */
-       if (!creds_server_step(p->dc, &q_u->sam_id.client.cred,  &r_u->srv_creds)) {
-               DEBUG(2,("_net_sam_logon: creds_server_step failed. Rejecting auth "
-                       "request from client %s machine account %s\n",
-                       p->dc->remote_machine, p->dc->mach_acct ));
-               return NT_STATUS_ACCESS_DENIED;
+               if (!p->dc) {
+                       /* Restore the saved state of the netlogon creds. */
+                       BOOL ret;
+
+                       become_root();
+                       ret = secrets_restore_schannel_session_info(p->pipe_state_mem_ctx,
+                                       remote_machine,
+                                       &p->dc);
+                       unbecome_root();
+                       if (!ret) {
+                               return NT_STATUS_INVALID_HANDLE;
+                       }
+               }
+
+               if (!p->dc || !p->dc->authenticated) {
+                       return NT_STATUS_INVALID_HANDLE;
+               }
+
+               /* checks and updates credentials.  creates reply credentials */
+               if (!creds_server_step(p->dc, &q_u->sam_id.client.cred,  &r_u->srv_creds)) {
+                       DEBUG(2,("_net_sam_logon: creds_server_step failed. Rejecting auth "
+                               "request from client %s machine account %s\n",
+                               remote_machine, p->dc->mach_acct ));
+                       return NT_STATUS_INVALID_PARAMETER;
+               }
+
+               /* We must store the creds state after an update. */
+               become_root();
+               secrets_store_schannel_session_info(p->pipe_state_mem_ctx,
+                                       remote_machine,
+                                       p->dc);
+               unbecome_root();
        }
 
-       /* find the username */
-    
        switch (q_u->sam_id.logon_level) {
        case INTERACTIVE_LOGON_TYPE:
                uni_samlogon_user = &ctr->auth.id1.uni_user_name;
@@ -692,9 +803,7 @@ NTSTATUS _net_sam_logon(pipes_struct *p, NET_Q_SAM_LOGON *q_u, NET_R_SAM_LOGON *
        rpcstr_pull(nt_domain,uni_samlogon_domain->buffer,sizeof(nt_domain),uni_samlogon_domain->uni_str_len*2,0);
        rpcstr_pull(nt_workstation,uni_samlogon_workstation->buffer,sizeof(nt_workstation),uni_samlogon_workstation->uni_str_len*2,0);
 
-       DEBUG(3,("User:[%s@%s] Requested Domain:[%s]\n", nt_username, 
-                 nt_workstation, nt_domain));
-       
+       DEBUG(3,("User:[%s@%s] Requested Domain:[%s]\n", nt_username, nt_workstation, nt_domain));
        fstrcpy(current_user_info.smb_name, nt_username);
        sub_set_smb_name(nt_username);
      
@@ -784,7 +893,7 @@ NTSTATUS _net_sam_logon(pipes_struct *p, NET_Q_SAM_LOGON *q_u, NET_R_SAM_LOGON *
                     && !is_trusted_domain(nt_domain) )
                        r_u->auth_resp = 0; /* We are not authoritative */
 
-               talloc_free(server_info);
+               TALLOC_FREE(server_info);
                return status;
        }
 
@@ -792,7 +901,7 @@ NTSTATUS _net_sam_logon(pipes_struct *p, NET_Q_SAM_LOGON *q_u, NET_R_SAM_LOGON *
                /* We don't like guest domain logons... */
                DEBUG(5,("_net_sam_logon: Attempted domain logon as GUEST "
                         "denied.\n"));
-               talloc_free(server_info);
+               TALLOC_FREE(server_info);
                return NT_STATUS_LOGON_FAILURE;
        }
 
@@ -811,9 +920,9 @@ NTSTATUS _net_sam_logon(pipes_struct *p, NET_Q_SAM_LOGON *q_u, NET_R_SAM_LOGON *
                pstring my_name;
                fstring user_sid_string;
                fstring group_sid_string;
-               uchar user_session_key[16];
-               uchar lm_session_key[16];
-               uchar netlogon_sess_key[16];
+               unsigned char user_session_key[16];
+               unsigned char lm_session_key[16];
+               unsigned char pipe_session_key[16];
 
                sampw = server_info->sam_account;
 
@@ -855,23 +964,42 @@ NTSTATUS _net_sam_logon(pipes_struct *p, NET_Q_SAM_LOGON *q_u, NET_R_SAM_LOGON *
                        return status;
                }
 
-               ZERO_STRUCT(netlogon_sess_key);
-               memcpy(netlogon_sess_key, p->dc->sess_key, 8);
                if (server_info->user_session_key.length) {
                        memcpy(user_session_key,
                               server_info->user_session_key.data, 
                               MIN(sizeof(user_session_key),
                                   server_info->user_session_key.length));
-                       SamOEMhash(user_session_key, netlogon_sess_key, 16);
+                       if (process_creds) {
+                               /* Get the pipe session key from the creds. */
+                               memcpy(pipe_session_key, p->dc->sess_key, 16);
+                       } else {
+                               /* Get the pipe session key from the schannel. */
+                               if (p->auth.auth_type != PIPE_AUTH_TYPE_SCHANNEL || p->auth.a_u.schannel_auth == NULL) {
+                                       return NT_STATUS_INVALID_HANDLE;
+                               }
+                               memcpy(pipe_session_key, p->auth.a_u.schannel_auth->sess_key, 16);
+                       }
+                       SamOEMhash(user_session_key, pipe_session_key, 16);
+                       memset(pipe_session_key, '\0', 16);
                }
                if (server_info->lm_session_key.length) {
                        memcpy(lm_session_key,
                               server_info->lm_session_key.data, 
                               MIN(sizeof(lm_session_key),
                                   server_info->lm_session_key.length));
-                       SamOEMhash(lm_session_key, netlogon_sess_key, 16);
+                       if (process_creds) {
+                               /* Get the pipe session key from the creds. */
+                               memcpy(pipe_session_key, p->dc->sess_key, 16);
+                       } else {
+                               /* Get the pipe session key from the schannel. */
+                               if (p->auth.auth_type != PIPE_AUTH_TYPE_SCHANNEL || p->auth.a_u.schannel_auth == NULL) {
+                                       return NT_STATUS_INVALID_HANDLE;
+                               }
+                               memcpy(pipe_session_key, p->auth.a_u.schannel_auth->sess_key, 16);
+                       }
+                       SamOEMhash(lm_session_key, pipe_session_key, 16);
+                       memset(pipe_session_key, '\0', 16);
                }
-               ZERO_STRUCT(netlogon_sess_key);
                
                init_net_user_info3(p->mem_ctx, usr_info, 
                                    user_rid,
@@ -888,12 +1016,12 @@ NTSTATUS _net_sam_logon(pipes_struct *p, NET_Q_SAM_LOGON *q_u, NET_R_SAM_LOGON *
                                    pdb_get_pass_last_set_time(sampw),
                                    pdb_get_pass_can_change_time(sampw),
                                    pdb_get_pass_must_change_time(sampw),
-                                   
                                    0, /* logon_count */
                                    0, /* bad_pw_count */
                                    num_gids,    /* uint32 num_groups */
                                    gids    , /* DOM_GID *gids */
-                                   0x20    , /* uint32 user_flgs (?) */
+                                   LOGON_EXTRA_SIDS, /* uint32 user_flgs (?) */
+                                   pdb_get_acct_ctrl(sampw),
                                    server_info->user_session_key.length ? user_session_key : NULL,
                                    server_info->lm_session_key.length ? lm_session_key : NULL,
                                    my_name     , /* char *logon_srv */
@@ -902,10 +1030,60 @@ NTSTATUS _net_sam_logon(pipes_struct *p, NET_Q_SAM_LOGON *q_u, NET_R_SAM_LOGON *
                ZERO_STRUCT(user_session_key);
                ZERO_STRUCT(lm_session_key);
        }
-       talloc_free(server_info);
+       TALLOC_FREE(server_info);
        return status;
 }
 
+/*************************************************************************
+ _net_sam_logon
+ *************************************************************************/
+
+NTSTATUS _net_sam_logon(pipes_struct *p, NET_Q_SAM_LOGON *q_u, NET_R_SAM_LOGON *r_u)
+{
+       return _net_sam_logon_internal(p, q_u, r_u, True);
+}
+/*************************************************************************
+ _net_sam_logon_ex - no credential chaining. Map into net sam logon.
+ *************************************************************************/
+
+NTSTATUS _net_sam_logon_ex(pipes_struct *p, NET_Q_SAM_LOGON_EX *q_u, NET_R_SAM_LOGON_EX *r_u)
+{
+       NET_Q_SAM_LOGON q;
+       NET_R_SAM_LOGON r;
+
+       ZERO_STRUCT(q);
+       ZERO_STRUCT(r);
+
+       /* Only allow this if the pipe is protected. */
+       if (p->auth.auth_type != PIPE_AUTH_TYPE_SCHANNEL) {
+               DEBUG(0,("_net_sam_logon_ex: client %s not using schannel for netlogon\n",
+                       get_remote_machine_name() ));
+               return NT_STATUS_INVALID_PARAMETER;
+        }
+
+       /* Map a NET_Q_SAM_LOGON_EX to NET_Q_SAM_LOGON. */
+       q.validation_level = q_u->validation_level;
+
+       /* Map a DOM_SAM_INFO_EX into a DOM_SAM_INFO with no creds. */
+       q.sam_id.client.login = q_u->sam_id.client;
+       q.sam_id.logon_level = q_u->sam_id.logon_level;
+       q.sam_id.ctr = q_u->sam_id.ctr;
+
+       r_u->status = _net_sam_logon_internal(p, &q, &r, False);
+
+       if (!NT_STATUS_IS_OK(r_u->status)) {
+               return r_u->status;
+       }
+
+       /* Map the NET_R_SAM_LOGON to NET_R_SAM_LOGON_EX. */
+       r_u->switch_value = r.switch_value;
+       r_u->user = r.user;
+       r_u->auth_resp = r.auth_resp;
+       r_u->flags = 0; /* FIXME ! */
+       return r_u->status;
+}
+
 /*************************************************************************
  _ds_enum_dom_trusts
  *************************************************************************/