Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : CLDAP server structures
5 :
6 : Copyright (C) Andrew Bartlett <abartlet@samba.org> 2008
7 :
8 : This program is free software; you can redistribute it and/or modify
9 : it under the terms of the GNU General Public License as published by
10 : the Free Software Foundation; either version 3 of the License, or
11 : (at your option) any later version.
12 :
13 : This program is distributed in the hope that it will be useful,
14 : but WITHOUT ANY WARRANTY; without even the implied warranty of
15 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 : GNU General Public License for more details.
17 :
18 : You should have received a copy of the GNU General Public License
19 : along with this program. If not, see <http://www.gnu.org/licenses/>.
20 : */
21 :
22 : #include "includes.h"
23 : #include "lib/util/util_file.h"
24 : #include "../libcli/netlogon/netlogon.h"
25 :
26 3006 : NTSTATUS push_netlogon_samlogon_response(DATA_BLOB *data, TALLOC_CTX *mem_ctx,
27 : struct netlogon_samlogon_response *response)
28 : {
29 36 : enum ndr_err_code ndr_err;
30 3006 : if (response->ntver == NETLOGON_NT_VERSION_1) {
31 164 : ndr_err = ndr_push_struct_blob(data, mem_ctx,
32 164 : &response->data.nt4,
33 : (ndr_push_flags_fn_t)ndr_push_NETLOGON_SAM_LOGON_RESPONSE_NT40);
34 2842 : } else if (response->ntver & NETLOGON_NT_VERSION_5EX) {
35 2769 : ndr_err = ndr_push_struct_blob(data, mem_ctx,
36 2769 : &response->data.nt5_ex,
37 : (ndr_push_flags_fn_t)ndr_push_NETLOGON_SAM_LOGON_RESPONSE_EX_with_flags);
38 73 : } else if (response->ntver & NETLOGON_NT_VERSION_5) {
39 73 : ndr_err = ndr_push_struct_blob(data, mem_ctx,
40 73 : &response->data.nt5,
41 : (ndr_push_flags_fn_t)ndr_push_NETLOGON_SAM_LOGON_RESPONSE);
42 : } else {
43 0 : DEBUG(0, ("Asked to push unknown netlogon response type 0x%02x\n", response->ntver));
44 0 : return NT_STATUS_INVALID_PARAMETER;
45 : }
46 3006 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
47 0 : DEBUG(2,("failed to push netlogon response of type 0x%02x\n",
48 : response->ntver));
49 0 : return ndr_map_error2ntstatus(ndr_err);
50 : }
51 3006 : return NT_STATUS_OK;
52 : }
53 :
54 2581 : NTSTATUS pull_netlogon_samlogon_response(DATA_BLOB *data, TALLOC_CTX *mem_ctx,
55 : struct netlogon_samlogon_response *response)
56 : {
57 36 : uint32_t ntver;
58 36 : enum ndr_err_code ndr_err;
59 :
60 2581 : if (data->length < 8) {
61 0 : return NT_STATUS_BUFFER_TOO_SMALL;
62 : }
63 :
64 : /* lmnttoken */
65 2581 : if (SVAL(data->data, data->length - 4) != 0xffff) {
66 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
67 : }
68 : /* lm20token */
69 2581 : if (SVAL(data->data, data->length - 2) != 0xffff) {
70 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
71 : }
72 :
73 2581 : ntver = IVAL(data->data, data->length - 8);
74 :
75 2581 : if (ntver == NETLOGON_NT_VERSION_1) {
76 147 : ndr_err = ndr_pull_struct_blob_all(data, mem_ctx,
77 147 : &response->data.nt4,
78 : (ndr_pull_flags_fn_t)ndr_pull_NETLOGON_SAM_LOGON_RESPONSE_NT40);
79 147 : response->ntver = NETLOGON_NT_VERSION_1;
80 147 : if (NDR_ERR_CODE_IS_SUCCESS(ndr_err) && DEBUGLEVEL >= 10) {
81 0 : NDR_PRINT_DEBUG(NETLOGON_SAM_LOGON_RESPONSE_NT40,
82 : &response->data.nt4);
83 : }
84 :
85 2434 : } else if (ntver & NETLOGON_NT_VERSION_5EX) {
86 36 : struct ndr_pull *ndr;
87 2361 : ndr = ndr_pull_init_blob(data, mem_ctx);
88 2361 : if (!ndr) {
89 0 : return NT_STATUS_NO_MEMORY;
90 : }
91 2361 : ndr_err = ndr_pull_NETLOGON_SAM_LOGON_RESPONSE_EX_with_flags(
92 : ndr, NDR_SCALARS|NDR_BUFFERS, &response->data.nt5_ex,
93 : ntver);
94 2361 : if (ndr->offset < ndr->data_size) {
95 0 : TALLOC_FREE(ndr);
96 : /*
97 : * We need to handle a bug in IPA (at least <= 4.1.2).
98 : *
99 : * They include the ip address information without setting
100 : * NETLOGON_NT_VERSION_5EX_WITH_IP, while using
101 : * ndr_push_NETLOGON_SAM_LOGON_RESPONSE_EX instead of
102 : * ndr_push_NETLOGON_SAM_LOGON_RESPONSE_EX_with_flags.
103 : */
104 0 : ndr_err = ndr_pull_struct_blob_all(data, mem_ctx,
105 0 : &response->data.nt5,
106 : (ndr_pull_flags_fn_t)ndr_pull_NETLOGON_SAM_LOGON_RESPONSE_EX);
107 : }
108 2361 : response->ntver = NETLOGON_NT_VERSION_5EX;
109 2361 : if (NDR_ERR_CODE_IS_SUCCESS(ndr_err) && DEBUGLEVEL >= 10) {
110 2 : NDR_PRINT_DEBUG(NETLOGON_SAM_LOGON_RESPONSE_EX,
111 : &response->data.nt5_ex);
112 : }
113 :
114 73 : } else if (ntver & NETLOGON_NT_VERSION_5) {
115 73 : ndr_err = ndr_pull_struct_blob_all(data, mem_ctx,
116 73 : &response->data.nt5,
117 : (ndr_pull_flags_fn_t)ndr_pull_NETLOGON_SAM_LOGON_RESPONSE);
118 73 : response->ntver = NETLOGON_NT_VERSION_5;
119 73 : if (NDR_ERR_CODE_IS_SUCCESS(ndr_err) && DEBUGLEVEL >= 10) {
120 0 : NDR_PRINT_DEBUG(NETLOGON_SAM_LOGON_RESPONSE,
121 : &response->data.nt5);
122 : }
123 : } else {
124 0 : DEBUG(2,("failed to parse netlogon response of type 0x%02x - unknown response type\n",
125 : ntver));
126 0 : dump_data(10, data->data, data->length);
127 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
128 : }
129 :
130 2581 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
131 0 : DEBUG(2,("failed to parse netlogon response of type 0x%02x\n",
132 : ntver));
133 0 : dump_data(10, data->data, data->length);
134 0 : return ndr_map_error2ntstatus(ndr_err);
135 : }
136 :
137 2581 : return NT_STATUS_OK;
138 : }
139 :
140 1606 : void map_netlogon_samlogon_response(struct netlogon_samlogon_response *response)
141 : {
142 36 : struct NETLOGON_SAM_LOGON_RESPONSE_EX response_5_ex;
143 1606 : switch (response->ntver) {
144 1333 : case NETLOGON_NT_VERSION_5EX:
145 1333 : break;
146 72 : case NETLOGON_NT_VERSION_5:
147 72 : ZERO_STRUCT(response_5_ex);
148 72 : response_5_ex.command = response->data.nt5.command;
149 72 : response_5_ex.pdc_name = response->data.nt5.pdc_name;
150 72 : response_5_ex.user_name = response->data.nt5.user_name;
151 72 : response_5_ex.domain_name = response->data.nt5.domain_name;
152 72 : response_5_ex.domain_uuid = response->data.nt5.domain_uuid;
153 72 : response_5_ex.forest = response->data.nt5.forest;
154 72 : response_5_ex.dns_domain = response->data.nt5.dns_domain;
155 72 : response_5_ex.pdc_dns_name = response->data.nt5.pdc_dns_name;
156 72 : response_5_ex.sockaddr.pdc_ip = response->data.nt5.pdc_ip;
157 72 : response_5_ex.server_type = response->data.nt5.server_type;
158 72 : response_5_ex.nt_version = response->data.nt5.nt_version;
159 72 : response_5_ex.lmnt_token = response->data.nt5.lmnt_token;
160 72 : response_5_ex.lm20_token = response->data.nt5.lm20_token;
161 72 : response->ntver = NETLOGON_NT_VERSION_5EX;
162 72 : response->data.nt5_ex = response_5_ex;
163 72 : break;
164 :
165 165 : case NETLOGON_NT_VERSION_1:
166 165 : ZERO_STRUCT(response_5_ex);
167 165 : response_5_ex.command = response->data.nt4.command;
168 165 : response_5_ex.pdc_name = response->data.nt4.pdc_name;
169 165 : response_5_ex.user_name = response->data.nt4.user_name;
170 165 : response_5_ex.domain_name = response->data.nt4.domain_name;
171 165 : response_5_ex.nt_version = response->data.nt4.nt_version;
172 165 : response_5_ex.lmnt_token = response->data.nt4.lmnt_token;
173 165 : response_5_ex.lm20_token = response->data.nt4.lm20_token;
174 165 : response->ntver = NETLOGON_NT_VERSION_5EX;
175 165 : response->data.nt5_ex = response_5_ex;
176 165 : break;
177 : }
178 1606 : return;
179 : }
180 :
181 73 : NTSTATUS push_nbt_netlogon_response(DATA_BLOB *data, TALLOC_CTX *mem_ctx,
182 : struct nbt_netlogon_response *response)
183 : {
184 0 : NTSTATUS status;
185 0 : enum ndr_err_code ndr_err;
186 73 : switch (response->response_type) {
187 15 : case NETLOGON_GET_PDC:
188 15 : ndr_err = ndr_push_struct_blob(data, mem_ctx,
189 15 : &response->data.get_pdc,
190 : (ndr_push_flags_fn_t)ndr_push_nbt_netlogon_response_from_pdc);
191 15 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
192 0 : status = ndr_map_error2ntstatus(ndr_err);
193 0 : DEBUG(0,("Failed to parse netlogon packet of length %d: %s\n",
194 : (int)data->length, nt_errstr(status)));
195 0 : if (DEBUGLVL(10)) {
196 0 : (void)file_save("netlogon.dat", data->data, data->length);
197 : }
198 0 : return status;
199 : }
200 15 : status = NT_STATUS_OK;
201 15 : break;
202 58 : case NETLOGON_SAMLOGON:
203 58 : status = push_netlogon_samlogon_response(
204 : data, mem_ctx,
205 : &response->data.samlogon);
206 58 : break;
207 0 : case NETLOGON_RESPONSE2:
208 0 : ndr_err = ndr_push_struct_blob(data, mem_ctx,
209 0 : &response->data.response2,
210 : (ndr_push_flags_fn_t)ndr_push_nbt_netlogon_response2);
211 0 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
212 0 : return ndr_map_error2ntstatus(ndr_err);
213 : }
214 0 : status = NT_STATUS_OK;
215 0 : break;
216 0 : default:
217 0 : status = NT_STATUS_INVALID_NETWORK_RESPONSE;
218 0 : break;
219 : }
220 :
221 73 : return status;
222 : }
223 :
224 :
225 42 : NTSTATUS pull_nbt_netlogon_response(DATA_BLOB *data, TALLOC_CTX *mem_ctx,
226 : struct nbt_netlogon_response *response)
227 : {
228 0 : NTSTATUS status;
229 0 : enum netlogon_command command;
230 0 : enum ndr_err_code ndr_err;
231 42 : if (data->length < 4) {
232 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
233 : }
234 :
235 42 : command = SVAL(data->data, 0);
236 :
237 42 : switch (command) {
238 15 : case NETLOGON_RESPONSE_FROM_PDC:
239 15 : ndr_err = ndr_pull_struct_blob_all(data, mem_ctx,
240 15 : &response->data.get_pdc,
241 : (ndr_pull_flags_fn_t)ndr_pull_nbt_netlogon_response_from_pdc);
242 15 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
243 0 : status = ndr_map_error2ntstatus(ndr_err);
244 0 : DEBUG(0,("Failed to parse netlogon packet of length %d: %s\n",
245 : (int)data->length, nt_errstr(status)));
246 0 : if (DEBUGLVL(10)) {
247 0 : (void)file_save("netlogon.dat", data->data, data->length);
248 : }
249 0 : return status;
250 : }
251 15 : status = NT_STATUS_OK;
252 15 : response->response_type = NETLOGON_GET_PDC;
253 42 : break;
254 0 : case LOGON_RESPONSE2:
255 0 : ndr_err = ndr_pull_struct_blob(data, mem_ctx, &response->data.response2,
256 : (ndr_pull_flags_fn_t)ndr_pull_nbt_netlogon_response2);
257 0 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
258 0 : return ndr_map_error2ntstatus(ndr_err);
259 : }
260 0 : status = NT_STATUS_OK;
261 0 : response->response_type = NETLOGON_RESPONSE2;
262 0 : break;
263 27 : case LOGON_SAM_LOGON_RESPONSE:
264 : case LOGON_SAM_LOGON_PAUSE_RESPONSE:
265 : case LOGON_SAM_LOGON_USER_UNKNOWN:
266 : case LOGON_SAM_LOGON_RESPONSE_EX:
267 : case LOGON_SAM_LOGON_PAUSE_RESPONSE_EX:
268 : case LOGON_SAM_LOGON_USER_UNKNOWN_EX:
269 27 : status = pull_netlogon_samlogon_response(
270 : data, mem_ctx,
271 : &response->data.samlogon);
272 27 : response->response_type = NETLOGON_SAMLOGON;
273 27 : break;
274 :
275 : /* These levels are queries, not responses */
276 0 : case LOGON_PRIMARY_QUERY:
277 : case LOGON_REQUEST:
278 : case NETLOGON_ANNOUNCE_UAS:
279 : case LOGON_SAM_LOGON_REQUEST:
280 : default:
281 0 : status = NT_STATUS_INVALID_NETWORK_RESPONSE;
282 : }
283 :
284 42 : return status;
285 :
286 : }
|