r2388: fix client quota support
[ira/wip.git] / source3 / smbd / sesssetup.c
index e9cfa47d0c635692c4db2bbef161cc5474ae51df..0122b662ebfabb7f0ed223b6919f879652ab5157 100644 (file)
@@ -141,18 +141,19 @@ static int reply_spnego_kerberos(connection_struct *conn,
                                 DATA_BLOB *secblob)
 {
        DATA_BLOB ticket;
-       char *client, *p;
-       const struct passwd *pw;
+       char *client, *p, *domain;
+       fstring netbios_domain_name;
+       struct passwd *pw;
        char *user;
        int sess_vuid;
        NTSTATUS ret;
        DATA_BLOB auth_data;
        DATA_BLOB ap_rep, ap_rep_wrapped, response;
        auth_serversupplied_info *server_info = NULL;
-       DATA_BLOB session_key;
+       DATA_BLOB session_key = data_blob(NULL, 0);
        uint8 tok_id[2];
-       BOOL foreign = False;
        DATA_BLOB nullblob = data_blob(NULL, 0);
+       fstring real_username;
 
        ZERO_STRUCT(ticket);
        ZERO_STRUCT(auth_data);
@@ -181,6 +182,7 @@ static int reply_spnego_kerberos(connection_struct *conn,
        if (!p) {
                DEBUG(3,("Doesn't look like a valid principal\n"));
                data_blob_free(&ap_rep);
+               data_blob_free(&session_key);
                SAFE_FREE(client);
                return ERROR_NT(NT_STATUS_LOGON_FAILURE);
        }
@@ -190,47 +192,105 @@ static int reply_spnego_kerberos(connection_struct *conn,
                DEBUG(3,("Ticket for foreign realm %s@%s\n", client, p+1));
                if (!lp_allow_trusted_domains()) {
                        data_blob_free(&ap_rep);
+                       data_blob_free(&session_key);
                        SAFE_FREE(client);
                        return ERROR_NT(NT_STATUS_LOGON_FAILURE);
                }
-               foreign = True;
        }
 
        /* this gives a fully qualified user name (ie. with full realm).
           that leads to very long usernames, but what else can we do? */
-          
-       asprintf(&user, "%s%c%s", p+1, *lp_winbind_separator(), client);
-       
-       pw = smb_getpwnam( user );
+
+       domain = p+1;
+
+       {
+               /* If we have winbind running, we can (and must) shorten the
+                  username by using the short netbios name. Otherwise we will
+                  have inconsistent user names. With Kerberos, we get the
+                  fully qualified realm, with ntlmssp we get the short
+                  name. And even w2k3 does use ntlmssp if you for example
+                  connect to an ip address. */
+
+               struct winbindd_request wb_request;
+               struct winbindd_response wb_response;
+               NSS_STATUS wb_result;
+
+               ZERO_STRUCT(wb_request);
+               ZERO_STRUCT(wb_response);
+
+               DEBUG(10, ("Mapping [%s] to short name\n", domain));
+
+               fstrcpy(wb_request.domain_name, domain);
+
+               wb_result = winbindd_request(WINBINDD_DOMAIN_INFO,
+                                            &wb_request, &wb_response);
+
+               if (wb_result == NSS_STATUS_SUCCESS) {
+
+                       fstrcpy(netbios_domain_name,
+                               wb_response.data.domain_info.name);
+                       domain = netbios_domain_name;
+
+                       DEBUG(10, ("Mapped to [%s]\n", domain));
+               } else {
+                       DEBUG(3, ("Could not find short name -- winbind "
+                                 "not running?\n"));
+               }
+       }
+
+       asprintf(&user, "%s%c%s", domain, *lp_winbind_separator(), client);
        
-       SAFE_FREE(user);
-       SAFE_FREE(client);
+       /* lookup the passwd struct, create a new user if necessary */
+
+       map_username( user );
 
+       pw = smb_getpwnam( user, real_username, True );
+       
        if (!pw) {
                DEBUG(1,("Username %s is invalid on this system\n",user));
+               SAFE_FREE(user);
+               SAFE_FREE(client);
                data_blob_free(&ap_rep);
+               data_blob_free(&session_key);
                return ERROR_NT(NT_STATUS_LOGON_FAILURE);
        }
 
        /* setup the string used by %U */
        
-       sub_set_smb_name(pw->pw_name);
+       sub_set_smb_name( real_username );
        reload_services(True);
        
-       if (!NT_STATUS_IS_OK(ret = make_server_info_pw(&server_info,pw))) {
+       if (!NT_STATUS_IS_OK(ret = make_server_info_pw(&server_info, real_username, pw))) 
+       {
                DEBUG(1,("make_server_info_from_pw failed!\n"));
+               SAFE_FREE(user);
+               SAFE_FREE(client);
                data_blob_free(&ap_rep);
+               data_blob_free(&session_key);
                return ERROR_NT(ret);
        }
 
+        /* make_server_info_pw does not set the domain. Without this we end up
+        * with the local netbios name in substitutions for %D. */
+
+        if (server_info->sam_account != NULL) {
+                pdb_set_domain(server_info->sam_account, domain, PDB_SET);
+        }
+
        /* register_vuid keeps the server info */
-       sess_vuid = register_vuid(server_info, session_key, nullblob, user);
+       /* register_vuid takes ownership of session_key, no need to free after this.
+          A better interface would copy it.... */
+       sess_vuid = register_vuid(server_info, session_key, nullblob, client);
 
-       free(user);
+       SAFE_FREE(user);
+       SAFE_FREE(client);
 
        if (sess_vuid == -1) {
                ret = NT_STATUS_LOGON_FAILURE;
        } else {
+               /* current_user_info is changed on new vuid */
+               reload_services( True );
+
                set_message(outbuf,4,0,True);
                SSVAL(outbuf, smb_vwv3, 0);
                        
@@ -240,14 +300,14 @@ static int reply_spnego_kerberos(connection_struct *conn,
                
                SSVAL(outbuf, smb_uid, sess_vuid);
 
-               if (!server_info->guest) {
+               if (!server_info->guest && !srv_signing_started()) {
                        /* We need to start the signing engine
                         * here but a W2K client sends the old
                         * "BSRSPYL " signature instead of the
                         * correct one. Subsequent packets will
                         * be correct.
                         */
-                       srv_check_sign_mac(inbuf);
+                       srv_check_sign_mac(inbuf, False);
                }
        }
 
@@ -304,6 +364,9 @@ static BOOL reply_spnego_ntlmssp(connection_struct *conn, char *inbuf, char *out
                        nt_status = NT_STATUS_LOGON_FAILURE;
                } else {
                        
+                       /* current_user_info is changed on new vuid */
+                       reload_services( True );
+
                        set_message(outbuf,4,0,True);
                        SSVAL(outbuf, smb_vwv3, 0);
                        
@@ -313,14 +376,15 @@ static BOOL reply_spnego_ntlmssp(connection_struct *conn, char *inbuf, char *out
                        
                        SSVAL(outbuf,smb_uid,sess_vuid);
 
-                       if (!server_info->guest) {
+                       if (!server_info->guest && !srv_signing_started()) {
                                /* We need to start the signing engine
                                 * here but a W2K client sends the old
                                 * "BSRSPYL " signature instead of the
                                 * correct one. Subsequent packets will
                                 * be correct.
                                 */
-                               srv_check_sign_mac(inbuf);
+
+                               srv_check_sign_mac(inbuf, False);
                        }
                }
        }
@@ -823,15 +887,12 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,
                return ERROR_NT(nt_status_squash(nt_status));
        }
 
-       if (server_info->nt_session_key.data) {
-               session_key = data_blob(server_info->nt_session_key.data, server_info->nt_session_key.length);
-       } else if (server_info->lm_session_key.length >= 8 && lm_resp.length == 24) {
-               session_key = data_blob(NULL, 16);
-               SMBsesskeygen_lmv1(server_info->lm_session_key.data, lm_resp.data, 
-                                  session_key.data);
+       if (server_info->user_session_key.data) {
+               session_key = data_blob(server_info->user_session_key.data, server_info->user_session_key.length);
+       } else {
+               session_key = data_blob(NULL, 0);
        }
 
-       data_blob_free(&lm_resp);
        data_blob_clear_free(&plaintext_password);
        
        /* it's ok - setup a reply */
@@ -851,14 +912,18 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,
           to a uid can get through without a password, on the same VC */
 
        /* register_vuid keeps the server info */
-       sess_vuid = register_vuid(server_info, session_key, nt_resp, sub_user);
+       sess_vuid = register_vuid(server_info, session_key, nt_resp.data ? nt_resp : lm_resp, sub_user);
        data_blob_free(&nt_resp);
+       data_blob_free(&lm_resp);
 
        if (sess_vuid == -1) {
                return ERROR_NT(NT_STATUS_LOGON_FAILURE);
        }
 
-       if (!server_info->guest && !srv_check_sign_mac(inbuf)) {
+       /* current_user_info is changed on new vuid */
+       reload_services( True );
+
+       if (!server_info->guest && !srv_signing_started() && !srv_check_sign_mac(inbuf, True)) {
                exit_server("reply_sesssetup_and_X: bad smb signature");
        }