s3-libsmb: use struct gensec_security directly
[ira/wip.git] / source3 / smbd / seal.c
1 /* 
2    Unix SMB/CIFS implementation.
3    SMB Transport encryption (sealing) code - server code.
4    Copyright (C) Jeremy Allison 2007.
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "includes.h"
21 #include "smbd/smbd.h"
22 #include "smbd/globals.h"
23 #include "../libcli/auth/spnego.h"
24 #include "../libcli/smb/smb_seal.h"
25 #include "../lib/util/asn1.h"
26 #include "auth.h"
27 #include "libsmb/libsmb.h"
28 #include "../lib/tsocket/tsocket.h"
29 #include "auth/gensec/gensec.h"
30
31 /******************************************************************************
32  Server side encryption.
33 ******************************************************************************/
34
35 /******************************************************************************
36  Return global enc context - this must change if we ever do multiple contexts.
37 ******************************************************************************/
38
39 static uint16_t srv_enc_ctx(const struct smb_trans_enc_state *es)
40 {
41         return es->enc_ctx_num;
42 }
43
44 /******************************************************************************
45  Is this an incoming encrypted packet ?
46 ******************************************************************************/
47
48 bool is_encrypted_packet(struct smbd_server_connection *sconn,
49                          const uint8_t *inbuf)
50 {
51         NTSTATUS status;
52         uint16_t enc_num;
53
54         /* Ignore non-session messages or non 0xFF'E' messages. */
55         if(CVAL(inbuf,0)
56            || (smb_len(inbuf) < 8)
57            || !(inbuf[4] == 0xFF && inbuf[5] == 'E')) {
58                 return false;
59         }
60
61         status = get_enc_ctx_num(inbuf, &enc_num);
62         if (!NT_STATUS_IS_OK(status)) {
63                 return false;
64         }
65
66         /* Encrypted messages are 0xFF'E'<ctx> */
67         if (srv_trans_enc_ctx && enc_num == srv_enc_ctx(srv_trans_enc_ctx)) {
68                 return true;
69         }
70         return false;
71 }
72
73 /******************************************************************************
74  Create an gensec_security and ensure pointer copy is correct.
75 ******************************************************************************/
76
77 static NTSTATUS make_auth_gensec(const struct tsocket_address *remote_address,
78                                  struct smb_trans_enc_state *es, const char *oid)
79 {
80         struct gensec_security *gensec_security;
81         NTSTATUS status = auth_generic_prepare(NULL, remote_address,
82                                                &gensec_security);
83         if (!NT_STATUS_IS_OK(status)) {
84                 return nt_status_squash(status);
85         }
86
87         gensec_want_feature(gensec_security, GENSEC_FEATURE_SEAL);
88
89         /*
90          * We could be accessing the secrets.tdb or krb5.keytab file here.
91          * ensure we have permissions to do so.
92          */
93         become_root();
94
95         status = gensec_start_mech_by_oid(gensec_security, oid);
96
97         unbecome_root();
98
99         if (!NT_STATUS_IS_OK(status)) {
100                 TALLOC_FREE(gensec_security);
101                 return nt_status_squash(status);
102         }
103
104         es->gensec_security = gensec_security;
105
106         return status;
107 }
108
109 /******************************************************************************
110  Shutdown a server encryption context.
111 ******************************************************************************/
112
113 static void srv_free_encryption_context(struct smb_trans_enc_state **pp_es)
114 {
115         struct smb_trans_enc_state *es = *pp_es;
116
117         if (!es) {
118                 return;
119         }
120
121         common_free_encryption_state(&es);
122
123         SAFE_FREE(es);
124         *pp_es = NULL;
125 }
126
127 /******************************************************************************
128  Create a server encryption context.
129 ******************************************************************************/
130
131 static NTSTATUS make_srv_encryption_context(const struct tsocket_address *remote_address,
132                                             enum smb_trans_enc_type smb_enc_type,
133                                             struct smb_trans_enc_state **pp_es)
134 {
135         NTSTATUS status;
136         const char *oid;
137         struct smb_trans_enc_state *es;
138
139         *pp_es = NULL;
140
141         ZERO_STRUCTP(partial_srv_trans_enc_ctx);
142         es = SMB_MALLOC_P(struct smb_trans_enc_state);
143         if (!es) {
144                 return NT_STATUS_NO_MEMORY;
145         }
146         ZERO_STRUCTP(es);
147         es->smb_enc_type = smb_enc_type;
148         switch (smb_enc_type) {
149                 case SMB_TRANS_ENC_NTLM:
150                         oid = GENSEC_OID_NTLMSSP;
151                         break;
152                 case SMB_TRANS_ENC_GSS:
153                         oid = GENSEC_OID_KERBEROS5;
154                         break;
155                 default:
156                         srv_free_encryption_context(&es);
157                         return NT_STATUS_INVALID_PARAMETER;
158         }
159         status = make_auth_gensec(remote_address,
160                                   es, oid);
161         if (!NT_STATUS_IS_OK(status)) {
162                 srv_free_encryption_context(&es);
163                 return status;
164         }
165         *pp_es = es;
166         return NT_STATUS_OK;
167 }
168
169 /******************************************************************************
170  Free an encryption-allocated buffer.
171 ******************************************************************************/
172
173 void srv_free_enc_buffer(struct smbd_server_connection *sconn, char *buf)
174 {
175         /* We know this is an smb buffer, and we
176          * didn't malloc, only copy, for a keepalive,
177          * so ignore non-session messages. */
178
179         if(CVAL(buf,0)) {
180                 return;
181         }
182
183         if (srv_trans_enc_ctx) {
184                 common_free_enc_buffer(srv_trans_enc_ctx, buf);
185         }
186 }
187
188 /******************************************************************************
189  Decrypt an incoming buffer.
190 ******************************************************************************/
191
192 NTSTATUS srv_decrypt_buffer(struct smbd_server_connection *sconn, char *buf)
193 {
194         /* Ignore non-session messages. */
195         if(CVAL(buf,0)) {
196                 return NT_STATUS_OK;
197         }
198
199         if (srv_trans_enc_ctx) {
200                 return common_decrypt_buffer(srv_trans_enc_ctx, buf);
201         }
202
203         return NT_STATUS_OK;
204 }
205
206 /******************************************************************************
207  Encrypt an outgoing buffer. Return the encrypted pointer in buf_out.
208 ******************************************************************************/
209
210 NTSTATUS srv_encrypt_buffer(struct smbd_server_connection *sconn, char *buf,
211                             char **buf_out)
212 {
213         *buf_out = buf;
214
215         /* Ignore non-session messages. */
216         if(CVAL(buf,0)) {
217                 return NT_STATUS_OK;
218         }
219
220         if (srv_trans_enc_ctx) {
221                 return common_encrypt_buffer(srv_trans_enc_ctx, buf, buf_out);
222         }
223         /* Not encrypting. */
224         return NT_STATUS_OK;
225 }
226
227 /******************************************************************************
228  Do the gss encryption negotiation. Parameters are in/out.
229  Until success we do everything on the partial enc ctx.
230 ******************************************************************************/
231
232 static NTSTATUS srv_enc_spnego_gss_negotiate(const struct tsocket_address *remote_address,
233                                              unsigned char **ppdata,
234                                              size_t *p_data_size,
235                                              DATA_BLOB secblob)
236 {
237         NTSTATUS status;
238         DATA_BLOB unwrapped_response = data_blob_null;
239         DATA_BLOB response = data_blob_null;
240
241         status = make_srv_encryption_context(remote_address,
242                                              SMB_TRANS_ENC_GSS,
243                                              &partial_srv_trans_enc_ctx);
244         if (!NT_STATUS_IS_OK(status)) {
245                 return status;
246         }
247
248         become_root();
249
250         status = gensec_update(partial_srv_trans_enc_ctx->gensec_security,
251                                talloc_tos(), NULL,
252                                secblob, &unwrapped_response);
253
254         unbecome_root();
255
256         /* status here should be NT_STATUS_MORE_PROCESSING_REQUIRED
257          * for success ... */
258
259         response = spnego_gen_auth_response(talloc_tos(), &unwrapped_response, status, OID_KERBEROS5);
260         data_blob_free(&unwrapped_response);
261
262         SAFE_FREE(*ppdata);
263         *ppdata = (unsigned char *)memdup(response.data, response.length);
264         if ((*ppdata) == NULL && response.length > 0) {
265                 status = NT_STATUS_NO_MEMORY;
266         }
267         *p_data_size = response.length;
268         data_blob_free(&response);
269
270         return status;
271 }
272
273 /******************************************************************************
274  Do the NTLM SPNEGO (or raw) encryption negotiation. Parameters are in/out.
275  Until success we do everything on the partial enc ctx.
276 ******************************************************************************/
277
278 static NTSTATUS srv_enc_ntlm_negotiate(const struct tsocket_address *remote_address,
279                                        unsigned char **ppdata,
280                                        size_t *p_data_size,
281                                        DATA_BLOB secblob,
282                                        bool spnego_wrap)
283 {
284         NTSTATUS status;
285         DATA_BLOB chal = data_blob_null;
286         DATA_BLOB response = data_blob_null;
287
288         status = make_srv_encryption_context(remote_address,
289                                              SMB_TRANS_ENC_NTLM,
290                                              &partial_srv_trans_enc_ctx);
291         if (!NT_STATUS_IS_OK(status)) {
292                 return status;
293         }
294
295         status = gensec_update(partial_srv_trans_enc_ctx->gensec_security,
296                                talloc_tos(), NULL,
297                                secblob, &chal);
298
299         /* status here should be NT_STATUS_MORE_PROCESSING_REQUIRED
300          * for success ... */
301
302         if (spnego_wrap) {
303                 response = spnego_gen_auth_response(talloc_tos(), &chal, status, OID_NTLMSSP);
304                 data_blob_free(&chal);
305         } else {
306                 /* Return the raw blob. */
307                 response = chal;
308         }
309
310         SAFE_FREE(*ppdata);
311         *ppdata = (unsigned char *)memdup(response.data, response.length);
312         if ((*ppdata) == NULL && response.length > 0) {
313                 status = NT_STATUS_NO_MEMORY;
314         }
315         *p_data_size = response.length;
316         data_blob_free(&response);
317
318         return status;
319 }
320
321 /******************************************************************************
322  Do the SPNEGO encryption negotiation. Parameters are in/out.
323  Based off code in smbd/sesssionsetup.c
324  Until success we do everything on the partial enc ctx.
325 ******************************************************************************/
326
327 static NTSTATUS srv_enc_spnego_negotiate(connection_struct *conn,
328                                         unsigned char **ppdata,
329                                         size_t *p_data_size,
330                                         unsigned char **pparam,
331                                         size_t *p_param_size)
332 {
333         NTSTATUS status;
334         DATA_BLOB blob = data_blob_null;
335         DATA_BLOB secblob = data_blob_null;
336         char *kerb_mech = NULL;
337
338         blob = data_blob_const(*ppdata, *p_data_size);
339
340         status = parse_spnego_mechanisms(talloc_tos(), blob, &secblob, &kerb_mech);
341         if (!NT_STATUS_IS_OK(status)) {
342                 return nt_status_squash(status);
343         }
344
345         /* We should have no partial context at this point. */
346
347         srv_free_encryption_context(&partial_srv_trans_enc_ctx);
348
349         if (kerb_mech) {
350                 TALLOC_FREE(kerb_mech);
351
352                 status = srv_enc_spnego_gss_negotiate(conn->sconn->remote_address,
353                                                       ppdata,
354                                                       p_data_size,
355                                                       secblob);
356         } else {
357                 status = srv_enc_ntlm_negotiate(conn->sconn->remote_address,
358                                                 ppdata,
359                                                 p_data_size,
360                                                 secblob,
361                                                 true);
362         }
363
364         data_blob_free(&secblob);
365
366         if (!NT_STATUS_EQUAL(status,NT_STATUS_MORE_PROCESSING_REQUIRED) && !NT_STATUS_IS_OK(status)) {
367                 srv_free_encryption_context(&partial_srv_trans_enc_ctx);
368                 return nt_status_squash(status);
369         }
370
371         if (NT_STATUS_IS_OK(status)) {
372                 /* Return the context we're using for this encryption state. */
373                 if (!(*pparam = SMB_MALLOC_ARRAY(unsigned char, 2))) {
374                         return NT_STATUS_NO_MEMORY;
375                 }
376                 SSVAL(*pparam,0,partial_srv_trans_enc_ctx->enc_ctx_num);
377                 *p_param_size = 2;
378         }
379
380         return status;
381 }
382
383 /******************************************************************************
384  Complete a SPNEGO encryption negotiation. Parameters are in/out.
385  We only get this for a NTLM auth second stage.
386 ******************************************************************************/
387
388 static NTSTATUS srv_enc_spnego_ntlm_auth(connection_struct *conn,
389                                         unsigned char **ppdata,
390                                         size_t *p_data_size,
391                                         unsigned char **pparam,
392                                         size_t *p_param_size)
393 {
394         NTSTATUS status;
395         DATA_BLOB blob = data_blob_null;
396         DATA_BLOB auth = data_blob_null;
397         DATA_BLOB auth_reply = data_blob_null;
398         DATA_BLOB response = data_blob_null;
399         struct smb_trans_enc_state *es = partial_srv_trans_enc_ctx;
400
401         /* We must have a partial context here. */
402
403         if (!es || es->gensec_security == NULL || es->smb_enc_type != SMB_TRANS_ENC_NTLM) {
404                 srv_free_encryption_context(&partial_srv_trans_enc_ctx);
405                 return NT_STATUS_INVALID_PARAMETER;
406         }
407
408         blob = data_blob_const(*ppdata, *p_data_size);
409         if (!spnego_parse_auth(talloc_tos(), blob, &auth)) {
410                 srv_free_encryption_context(&partial_srv_trans_enc_ctx);
411                 return NT_STATUS_INVALID_PARAMETER;
412         }
413
414         status = gensec_update(es->gensec_security, talloc_tos(), NULL, auth, &auth_reply);
415         data_blob_free(&auth);
416
417         /* From RFC4178.
418          *
419          *    supportedMech
420          *
421          *          This field SHALL only be present in the first reply from the
422          *                target.
423          * So set mechOID to NULL here.
424          */
425
426         response = spnego_gen_auth_response(talloc_tos(), &auth_reply, status, NULL);
427         data_blob_free(&auth_reply);
428
429         if (NT_STATUS_IS_OK(status)) {
430                 /* Return the context we're using for this encryption state. */
431                 if (!(*pparam = SMB_MALLOC_ARRAY(unsigned char, 2))) {
432                         return NT_STATUS_NO_MEMORY;
433                 }
434                 SSVAL(*pparam,0,es->enc_ctx_num);
435                 *p_param_size = 2;
436         }
437
438         SAFE_FREE(*ppdata);
439         *ppdata = (unsigned char *)memdup(response.data, response.length);
440         if ((*ppdata) == NULL && response.length > 0)
441                 return NT_STATUS_NO_MEMORY;
442         *p_data_size = response.length;
443         data_blob_free(&response);
444         return status;
445 }
446
447 /******************************************************************************
448  Raw NTLM encryption negotiation. Parameters are in/out.
449  This function does both steps.
450 ******************************************************************************/
451
452 static NTSTATUS srv_enc_raw_ntlm_auth(connection_struct *conn,
453                                         unsigned char **ppdata,
454                                         size_t *p_data_size,
455                                         unsigned char **pparam,
456                                         size_t *p_param_size)
457 {
458         NTSTATUS status;
459         DATA_BLOB blob = data_blob_const(*ppdata, *p_data_size);
460         DATA_BLOB response = data_blob_null;
461         struct smb_trans_enc_state *es;
462
463         if (!partial_srv_trans_enc_ctx) {
464                 /* This is the initial step. */
465                 status = srv_enc_ntlm_negotiate(conn->sconn->remote_address,
466                                                 ppdata,
467                                                 p_data_size,
468                                                 blob,
469                                                 false);
470                 if (!NT_STATUS_EQUAL(status,NT_STATUS_MORE_PROCESSING_REQUIRED) && !NT_STATUS_IS_OK(status)) {
471                         srv_free_encryption_context(&partial_srv_trans_enc_ctx);
472                         return nt_status_squash(status);
473                 }
474                 return status;
475         }
476
477         es = partial_srv_trans_enc_ctx;
478         if (!es || es->gensec_security == NULL || es->smb_enc_type != SMB_TRANS_ENC_NTLM) {
479                 srv_free_encryption_context(&partial_srv_trans_enc_ctx);
480                 return NT_STATUS_INVALID_PARAMETER;
481         }
482
483         /* Second step. */
484         status = gensec_update(partial_srv_trans_enc_ctx->gensec_security,
485                                talloc_tos(), NULL,
486                                blob, &response);
487
488         if (NT_STATUS_IS_OK(status)) {
489                 /* Return the context we're using for this encryption state. */
490                 if (!(*pparam = SMB_MALLOC_ARRAY(unsigned char, 2))) {
491                         return NT_STATUS_NO_MEMORY;
492                 }
493                 SSVAL(*pparam, 0, es->enc_ctx_num);
494                 *p_param_size = 2;
495         }
496
497         /* Return the raw blob. */
498         SAFE_FREE(*ppdata);
499         *ppdata = (unsigned char *)memdup(response.data, response.length);
500         if ((*ppdata) == NULL && response.length > 0)
501                 return NT_STATUS_NO_MEMORY;
502         *p_data_size = response.length;
503         data_blob_free(&response);
504         return status;
505 }
506
507 /******************************************************************************
508  Do the SPNEGO encryption negotiation. Parameters are in/out.
509 ******************************************************************************/
510
511 NTSTATUS srv_request_encryption_setup(connection_struct *conn,
512                                         unsigned char **ppdata,
513                                         size_t *p_data_size,
514                                         unsigned char **pparam,
515                                         size_t *p_param_size)
516 {
517         unsigned char *pdata = *ppdata;
518
519         SAFE_FREE(*pparam);
520         *p_param_size = 0;
521
522         if (*p_data_size < 1) {
523                 return NT_STATUS_INVALID_PARAMETER;
524         }
525
526         if (pdata[0] == ASN1_APPLICATION(0)) {
527                 /* its a negTokenTarg packet */
528                 return srv_enc_spnego_negotiate(conn, ppdata, p_data_size, pparam, p_param_size);
529         }
530
531         if (pdata[0] == ASN1_CONTEXT(1)) {
532                 /* It's an auth packet */
533                 return srv_enc_spnego_ntlm_auth(conn, ppdata, p_data_size, pparam, p_param_size);
534         }
535
536         /* Maybe it's a raw unwrapped auth ? */
537         if (*p_data_size < 7) {
538                 return NT_STATUS_INVALID_PARAMETER;
539         }
540
541         if (strncmp((char *)pdata, "NTLMSSP", 7) == 0) {
542                 return srv_enc_raw_ntlm_auth(conn, ppdata, p_data_size, pparam, p_param_size);
543         }
544
545         DEBUG(1,("srv_request_encryption_setup: Unknown packet\n"));
546
547         return NT_STATUS_LOGON_FAILURE;
548 }
549
550 /******************************************************************************
551  Negotiation was successful - turn on server-side encryption.
552 ******************************************************************************/
553
554 static NTSTATUS check_enc_good(struct smb_trans_enc_state *es)
555 {
556         if (!es) {
557                 return NT_STATUS_LOGON_FAILURE;
558         }
559
560         if (es->smb_enc_type == SMB_TRANS_ENC_NTLM) {
561                 if (!gensec_have_feature(es->gensec_security, GENSEC_FEATURE_SIGN)) {
562                         return NT_STATUS_INVALID_PARAMETER;
563                 }
564
565                 if (!gensec_have_feature(es->gensec_security, GENSEC_FEATURE_SEAL)) {
566                         return NT_STATUS_INVALID_PARAMETER;
567                 }
568         }
569         /* Todo - check gssapi case. */
570
571         return NT_STATUS_OK;
572 }
573
574 /******************************************************************************
575  Negotiation was successful - turn on server-side encryption.
576 ******************************************************************************/
577
578 NTSTATUS srv_encryption_start(connection_struct *conn)
579 {
580         NTSTATUS status;
581
582         /* Check that we are really doing sign+seal. */
583         status = check_enc_good(partial_srv_trans_enc_ctx);
584         if (!NT_STATUS_IS_OK(status)) {
585                 return status;
586         }
587         /* Throw away the context we're using currently (if any). */
588         srv_free_encryption_context(&srv_trans_enc_ctx);
589
590         /* Steal the partial pointer. Deliberate shallow copy. */
591         srv_trans_enc_ctx = partial_srv_trans_enc_ctx;
592         srv_trans_enc_ctx->enc_on = true;
593
594         partial_srv_trans_enc_ctx = NULL;
595
596         DEBUG(1,("srv_encryption_start: context negotiated\n"));
597         return NT_STATUS_OK;
598 }
599
600 /******************************************************************************
601  Shutdown all server contexts.
602 ******************************************************************************/
603
604 void server_encryption_shutdown(struct smbd_server_connection *sconn)
605 {
606         srv_free_encryption_context(&partial_srv_trans_enc_ctx);
607         srv_free_encryption_context(&srv_trans_enc_ctx);
608 }