r2284: Thanks to some great detective work by tridge, NTLM2 signing now works.
[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 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                 return True;
132         } else if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
133                 dce_conn->auth_state.auth_info->auth_pad_length = 0;
134                 dce_conn->auth_state.auth_info->auth_reserved = 0;
135                 return True;
136         } else {
137                 DEBUG(2, ("Failed to start dcesrv auth negotiate: %s\n", nt_errstr(status)));
138                 return False;
139         }
140 }
141
142
143 /*
144   process the final stage of a auth request
145 */
146 BOOL dcesrv_auth_auth3(struct dcesrv_call_state *call)
147 {
148         struct dcerpc_packet *pkt = &call->pkt;
149         struct dcesrv_connection *dce_conn = call->conn;
150         NTSTATUS status;
151
152         /* We can't work without an existing gensec state, and an new blob to feed it */
153         if (!dce_conn->auth_state.auth_info ||
154             !dce_conn->auth_state.gensec_security ||
155             pkt->u.auth.auth_info.length == 0) {
156                 return False;
157         }
158
159         status = ndr_pull_struct_blob(&pkt->u.auth.auth_info,
160                                       call->mem_ctx,
161                                       dce_conn->auth_state.auth_info,
162                                       (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
163         if (!NT_STATUS_IS_OK(status)) {
164                 return False;
165         }
166
167         /* Pass the extra data we got from the client down to gensec for processing */
168         status = gensec_update(dce_conn->auth_state.gensec_security,
169                                call->mem_ctx,
170                                dce_conn->auth_state.auth_info->credentials, 
171                                &dce_conn->auth_state.auth_info->credentials);
172         if (NT_STATUS_IS_OK(status)) {
173                 status = gensec_session_info(dce_conn->auth_state.gensec_security,
174                                              &dce_conn->auth_state.session_info);
175                 if (!NT_STATUS_IS_OK(status)) {
176                         DEBUG(1, ("Failed to establish session_info: %s\n", nt_errstr(status)));
177                         return False;
178                 }
179                 return True;
180         } else {
181                 DEBUG(4, ("dcesrv_auth_auth3: failed to authenticate: %s\n", 
182                           nt_errstr(status)));
183                 return False;
184         }
185
186         return True;
187 }
188
189 /*
190   check credentials on a request
191 */
192 BOOL dcesrv_auth_request(struct dcesrv_call_state *call, DATA_BLOB *full_packet)
193 {
194         struct dcerpc_packet *pkt = &call->pkt;
195         struct dcesrv_connection *dce_conn = call->conn;
196         DATA_BLOB auth_blob;
197         struct dcerpc_auth auth;
198         struct ndr_pull *ndr;
199         NTSTATUS status;
200
201         if (!dce_conn->auth_state.auth_info ||
202             !dce_conn->auth_state.gensec_security) {
203                 return True;
204         }
205
206         auth_blob.length = 8 + pkt->auth_length;
207
208         /* check for a valid length */
209         if (pkt->u.request.stub_and_verifier.length < auth_blob.length) {
210                 return False;
211         }
212
213         auth_blob.data = 
214                 pkt->u.request.stub_and_verifier.data + 
215                 pkt->u.request.stub_and_verifier.length - auth_blob.length;
216         pkt->u.request.stub_and_verifier.length -= auth_blob.length;
217
218         /* pull the auth structure */
219         ndr = ndr_pull_init_blob(&auth_blob, call->mem_ctx);
220         if (!ndr) {
221                 return False;
222         }
223
224         if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
225                 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
226         }
227
228         status = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, &auth);
229         if (!NT_STATUS_IS_OK(status)) {
230                 return False;
231         }
232
233         /* check signature or unseal the packet */
234         switch (dce_conn->auth_state.auth_info->auth_level) {
235         case DCERPC_AUTH_LEVEL_PRIVACY:
236                 status = gensec_unseal_packet(dce_conn->auth_state.gensec_security,
237                                               call->mem_ctx,
238                                               pkt->u.request.stub_and_verifier.data, 
239                                               pkt->u.request.stub_and_verifier.length, 
240                                               full_packet->data,
241                                               full_packet->length-auth.credentials.length,
242                                               &auth.credentials);
243                 break;
244
245         case DCERPC_AUTH_LEVEL_INTEGRITY:
246                 status = gensec_check_packet(dce_conn->auth_state.gensec_security,
247                                              call->mem_ctx,
248                                              pkt->u.request.stub_and_verifier.data, 
249                                              pkt->u.request.stub_and_verifier.length,
250                                              full_packet->data,
251                                              full_packet->length-auth.credentials.length,
252                                              &auth.credentials);
253                 break;
254
255         default:
256                 status = NT_STATUS_INVALID_LEVEL;
257                 break;
258         }
259
260         /* remove the indicated amount of padding */
261         if (pkt->u.request.stub_and_verifier.length < auth.auth_pad_length) {
262                 return False;
263         }
264         pkt->u.request.stub_and_verifier.length -= auth.auth_pad_length;
265
266         return NT_STATUS_IS_OK(status);
267 }
268
269
270 /* 
271    push a signed or sealed dcerpc request packet into a blob
272 */
273 BOOL dcesrv_auth_response(struct dcesrv_call_state *call,
274                           DATA_BLOB *blob, struct dcerpc_packet *pkt)
275 {
276         struct dcesrv_connection *dce_conn = call->conn;
277         NTSTATUS status;
278         struct ndr_push *ndr;
279
280         /* non-signed packets are simple */
281         if (!dce_conn->auth_state.auth_info || !dce_conn->auth_state.gensec_security) {
282                 status = dcerpc_push_auth(blob, call->mem_ctx, pkt, NULL);
283                 return NT_STATUS_IS_OK(status);
284         }
285
286         ndr = ndr_push_init_ctx(call->mem_ctx);
287         if (!ndr) {
288                 return False;
289         }
290
291         if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
292                 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
293         }
294
295         status = ndr_push_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
296         if (!NT_STATUS_IS_OK(status)) {
297                 return False;
298         }
299
300         /* pad to 8 byte multiple */
301         dce_conn->auth_state.auth_info->auth_pad_length = NDR_ALIGN(ndr, 8);
302         ndr_push_zero(ndr, dce_conn->auth_state.auth_info->auth_pad_length);
303
304         
305         dce_conn->auth_state.auth_info->credentials
306                 = data_blob_talloc(call->mem_ctx, NULL, 
307                                    gensec_sig_size(dce_conn->auth_state.gensec_security));
308
309         /* add the auth verifier */
310         status = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, dce_conn->auth_state.auth_info);
311         if (!NT_STATUS_IS_OK(status)) {
312                 return False;
313         }
314
315         /* extract the whole packet as a blob */
316         *blob = ndr_push_blob(ndr);
317
318         /* fill in the fragment length and auth_length, we can't fill
319            in these earlier as we don't know the signature length (it
320            could be variable length) */
321         dcerpc_set_frag_length(blob, blob->length);
322         dcerpc_set_auth_length(blob, dce_conn->auth_state.auth_info->credentials.length);
323
324         /* sign or seal the packet */
325         switch (dce_conn->auth_state.auth_info->auth_level) {
326         case DCERPC_AUTH_LEVEL_PRIVACY:
327                 status = gensec_seal_packet(dce_conn->auth_state.gensec_security, 
328                                             call->mem_ctx,
329                                             ndr->data + DCERPC_REQUEST_LENGTH, 
330                                             ndr->offset - DCERPC_REQUEST_LENGTH,
331                                             blob->data,
332                                             blob->length - dce_conn->auth_state.auth_info->credentials.length,
333                                               &dce_conn->auth_state.auth_info->credentials);
334                 break;
335
336         case DCERPC_AUTH_LEVEL_INTEGRITY:
337                 status = gensec_sign_packet(dce_conn->auth_state.gensec_security, 
338                                             call->mem_ctx,
339                                             ndr->data + DCERPC_REQUEST_LENGTH, 
340                                             ndr->offset - DCERPC_REQUEST_LENGTH,
341                                             blob->data,
342                                             blob->length - dce_conn->auth_state.auth_info->credentials.length,
343                                             &dce_conn->auth_state.auth_info->credentials);
344
345                 break;
346         default:
347                 status = NT_STATUS_INVALID_LEVEL;
348                 break;
349         }
350
351         if (!NT_STATUS_IS_OK(status)) {
352                 return False;
353         }       
354
355         memcpy(blob->data + blob->length - dce_conn->auth_state.auth_info->credentials.length, 
356                dce_conn->auth_state.auth_info->credentials.data, dce_conn->auth_state.auth_info->credentials.length);
357         
358         data_blob_free(&dce_conn->auth_state.auth_info->credentials);
359
360         return True;
361 }