gensec: Remove mem_ctx from calls that do not return memory
[nivanova/samba-autobuild/.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 3 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, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include "includes.h"
24 #include "rpc_server/dcerpc_server.h"
25 #include "rpc_server/dcerpc_server_proto.h"
26 #include "rpc_server/common/proto.h"
27 #include "librpc/rpc/dcerpc_proto.h"
28 #include "librpc/gen_ndr/ndr_dcerpc.h"
29 #include "auth/credentials/credentials.h"
30 #include "auth/gensec/gensec.h"
31 #include "auth/auth.h"
32 #include "param/param.h"
33 #include "librpc/rpc/rpc_common.h"
34
35 /*
36   parse any auth information from a dcerpc bind request
37   return false if we can't handle the auth request for some 
38   reason (in which case we send a bind_nak)
39 */
40 bool dcesrv_auth_bind(struct dcesrv_call_state *call)
41 {
42         struct cli_credentials *server_credentials;
43         struct ncacn_packet *pkt = &call->pkt;
44         struct dcesrv_connection *dce_conn = call->conn;
45         struct dcesrv_auth *auth = &dce_conn->auth_state;
46         NTSTATUS status;
47         uint32_t auth_length;
48
49         if (pkt->u.bind.auth_info.length == 0) {
50                 dce_conn->auth_state.auth_info = NULL;
51                 return true;
52         }
53
54         dce_conn->auth_state.auth_info = talloc(dce_conn, struct dcerpc_auth);
55         if (!dce_conn->auth_state.auth_info) {
56                 return false;
57         }
58
59         status = dcerpc_pull_auth_trailer(pkt, call, &pkt->u.bind.auth_info,
60                                           dce_conn->auth_state.auth_info,
61                                           &auth_length, false);
62         server_credentials 
63                 = cli_credentials_init(call);
64         if (!server_credentials) {
65                 DEBUG(1, ("Failed to init server credentials\n"));
66                 return false;
67         }
68         
69         cli_credentials_set_conf(server_credentials, call->conn->dce_ctx->lp_ctx);
70         status = cli_credentials_set_machine_account(server_credentials, call->conn->dce_ctx->lp_ctx);
71         if (!NT_STATUS_IS_OK(status)) {
72                 DEBUG(10, ("Failed to obtain server credentials, perhaps a standalone server?: %s\n", nt_errstr(status)));
73                 talloc_free(server_credentials);
74                 server_credentials = NULL;
75         }
76
77         status = samba_server_gensec_start(dce_conn, call->event_ctx, 
78                                            call->msg_ctx,
79                                            call->conn->dce_ctx->lp_ctx,
80                                            server_credentials,
81                                            NULL,
82                                            &auth->gensec_security);
83
84         status = gensec_start_mech_by_authtype(auth->gensec_security, auth->auth_info->auth_type, 
85                                                auth->auth_info->auth_level);
86
87         if (!NT_STATUS_IS_OK(status)) {
88                 DEBUG(3, ("Failed to start GENSEC mechanism for DCERPC server: auth_type=%d, auth_level=%d: %s\n",
89                           (int)auth->auth_info->auth_type,
90                           (int)auth->auth_info->auth_level,
91                           nt_errstr(status)));
92                 return false;
93         }
94
95         if (call->conn->state_flags & DCESRV_CALL_STATE_FLAG_HEADER_SIGNING) {
96                 gensec_want_feature(auth->gensec_security, GENSEC_FEATURE_SIGN_PKT_HEADER);
97         }
98
99         return true;
100 }
101
102 /*
103   add any auth information needed in a bind ack, and process the authentication
104   information found in the bind.
105 */
106 NTSTATUS dcesrv_auth_bind_ack(struct dcesrv_call_state *call, struct ncacn_packet *pkt)
107 {
108         struct dcesrv_connection *dce_conn = call->conn;
109         NTSTATUS status;
110
111         if (!call->conn->auth_state.gensec_security) {
112                 return NT_STATUS_OK;
113         }
114
115         status = gensec_update(dce_conn->auth_state.gensec_security,
116                                call,
117                                dce_conn->auth_state.auth_info->credentials, 
118                                &dce_conn->auth_state.auth_info->credentials);
119         
120         if (NT_STATUS_IS_OK(status)) {
121                 status = gensec_session_info(dce_conn->auth_state.gensec_security,
122                                              &dce_conn->auth_state.session_info);
123                 if (!NT_STATUS_IS_OK(status)) {
124                         DEBUG(1, ("Failed to establish session_info: %s\n", nt_errstr(status)));
125                         return status;
126                 }
127
128                 if (dce_conn->state_flags & DCESRV_CALL_STATE_FLAG_HEADER_SIGNING) {
129                         gensec_want_feature(dce_conn->auth_state.gensec_security,
130                                             GENSEC_FEATURE_SIGN_PKT_HEADER);
131                 }
132
133                 /* Now that we are authenticated, go back to the generic session key... */
134                 dce_conn->auth_state.session_key = dcesrv_generic_session_key;
135                 return NT_STATUS_OK;
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 NT_STATUS_OK;
140         } else {
141                 DEBUG(4, ("GENSEC mech rejected the incoming authentication at bind_ack: %s\n",
142                           nt_errstr(status)));
143                 return status;
144         }
145 }
146
147
148 /*
149   process the final stage of a auth request
150 */
151 bool dcesrv_auth_auth3(struct dcesrv_call_state *call)
152 {
153         struct ncacn_packet *pkt = &call->pkt;
154         struct dcesrv_connection *dce_conn = call->conn;
155         NTSTATUS status;
156         uint32_t auth_length;
157
158         /* We can't work without an existing gensec state, and an new blob to feed it */
159         if (!dce_conn->auth_state.auth_info ||
160             !dce_conn->auth_state.gensec_security ||
161             pkt->u.auth3.auth_info.length == 0) {
162                 return false;
163         }
164
165         status = dcerpc_pull_auth_trailer(pkt, call, &pkt->u.auth3.auth_info,
166                                           dce_conn->auth_state.auth_info, &auth_length, true);
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, go 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, ("GENSEC mech rejected the incoming authentication at bind_auth3: %s\n",
188                           nt_errstr(status)));
189                 return false;
190         }
191 }
192
193 /*
194   parse any auth information from a dcerpc alter request
195   return false if we can't handle the auth request for some 
196   reason (in which case we send a bind_nak (is this true for here?))
197 */
198 bool dcesrv_auth_alter(struct dcesrv_call_state *call)
199 {
200         struct ncacn_packet *pkt = &call->pkt;
201         struct dcesrv_connection *dce_conn = call->conn;
202         NTSTATUS status;
203         uint32_t auth_length;
204
205         /* on a pure interface change there is no auth blob */
206         if (pkt->u.alter.auth_info.length == 0) {
207                 return true;
208         }
209
210         /* We can't work without an existing gensec state */
211         if (!dce_conn->auth_state.gensec_security) {
212                 return false;
213         }
214
215         dce_conn->auth_state.auth_info = talloc(dce_conn, struct dcerpc_auth);
216         if (!dce_conn->auth_state.auth_info) {
217                 return false;
218         }
219
220         status = dcerpc_pull_auth_trailer(pkt, call, &pkt->u.alter.auth_info,
221                                           dce_conn->auth_state.auth_info,
222                                           &auth_length, true);
223         if (!NT_STATUS_IS_OK(status)) {
224                 return false;
225         }
226
227         return true;
228 }
229
230 /*
231   add any auth information needed in a alter ack, and process the authentication
232   information found in the alter.
233 */
234 NTSTATUS dcesrv_auth_alter_ack(struct dcesrv_call_state *call, struct ncacn_packet *pkt)
235 {
236         struct dcesrv_connection *dce_conn = call->conn;
237         NTSTATUS status;
238
239         /* on a pure interface change there is no auth_info structure
240            setup */
241         if (!call->conn->auth_state.auth_info ||
242             dce_conn->auth_state.auth_info->credentials.length == 0) {
243                 return NT_STATUS_OK;
244         }
245
246         if (!call->conn->auth_state.gensec_security) {
247                 return NT_STATUS_INVALID_PARAMETER;
248         }
249
250         status = gensec_update(dce_conn->auth_state.gensec_security,
251                                call,
252                                dce_conn->auth_state.auth_info->credentials, 
253                                &dce_conn->auth_state.auth_info->credentials);
254
255         if (NT_STATUS_IS_OK(status)) {
256                 status = gensec_session_info(dce_conn->auth_state.gensec_security,
257                                              &dce_conn->auth_state.session_info);
258                 if (!NT_STATUS_IS_OK(status)) {
259                         DEBUG(1, ("Failed to establish session_info: %s\n", nt_errstr(status)));
260                         return status;
261                 }
262
263                 /* Now that we are authenticated, got back to the generic session key... */
264                 dce_conn->auth_state.session_key = dcesrv_generic_session_key;
265                 return NT_STATUS_OK;
266         } else if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
267                 dce_conn->auth_state.auth_info->auth_pad_length = 0;
268                 dce_conn->auth_state.auth_info->auth_reserved = 0;
269                 return NT_STATUS_OK;
270         }
271
272         DEBUG(4, ("GENSEC mech rejected the incoming authentication at auth alter_ack: %s\n",
273                   nt_errstr(status)));
274         return status;
275 }
276
277 /*
278   check credentials on a request
279 */
280 bool dcesrv_auth_request(struct dcesrv_call_state *call, DATA_BLOB *full_packet)
281 {
282         struct ncacn_packet *pkt = &call->pkt;
283         struct dcesrv_connection *dce_conn = call->conn;
284         struct dcerpc_auth auth;
285         NTSTATUS status;
286         uint32_t auth_length;
287         size_t hdr_size = DCERPC_REQUEST_LENGTH;
288
289         if (!dce_conn->auth_state.auth_info ||
290             !dce_conn->auth_state.gensec_security) {
291                 return true;
292         }
293
294         if (pkt->pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
295                 hdr_size += 16;
296         }
297
298         switch (dce_conn->auth_state.auth_info->auth_level) {
299         case DCERPC_AUTH_LEVEL_PRIVACY:
300         case DCERPC_AUTH_LEVEL_INTEGRITY:
301                 break;
302
303         case DCERPC_AUTH_LEVEL_CONNECT:
304                 if (pkt->auth_length != 0) {
305                         break;
306                 }
307                 return true;
308         case DCERPC_AUTH_LEVEL_NONE:
309                 if (pkt->auth_length != 0) {
310                         return false;
311                 }
312                 return true;
313
314         default:
315                 return false;
316         }
317
318         status = dcerpc_pull_auth_trailer(pkt, call,
319                                           &pkt->u.request.stub_and_verifier,
320                                           &auth, &auth_length, false);
321         if (!NT_STATUS_IS_OK(status)) {
322                 return false;
323         }
324
325         pkt->u.request.stub_and_verifier.length -= auth_length;
326
327         /* check signature or unseal the packet */
328         switch (dce_conn->auth_state.auth_info->auth_level) {
329         case DCERPC_AUTH_LEVEL_PRIVACY:
330                 status = gensec_unseal_packet(dce_conn->auth_state.gensec_security,
331                                               full_packet->data + hdr_size,
332                                               pkt->u.request.stub_and_verifier.length, 
333                                               full_packet->data,
334                                               full_packet->length-auth.credentials.length,
335                                               &auth.credentials);
336                 memcpy(pkt->u.request.stub_and_verifier.data, 
337                        full_packet->data + hdr_size,
338                        pkt->u.request.stub_and_verifier.length);
339                 break;
340
341         case DCERPC_AUTH_LEVEL_INTEGRITY:
342                 status = gensec_check_packet(dce_conn->auth_state.gensec_security,
343                                              pkt->u.request.stub_and_verifier.data, 
344                                              pkt->u.request.stub_and_verifier.length,
345                                              full_packet->data,
346                                              full_packet->length-auth.credentials.length,
347                                              &auth.credentials);
348                 break;
349
350         case DCERPC_AUTH_LEVEL_CONNECT:
351                 /* for now we ignore possible signatures here */
352                 status = NT_STATUS_OK;
353                 break;
354
355         default:
356                 status = NT_STATUS_INVALID_LEVEL;
357                 break;
358         }
359
360         /* remove the indicated amount of padding */
361         if (pkt->u.request.stub_and_verifier.length < auth.auth_pad_length) {
362                 return false;
363         }
364         pkt->u.request.stub_and_verifier.length -= auth.auth_pad_length;
365
366         return NT_STATUS_IS_OK(status);
367 }
368
369
370 /* 
371    push a signed or sealed dcerpc request packet into a blob
372 */
373 bool dcesrv_auth_response(struct dcesrv_call_state *call,
374                           DATA_BLOB *blob, size_t sig_size,
375                           struct ncacn_packet *pkt)
376 {
377         struct dcesrv_connection *dce_conn = call->conn;
378         NTSTATUS status;
379         enum ndr_err_code ndr_err;
380         struct ndr_push *ndr;
381         uint32_t payload_length;
382         DATA_BLOB creds2;
383
384         /* non-signed packets are simple */
385         if (sig_size == 0) {
386                 status = ncacn_push_auth(blob, call, pkt, NULL);
387                 return NT_STATUS_IS_OK(status);
388         }
389
390         switch (dce_conn->auth_state.auth_info->auth_level) {
391         case DCERPC_AUTH_LEVEL_PRIVACY:
392         case DCERPC_AUTH_LEVEL_INTEGRITY:
393                 break;
394
395         case DCERPC_AUTH_LEVEL_CONNECT:
396                 /*
397                  * TODO: let the gensec mech decide if it wants to generate a
398                  *       signature that might be needed for schannel...
399                  */
400                 status = ncacn_push_auth(blob, call, pkt, NULL);
401                 return NT_STATUS_IS_OK(status);
402
403         case DCERPC_AUTH_LEVEL_NONE:
404                 status = ncacn_push_auth(blob, call, pkt, NULL);
405                 return NT_STATUS_IS_OK(status);
406
407         default:
408                 return false;
409         }
410
411         ndr = ndr_push_init_ctx(call);
412         if (!ndr) {
413                 return false;
414         }
415
416         if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
417                 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
418         }
419
420         ndr_err = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
421         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
422                 return false;
423         }
424
425         /* pad to 16 byte multiple in the payload portion of the
426            packet. This matches what w2k3 does. Note that we can't use
427            ndr_push_align() as that is relative to the start of the
428            whole packet, whereas w2k8 wants it relative to the start
429            of the stub */
430         dce_conn->auth_state.auth_info->auth_pad_length =
431                 (16 - (pkt->u.response.stub_and_verifier.length & 15)) & 15;
432         ndr_err = ndr_push_zero(ndr,
433                                 dce_conn->auth_state.auth_info->auth_pad_length);
434         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
435                 return false;
436         }
437
438         payload_length = pkt->u.response.stub_and_verifier.length +
439                 dce_conn->auth_state.auth_info->auth_pad_length;
440
441         /* we start without signature, it will appended later */
442         dce_conn->auth_state.auth_info->credentials = data_blob(NULL, 0);
443
444         /* add the auth verifier */
445         ndr_err = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS,
446                                        dce_conn->auth_state.auth_info);
447         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
448                 return false;
449         }
450
451         /* extract the whole packet as a blob */
452         *blob = ndr_push_blob(ndr);
453
454         /*
455          * Setup the frag and auth length in the packet buffer.
456          * This is needed if the GENSEC mech does AEAD signing
457          * of the packet headers. The signature itself will be
458          * appended later.
459          */
460         dcerpc_set_frag_length(blob, blob->length + sig_size);
461         dcerpc_set_auth_length(blob, sig_size);
462
463         /* sign or seal the packet */
464         switch (dce_conn->auth_state.auth_info->auth_level) {
465         case DCERPC_AUTH_LEVEL_PRIVACY:
466                 status = gensec_seal_packet(dce_conn->auth_state.gensec_security, 
467                                             call,
468                                             ndr->data + DCERPC_REQUEST_LENGTH, 
469                                             payload_length,
470                                             blob->data,
471                                             blob->length,
472                                             &creds2);
473                 break;
474
475         case DCERPC_AUTH_LEVEL_INTEGRITY:
476                 status = gensec_sign_packet(dce_conn->auth_state.gensec_security, 
477                                             call,
478                                             ndr->data + DCERPC_REQUEST_LENGTH, 
479                                             payload_length,
480                                             blob->data,
481                                             blob->length,
482                                             &creds2);
483                 break;
484
485         default:
486                 status = NT_STATUS_INVALID_LEVEL;
487                 break;
488         }
489
490         if (!NT_STATUS_IS_OK(status)) {
491                 return false;
492         }       
493
494         if (creds2.length != sig_size) {
495                 DEBUG(3,("dcesrv_auth_response: creds2.length[%u] != sig_size[%u] pad[%u] stub[%u]\n",
496                          (unsigned)creds2.length, (uint32_t)sig_size,
497                          (unsigned)dce_conn->auth_state.auth_info->auth_pad_length,
498                          (unsigned)pkt->u.response.stub_and_verifier.length));
499                 dcerpc_set_frag_length(blob, blob->length + creds2.length);
500                 dcerpc_set_auth_length(blob, creds2.length);
501         }
502
503         if (!data_blob_append(call, blob, creds2.data, creds2.length)) {
504                 status = NT_STATUS_NO_MEMORY;
505                 return false;
506         }
507         data_blob_free(&creds2);
508
509         return true;
510 }