aa37de28265a2f2b823bbb64316c6beb0ff6256f
[bbaumbach/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 "librpc/gen_ndr/ndr_dcerpc.h"
26 #include "auth/credentials/credentials.h"
27 #include "auth/gensec/gensec.h"
28 #include "param/param.h"
29
30 /*
31   parse any auth information from a dcerpc bind request
32   return false if we can't handle the auth request for some 
33   reason (in which case we send a bind_nak)
34 */
35 bool dcesrv_auth_bind(struct dcesrv_call_state *call)
36 {
37         struct cli_credentials *server_credentials;
38         struct ncacn_packet *pkt = &call->pkt;
39         struct dcesrv_connection *dce_conn = call->conn;
40         struct dcesrv_auth *auth = &dce_conn->auth_state;
41         NTSTATUS status;
42         enum ndr_err_code ndr_err;
43
44         if (pkt->u.bind.auth_info.length == 0) {
45                 dce_conn->auth_state.auth_info = NULL;
46                 return true;
47         }
48
49         dce_conn->auth_state.auth_info = talloc(dce_conn, struct dcerpc_auth);
50         if (!dce_conn->auth_state.auth_info) {
51                 return false;
52         }
53
54         ndr_err = ndr_pull_struct_blob(&pkt->u.bind.auth_info,
55                                        call,
56                                        dce_conn->auth_state.auth_info,
57                                        (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
58         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
59                 return false;
60         }
61
62         status = gensec_server_start(dce_conn, call->event_ctx, call->conn->dce_ctx->lp_ctx, call->msg_ctx, &auth->gensec_security);
63         if (!NT_STATUS_IS_OK(status)) {
64                 DEBUG(1, ("Failed to start GENSEC for DCERPC server: %s\n", nt_errstr(status)));
65                 return false;
66         }
67
68         server_credentials 
69                 = cli_credentials_init(call);
70         if (!server_credentials) {
71                 DEBUG(1, ("Failed to init server credentials\n"));
72                 return false;
73         }
74         
75         cli_credentials_set_conf(server_credentials, call->conn->dce_ctx->lp_ctx);
76         status = cli_credentials_set_machine_account(server_credentials, call->conn->dce_ctx->lp_ctx);
77         if (!NT_STATUS_IS_OK(status)) {
78                 DEBUG(10, ("Failed to obtain server credentials, perhaps a standalone server?: %s\n", nt_errstr(status)));
79                 talloc_free(server_credentials);
80                 server_credentials = NULL;
81         }
82
83         gensec_set_credentials(auth->gensec_security, server_credentials);
84
85         status = gensec_start_mech_by_authtype(auth->gensec_security, auth->auth_info->auth_type, 
86                                                auth->auth_info->auth_level);
87
88         if (!NT_STATUS_IS_OK(status)) {
89                 DEBUG(1, ("Failed to start GENSEC mechanism for DCERPC server: auth_type=%d, auth_level=%d: %s\n", 
90                           (int)auth->auth_info->auth_type,
91                           (int)auth->auth_info->auth_level,
92                           nt_errstr(status)));
93                 return false;
94         }
95
96         return true;
97 }
98
99 /*
100   add any auth information needed in a bind ack, and process the authentication
101   information found in the bind.
102 */
103 NTSTATUS dcesrv_auth_bind_ack(struct dcesrv_call_state *call, struct ncacn_packet *pkt)
104 {
105         struct dcesrv_connection *dce_conn = call->conn;
106         NTSTATUS status;
107
108         if (!call->conn->auth_state.gensec_security) {
109                 return NT_STATUS_OK;
110         }
111
112         status = gensec_update(dce_conn->auth_state.gensec_security,
113                                call,
114                                dce_conn->auth_state.auth_info->credentials, 
115                                &dce_conn->auth_state.auth_info->credentials);
116         
117         if (NT_STATUS_IS_OK(status)) {
118                 status = gensec_session_info(dce_conn->auth_state.gensec_security,
119                                              &dce_conn->auth_state.session_info);
120                 if (!NT_STATUS_IS_OK(status)) {
121                         DEBUG(1, ("Failed to establish session_info: %s\n", nt_errstr(status)));
122                         return status;
123                 }
124
125                 /* Now that we are authenticated, go back to the generic session key... */
126                 dce_conn->auth_state.session_key = dcesrv_generic_session_key;
127                 return NT_STATUS_OK;
128         } else if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
129                 dce_conn->auth_state.auth_info->auth_pad_length = 0;
130                 dce_conn->auth_state.auth_info->auth_reserved = 0;
131                 return NT_STATUS_OK;
132         } else {
133                 DEBUG(2, ("Failed to start dcesrv auth negotiate: %s\n", nt_errstr(status)));
134                 return status;
135         }
136 }
137
138
139 /*
140   process the final stage of a auth request
141 */
142 bool dcesrv_auth_auth3(struct dcesrv_call_state *call)
143 {
144         struct ncacn_packet *pkt = &call->pkt;
145         struct dcesrv_connection *dce_conn = call->conn;
146         NTSTATUS status;
147         enum ndr_err_code ndr_err;
148
149         /* We can't work without an existing gensec state, and an new blob to feed it */
150         if (!dce_conn->auth_state.auth_info ||
151             !dce_conn->auth_state.gensec_security ||
152             pkt->u.auth3.auth_info.length == 0) {
153                 return false;
154         }
155
156         ndr_err = ndr_pull_struct_blob(&pkt->u.auth3.auth_info,
157                                        call,
158                                        dce_conn->auth_state.auth_info,
159                                        (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
160         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
161                 return false;
162         }
163
164         /* Pass the extra data we got from the client down to gensec for processing */
165         status = gensec_update(dce_conn->auth_state.gensec_security,
166                                call,
167                                dce_conn->auth_state.auth_info->credentials, 
168                                &dce_conn->auth_state.auth_info->credentials);
169         if (NT_STATUS_IS_OK(status)) {
170                 status = gensec_session_info(dce_conn->auth_state.gensec_security,
171                                              &dce_conn->auth_state.session_info);
172                 if (!NT_STATUS_IS_OK(status)) {
173                         DEBUG(1, ("Failed to establish session_info: %s\n", nt_errstr(status)));
174                         return false;
175                 }
176                 /* Now that we are authenticated, go back to the generic session key... */
177                 dce_conn->auth_state.session_key = dcesrv_generic_session_key;
178                 return true;
179         } else {
180                 DEBUG(4, ("dcesrv_auth_auth3: failed to authenticate: %s\n", 
181                           nt_errstr(status)));
182                 return false;
183         }
184
185         return true;
186 }
187
188 /*
189   parse any auth information from a dcerpc alter request
190   return false if we can't handle the auth request for some 
191   reason (in which case we send a bind_nak (is this true for here?))
192 */
193 bool dcesrv_auth_alter(struct dcesrv_call_state *call)
194 {
195         struct ncacn_packet *pkt = &call->pkt;
196         struct dcesrv_connection *dce_conn = call->conn;
197         enum ndr_err_code ndr_err;
198
199         /* on a pure interface change there is no auth blob */
200         if (pkt->u.alter.auth_info.length == 0) {
201                 return true;
202         }
203
204         /* We can't work without an existing gensec state */
205         if (!dce_conn->auth_state.gensec_security) {
206                 return false;
207         }
208
209         dce_conn->auth_state.auth_info = talloc(dce_conn, struct dcerpc_auth);
210         if (!dce_conn->auth_state.auth_info) {
211                 return false;
212         }
213
214         ndr_err = ndr_pull_struct_blob(&pkt->u.alter.auth_info,
215                                        call,
216                                        dce_conn->auth_state.auth_info,
217                                        (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
218         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
219                 return false;
220         }
221
222         return true;
223 }
224
225 /*
226   add any auth information needed in a alter ack, and process the authentication
227   information found in the alter.
228 */
229 NTSTATUS dcesrv_auth_alter_ack(struct dcesrv_call_state *call, struct ncacn_packet *pkt)
230 {
231         struct dcesrv_connection *dce_conn = call->conn;
232         NTSTATUS status;
233
234         /* on a pure interface change there is no auth_info structure
235            setup */
236         if (!call->conn->auth_state.auth_info ||
237             dce_conn->auth_state.auth_info->credentials.length == 0) {
238                 return NT_STATUS_OK;
239         }
240
241         if (!call->conn->auth_state.gensec_security) {
242                 return NT_STATUS_INVALID_PARAMETER;
243         }
244
245         status = gensec_update(dce_conn->auth_state.gensec_security,
246                                call,
247                                dce_conn->auth_state.auth_info->credentials, 
248                                &dce_conn->auth_state.auth_info->credentials);
249
250         if (NT_STATUS_IS_OK(status)) {
251                 status = gensec_session_info(dce_conn->auth_state.gensec_security,
252                                              &dce_conn->auth_state.session_info);
253                 if (!NT_STATUS_IS_OK(status)) {
254                         DEBUG(1, ("Failed to establish session_info: %s\n", nt_errstr(status)));
255                         return status;
256                 }
257
258                 /* Now that we are authenticated, got back to the generic session key... */
259                 dce_conn->auth_state.session_key = dcesrv_generic_session_key;
260                 return NT_STATUS_OK;
261         } else if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
262                 dce_conn->auth_state.auth_info->auth_pad_length = 0;
263                 dce_conn->auth_state.auth_info->auth_reserved = 0;
264                 return NT_STATUS_OK;
265         }
266
267         DEBUG(2, ("Failed to finish dcesrv auth alter_ack: %s\n", nt_errstr(status)));
268         return status;
269 }
270
271 /*
272   generate a CONNECT level verifier
273 */
274 static NTSTATUS dcesrv_connect_verifier(TALLOC_CTX *mem_ctx, DATA_BLOB *blob)
275 {
276         *blob = data_blob_talloc(mem_ctx, NULL, 16);
277         if (blob->data == NULL) {
278                 return NT_STATUS_NO_MEMORY;
279         }
280         SIVAL(blob->data, 0, 1);
281         memset(blob->data+4, 0, 12);
282         return NT_STATUS_OK;
283 }
284
285 /*
286   generate a CONNECT level verifier
287 */
288 static NTSTATUS dcesrv_check_connect_verifier(DATA_BLOB *blob)
289 {
290         if (blob->length != 16 ||
291             IVAL(blob->data, 0) != 1) {
292                 return NT_STATUS_ACCESS_DENIED;
293         }
294         return NT_STATUS_OK;
295 }
296
297
298 /*
299   check credentials on a request
300 */
301 bool dcesrv_auth_request(struct dcesrv_call_state *call, DATA_BLOB *full_packet)
302 {
303         struct ncacn_packet *pkt = &call->pkt;
304         struct dcesrv_connection *dce_conn = call->conn;
305         DATA_BLOB auth_blob;
306         struct dcerpc_auth auth;
307         struct ndr_pull *ndr;
308         NTSTATUS status;
309         enum ndr_err_code ndr_err;
310
311         if (!dce_conn->auth_state.auth_info ||
312             !dce_conn->auth_state.gensec_security) {
313                 return true;
314         }
315
316         auth_blob.length = 8 + pkt->auth_length;
317
318         /* check for a valid length */
319         if (pkt->u.request.stub_and_verifier.length < auth_blob.length) {
320                 return false;
321         }
322
323         auth_blob.data = 
324                 pkt->u.request.stub_and_verifier.data + 
325                 pkt->u.request.stub_and_verifier.length - auth_blob.length;
326         pkt->u.request.stub_and_verifier.length -= auth_blob.length;
327
328         /* pull the auth structure */
329         ndr = ndr_pull_init_blob(&auth_blob, call, lp_iconv_convenience(call->conn->dce_ctx->lp_ctx));
330         if (!ndr) {
331                 return false;
332         }
333
334         if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
335                 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
336         }
337
338         ndr_err = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, &auth);
339         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
340                 talloc_free(ndr);
341                 return false;
342         }
343
344         /* check signature or unseal the packet */
345         switch (dce_conn->auth_state.auth_info->auth_level) {
346         case DCERPC_AUTH_LEVEL_PRIVACY:
347                 status = gensec_unseal_packet(dce_conn->auth_state.gensec_security,
348                                               call,
349                                               full_packet->data + DCERPC_REQUEST_LENGTH,
350                                               pkt->u.request.stub_and_verifier.length, 
351                                               full_packet->data,
352                                               full_packet->length-auth.credentials.length,
353                                               &auth.credentials);
354                 memcpy(pkt->u.request.stub_and_verifier.data, 
355                        full_packet->data + DCERPC_REQUEST_LENGTH,
356                        pkt->u.request.stub_and_verifier.length);
357                 break;
358
359         case DCERPC_AUTH_LEVEL_INTEGRITY:
360                 status = gensec_check_packet(dce_conn->auth_state.gensec_security,
361                                              call,
362                                              pkt->u.request.stub_and_verifier.data, 
363                                              pkt->u.request.stub_and_verifier.length,
364                                              full_packet->data,
365                                              full_packet->length-auth.credentials.length,
366                                              &auth.credentials);
367                 break;
368
369         case DCERPC_AUTH_LEVEL_CONNECT:
370                 status = dcesrv_check_connect_verifier(&auth.credentials);
371                 break;
372
373         default:
374                 status = NT_STATUS_INVALID_LEVEL;
375                 break;
376         }
377
378         /* remove the indicated amount of padding */
379         if (pkt->u.request.stub_and_verifier.length < auth.auth_pad_length) {
380                 talloc_free(ndr);
381                 return false;
382         }
383         pkt->u.request.stub_and_verifier.length -= auth.auth_pad_length;
384         talloc_free(ndr);
385
386         return NT_STATUS_IS_OK(status);
387 }
388
389
390 /* 
391    push a signed or sealed dcerpc request packet into a blob
392 */
393 bool dcesrv_auth_response(struct dcesrv_call_state *call,
394                           DATA_BLOB *blob, struct ncacn_packet *pkt)
395 {
396         struct dcesrv_connection *dce_conn = call->conn;
397         NTSTATUS status;
398         enum ndr_err_code ndr_err;
399         struct ndr_push *ndr;
400         uint32_t payload_length;
401         DATA_BLOB creds2;
402
403         /* non-signed packets are simple */
404         if (!dce_conn->auth_state.auth_info || !dce_conn->auth_state.gensec_security) {
405                 status = ncacn_push_auth(blob, call, pkt, NULL);
406                 return NT_STATUS_IS_OK(status);
407         }
408
409         ndr = ndr_push_init_ctx(call, lp_iconv_convenience(dce_conn->dce_ctx->lp_ctx));
410         if (!ndr) {
411                 return false;
412         }
413
414         if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
415                 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
416         }
417
418         ndr_err = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
419         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
420                 return false;
421         }
422
423         /* pad to 16 byte multiple, match win2k3 */
424         dce_conn->auth_state.auth_info->auth_pad_length = NDR_ALIGN(ndr, 16);
425         ndr_push_zero(ndr, dce_conn->auth_state.auth_info->auth_pad_length);
426
427         payload_length = ndr->offset - DCERPC_REQUEST_LENGTH;
428
429         if (dce_conn->auth_state.auth_info->auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
430                 status = dcesrv_connect_verifier(call,
431                                                  &dce_conn->auth_state.auth_info->credentials);
432                 if (!NT_STATUS_IS_OK(status)) {
433                         return false;
434                 }
435         } else {
436
437                 /* We hope this length is accruate.  If must be if the
438                  * GENSEC mech does AEAD signing of the packet
439                  * headers */
440                 dce_conn->auth_state.auth_info->credentials
441                         = data_blob_talloc(call, NULL, 
442                                            gensec_sig_size(dce_conn->auth_state.gensec_security, 
443                                                            payload_length));
444                 data_blob_clear(&dce_conn->auth_state.auth_info->credentials);
445         }
446
447         /* add the auth verifier */
448         ndr_err = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS,
449                                       dce_conn->auth_state.auth_info);
450         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
451                 return false;
452         }
453
454         /* extract the whole packet as a blob */
455         *blob = ndr_push_blob(ndr);
456
457         /* fill in the fragment length and auth_length, we can't fill
458            in these earlier as we don't know the signature length (it
459            could be variable length) */
460         dcerpc_set_frag_length(blob, blob->length);
461
462         /* We hope this value is accruate.  If must be if the GENSEC
463          * mech does AEAD signing of the packet headers */
464         dcerpc_set_auth_length(blob, dce_conn->auth_state.auth_info->credentials.length);
465
466         /* sign or seal the packet */
467         switch (dce_conn->auth_state.auth_info->auth_level) {
468         case DCERPC_AUTH_LEVEL_PRIVACY:
469                 status = gensec_seal_packet(dce_conn->auth_state.gensec_security, 
470                                             call,
471                                             ndr->data + DCERPC_REQUEST_LENGTH, 
472                                             payload_length,
473                                             blob->data,
474                                             blob->length - dce_conn->auth_state.auth_info->credentials.length,
475                                             &creds2);
476
477                 if (NT_STATUS_IS_OK(status)) {
478                         blob->length -= dce_conn->auth_state.auth_info->credentials.length;
479                         if (!data_blob_append(call, blob, creds2.data, creds2.length))
480                                 status = NT_STATUS_NO_MEMORY;
481                         else
482                                 status = NT_STATUS_OK;
483                 }
484
485                 /* If we did AEAD signing of the packet headers, then we hope
486                  * this value didn't change... */
487                 dcerpc_set_auth_length(blob, creds2.length);
488                 dcerpc_set_frag_length(blob, dcerpc_get_frag_length(blob)+creds2.length);
489                 data_blob_free(&creds2);
490                 break;
491
492         case DCERPC_AUTH_LEVEL_INTEGRITY:
493                 status = gensec_sign_packet(dce_conn->auth_state.gensec_security, 
494                                             call,
495                                             ndr->data + DCERPC_REQUEST_LENGTH, 
496                                             payload_length,
497                                             blob->data,
498                                             blob->length - dce_conn->auth_state.auth_info->credentials.length,
499                                             &creds2);
500                 if (NT_STATUS_IS_OK(status)) {
501                         blob->length -= dce_conn->auth_state.auth_info->credentials.length;
502                         if (!data_blob_append(call, blob, creds2.data, creds2.length))
503                                 status = NT_STATUS_NO_MEMORY;
504                         else
505                                 status = NT_STATUS_OK;
506                 }
507
508                 /* If we did AEAD signing of the packet headers, then we hope
509                  * this value didn't change... */
510                 dcerpc_set_auth_length(blob, creds2.length);
511                 dcerpc_set_frag_length(blob, dcerpc_get_frag_length(blob)+creds2.length);
512                 data_blob_free(&creds2);
513                 break;
514
515         case DCERPC_AUTH_LEVEL_CONNECT:
516                 break;
517
518         default:
519                 status = NT_STATUS_INVALID_LEVEL;
520                 break;
521         }
522
523         data_blob_free(&dce_conn->auth_state.auth_info->credentials);
524
525         if (!NT_STATUS_IS_OK(status)) {
526                 return false;
527         }       
528
529         return true;
530 }