r2627: use the new talloc capabilities in a bunch more places in the rpc
[ira/wip.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             auth->auth_info->auth_level != DCERPC_AUTH_LEVEL_CONNECT) {
36                 DEBUG(2,("auth_level %d not supported in dcesrv auth\n", 
37                          auth->auth_info->auth_level));
38                 return NT_STATUS_INVALID_PARAMETER;
39         }
40
41         if (auth->gensec_security != NULL) {
42                 /* TODO:
43                  * this this function should not be called
44                  * twice per dcesrv_connection!
45                  * 
46                  * so we need to find out the right
47                  * dcerpc error to return
48                  */
49         }
50
51         status = gensec_server_start(&auth->gensec_security);
52         if (!NT_STATUS_IS_OK(status)) {
53                 DEBUG(1, ("Failed to start GENSEC server code: %s\n", nt_errstr(status)));
54                 return status;
55         }
56
57         status = gensec_start_mech_by_authtype(auth->gensec_security, auth->auth_info->auth_type, 
58                                                auth->auth_info->auth_level);
59
60         if (!NT_STATUS_IS_OK(status)) {
61                 DEBUG(1, ("Failed to start GENSEC mech-specific server code (%d): %s\n", 
62                           (int)auth->auth_info->auth_type,
63                           nt_errstr(status)));
64                 return status;
65         }
66
67         return status;
68 }
69
70 /*
71   parse any auth information from a dcerpc bind request
72   return False if we can't handle the auth request for some 
73   reason (in which case we send a bind_nak)
74 */
75 BOOL dcesrv_auth_bind(struct dcesrv_call_state *call)
76 {
77         struct dcerpc_packet *pkt = &call->pkt;
78         struct dcesrv_connection *dce_conn = call->conn;
79         NTSTATUS status;
80
81         if (pkt->u.bind.auth_info.length == 0) {
82                 dce_conn->auth_state.auth_info = NULL;
83                 return True;
84         }
85
86         dce_conn->auth_state.auth_info = talloc_p(dce_conn, struct dcerpc_auth);
87         if (!dce_conn->auth_state.auth_info) {
88                 return False;
89         }
90
91         status = ndr_pull_struct_blob(&pkt->u.bind.auth_info,
92                                       call,
93                                       dce_conn->auth_state.auth_info,
94                                       (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
95         if (!NT_STATUS_IS_OK(status)) {
96                 return False;
97         }
98
99         status = dcesrv_crypto_select_type(dce_conn, &dce_conn->auth_state);
100         if (!NT_STATUS_IS_OK(status)) {
101                 return False;
102         }
103
104         return True;
105 }
106
107 /*
108   add any auth information needed in a bind ack, and process the authentication
109   information found in the bind.
110 */
111 BOOL dcesrv_auth_bind_ack(struct dcesrv_call_state *call, struct dcerpc_packet *pkt)
112 {
113         struct dcesrv_connection *dce_conn = call->conn;
114         NTSTATUS status;
115
116         if (!call->conn->auth_state.gensec_security) {
117                 return True;
118         }
119
120         status = gensec_update(dce_conn->auth_state.gensec_security,
121                                call,
122                                dce_conn->auth_state.auth_info->credentials, 
123                                &dce_conn->auth_state.auth_info->credentials);
124         
125         if (NT_STATUS_IS_OK(status)) {
126                 status = gensec_session_info(dce_conn->auth_state.gensec_security,
127                                              &dce_conn->auth_state.session_info);
128                 if (!NT_STATUS_IS_OK(status)) {
129                         DEBUG(1, ("Failed to establish session_info: %s\n", nt_errstr(status)));
130                         return False;
131                 }
132
133                 /* Now that we are authenticated, got back to the generic session key... */
134                 dce_conn->auth_state.session_key = dcesrv_generic_session_key;
135                 return True;
136         } else if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
137                 dce_conn->auth_state.auth_info->auth_pad_length = 0;
138                 dce_conn->auth_state.auth_info->auth_reserved = 0;
139                 return True;
140         } else {
141                 DEBUG(2, ("Failed to start dcesrv auth negotiate: %s\n", nt_errstr(status)));
142                 return False;
143         }
144 }
145
146
147 /*
148   process the final stage of a auth request
149 */
150 BOOL dcesrv_auth_auth3(struct dcesrv_call_state *call)
151 {
152         struct dcerpc_packet *pkt = &call->pkt;
153         struct dcesrv_connection *dce_conn = call->conn;
154         NTSTATUS status;
155
156         /* We can't work without an existing gensec state, and an new blob to feed it */
157         if (!dce_conn->auth_state.auth_info ||
158             !dce_conn->auth_state.gensec_security ||
159             pkt->u.auth.auth_info.length == 0) {
160                 return False;
161         }
162
163         status = ndr_pull_struct_blob(&pkt->u.auth.auth_info,
164                                       call,
165                                       dce_conn->auth_state.auth_info,
166                                       (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
167         if (!NT_STATUS_IS_OK(status)) {
168                 return False;
169         }
170
171         /* Pass the extra data we got from the client down to gensec for processing */
172         status = gensec_update(dce_conn->auth_state.gensec_security,
173                                call,
174                                dce_conn->auth_state.auth_info->credentials, 
175                                &dce_conn->auth_state.auth_info->credentials);
176         if (NT_STATUS_IS_OK(status)) {
177                 status = gensec_session_info(dce_conn->auth_state.gensec_security,
178                                              &dce_conn->auth_state.session_info);
179                 if (!NT_STATUS_IS_OK(status)) {
180                         DEBUG(1, ("Failed to establish session_info: %s\n", nt_errstr(status)));
181                         return False;
182                 }
183                 /* Now that we are authenticated, got back to the generic session key... */
184                 dce_conn->auth_state.session_key = dcesrv_generic_session_key;
185                 return True;
186         } else {
187                 DEBUG(4, ("dcesrv_auth_auth3: failed to authenticate: %s\n", 
188                           nt_errstr(status)));
189                 return False;
190         }
191
192         return True;
193 }
194
195
196 /*
197   generate a CONNECT level verifier
198 */
199 static NTSTATUS dcesrv_connect_verifier(TALLOC_CTX *mem_ctx, DATA_BLOB *blob)
200 {
201         *blob = data_blob_talloc(mem_ctx, NULL, 16);
202         if (blob->data == NULL) {
203                 return NT_STATUS_NO_MEMORY;
204         }
205         SIVAL(blob->data, 0, 1);
206         memset(blob->data+4, 0, 12);
207         return NT_STATUS_OK;
208 }
209
210 /*
211   generate a CONNECT level verifier
212 */
213 static NTSTATUS dcesrv_check_connect_verifier(DATA_BLOB *blob)
214 {
215         if (blob->length != 16 ||
216             IVAL(blob->data, 0) != 1) {
217                 return NT_STATUS_ACCESS_DENIED;
218         }
219         return NT_STATUS_OK;
220 }
221
222
223 /*
224   check credentials on a request
225 */
226 BOOL dcesrv_auth_request(struct dcesrv_call_state *call, DATA_BLOB *full_packet)
227 {
228         struct dcerpc_packet *pkt = &call->pkt;
229         struct dcesrv_connection *dce_conn = call->conn;
230         DATA_BLOB auth_blob;
231         struct dcerpc_auth auth;
232         struct ndr_pull *ndr;
233         NTSTATUS status;
234
235         if (!dce_conn->auth_state.auth_info ||
236             !dce_conn->auth_state.gensec_security) {
237                 return True;
238         }
239
240         auth_blob.length = 8 + pkt->auth_length;
241
242         /* check for a valid length */
243         if (pkt->u.request.stub_and_verifier.length < auth_blob.length) {
244                 return False;
245         }
246
247         auth_blob.data = 
248                 pkt->u.request.stub_and_verifier.data + 
249                 pkt->u.request.stub_and_verifier.length - auth_blob.length;
250         pkt->u.request.stub_and_verifier.length -= auth_blob.length;
251
252         /* pull the auth structure */
253         ndr = ndr_pull_init_blob(&auth_blob, call);
254         if (!ndr) {
255                 return False;
256         }
257
258         if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
259                 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
260         }
261
262         status = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, &auth);
263         if (!NT_STATUS_IS_OK(status)) {
264                 talloc_free(ndr);
265                 return False;
266         }
267
268         /* check signature or unseal the packet */
269         switch (dce_conn->auth_state.auth_info->auth_level) {
270         case DCERPC_AUTH_LEVEL_PRIVACY:
271                 status = gensec_unseal_packet(dce_conn->auth_state.gensec_security,
272                                               call,
273                                               full_packet->data + DCERPC_REQUEST_LENGTH,
274                                               pkt->u.request.stub_and_verifier.length, 
275                                               full_packet->data,
276                                               full_packet->length-auth.credentials.length,
277                                               &auth.credentials);
278                 memcpy(pkt->u.request.stub_and_verifier.data, 
279                        full_packet->data + DCERPC_REQUEST_LENGTH,
280                        pkt->u.request.stub_and_verifier.length);
281                 break;
282
283         case DCERPC_AUTH_LEVEL_INTEGRITY:
284                 status = gensec_check_packet(dce_conn->auth_state.gensec_security,
285                                              call,
286                                              pkt->u.request.stub_and_verifier.data, 
287                                              pkt->u.request.stub_and_verifier.length,
288                                              full_packet->data,
289                                              full_packet->length-auth.credentials.length,
290                                              &auth.credentials);
291                 break;
292
293         case DCERPC_AUTH_LEVEL_CONNECT:
294                 status = dcesrv_check_connect_verifier(&auth.credentials);
295                 break;
296
297         default:
298                 status = NT_STATUS_INVALID_LEVEL;
299                 break;
300         }
301
302         /* remove the indicated amount of padding */
303         if (pkt->u.request.stub_and_verifier.length < auth.auth_pad_length) {
304                 talloc_free(ndr);
305                 return False;
306         }
307         pkt->u.request.stub_and_verifier.length -= auth.auth_pad_length;
308         talloc_free(ndr);
309
310         return NT_STATUS_IS_OK(status);
311 }
312
313
314 /* 
315    push a signed or sealed dcerpc request packet into a blob
316 */
317 BOOL dcesrv_auth_response(struct dcesrv_call_state *call,
318                           DATA_BLOB *blob, struct dcerpc_packet *pkt)
319 {
320         struct dcesrv_connection *dce_conn = call->conn;
321         NTSTATUS status;
322         struct ndr_push *ndr;
323         uint32_t payload_length;
324
325         /* non-signed packets are simple */
326         if (!dce_conn->auth_state.auth_info || !dce_conn->auth_state.gensec_security) {
327                 status = dcerpc_push_auth(blob, call, pkt, NULL);
328                 return NT_STATUS_IS_OK(status);
329         }
330
331         ndr = ndr_push_init_ctx(call);
332         if (!ndr) {
333                 return False;
334         }
335
336         if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
337                 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
338         }
339
340         status = ndr_push_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
341         if (!NT_STATUS_IS_OK(status)) {
342                 return False;
343         }
344
345         /* pad to 8 byte multiple */
346         dce_conn->auth_state.auth_info->auth_pad_length = NDR_ALIGN(ndr, 8);
347         ndr_push_zero(ndr, dce_conn->auth_state.auth_info->auth_pad_length);
348
349         payload_length = ndr->offset - DCERPC_REQUEST_LENGTH;
350
351         if (dce_conn->auth_state.auth_info->auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
352                 status = dcesrv_connect_verifier(call,
353                                                  &dce_conn->auth_state.auth_info->credentials);
354                 if (!NT_STATUS_IS_OK(status)) {
355                         return False;
356                 }
357         } else {
358                 dce_conn->auth_state.auth_info->credentials
359                         = data_blob_talloc(call, NULL, 
360                                            gensec_sig_size(dce_conn->auth_state.gensec_security));
361         }
362
363         /* add the auth verifier */
364         status = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, dce_conn->auth_state.auth_info);
365         if (!NT_STATUS_IS_OK(status)) {
366                 return False;
367         }
368
369         /* extract the whole packet as a blob */
370         *blob = ndr_push_blob(ndr);
371
372         /* fill in the fragment length and auth_length, we can't fill
373            in these earlier as we don't know the signature length (it
374            could be variable length) */
375         dcerpc_set_frag_length(blob, blob->length);
376         dcerpc_set_auth_length(blob, dce_conn->auth_state.auth_info->credentials.length);
377
378         /* sign or seal the packet */
379         switch (dce_conn->auth_state.auth_info->auth_level) {
380         case DCERPC_AUTH_LEVEL_PRIVACY:
381                 status = gensec_seal_packet(dce_conn->auth_state.gensec_security, 
382                                             call,
383                                             ndr->data + DCERPC_REQUEST_LENGTH, 
384                                             payload_length,
385                                             blob->data,
386                                             blob->length - dce_conn->auth_state.auth_info->credentials.length,
387                                             &dce_conn->auth_state.auth_info->credentials);
388                 break;
389
390         case DCERPC_AUTH_LEVEL_INTEGRITY:
391                 status = gensec_sign_packet(dce_conn->auth_state.gensec_security, 
392                                             call,
393                                             ndr->data + DCERPC_REQUEST_LENGTH, 
394                                             payload_length,
395                                             blob->data,
396                                             blob->length - dce_conn->auth_state.auth_info->credentials.length,
397                                             &dce_conn->auth_state.auth_info->credentials);
398
399                 break;
400
401         case DCERPC_AUTH_LEVEL_CONNECT:
402                 break;
403
404         default:
405                 status = NT_STATUS_INVALID_LEVEL;
406                 break;
407         }
408
409         if (!NT_STATUS_IS_OK(status)) {
410                 return False;
411         }       
412
413         memcpy(blob->data + blob->length - dce_conn->auth_state.auth_info->credentials.length, 
414                dce_conn->auth_state.auth_info->credentials.data, dce_conn->auth_state.auth_info->credentials.length);
415         
416         data_blob_free(&dce_conn->auth_state.auth_info->credentials);
417
418         return True;
419 }