From 2e70035f87ebcdfbdc3cf8d05cd89d4eeeebc16c Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Tue, 2 Dec 2003 02:15:33 +0000 Subject: another big improvement in the credentials API. I think it now actually makes sense, and as a nice side effect it matches the debug output of the w2k3 netlogon.log (This used to be commit 3c7287c24e5970e5b7447ad042848505537c7d3b) --- source4/libcli/auth/credentials.c | 111 +++++++++------ source4/librpc/idl/netlogon.idl | 285 ++++++++++++++++++++++++++------------ source4/torture/rpc/netlogon.c | 32 +++-- 3 files changed, 285 insertions(+), 143 deletions(-) diff --git a/source4/libcli/auth/credentials.c b/source4/libcli/auth/credentials.c index 1749037e8f..5814053d5f 100644 --- a/source4/libcli/auth/credentials.c +++ b/source4/libcli/auth/credentials.c @@ -28,11 +28,10 @@ this call is made after the netr_ServerReqChallenge call */ -void creds_init(struct netr_CredentialState *creds, - const struct netr_Credential *client_challenge, - const struct netr_Credential *server_challenge, - const uint8 machine_password[16], - struct netr_Credential *initial_creds) +static void creds_init(struct netr_CredentialState *creds, + const struct netr_Credential *client_challenge, + const struct netr_Credential *server_challenge, + const uint8 machine_password[16]) { struct netr_Credential time_cred; uint32 sum[2]; @@ -46,36 +45,82 @@ void creds_init(struct netr_CredentialState *creds, cred_hash1(creds->session_key, sum2, machine_password); - creds->sequence = 0; + creds->sequence = time(NULL); SIVAL(time_cred.data, 0, IVAL(client_challenge->data, 0)); SIVAL(time_cred.data, 4, IVAL(client_challenge->data, 4)); + cred_hash2(creds->client.data, time_cred.data, creds->session_key); - cred_hash2(creds->cred2.data, time_cred.data, creds->session_key); + SIVAL(time_cred.data, 0, IVAL(server_challenge->data, 0)); + SIVAL(time_cred.data, 4, IVAL(server_challenge->data, 4)); + cred_hash2(creds->server.data, time_cred.data, creds->session_key); - creds->cred1 = *server_challenge; + creds->seed = creds->client; +} + + +/* + step the credentials to the next element in the chain +*/ +static void creds_step(struct netr_CredentialState *creds) +{ + struct netr_Credential time_cred; + + creds->sequence += 2; + + DEBUG(5,("\tseed %08x:%08x\n", + IVAL(creds->seed.data, 0), IVAL(creds->seed.data, 4))); + + SIVAL(time_cred.data, 0, IVAL(creds->seed.data, 0) + creds->sequence); + SIVAL(time_cred.data, 4, IVAL(creds->seed.data, 4)); + + DEBUG(5,("\tseed+time %08x:%08x\n", IVAL(time_cred.data, 0), IVAL(time_cred.data, 4))); + + cred_hash2(creds->client.data, time_cred.data, creds->session_key); + + DEBUG(5,("\tCLIENT %08x:%08x\n", + IVAL(creds->client.data, 0), IVAL(creds->client.data, 4))); + + SIVAL(time_cred.data, 0, IVAL(creds->seed.data, 0) + creds->sequence + 1); + SIVAL(time_cred.data, 4, IVAL(creds->seed.data, 4)); + + DEBUG(5,("\tseed+time+1 %08x:%08x\n", + IVAL(time_cred.data, 0), IVAL(time_cred.data, 4))); + + cred_hash2(creds->server.data, time_cred.data, creds->session_key); - *initial_creds = creds->cred2; + DEBUG(5,("\tSERVER %08x:%08x\n", + IVAL(creds->server.data, 0), IVAL(creds->server.data, 4))); + + creds->seed = time_cred; } /* - check that a credentials reply is correct + initialise the credentials chain and return the first client + credentials */ -BOOL creds_check(struct netr_CredentialState *creds, - const struct netr_Credential *received_credentials) +void creds_client_init(struct netr_CredentialState *creds, + const struct netr_Credential *client_challenge, + const struct netr_Credential *server_challenge, + const uint8 machine_password[16], + struct netr_Credential *initial_credential) { - struct netr_Credential cred2, time_cred; - uint32 sequence = creds->sequence?creds->sequence+1:0; + creds_init(creds, client_challenge, server_challenge, machine_password); + + *initial_credential = creds->client; +} - SIVAL(time_cred.data, 0, IVAL(creds->cred1.data, 0) + sequence); - SIVAL(time_cred.data, 4, IVAL(creds->cred1.data, 4)); - cred_hash2(cred2.data, time_cred.data, creds->session_key); - if (memcmp(received_credentials->data, cred2.data, 8) != 0) { +/* + check that a credentials reply from a server is correct +*/ +BOOL creds_client_check(struct netr_CredentialState *creds, + const struct netr_Credential *received_credentials) +{ + if (memcmp(received_credentials->data, creds->server.data, 8) != 0) { DEBUG(2,("credentials check failed\n")); return False; } - return True; } @@ -83,30 +128,12 @@ BOOL creds_check(struct netr_CredentialState *creds, produce the next authenticator in the sequence ready to send to the server */ -void creds_authenticator(struct netr_CredentialState *creds, - struct netr_Authenticator *next) +void creds_client_authenticator(struct netr_CredentialState *creds, + struct netr_Authenticator *next) { - struct netr_Credential cred2; - struct netr_Credential time_cred; - - if (creds->sequence == 0) { - creds->sequence = time(NULL); - } - - /* this step size is quite arbitrary - the client can choose - any sequence number it likes */ - creds->sequence += 2; - - creds->cred1 = creds->cred2; - - SIVAL(time_cred.data, 0, IVAL(creds->cred2.data, 0) + creds->sequence); - SIVAL(time_cred.data, 4, IVAL(creds->cred2.data, 4)); - - cred_hash2(cred2.data, time_cred.data, creds->session_key); - - creds->cred2 = cred2; + creds_step(creds); - next->cred = creds->cred2; + next->cred = creds->client; next->timestamp = creds->sequence; } @@ -114,7 +141,7 @@ void creds_authenticator(struct netr_CredentialState *creds, /* encrypt a 16 byte password buffer using the session key */ -void creds_encrypt(struct netr_CredentialState *creds, struct netr_Password *pass) +void creds_client_encrypt(struct netr_CredentialState *creds, struct netr_Password *pass) { struct netr_Password tmp; cred_hash3(tmp.data, pass->data, creds->session_key, 1); diff --git a/source4/librpc/idl/netlogon.idl b/source4/librpc/idl/netlogon.idl index 6dd7ae3fe5..5d30b51157 100644 --- a/source4/librpc/idl/netlogon.idl +++ b/source4/librpc/idl/netlogon.idl @@ -71,8 +71,9 @@ interface netlogon typedef [flag(NDR_PAHEX)] struct { uint8 session_key[8]; uint32 sequence; - netr_Credential cred1; - netr_Credential cred2; + netr_Credential seed; + netr_Credential client; + netr_Credential server; } netr_CredentialState; typedef struct { @@ -229,6 +230,10 @@ interface netlogon [out] uint32 authoritative ); + + /*****************/ + /* Function 0x03 */ + NTSTATUS netr_LogonSamLogoff( [in] unistr *server_name, [in] unistr *computer_name, @@ -238,13 +243,22 @@ interface netlogon [in] [switch_is(logon_level)] netr_LogonLevel logon ); - WERROR netr_ServerReqChallenge( + + + /*****************/ + /* Function 0x04 */ + + NTSTATUS netr_ServerReqChallenge( [in] unistr *server_name, [in] unistr computer_name, [in][out] netr_Credential credentials ); - WERROR netr_ServerAuthenticate( + + /*****************/ + /* Function 0x05 */ + + NTSTATUS netr_ServerAuthenticate( [in] unistr *server_name, [in] unistr username, [in] uint16 secure_challenge_type, @@ -253,6 +267,9 @@ interface netlogon ); + /*****************/ + /* Function 0x06 */ + NTSTATUS netr_ServerPasswordSet( [in] unistr *server_name, [in] unistr username, @@ -264,22 +281,28 @@ interface netlogon ); #if 0 + + /*****************/ + /* Function 0x07 */ + typedef struct { unistr *username; - netr_String dummy1; - netr_String dummy2; - netr_String dummy3; - netr_String dummy4; - uint32 dummy5; - uint32 dummy6; - uint32 dummy7; - uint32 dummy8; + netr_String unknown1; + netr_String unknown2; + netr_String unknown3; + netr_String unknown4; + uint32 unknown5; + uint32 unknown6; + uint32 unknown7; + uint32 unknown8; } DELTA_DELETE_USER; + typedef struct { bool SensitiveDataFlag; uint32 DataLength; [size_is(DataLength)] uint8 *SensitiveData; } USER_PRIVATE_INFO; + typedef struct { netr_String username; netr_String FullName; @@ -310,15 +333,16 @@ interface netlogon USER_PRIVATE_INFO user_private_info; uint32 SecurityInformation; LSA_SECURITY_DESCRIPTOR sec_desc; - netr_String dummy1; - netr_String dummy2; - netr_String dummy3; - netr_String dummy4; - uint32 dummy5; - uint32 dummy6; - uint32 dummy7; - uint32 dummy8; + netr_String unknown1; + netr_String unknown2; + netr_String unknown3; + netr_String unknown4; + uint32 unknown5; + uint32 unknown6; + uint32 unknown7; + uint32 unknown8; } DELTA_USER; + typedef struct { netr_String DomainName; netr_String OEMInfo; @@ -331,72 +355,78 @@ interface netlogon NTTIME domain_create_time; uint32 SecurityInformation; LSA_SECURITY_DESCRIPTOR sec_desc; - netr_String dummy1; - netr_String dummy2; - netr_String dummy3; - netr_String dummy4; - uint32 dummy5; - uint32 dummy6; - uint32 dummy7; - uint32 dummy8; + netr_String unknown1; + netr_String unknown2; + netr_String unknown3; + netr_String unknown4; + uint32 unknown5; + uint32 unknown6; + uint32 unknown7; + uint32 unknown8; } DELTA_DOMAIN; + typedef struct { netr_String groupname; GROUP_MEMBERSHIP group_membership; netr_String comment; uint32 SecurityInformation; LSA_SECURITY_DESCRIPTOR sec_desc; - netr_String dummy1; - netr_String dummy2; - netr_String dummy3; - netr_String dummy4; - uint32 dummy5; - uint32 dummy6; - uint32 dummy7; - uint32 dummy8; + netr_String unknown1; + netr_String unknown2; + netr_String unknown3; + netr_String unknown4; + uint32 unknown5; + uint32 unknown6; + uint32 unknown7; + uint32 unknown8; } DELTA_GROUP; + typedef struct { netr_String OldName; netr_String NewName; - netr_String dummy1; - netr_String dummy2; - netr_String dummy3; - netr_String dummy4; - uint32 dummy5; - uint32 dummy6; - uint32 dummy7; - uint32 dummy8; + netr_String unknown1; + netr_String unknown2; + netr_String unknown3; + netr_String unknown4; + uint32 unknown5; + uint32 unknown6; + uint32 unknown7; + uint32 unknown8; } DELTA_RENAME; + typedef struct { [size_is(num_rids)] uint32 *rids; [size_is(num_rids)] uint32 *attribs; uint32 num_rids; - uint32 dummy1; - uint32 dummy2; - uint32 dummy3; - uint32 dummy4; + uint32 unknown1; + uint32 unknown2; + uint32 unknown3; + uint32 unknown4; } DELTA_GROUP_MEMBER; + typedef struct { netr_String alias_name; uint32 rid; uint32 SecurityInformation; LSA_SECURITY_DESCRIPTOR sec_desc; - netr_String dummy1; - netr_String dummy2; - netr_String dummy3; - netr_String dummy4; - uint32 dummy5; - uint32 dummy6; - uint32 dummy7; - uint32 dummy8; + netr_String unknown1; + netr_String unknown2; + netr_String unknown3; + netr_String unknown4; + uint32 unknown5; + uint32 unknown6; + uint32 unknown7; + uint32 unknown8; } DELTA_ALIAS; + typedef struct { SID_ARRAY sids; - uint32 dummy1; - uint32 dummy2; - uint32 dummy3; - uint32 dummy4; + uint32 unknown1; + uint32 unknown2; + uint32 unknown3; + uint32 unknown4; } DELTA_ALIAS_MEMBER; + typedef struct { uint32 pagedpoollimit; uint32 nonpagedpoollimit; @@ -405,6 +435,7 @@ interface netlogon uint32 pagefilelimit; NTTIME timelimit; } QUOTA_LIMITS; + typedef struct { uint32 maxlogsize; NTTIME auditretentionperiod; @@ -418,30 +449,32 @@ interface netlogon NTTIME db_create_time; uint32 SecurityInformation; LSA_SECURITY_DESCRIPTOR sec_desc; - netr_String dummy1; - netr_String dummy2; - netr_String dummy3; - netr_String dummy4; - uint32 dummy5; - uint32 dummy6; - uint32 dummy7; - uint32 dummy8; + netr_String unknown1; + netr_String unknown2; + netr_String unknown3; + netr_String unknown4; + uint32 unknown5; + uint32 unknown6; + uint32 unknown7; + uint32 unknown8; } DELTA_POLICY; + typedef struct { netr_String DomainName; uint32 num_controllers; [size_is(num_controllers)] netr_String *controller_names; uint32 SecurityInformation; LSA_SECURITY_DESCRIPTOR sec_desc; - netr_String dummy1; - netr_String dummy2; - netr_String dummy3; - netr_String dummy4; - uint32 dummy5; - uint32 dummy6; - uint32 dummy7; - uint32 dummy8; + netr_String unknown1; + netr_String unknown2; + netr_String unknown3; + netr_String unknown4; + uint32 unknown5; + uint32 unknown6; + uint32 unknown7; + uint32 unknown8; } DELTA_TRUSTED_DOMAINS; + typedef struct { uint32 privilegeentries; uint32 provolegecontrol; @@ -450,20 +483,22 @@ interface netlogon QUOTALIMITS quotalimits; uint32 SecurityInformation; LSA_SECURITY_DESCRIPTOR sec_desc; - netr_String dummy1; - netr_String dummy2; - netr_String dummy3; - netr_String dummy4; - uint32 dummy5; - uint32 dummy6; - uint32 dummy7; - uint32 dummy8; + netr_String unknown1; + netr_String unknown2; + netr_String unknown3; + netr_String unknown4; + uint32 unknown5; + uint32 unknown6; + uint32 unknown7; + uint32 unknown8; } DELTA_ACCOUNTS; + typedef struct { uint32 len; uint32 maxlen; [size_is(maxlen)][length_is(len)] uint8 *cipher_data; } CIPHER_VALUE; + typedef struct { CIPHER_VALUE current_cipher; NTTIME current_cipher_set_time; @@ -471,15 +506,16 @@ interface netlogon NTTIME old_cipher_set_time; uint32 SecurityInformation; LSA_SECURITY_DESCRIPTOR sec_desc; - netr_String dummy1; - netr_String dummy2; - netr_String dummy3; - netr_String dummy4; - uint32 dummy5; - uint32 dummy6; - uint32 dummy7; - uint32 dummy8; + netr_String unknown1; + netr_String unknown2; + netr_String unknown3; + netr_String unknown4; + uint32 unknown5; + uint32 unknown6; + uint32 unknown7; + uint32 unknown8; } DELTA_SECRET; + typedef struct { uint32 low_value; uint32 high_value; @@ -527,15 +563,19 @@ interface netlogon [case(20)] uint32 rid; [case(21)] uint32 rid; } DELTA_ID_UNION; + typedef struct { uint16 delta_type; DELTA_ID_UNION delta_id_union; DELTA_UNION delta_union; } DELTA_ENUM; + typedef struct { uint32 num_deltas; [size_is(num_deltas)] DELTA_ENUM *delta_enum; } DELTA_ENUM_ARRAY; + + WERROR netr_DatabaseDeltas( [in][string][ref] wchar_t *logonserver, # REF!!! [in][string][ref] wchar_t *computername, @@ -546,6 +586,11 @@ interface netlogon [in] uint32 preferredmaximumlength, [out] DELTA_ENUM_ARRAY *delta_enum_array ); + + + /*****************/ + /* Function 0x08 */ + WERROR netr_DatabaseSync( [in][string][ref] wchar_t *logonserver, # REF!!! [in][string][ref] wchar_t *computername, @@ -556,11 +601,17 @@ interface netlogon [in] uint32 preferredmaximumlength, [out] DELTA_ENUM_ARRAY *delta_enum_array ); + + + /*****************/ + /* Function 0x09 */ + typedef struct { uint8 computer_name[16]; uint32 timecreated; uint32 serial_number; } UAS_INFO_0; + WERROR netr_AccountDeltas( [in][string] wchar_t *logonserver, [in][string][ref] wchar_t *computername, @@ -574,6 +625,11 @@ interface netlogon [in][long] level, [in][long] buffersize, ); + + + /*****************/ + /* Function 0x0A */ + WERROR netr_AccountSync( [in][string] wchar_t *logonserver, [in][string][ref] wchar_t *computername, @@ -588,21 +644,29 @@ interface netlogon [in][long] buffersize, [in][out][ref] UAS_INFO_0 recordid, ); + + + /*****************/ + /* Function 0x0B */ + WERROR netr_GetDcName( [in] unistr logon_server, [in] unistr *domainname, [out]unistr *dcname, }; + typedef struct { uint32 flags; uint32 pdc_connection_status; } NETLOGON_INFO_1; + typedef struct { uint32 flags; uint32 pdc_connection_status; unistrtrusted_dc_name; uint32 tc_connection_status; } NETLOGON_INFO_2; + typedef struct { uint32 flags; uint32 logon_attempts; @@ -612,28 +676,45 @@ interface netlogon uint32 reserved; uint32 reserved; } NETLOGON_INFO_3; + typedef [switch_type(long)] union { [case(1)] NETLOGON_INFO_1 *i1; [case(2)] NETLOGON_INFO_2 *i2; [case(3)] NETLOGON_INFO_3 *i3; } CONTROL_QUERY_INFORMATION; + + + /*****************/ + /* Function 0x0C */ + WERROR netr_LogonControl( [in][string] wchar_t *logonserver, [in] uint32 function_code, [in] uint32 level, [out][ref] CONTROL_QUERY_INFORMATION ); + + + /*****************/ + /* Function 0x0D */ + WERROR netr_GetAnyDCName( [in] unistr *logon_server, [in] unistr *domainname, [out]unistr *dcname, }; + typedef [switch_type(long)] union { [case(5)] unistr *unknown; [case(6)] unistr *unknown; [case(0xfffe)] uint32 unknown; [case(7)] unistry*unknown; } CONTROL_DATA_INFORMATION; + + + /*****************/ + /* Function 0x0E */ + WERROR netr_LogonControl2( [in][string] wchar_t *logonserver, [in] uint32 function_code, @@ -641,6 +722,11 @@ interface netlogon [in][ref] CONTROL_DATA_INFORMATION *data, [out][ref] CONTROL_QUERY_INFORMATION *query ); + + + /*****************/ + /* Function 0x0F */ + WERROR netr_ServerAuthenticate2( [in][string] wchar_t *logonserver, [in] unistr username, @@ -650,6 +736,11 @@ interface netlogon [out][ref] CREDENTIAL *server_chal, [in][out][ref] uint32 *negotiate_flags, ); + + + /*****************/ + /* Function 0x10 */ + WERROR netr_DatabaseSync2( [in][string][ref] wchar_t *logonserver, # REF!!! [in][string][ref] wchar_t *computername, @@ -661,6 +752,11 @@ interface netlogon [in] uint32 preferredmaximumlength, [out] DELTA_ENUM_ARRAY *delta_enum_array ); + + + /*****************/ + /* Function 0x11 */ + WERROR netr_DatabaseRedo( [in][string][ref] wchar_t *logonserver, # REF!!! [in][string][ref] wchar_t *computername, @@ -670,6 +766,11 @@ interface netlogon [in] uint32 change_log_entry_size, [out] DELTA_ENUM_ARRAY *delta_enum_array ); + + + /*****************/ + /* Function 0x12 */ + WERROR netr_LogonControl2Ex( [in][string] wchar_t *logonserver, [in] uint32 function_code, diff --git a/source4/torture/rpc/netlogon.c b/source4/torture/rpc/netlogon.c index bef658e92f..354a516884 100644 --- a/source4/torture/rpc/netlogon.c +++ b/source4/torture/rpc/netlogon.c @@ -94,8 +94,8 @@ static BOOL test_SetupCredentials(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, E_md4hash(plain_pass, mach_pwd); - creds_init(creds, &r.in.credentials, &r.out.credentials, mach_pwd, - &a.in.credentials); + creds_client_init(creds, &r.in.credentials, &r.out.credentials, mach_pwd, + &a.in.credentials); a.in.server_name = NULL; a.in.username = talloc_asprintf(mem_ctx, "%s$", lp_netbios_name()); @@ -110,7 +110,7 @@ static BOOL test_SetupCredentials(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx, return False; } - if (!creds_check(creds, &a.out.credentials)) { + if (!creds_client_check(creds, &a.out.credentials)) { printf("Credential chaining failed\n"); return False; } @@ -152,7 +152,7 @@ static BOOL test_SamLogon(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx) ZERO_STRUCT(auth2); - creds_authenticator(&creds, &auth); + creds_client_authenticator(&creds, &auth); r.in.server_name = talloc_asprintf(mem_ctx, "\\\\%s", dcerpc_server_name(p)); r.in.workstation = lp_netbios_name(); @@ -170,7 +170,7 @@ static BOOL test_SamLogon(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx) return False; } - if (!creds_check(&creds, &r.out.authenticator->cred)) { + if (!creds_client_check(&creds, &r.out.authenticator->cred)) { printf("Credential chaining failed\n"); } @@ -192,8 +192,6 @@ static BOOL test_SetPassword(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx) return False; } - creds_authenticator(&creds, &r.in.credential); - r.in.server_name = talloc_asprintf(mem_ctx, "\\\\%s", dcerpc_server_name(p)); r.in.username = talloc_asprintf(mem_ctx, "%s$", lp_netbios_name()); r.in.secure_challenge_type = 2; @@ -202,10 +200,12 @@ static BOOL test_SetPassword(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx) password = generate_random_str(8); E_md4hash(password, r.in.new_password.data); - creds_encrypt(&creds, &r.in.new_password); + creds_client_encrypt(&creds, &r.in.new_password); printf("Testing ServerPasswordSet on machine account\n"); + creds_client_authenticator(&creds, &r.in.credential); + status = dcerpc_netr_ServerPasswordSet(p, mem_ctx, &r); if (!NT_STATUS_IS_OK(status)) { printf("ServerPasswordSet - %s\n", nt_errstr(status)); @@ -216,7 +216,21 @@ static BOOL test_SetPassword(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx) printf("Failed to save machine password\n"); } - if (!creds_check(&creds, &r.out.return_authenticator.cred)) { + if (!creds_client_check(&creds, &r.out.return_authenticator.cred)) { + printf("Credential chaining failed\n"); + } + + printf("Testing a second ServerPasswordSet on machine account\n"); + + creds_client_authenticator(&creds, &r.in.credential); + + status = dcerpc_netr_ServerPasswordSet(p, mem_ctx, &r); + if (!NT_STATUS_IS_OK(status)) { + printf("ServerPasswordSet - %s\n", nt_errstr(status)); + return False; + } + + if (!creds_client_check(&creds, &r.out.return_authenticator.cred)) { printf("Credential chaining failed\n"); } -- cgit