s3:ntlmssp Move ntlmssp_sign.c from source3 to common code.
[kai/samba.git] / libcli / netlogon.c
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 "../libcli/netlogon.h"
24
25 #undef DEBUG
26 #define DEBUG(x, y)
27 #undef DEBUGLVL
28 #define DEBUGLVL(x) false
29 #undef DEBUGLEVEL
30 #define DEBUGLEVEL 0
31
32 NTSTATUS push_netlogon_samlogon_response(DATA_BLOB *data, TALLOC_CTX *mem_ctx,
33                                          struct netlogon_samlogon_response *response)
34 {
35         enum ndr_err_code ndr_err;
36         if (response->ntver == NETLOGON_NT_VERSION_1) {
37                 ndr_err = ndr_push_struct_blob(data, mem_ctx,
38                                                &response->data.nt4,
39                                                (ndr_push_flags_fn_t)ndr_push_NETLOGON_SAM_LOGON_RESPONSE_NT40);
40         } else if (response->ntver & NETLOGON_NT_VERSION_5EX) {
41                 ndr_err = ndr_push_struct_blob(data, mem_ctx,
42                                                &response->data.nt5_ex,
43                                                (ndr_push_flags_fn_t)ndr_push_NETLOGON_SAM_LOGON_RESPONSE_EX_with_flags);
44         } else if (response->ntver & NETLOGON_NT_VERSION_5) {
45                 ndr_err = ndr_push_struct_blob(data, mem_ctx,
46                                                &response->data.nt5,
47                                                (ndr_push_flags_fn_t)ndr_push_NETLOGON_SAM_LOGON_RESPONSE);
48         } else {
49                 DEBUG(0, ("Asked to push unknown netlogon response type 0x%02x\n", response->ntver));
50                 return NT_STATUS_INVALID_PARAMETER;
51         }
52         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
53                 DEBUG(2,("failed to push netlogon response of type 0x%02x\n",
54                          response->ntver));
55                 return ndr_map_error2ntstatus(ndr_err);
56         }
57         return NT_STATUS_OK;
58 }
59
60 NTSTATUS pull_netlogon_samlogon_response(DATA_BLOB *data, TALLOC_CTX *mem_ctx,
61                                          struct netlogon_samlogon_response *response)
62 {
63         uint32_t ntver;
64         enum ndr_err_code ndr_err;
65
66         if (data->length < 8) {
67                 return NT_STATUS_BUFFER_TOO_SMALL;
68         }
69
70         /* lmnttoken */
71         if (SVAL(data->data, data->length - 4) != 0xffff) {
72                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
73         }
74         /* lm20token */
75         if (SVAL(data->data, data->length - 2) != 0xffff) {
76                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
77         }
78
79         ntver = IVAL(data->data, data->length - 8);
80
81         if (ntver == NETLOGON_NT_VERSION_1) {
82                 ndr_err = ndr_pull_struct_blob_all(data, mem_ctx,
83                                                    &response->data.nt4,
84                                                    (ndr_pull_flags_fn_t)ndr_pull_NETLOGON_SAM_LOGON_RESPONSE_NT40);
85                 response->ntver = NETLOGON_NT_VERSION_1;
86                 if (NDR_ERR_CODE_IS_SUCCESS(ndr_err) && DEBUGLEVEL >= 10) {
87                         NDR_PRINT_DEBUG(NETLOGON_SAM_LOGON_RESPONSE_NT40,
88                                         &response->data.nt4);
89                 }
90
91         } else if (ntver & NETLOGON_NT_VERSION_5EX) {
92                 struct ndr_pull *ndr;
93                 ndr = ndr_pull_init_blob(data, mem_ctx);
94                 if (!ndr) {
95                         return NT_STATUS_NO_MEMORY;
96                 }
97                 ndr_err = ndr_pull_NETLOGON_SAM_LOGON_RESPONSE_EX_with_flags(
98                         ndr, NDR_SCALARS|NDR_BUFFERS, &response->data.nt5_ex,
99                         ntver);
100                 if (ndr->offset < ndr->data_size) {
101                         ndr_err = ndr_pull_error(ndr, NDR_ERR_UNREAD_BYTES,
102                                                  "not all bytes consumed ofs[%u] size[%u]",
103                                                  ndr->offset, ndr->data_size);
104                 }
105                 response->ntver = NETLOGON_NT_VERSION_5EX;
106                 if (NDR_ERR_CODE_IS_SUCCESS(ndr_err) && DEBUGLEVEL >= 10) {
107                         NDR_PRINT_DEBUG(NETLOGON_SAM_LOGON_RESPONSE_EX,
108                                         &response->data.nt5_ex);
109                 }
110
111         } else if (ntver & NETLOGON_NT_VERSION_5) {
112                 ndr_err = ndr_pull_struct_blob_all(data, mem_ctx,
113                                                    &response->data.nt5,
114                                                    (ndr_pull_flags_fn_t)ndr_pull_NETLOGON_SAM_LOGON_RESPONSE);
115                 response->ntver = NETLOGON_NT_VERSION_5;
116                 if (NDR_ERR_CODE_IS_SUCCESS(ndr_err) && DEBUGLEVEL >= 10) {
117                         NDR_PRINT_DEBUG(NETLOGON_SAM_LOGON_RESPONSE,
118                                         &response->data.nt5);
119                 }
120         } else {
121                 DEBUG(2,("failed to parse netlogon response of type 0x%02x - unknown response type\n",
122                          ntver));
123                 dump_data(10, data->data, data->length);
124                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
125         }
126
127         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
128                 DEBUG(2,("failed to parse netlogon response of type 0x%02x\n",
129                          ntver));
130                 dump_data(10, data->data, data->length);
131                 return ndr_map_error2ntstatus(ndr_err);
132         }
133
134         return NT_STATUS_OK;
135 }
136
137 void map_netlogon_samlogon_response(struct netlogon_samlogon_response *response)
138 {
139         struct NETLOGON_SAM_LOGON_RESPONSE_EX response_5_ex;
140         switch (response->ntver) {
141         case NETLOGON_NT_VERSION_5EX:
142                 break;
143         case NETLOGON_NT_VERSION_5:
144                 ZERO_STRUCT(response_5_ex);
145                 response_5_ex.command = response->data.nt5.command;
146                 response_5_ex.pdc_name = response->data.nt5.pdc_name;
147                 response_5_ex.user_name = response->data.nt5.user_name;
148                 response_5_ex.domain_name = response->data.nt5.domain_name;
149                 response_5_ex.domain_uuid = response->data.nt5.domain_uuid;
150                 response_5_ex.forest = response->data.nt5.forest;
151                 response_5_ex.dns_domain = response->data.nt5.dns_domain;
152                 response_5_ex.pdc_dns_name = response->data.nt5.pdc_dns_name;
153                 response_5_ex.sockaddr.pdc_ip = response->data.nt5.pdc_ip;
154                 response_5_ex.server_type = response->data.nt5.server_type;
155                 response_5_ex.nt_version = response->data.nt5.nt_version;
156                 response_5_ex.lmnt_token = response->data.nt5.lmnt_token;
157                 response_5_ex.lm20_token = response->data.nt5.lm20_token;
158                 response->ntver = NETLOGON_NT_VERSION_5EX;
159                 response->data.nt5_ex = response_5_ex;
160                 break;
161
162         case NETLOGON_NT_VERSION_1:
163                 ZERO_STRUCT(response_5_ex);
164                 response_5_ex.command = response->data.nt4.command;
165                 response_5_ex.pdc_name = response->data.nt4.pdc_name;
166                 response_5_ex.user_name = response->data.nt4.user_name;
167                 response_5_ex.domain_name = response->data.nt4.domain_name;
168                 response_5_ex.nt_version = response->data.nt4.nt_version;
169                 response_5_ex.lmnt_token = response->data.nt4.lmnt_token;
170                 response_5_ex.lm20_token = response->data.nt4.lm20_token;
171                 response->ntver = NETLOGON_NT_VERSION_5EX;
172                 response->data.nt5_ex = response_5_ex;
173                 break;
174         }
175         return;
176 }
177
178 NTSTATUS push_nbt_netlogon_response(DATA_BLOB *data, TALLOC_CTX *mem_ctx,
179                                     struct nbt_netlogon_response *response)
180 {
181         NTSTATUS status = NT_STATUS_INVALID_NETWORK_RESPONSE;
182         enum ndr_err_code ndr_err;
183         switch (response->response_type) {
184         case NETLOGON_GET_PDC:
185                 ndr_err = ndr_push_struct_blob(data, mem_ctx,
186                                                &response->data.get_pdc,
187                                                (ndr_push_flags_fn_t)ndr_push_nbt_netlogon_response_from_pdc);
188                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
189                         status = ndr_map_error2ntstatus(ndr_err);
190                         DEBUG(0,("Failed to parse netlogon packet of length %d: %s\n",
191                                  (int)data->length, nt_errstr(status)));
192                         if (DEBUGLVL(10)) {
193                                 file_save("netlogon.dat", data->data, data->length);
194                         }
195                         return status;
196                 }
197                 status = NT_STATUS_OK;
198                 break;
199         case NETLOGON_SAMLOGON:
200                 status = push_netlogon_samlogon_response(
201                         data, mem_ctx, 
202                         &response->data.samlogon);
203                 break;
204         }
205         return status;
206 }
207
208
209 NTSTATUS pull_nbt_netlogon_response(DATA_BLOB *data, TALLOC_CTX *mem_ctx,
210                                          struct nbt_netlogon_response *response)
211 {
212         NTSTATUS status = NT_STATUS_INVALID_NETWORK_RESPONSE;
213         enum netlogon_command command;
214         enum ndr_err_code ndr_err;
215         if (data->length < 4) {
216                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
217         }
218
219         command = SVAL(data->data, 0);
220
221         switch (command) {
222         case NETLOGON_RESPONSE_FROM_PDC:
223                 ndr_err = ndr_pull_struct_blob_all(data, mem_ctx,
224                                                    &response->data.get_pdc,
225                                                    (ndr_pull_flags_fn_t)ndr_pull_nbt_netlogon_response_from_pdc);
226                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
227                         status = ndr_map_error2ntstatus(ndr_err);
228                         DEBUG(0,("Failed to parse netlogon packet of length %d: %s\n",
229                                  (int)data->length, nt_errstr(status)));
230                         if (DEBUGLVL(10)) {
231                                 file_save("netlogon.dat", data->data, data->length);
232                         }
233                         return status;
234                 }
235                 status = NT_STATUS_OK;
236                 response->response_type = NETLOGON_GET_PDC;
237                 break;
238         case LOGON_SAM_LOGON_RESPONSE:
239         case LOGON_SAM_LOGON_PAUSE_RESPONSE:
240         case LOGON_SAM_LOGON_USER_UNKNOWN:
241         case LOGON_SAM_LOGON_RESPONSE_EX:
242         case LOGON_SAM_LOGON_PAUSE_RESPONSE_EX:
243         case LOGON_SAM_LOGON_USER_UNKNOWN_EX:
244                 status = pull_netlogon_samlogon_response(
245                         data, mem_ctx, 
246                         &response->data.samlogon);
247                 response->response_type = NETLOGON_SAMLOGON;
248                 break;
249
250         /* These levels are queries, not responses */
251         case LOGON_PRIMARY_QUERY:
252         case NETLOGON_ANNOUNCE_UAS:
253         case LOGON_SAM_LOGON_REQUEST:
254                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
255         }
256
257         return status;
258
259 }