Kill of Get_Pwnam_Modify and smb_getpwnam(). The latter assumes some things
[kai/samba.git] / source3 / smbd / sesssetup.c
index 66eb6a2d92b9e89e954fcda9117fb341589f8a06..785f8d6821141307eb88c482e0f143939485d1c3 100644 (file)
@@ -3,6 +3,7 @@
    handle SMBsessionsetup
    Copyright (C) Andrew Tridgell 1998-2001
    Copyright (C) Andrew Bartlett      2001
+   Copyright (C) Jim McDonough        2002
 
    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
@@ -122,6 +123,12 @@ static int reply_spnego_kerberos(connection_struct *conn,
 
        ads = ads_init_simple();
 
+       if (!ads) {
+               return ERROR_NT(NT_STATUS_LOGON_FAILURE);
+       }
+
+       ads->auth.realm = strdup(lp_realm());
+
        ret = ads_verify_ticket(ads, &ticket, &client, &auth_data);
        if (!NT_STATUS_IS_OK(ret)) {
                DEBUG(1,("Failed to verify incoming ticket!\n"));       
@@ -139,7 +146,7 @@ static int reply_spnego_kerberos(connection_struct *conn,
        }
 
        *p = 0;
-       if (strcasecmp(p+1, ads->realm) != 0) {
+       if (strcasecmp(p+1, ads->auth.realm) != 0) {
                DEBUG(3,("Ticket for foreign realm %s@%s\n", client, p+1));
                if (!lp_allow_trusted_domains()) {
                        return ERROR_NT(NT_STATUS_LOGON_FAILURE);
@@ -153,12 +160,12 @@ static int reply_spnego_kerberos(connection_struct *conn,
        ads_destroy(&ads);
 
        /* the password is good - let them in */
-       pw = smb_getpwnam(user,False);
+       pw = Get_Pwnam(user);
        if (!pw && !strstr(user, lp_winbind_separator())) {
                char *user2;
                /* try it with a winbind domain prefix */
                asprintf(&user2, "%s%s%s", lp_workgroup(), lp_winbind_separator(), user);
-               pw = smb_getpwnam(user2,False);
+               pw = Get_Pwnam(user2);
                if (pw) {
                        free(user);
                        user = user2;
@@ -170,9 +177,9 @@ static int reply_spnego_kerberos(connection_struct *conn,
                return ERROR_NT(NT_STATUS_NO_SUCH_USER);
        }
 
-       if (!make_server_info_pw(&server_info,pw)) {
+       if (!NT_STATUS_IS_OK(ret = make_server_info_pw(&server_info,pw))) {
                DEBUG(1,("make_server_info_from_pw failed!\n"));
-               return ERROR_NT(NT_STATUS_NO_MEMORY);
+               return ERROR_NT(ret);
        }
        
        sess_vuid = register_vuid(server_info, user);
@@ -200,7 +207,7 @@ static int reply_spnego_kerberos(connection_struct *conn,
 send a security blob via a session setup reply
 ****************************************************************************/
 static BOOL reply_sesssetup_blob(connection_struct *conn, char *outbuf,
-                                DATA_BLOB blob)
+                                DATA_BLOB blob, uint32 errcode)
 {
        char *p;
 
@@ -209,7 +216,7 @@ static BOOL reply_sesssetup_blob(connection_struct *conn, char *outbuf,
        /* we set NT_STATUS_MORE_PROCESSING_REQUIRED to tell the other end
           that we aren't finished yet */
 
-       SIVAL(outbuf, smb_rcls, NT_STATUS_V(NT_STATUS_MORE_PROCESSING_REQUIRED));
+       SIVAL(outbuf, smb_rcls, errcode);
        SSVAL(outbuf, smb_vwv0, 0xFF); /* no chaining possible */
        SSVAL(outbuf, smb_vwv3, blob.length);
        p = smb_buf(outbuf);
@@ -235,11 +242,13 @@ static int reply_spnego_negotiate(connection_struct *conn,
        char *OIDs[ASN1_MAX_OIDS];
        DATA_BLOB secblob;
        int i;
-       uint32 ntlmssp_command, neg_flags;
-       DATA_BLOB sess_key, chal, spnego_chal;
+       uint32 ntlmssp_command, neg_flags, chal_flags;
+       DATA_BLOB chal, spnego_chal;
        const uint8 *cryptkey;
        BOOL got_kerberos = False;
        NTSTATUS nt_status;
+       extern pstring global_myname;
+       char *cliname=NULL, *domname=NULL;
 
        /* parse out the OIDs and the first sec blob */
        if (!parse_negTokenTarg(blob1, OIDs, &secblob)) {
@@ -257,7 +266,7 @@ static int reply_spnego_negotiate(connection_struct *conn,
        DEBUG(3,("Got secblob of size %d\n", secblob.length));
 
 #ifdef HAVE_KRB5
-       if (got_kerberos) {
+       if (got_kerberos && (SEC_ADS == lp_security())) {
                int ret = reply_spnego_kerberos(conn, inbuf, outbuf, 
                                                length, bufsize, &secblob);
                data_blob_free(&secblob);
@@ -270,22 +279,22 @@ static int reply_spnego_negotiate(connection_struct *conn,
        file_save("secblob.dat", secblob.data, secblob.length);
 #endif
 
-       if (!msrpc_parse(&secblob, "CddB",
+       if (!msrpc_parse(&secblob, "CddAA",
                         "NTLMSSP",
                         &ntlmssp_command,
                         &neg_flags,
-                        &sess_key)) {
+                        &cliname,
+                        &domname)) {
                return ERROR_NT(NT_STATUS_LOGON_FAILURE);
        }
-
+       
        data_blob_free(&secblob);
-       data_blob_free(&sess_key);
 
        if (ntlmssp_command != NTLMSSP_NEGOTIATE) {
                return ERROR_NT(NT_STATUS_LOGON_FAILURE);
        }
 
-       DEBUG(3,("Got neg_flags=%08x\n", neg_flags));
+       debug_ntlmssp_flags(neg_flags);
 
        if (ntlmssp_auth_context) {
                (ntlmssp_auth_context->free)(&ntlmssp_auth_context);
@@ -300,27 +309,55 @@ static int reply_spnego_negotiate(connection_struct *conn,
        /* Give them the challenge. For now, ignore neg_flags and just
           return the flags we want. Obviously this is not correct */
        
-       neg_flags = NTLMSSP_NEGOTIATE_UNICODE | 
-               NTLMSSP_NEGOTIATE_LM_KEY | 
-               NTLMSSP_NEGOTIATE_NTLM;
-
-       msrpc_gen(&chal, "Cddddbdddd",
-                 "NTLMSSP", 
-                 NTLMSSP_CHALLENGE,
-                 0,
-                 0x30, /* ?? */
-                 neg_flags,
-                 cryptkey, 8,
-                 0, 0, 0,
-                 0x3000); /* ?? */
+       chal_flags = NTLMSSP_NEGOTIATE_UNICODE | 
+               NTLMSSP_NEGOTIATE_128 | 
+               NTLMSSP_NEGOTIATE_NTLM |
+               NTLMSSP_CHAL_TARGET_INFO;
+       
+       {
+               DATA_BLOB domain_blob, struct_blob;
+               fstring dnsname, dnsdomname;
+               
+               msrpc_gen(&domain_blob, 
+                         "U",
+                         lp_workgroup());
+
+               fstrcpy(dnsdomname, lp_realm());
+               strlower(dnsdomname);
+
+               fstrcpy(dnsname, global_myname);
+               fstrcat(dnsname, ".");
+               fstrcat(dnsname, lp_realm());
+               strlower(dnsname);
+
+               msrpc_gen(&struct_blob, "aaaaa",
+                         2, lp_workgroup(),
+                         1, global_myname,
+                         4, dnsdomname,
+                         3, dnsname,
+                         0, "");
+
+               msrpc_gen(&chal, "CdUdbddB",
+                         "NTLMSSP", 
+                         NTLMSSP_CHALLENGE,
+                         lp_workgroup(),
+                         chal_flags,
+                         cryptkey, 8,
+                         0, 0,
+                         struct_blob.data, struct_blob.length);
+
+               data_blob_free(&domain_blob);
+               data_blob_free(&struct_blob);
+       }
 
        if (!spnego_gen_challenge(&spnego_chal, &chal, &chal)) {
                DEBUG(3,("Failed to generate challenge\n"));
+               data_blob_free(&chal);
                return ERROR_NT(NT_STATUS_LOGON_FAILURE);
        }
 
        /* now tell the client to send the auth packet */
-       reply_sesssetup_blob(conn, outbuf, spnego_chal);
+       reply_sesssetup_blob(conn, outbuf, spnego_chal, NT_STATUS_V(NT_STATUS_MORE_PROCESSING_REQUIRED));
 
        data_blob_free(&chal);
        data_blob_free(&spnego_chal);
@@ -337,7 +374,7 @@ static int reply_spnego_auth(connection_struct *conn, char *inbuf, char *outbuf,
                             int length, int bufsize,
                             DATA_BLOB blob1)
 {
-       DATA_BLOB auth;
+       DATA_BLOB auth, response;
        char *workgroup = NULL, *user = NULL, *machine = NULL;
        DATA_BLOB lmhash, nthash, sess_key;
        DATA_BLOB plaintext_password = data_blob(NULL, 0);
@@ -382,6 +419,13 @@ static int reply_spnego_auth(connection_struct *conn, char *inbuf, char *outbuf,
        DEBUG(3,("Got user=[%s] workgroup=[%s] machine=[%s] len1=%d len2=%d\n",
                 user, workgroup, machine, lmhash.length, nthash.length));
 
+       /* the client has given us its machine name (which we otherwise would not get on port 445).
+          we need to possibly reload smb.conf if smb.conf includes depend on the machine name */
+
+       set_remote_machine_name(machine);
+
+       reload_services(True);
+
 #if 0
        file_save("nthash1.dat", nthash.data, nthash.length);
        file_save("lmhash1.dat", lmhash.data, lmhash.length);
@@ -395,14 +439,14 @@ static int reply_spnego_auth(connection_struct *conn, char *inbuf, char *outbuf,
                auth_flags |= AUTH_FLAG_NTLM_RESP;
        } else if (nthash.length > 24) {
                auth_flags |= AUTH_FLAG_NTLMv2_RESP;
-       }
+       };
+
+       nt_status = make_user_info_map(&user_info, user, workgroup, machine, 
+                                      lmhash, nthash, plaintext_password, 
+                                      auth_flags, True);
 
-       if (!make_user_info_map(&user_info, 
-                               user, workgroup, 
-                               machine, 
-                               lmhash, nthash,
-                               plaintext_password, 
-                               auth_flags, True)) {
+       /* it looks a bit weird, but this function returns int type... */
+       if (!NT_STATUS_IS_OK(nt_status)) {
                return ERROR_NT(NT_STATUS_NO_MEMORY);
        }
 
@@ -450,8 +494,12 @@ static int reply_spnego_auth(connection_struct *conn, char *inbuf, char *outbuf,
  
        SSVAL(outbuf,smb_uid,sess_vuid);
        SSVAL(inbuf,smb_uid,sess_vuid);
-       
-       return chain_reply(inbuf,outbuf,length,bufsize);
+
+        response = spnego_gen_auth_response();
+       reply_sesssetup_blob(conn, outbuf, response, 0);
+
+       /* and tell smbd that we have already replied to this packet */
+       return -1;
 }
 
 
@@ -563,7 +611,6 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,
        extern BOOL global_encrypted_passwords_negotiated;
        extern BOOL global_spnego_negotiated;
        extern int Protocol;
-       extern fstring remote_machine;
        extern userdom_struct current_user_info;
        extern int max_send;
 
@@ -574,7 +621,7 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,
        NTSTATUS nt_status;
 
        BOOL doencrypt = global_encrypted_passwords_negotiated;
-
+       
        START_PROFILE(SMBsesssetupX);
 
        ZERO_STRUCT(lm_resp);
@@ -599,8 +646,8 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,
 
        if (Protocol < PROTOCOL_NT1) {
                uint16 passlen1 = SVAL(inbuf,smb_vwv7);
-               if (passlen1 > MAX_PASS_LEN) {
-                       return ERROR_DOS(ERRDOS,ERRbuftoosmall);
+               if ((passlen1 > MAX_PASS_LEN) || (passlen1 > smb_bufrem(inbuf, smb_buf(inbuf)))) {
+                       return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
                }
 
                if (doencrypt) {
@@ -634,13 +681,6 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,
                        }
                }
                
-               if (passlen1 > MAX_PASS_LEN) {
-                       return ERROR_DOS(ERRDOS,ERRbuftoosmall);
-               }
-
-               passlen1 = MIN(passlen1, MAX_PASS_LEN);
-               passlen2 = MIN(passlen2, MAX_PASS_LEN);
-
                if (!doencrypt) {
                        /* both Win95 and WinNT stuff up the password lengths for
                           non-encrypting systems. Uggh. 
@@ -658,19 +698,29 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,
                                passlen2 = 0;
                }
                
+               /* check for nasty tricks */
+               if (passlen1 > MAX_PASS_LEN || passlen1 > smb_bufrem(inbuf, p)) {
+                       return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+               }
+
+               if (passlen2 > MAX_PASS_LEN || passlen2 > smb_bufrem(inbuf, p+passlen1)) {
+                       return ERROR_NT(NT_STATUS_INVALID_PARAMETER);
+               }
+
                /* Save the lanman2 password and the NT md4 password. */
                
                if ((doencrypt) && (passlen1 != 0) && (passlen1 != 24)) {
                        doencrypt = False;
                }
-               
+
                if (doencrypt) {
                        lm_resp = data_blob(p, passlen1);
                        nt_resp = data_blob(p+passlen1, passlen2);
                } else {
-                       plaintext_password = data_blob(p, passlen1+1);
-                       /* Ensure null termination */
-                       plaintext_password.data[passlen1] = 0;
+                       pstring pass;
+                       srvstr_pull(inbuf, pass, smb_buf(inbuf), 
+                                   sizeof(pass),  passlen1, STR_TERMINATE);
+                       plaintext_password = data_blob(pass, strlen(pass)+1);
                }
                
                p += passlen1 + passlen2;
@@ -684,12 +734,12 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,
        
        /* don't allow for weird usernames or domains */
        alpha_strcpy(user, user, ". _-$", sizeof(user));
-       alpha_strcpy(domain, domain, ". _-", sizeof(domain));
+       alpha_strcpy(domain, domain, ". _-@", sizeof(domain));
        if (strstr(user, "..") || strstr(domain,"..")) {
                return ERROR_NT(NT_STATUS_LOGON_FAILURE);
        }
 
-       DEBUG(3,("sesssetupX:name=[%s]\\[%s]@[%s]\n", domain, user, remote_machine));
+       DEBUG(3,("sesssetupX:name=[%s]\\[%s]@[%s]\n", domain, user, get_remote_machine_name()));
 
        if (*user) {
                if (global_spnego_negotiated) {
@@ -726,11 +776,9 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,
                nt_status = check_guest_password(&server_info);
 
        } else if (doencrypt) {
-               if (!make_user_info_for_reply_enc(&user_info, 
-                                                 user, domain, 
-                                                 lm_resp, nt_resp)) {
-                       nt_status = NT_STATUS_NO_MEMORY;
-               } else {
+               nt_status = make_user_info_for_reply_enc(&user_info, user, domain,
+                                                        lm_resp, nt_resp);
+               if (NT_STATUS_IS_OK(nt_status)) {
                        nt_status = negprot_global_auth_context->check_ntlm_password(negprot_global_auth_context, 
                                                                                     user_info, 
                                                                                     &server_info);