r2294: this fixes the NTLM2 sign+seal combination. I have now tested:
[samba.git] / source4 / rpc_server / dcesrv_auth.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    server side dcerpc authentication code
5
6    Copyright (C) Andrew Tridgell 2003
7    Copyright (C) Stefan (metze) Metzmacher 2004
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 2 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23
24 #include "includes.h"
25
26 /*
27   startup the cryptographic side of an authenticated dcerpc server
28 */
29 NTSTATUS dcesrv_crypto_select_type(struct dcesrv_connection *dce_conn,
30                                struct dcesrv_auth *auth)
31 {
32         NTSTATUS status;
33         if (auth->auth_info->auth_level != DCERPC_AUTH_LEVEL_INTEGRITY &&
34             auth->auth_info->auth_level != DCERPC_AUTH_LEVEL_PRIVACY) {
35                 DEBUG(2,("auth_level %d not supported in dcesrv auth\n", 
36                          auth->auth_info->auth_level));
37                 return NT_STATUS_INVALID_PARAMETER;
38         }
39
40         if (auth->gensec_security != NULL) {
41                 /* TODO:
42                  * this this function should not be called
43                  * twice per dcesrv_connection!
44                  * 
45                  * so we need to find out the right
46                  * dcerpc error to return
47                  */
48         }
49
50         status = gensec_server_start(&auth->gensec_security);
51         if (!NT_STATUS_IS_OK(status)) {
52                 DEBUG(1, ("Failed to start GENSEC server code: %s\n", nt_errstr(status)));
53                 return status;
54         }
55
56         status = gensec_start_mech_by_authtype(auth->gensec_security, auth->auth_info->auth_type, 
57                                                auth->auth_info->auth_level);
58
59         if (!NT_STATUS_IS_OK(status)) {
60                 DEBUG(1, ("Failed to start GENSEC mech-specific server code (%d): %s\n", 
61                           (int)auth->auth_info->auth_type,
62                           nt_errstr(status)));
63                 return status;
64         }
65
66         return status;
67 }
68
69 /*
70   parse any auth information from a dcerpc bind request
71   return False if we can't handle the auth request for some 
72   reason (in which case we send a bind_nak)
73 */
74 BOOL dcesrv_auth_bind(struct dcesrv_call_state *call)
75 {
76         struct dcerpc_packet *pkt = &call->pkt;
77         struct dcesrv_connection *dce_conn = call->conn;
78         NTSTATUS status;
79
80         if (pkt->u.bind.auth_info.length == 0) {
81                 dce_conn->auth_state.auth_info = NULL;
82                 return True;
83         }
84
85         dce_conn->auth_state.auth_info = talloc_p(dce_conn->mem_ctx, struct dcerpc_auth);
86         if (!dce_conn->auth_state.auth_info) {
87                 return False;
88         }
89
90         status = ndr_pull_struct_blob(&pkt->u.bind.auth_info,
91                                       call->mem_ctx,
92                                       dce_conn->auth_state.auth_info,
93                                       (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
94         if (!NT_STATUS_IS_OK(status)) {
95                 return False;
96         }
97
98         status = dcesrv_crypto_select_type(dce_conn, &dce_conn->auth_state);
99         if (!NT_STATUS_IS_OK(status)) {
100                 return False;
101         }
102
103         return True;
104 }
105
106 /*
107   add any auth information needed in a bind ack, and process the authentication
108   information found in the bind.
109 */
110 BOOL dcesrv_auth_bind_ack(struct dcesrv_call_state *call, struct dcerpc_packet *pkt)
111 {
112         struct dcesrv_connection *dce_conn = call->conn;
113         NTSTATUS status;
114
115         if (!call->conn->auth_state.gensec_security) {
116                 return True;
117         }
118
119         status = gensec_update(dce_conn->auth_state.gensec_security,
120                                call->mem_ctx,
121                                dce_conn->auth_state.auth_info->credentials, 
122                                &dce_conn->auth_state.auth_info->credentials);
123         
124         if (NT_STATUS_IS_OK(status)) {
125                 status = gensec_session_info(dce_conn->auth_state.gensec_security,
126                                              &dce_conn->auth_state.session_info);
127                 if (!NT_STATUS_IS_OK(status)) {
128                         DEBUG(1, ("Failed to establish session_info: %s\n", nt_errstr(status)));
129                         return False;
130                 }
131
132                 /* Now that we are authenticated, got back to the generic session key... */
133                 dce_conn->auth_state.session_key = dcesrv_generic_session_key;
134                 return True;
135         } else if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
136                 dce_conn->auth_state.auth_info->auth_pad_length = 0;
137                 dce_conn->auth_state.auth_info->auth_reserved = 0;
138                 return True;
139         } else {
140                 DEBUG(2, ("Failed to start dcesrv auth negotiate: %s\n", nt_errstr(status)));
141                 return False;
142         }
143 }
144
145
146 /*
147   process the final stage of a auth request
148 */
149 BOOL dcesrv_auth_auth3(struct dcesrv_call_state *call)
150 {
151         struct dcerpc_packet *pkt = &call->pkt;
152         struct dcesrv_connection *dce_conn = call->conn;
153         NTSTATUS status;
154
155         /* We can't work without an existing gensec state, and an new blob to feed it */
156         if (!dce_conn->auth_state.auth_info ||
157             !dce_conn->auth_state.gensec_security ||
158             pkt->u.auth.auth_info.length == 0) {
159                 return False;
160         }
161
162         status = ndr_pull_struct_blob(&pkt->u.auth.auth_info,
163                                       call->mem_ctx,
164                                       dce_conn->auth_state.auth_info,
165                                       (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
166         if (!NT_STATUS_IS_OK(status)) {
167                 return False;
168         }
169
170         /* Pass the extra data we got from the client down to gensec for processing */
171         status = gensec_update(dce_conn->auth_state.gensec_security,
172                                call->mem_ctx,
173                                dce_conn->auth_state.auth_info->credentials, 
174                                &dce_conn->auth_state.auth_info->credentials);
175         if (NT_STATUS_IS_OK(status)) {
176                 status = gensec_session_info(dce_conn->auth_state.gensec_security,
177                                              &dce_conn->auth_state.session_info);
178                 if (!NT_STATUS_IS_OK(status)) {
179                         DEBUG(1, ("Failed to establish session_info: %s\n", nt_errstr(status)));
180                         return False;
181                 }
182                 /* Now that we are authenticated, got back to the generic session key... */
183                 dce_conn->auth_state.session_key = dcesrv_generic_session_key;
184                 return True;
185         } else {
186                 DEBUG(4, ("dcesrv_auth_auth3: failed to authenticate: %s\n", 
187                           nt_errstr(status)));
188                 return False;
189         }
190
191         return True;
192 }
193
194 /*
195   check credentials on a request
196 */
197 BOOL dcesrv_auth_request(struct dcesrv_call_state *call, DATA_BLOB *full_packet)
198 {
199         struct dcerpc_packet *pkt = &call->pkt;
200         struct dcesrv_connection *dce_conn = call->conn;
201         DATA_BLOB auth_blob;
202         struct dcerpc_auth auth;
203         struct ndr_pull *ndr;
204         NTSTATUS status;
205
206         if (!dce_conn->auth_state.auth_info ||
207             !dce_conn->auth_state.gensec_security) {
208                 return True;
209         }
210
211         auth_blob.length = 8 + pkt->auth_length;
212
213         /* check for a valid length */
214         if (pkt->u.request.stub_and_verifier.length < auth_blob.length) {
215                 return False;
216         }
217
218         auth_blob.data = 
219                 pkt->u.request.stub_and_verifier.data + 
220                 pkt->u.request.stub_and_verifier.length - auth_blob.length;
221         pkt->u.request.stub_and_verifier.length -= auth_blob.length;
222
223         /* pull the auth structure */
224         ndr = ndr_pull_init_blob(&auth_blob, call->mem_ctx);
225         if (!ndr) {
226                 return False;
227         }
228
229         if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
230                 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
231         }
232
233         status = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, &auth);
234         if (!NT_STATUS_IS_OK(status)) {
235                 return False;
236         }
237
238         /* check signature or unseal the packet */
239         switch (dce_conn->auth_state.auth_info->auth_level) {
240         case DCERPC_AUTH_LEVEL_PRIVACY:
241                 status = gensec_unseal_packet(dce_conn->auth_state.gensec_security,
242                                               call->mem_ctx,
243                                               full_packet->data + DCERPC_REQUEST_LENGTH,
244                                               pkt->u.request.stub_and_verifier.length, 
245                                               full_packet->data,
246                                               full_packet->length-auth.credentials.length,
247                                               &auth.credentials);
248                 memcpy(pkt->u.request.stub_and_verifier.data, 
249                        full_packet->data + DCERPC_REQUEST_LENGTH,
250                        pkt->u.request.stub_and_verifier.length);
251                 break;
252
253         case DCERPC_AUTH_LEVEL_INTEGRITY:
254                 status = gensec_check_packet(dce_conn->auth_state.gensec_security,
255                                              call->mem_ctx,
256                                              pkt->u.request.stub_and_verifier.data, 
257                                              pkt->u.request.stub_and_verifier.length,
258                                              full_packet->data,
259                                              full_packet->length-auth.credentials.length,
260                                              &auth.credentials);
261                 break;
262
263         default:
264                 status = NT_STATUS_INVALID_LEVEL;
265                 break;
266         }
267
268         /* remove the indicated amount of padding */
269         if (pkt->u.request.stub_and_verifier.length < auth.auth_pad_length) {
270                 return False;
271         }
272         pkt->u.request.stub_and_verifier.length -= auth.auth_pad_length;
273
274         return NT_STATUS_IS_OK(status);
275 }
276
277
278 /* 
279    push a signed or sealed dcerpc request packet into a blob
280 */
281 BOOL dcesrv_auth_response(struct dcesrv_call_state *call,
282                           DATA_BLOB *blob, struct dcerpc_packet *pkt)
283 {
284         struct dcesrv_connection *dce_conn = call->conn;
285         NTSTATUS status;
286         struct ndr_push *ndr;
287         uint32_t payload_length;
288
289         /* non-signed packets are simple */
290         if (!dce_conn->auth_state.auth_info || !dce_conn->auth_state.gensec_security) {
291                 status = dcerpc_push_auth(blob, call->mem_ctx, pkt, NULL);
292                 return NT_STATUS_IS_OK(status);
293         }
294
295         ndr = ndr_push_init_ctx(call->mem_ctx);
296         if (!ndr) {
297                 return False;
298         }
299
300         if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
301                 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
302         }
303
304         status = ndr_push_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
305         if (!NT_STATUS_IS_OK(status)) {
306                 return False;
307         }
308
309         /* pad to 8 byte multiple */
310         dce_conn->auth_state.auth_info->auth_pad_length = NDR_ALIGN(ndr, 8);
311         ndr_push_zero(ndr, dce_conn->auth_state.auth_info->auth_pad_length);
312
313         payload_length = ndr->offset - DCERPC_REQUEST_LENGTH;
314         
315         dce_conn->auth_state.auth_info->credentials
316                 = data_blob_talloc(call->mem_ctx, NULL, 
317                                    gensec_sig_size(dce_conn->auth_state.gensec_security));
318
319         /* add the auth verifier */
320         status = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, dce_conn->auth_state.auth_info);
321         if (!NT_STATUS_IS_OK(status)) {
322                 return False;
323         }
324
325         /* extract the whole packet as a blob */
326         *blob = ndr_push_blob(ndr);
327
328         /* fill in the fragment length and auth_length, we can't fill
329            in these earlier as we don't know the signature length (it
330            could be variable length) */
331         dcerpc_set_frag_length(blob, blob->length);
332         dcerpc_set_auth_length(blob, dce_conn->auth_state.auth_info->credentials.length);
333
334         /* sign or seal the packet */
335         switch (dce_conn->auth_state.auth_info->auth_level) {
336         case DCERPC_AUTH_LEVEL_PRIVACY:
337                 status = gensec_seal_packet(dce_conn->auth_state.gensec_security, 
338                                             call->mem_ctx,
339                                             ndr->data + DCERPC_REQUEST_LENGTH, 
340                                             payload_length,
341                                             blob->data,
342                                             blob->length - dce_conn->auth_state.auth_info->credentials.length,
343                                               &dce_conn->auth_state.auth_info->credentials);
344                 break;
345
346         case DCERPC_AUTH_LEVEL_INTEGRITY:
347                 status = gensec_sign_packet(dce_conn->auth_state.gensec_security, 
348                                             call->mem_ctx,
349                                             ndr->data + DCERPC_REQUEST_LENGTH, 
350                                             payload_length,
351                                             blob->data,
352                                             blob->length - dce_conn->auth_state.auth_info->credentials.length,
353                                             &dce_conn->auth_state.auth_info->credentials);
354
355                 break;
356         default:
357                 status = NT_STATUS_INVALID_LEVEL;
358                 break;
359         }
360
361         if (!NT_STATUS_IS_OK(status)) {
362                 return False;
363         }       
364
365         memcpy(blob->data + blob->length - dce_conn->auth_state.auth_info->credentials.length, 
366                dce_conn->auth_state.auth_info->credentials.data, dce_conn->auth_state.auth_info->credentials.length);
367         
368         data_blob_free(&dce_conn->auth_state.auth_info->credentials);
369
370         return True;
371 }