s3-auth use gensec directly rather than via auth_generic_state
[kai/samba.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 "../auth/ntlmssp/ntlmssp.h"
25 #include "ntlmssp_wrap.h"
26 #include "../libcli/smb/smb_seal.h"
27 #include "../lib/util/asn1.h"
28 #include "auth.h"
29 #include "libsmb/libsmb.h"
30 #include "../lib/tsocket/tsocket.h"
31 #include "auth/gensec/gensec.h"
32
33 /******************************************************************************
34  Server side encryption.
35 ******************************************************************************/
36
37 /******************************************************************************
38  Return global enc context - this must change if we ever do multiple contexts.
39 ******************************************************************************/
40
41 static uint16_t srv_enc_ctx(const struct smb_trans_enc_state *es)
42 {
43         return es->enc_ctx_num;
44 }
45
46 /******************************************************************************
47  Is this an incoming encrypted packet ?
48 ******************************************************************************/
49
50 bool is_encrypted_packet(struct smbd_server_connection *sconn,
51                          const uint8_t *inbuf)
52 {
53         NTSTATUS status;
54         uint16_t enc_num;
55
56         /* Ignore non-session messages or non 0xFF'E' messages. */
57         if(CVAL(inbuf,0)
58            || (smb_len(inbuf) < 8)
59            || !(inbuf[4] == 0xFF && inbuf[5] == 'E')) {
60                 return false;
61         }
62
63         status = get_enc_ctx_num(inbuf, &enc_num);
64         if (!NT_STATUS_IS_OK(status)) {
65                 return false;
66         }
67
68         /* Encrypted messages are 0xFF'E'<ctx> */
69         if (srv_trans_enc_ctx && enc_num == srv_enc_ctx(srv_trans_enc_ctx)) {
70                 return true;
71         }
72         return false;
73 }
74
75 /******************************************************************************
76  Create an gensec_security and ensure pointer copy is correct.
77 ******************************************************************************/
78
79 static NTSTATUS make_auth_ntlmssp(const struct tsocket_address *remote_address,
80                                   struct smb_trans_enc_state *es)
81 {
82         struct gensec_security *gensec_security;
83         NTSTATUS status = auth_generic_prepare(NULL, remote_address,
84                                                &gensec_security);
85         if (!NT_STATUS_IS_OK(status)) {
86                 return nt_status_squash(status);
87         }
88
89         gensec_want_feature(gensec_security, GENSEC_FEATURE_SEAL);
90
91         status = gensec_start_mech_by_oid(gensec_security, GENSEC_OID_NTLMSSP);
92
93         if (!NT_STATUS_IS_OK(status)) {
94                 TALLOC_FREE(gensec_security);
95                 return nt_status_squash(status);
96         }
97
98         /* We do not need the auth_ntlmssp layer any more, which was
99          * allocated on NULL, so promote gensec_security to the NULL
100          * context */
101         es->s.gensec_security = gensec_security;
102
103         return status;
104 }
105
106 #if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
107
108 /******************************************************************************
109  Import a name.
110 ******************************************************************************/
111
112 static NTSTATUS get_srv_gss_creds(const char *service,
113                                 const char *name,
114                                 gss_cred_usage_t cred_type,
115                                 gss_cred_id_t *p_srv_cred)
116 {
117         OM_uint32 ret;
118         OM_uint32 min;
119         gss_name_t srv_name;
120         gss_buffer_desc input_name;
121         char *host_princ_s = NULL;
122         NTSTATUS status = NT_STATUS_OK;
123
124         gss_OID_desc nt_hostbased_service =
125         {10, discard_const_p(char, "\x2a\x86\x48\x86\xf7\x12\x01\x02\x01\x04")};
126
127         if (asprintf(&host_princ_s, "%s@%s", service, name) == -1) {
128                 return NT_STATUS_NO_MEMORY;
129         }
130
131         input_name.value = host_princ_s;
132         input_name.length = strlen(host_princ_s) + 1;
133
134         ret = gss_import_name(&min,
135                                 &input_name,
136                                 &nt_hostbased_service,
137                                 &srv_name);
138
139         DEBUG(10,("get_srv_gss_creds: imported name %s\n",
140                 host_princ_s ));
141
142         if (ret != GSS_S_COMPLETE) {
143                 SAFE_FREE(host_princ_s);
144                 return map_nt_error_from_gss(ret, min);
145         }
146
147         /*
148          * We're accessing the krb5.keytab file here.
149          * ensure we have permissions to do so.
150          */
151         become_root();
152
153         ret = gss_acquire_cred(&min,
154                                 srv_name,
155                                 GSS_C_INDEFINITE,
156                                 GSS_C_NULL_OID_SET,
157                                 cred_type,
158                                 p_srv_cred,
159                                 NULL,
160                                 NULL);
161         unbecome_root();
162
163         if (ret != GSS_S_COMPLETE) {
164                 ADS_STATUS adss = ADS_ERROR_GSS(ret, min);
165                 DEBUG(10,("get_srv_gss_creds: gss_acquire_cred failed with %s\n",
166                         ads_errstr(adss)));
167                 status = map_nt_error_from_gss(ret, min);
168         }
169
170         SAFE_FREE(host_princ_s);
171         gss_release_name(&min, &srv_name);
172         return status;
173 }
174
175 /******************************************************************************
176  Create a gss state.
177  Try and get the cifs/server@realm principal first, then fall back to
178  host/server@realm.
179 ******************************************************************************/
180
181 static NTSTATUS make_auth_gss(struct smb_trans_enc_state *es)
182 {
183         NTSTATUS status;
184         gss_cred_id_t srv_cred;
185         fstring fqdn;
186
187         name_to_fqdn(fqdn, lp_netbios_name());
188         strlower_m(fqdn);
189
190         status = get_srv_gss_creds("cifs", fqdn, GSS_C_ACCEPT, &srv_cred);
191         if (!NT_STATUS_IS_OK(status)) {
192                 status = get_srv_gss_creds("host", fqdn, GSS_C_ACCEPT, &srv_cred);
193                 if (!NT_STATUS_IS_OK(status)) {
194                         return nt_status_squash(status);
195                 }
196         }
197
198         es->s.gss_state = SMB_MALLOC_P(struct smb_tran_enc_state_gss);
199         if (!es->s.gss_state) {
200                 OM_uint32 min;
201                 gss_release_cred(&min, &srv_cred);
202                 return NT_STATUS_NO_MEMORY;
203         }
204         ZERO_STRUCTP(es->s.gss_state);
205         es->s.gss_state->creds = srv_cred;
206
207         /* No context yet. */
208         es->s.gss_state->gss_ctx = GSS_C_NO_CONTEXT;
209
210         return NT_STATUS_OK;
211 }
212 #endif
213
214 /******************************************************************************
215  Shutdown a server encryption context.
216 ******************************************************************************/
217
218 static void srv_free_encryption_context(struct smb_trans_enc_state **pp_es)
219 {
220         struct smb_trans_enc_state *es = *pp_es;
221
222         if (!es) {
223                 return;
224         }
225
226         common_free_encryption_state(&es);
227
228         SAFE_FREE(es);
229         *pp_es = NULL;
230 }
231
232 /******************************************************************************
233  Create a server encryption context.
234 ******************************************************************************/
235
236 static NTSTATUS make_srv_encryption_context(const struct tsocket_address *remote_address,
237                                             enum smb_trans_enc_type smb_enc_type,
238                                             struct smb_trans_enc_state **pp_es)
239 {
240         struct smb_trans_enc_state *es;
241
242         *pp_es = NULL;
243
244         ZERO_STRUCTP(partial_srv_trans_enc_ctx);
245         es = SMB_MALLOC_P(struct smb_trans_enc_state);
246         if (!es) {
247                 return NT_STATUS_NO_MEMORY;
248         }
249         ZERO_STRUCTP(es);
250         es->smb_enc_type = smb_enc_type;
251         switch (smb_enc_type) {
252                 case SMB_TRANS_ENC_NTLM:
253                         {
254                                 NTSTATUS status = make_auth_ntlmssp(remote_address,
255                                                                     es);
256                                 if (!NT_STATUS_IS_OK(status)) {
257                                         srv_free_encryption_context(&es);
258                                         return status;
259                                 }
260                         }
261                         break;
262
263 #if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
264                 case SMB_TRANS_ENC_GSS:
265                         /* Acquire our credentials by calling gss_acquire_cred here. */
266                         {
267                                 NTSTATUS status = make_auth_gss(es);
268                                 if (!NT_STATUS_IS_OK(status)) {
269                                         srv_free_encryption_context(&es);
270                                         return status;
271                                 }
272                         }
273                         break;
274 #endif
275                 default:
276                         srv_free_encryption_context(&es);
277                         return NT_STATUS_INVALID_PARAMETER;
278         }
279         *pp_es = es;
280         return NT_STATUS_OK;
281 }
282
283 /******************************************************************************
284  Free an encryption-allocated buffer.
285 ******************************************************************************/
286
287 void srv_free_enc_buffer(struct smbd_server_connection *sconn, char *buf)
288 {
289         /* We know this is an smb buffer, and we
290          * didn't malloc, only copy, for a keepalive,
291          * so ignore non-session messages. */
292
293         if(CVAL(buf,0)) {
294                 return;
295         }
296
297         if (srv_trans_enc_ctx) {
298                 common_free_enc_buffer(srv_trans_enc_ctx, buf);
299         }
300 }
301
302 /******************************************************************************
303  Decrypt an incoming buffer.
304 ******************************************************************************/
305
306 NTSTATUS srv_decrypt_buffer(struct smbd_server_connection *sconn, char *buf)
307 {
308         /* Ignore non-session messages. */
309         if(CVAL(buf,0)) {
310                 return NT_STATUS_OK;
311         }
312
313         if (srv_trans_enc_ctx) {
314                 return common_decrypt_buffer(srv_trans_enc_ctx, buf);
315         }
316
317         return NT_STATUS_OK;
318 }
319
320 /******************************************************************************
321  Encrypt an outgoing buffer. Return the encrypted pointer in buf_out.
322 ******************************************************************************/
323
324 NTSTATUS srv_encrypt_buffer(struct smbd_server_connection *sconn, char *buf,
325                             char **buf_out)
326 {
327         *buf_out = buf;
328
329         /* Ignore non-session messages. */
330         if(CVAL(buf,0)) {
331                 return NT_STATUS_OK;
332         }
333
334         if (srv_trans_enc_ctx) {
335                 return common_encrypt_buffer(srv_trans_enc_ctx, buf, buf_out);
336         }
337         /* Not encrypting. */
338         return NT_STATUS_OK;
339 }
340
341 /******************************************************************************
342  Do the gss encryption negotiation. Parameters are in/out.
343  Until success we do everything on the partial enc ctx.
344 ******************************************************************************/
345
346 #if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
347 static NTSTATUS srv_enc_spnego_gss_negotiate(const struct tsocket_address *remote_address,
348                                              unsigned char **ppdata,
349                                              size_t *p_data_size,
350                                              DATA_BLOB secblob)
351 {
352         OM_uint32 ret;
353         OM_uint32 min;
354         OM_uint32 flags = 0;
355         gss_buffer_desc in_buf, out_buf;
356         struct smb_tran_enc_state_gss *gss_state;
357         DATA_BLOB auth_reply = data_blob_null;
358         DATA_BLOB response = data_blob_null;
359         NTSTATUS status;
360
361         if (!partial_srv_trans_enc_ctx) {
362                 status = make_srv_encryption_context(remote_address,
363                                                      SMB_TRANS_ENC_GSS,
364                                                      &partial_srv_trans_enc_ctx);
365                 if (!NT_STATUS_IS_OK(status)) {
366                         return status;
367                 }
368         }
369
370         gss_state = partial_srv_trans_enc_ctx->s.gss_state;
371
372         in_buf.value = secblob.data;
373         in_buf.length = secblob.length;
374
375         out_buf.value = NULL;
376         out_buf.length = 0;
377
378         become_root();
379
380         ret = gss_accept_sec_context(&min,
381                                 &gss_state->gss_ctx,
382                                 gss_state->creds,
383                                 &in_buf,
384                                 GSS_C_NO_CHANNEL_BINDINGS,
385                                 NULL,
386                                 NULL,           /* Ignore oids. */
387                                 &out_buf,       /* To return. */
388                                 &flags,
389                                 NULL,           /* Ingore time. */
390                                 NULL);          /* Ignore delegated creds. */
391         unbecome_root();
392
393         status = gss_err_to_ntstatus(ret, min);
394         if (ret != GSS_S_COMPLETE && ret != GSS_S_CONTINUE_NEEDED) {
395                 return status;
396         }
397
398         /* Ensure we've got sign+seal available. */
399         if (ret == GSS_S_COMPLETE) {
400                 if ((flags & (GSS_C_INTEG_FLAG|GSS_C_CONF_FLAG|GSS_C_REPLAY_FLAG|GSS_C_SEQUENCE_FLAG)) !=
401                                 (GSS_C_INTEG_FLAG|GSS_C_CONF_FLAG|GSS_C_REPLAY_FLAG|GSS_C_SEQUENCE_FLAG)) {
402                         DEBUG(0,("srv_enc_spnego_gss_negotiate: quality of service not good enough "
403                                 "for SMB sealing.\n"));
404                         gss_release_buffer(&min, &out_buf);
405                         return NT_STATUS_ACCESS_DENIED;
406                 }
407         }
408
409         auth_reply = data_blob(out_buf.value, out_buf.length);
410         gss_release_buffer(&min, &out_buf);
411
412         /* Wrap in SPNEGO. */
413         response = spnego_gen_auth_response(talloc_tos(), &auth_reply, status, OID_KERBEROS5);
414         data_blob_free(&auth_reply);
415
416         SAFE_FREE(*ppdata);
417         *ppdata = (unsigned char *)memdup(response.data, response.length);
418         if ((*ppdata) == NULL && response.length > 0) {
419                 status = NT_STATUS_NO_MEMORY;
420         }
421         *p_data_size = response.length;
422
423         data_blob_free(&response);
424
425         return status;
426 }
427 #endif
428
429 /******************************************************************************
430  Do the NTLM SPNEGO (or raw) encryption negotiation. Parameters are in/out.
431  Until success we do everything on the partial enc ctx.
432 ******************************************************************************/
433
434 static NTSTATUS srv_enc_ntlm_negotiate(const struct tsocket_address *remote_address,
435                                        unsigned char **ppdata,
436                                        size_t *p_data_size,
437                                        DATA_BLOB secblob,
438                                        bool spnego_wrap)
439 {
440         NTSTATUS status;
441         DATA_BLOB chal = data_blob_null;
442         DATA_BLOB response = data_blob_null;
443
444         status = make_srv_encryption_context(remote_address,
445                                              SMB_TRANS_ENC_NTLM,
446                                              &partial_srv_trans_enc_ctx);
447         if (!NT_STATUS_IS_OK(status)) {
448                 return status;
449         }
450
451         status = gensec_update(partial_srv_trans_enc_ctx->s.gensec_security,
452                                talloc_tos(), NULL,
453                                secblob, &chal);
454
455         /* status here should be NT_STATUS_MORE_PROCESSING_REQUIRED
456          * for success ... */
457
458         if (spnego_wrap) {
459                 response = spnego_gen_auth_response(talloc_tos(), &chal, status, OID_NTLMSSP);
460                 data_blob_free(&chal);
461         } else {
462                 /* Return the raw blob. */
463                 response = chal;
464         }
465
466         SAFE_FREE(*ppdata);
467         *ppdata = (unsigned char *)memdup(response.data, response.length);
468         if ((*ppdata) == NULL && response.length > 0) {
469                 status = NT_STATUS_NO_MEMORY;
470         }
471         *p_data_size = response.length;
472         data_blob_free(&response);
473
474         return status;
475 }
476
477 /******************************************************************************
478  Do the SPNEGO encryption negotiation. Parameters are in/out.
479  Based off code in smbd/sesssionsetup.c
480  Until success we do everything on the partial enc ctx.
481 ******************************************************************************/
482
483 static NTSTATUS srv_enc_spnego_negotiate(connection_struct *conn,
484                                         unsigned char **ppdata,
485                                         size_t *p_data_size,
486                                         unsigned char **pparam,
487                                         size_t *p_param_size)
488 {
489         NTSTATUS status;
490         DATA_BLOB blob = data_blob_null;
491         DATA_BLOB secblob = data_blob_null;
492         char *kerb_mech = NULL;
493
494         blob = data_blob_const(*ppdata, *p_data_size);
495
496         status = parse_spnego_mechanisms(talloc_tos(), blob, &secblob, &kerb_mech);
497         if (!NT_STATUS_IS_OK(status)) {
498                 return nt_status_squash(status);
499         }
500
501         /* We should have no partial context at this point. */
502
503         srv_free_encryption_context(&partial_srv_trans_enc_ctx);
504
505         if (kerb_mech) {
506                 TALLOC_FREE(kerb_mech);
507
508 #if defined(HAVE_GSSAPI) && defined(HAVE_KRB5)
509                 status = srv_enc_spnego_gss_negotiate(conn->sconn->remote_address,
510                                                       ppdata,
511                                                       p_data_size,
512                                                       secblob);
513 #else
514                 /* Currently we don't SPNEGO negotiate
515                  * back to NTLMSSP as we do in sessionsetupX. We should... */
516                 return NT_STATUS_LOGON_FAILURE;
517 #endif
518         } else {
519                 status = srv_enc_ntlm_negotiate(conn->sconn->remote_address,
520                                                 ppdata,
521                                                 p_data_size,
522                                                 secblob,
523                                                 true);
524         }
525
526         data_blob_free(&secblob);
527
528         if (!NT_STATUS_EQUAL(status,NT_STATUS_MORE_PROCESSING_REQUIRED) && !NT_STATUS_IS_OK(status)) {
529                 srv_free_encryption_context(&partial_srv_trans_enc_ctx);
530                 return nt_status_squash(status);
531         }
532
533         if (NT_STATUS_IS_OK(status)) {
534                 /* Return the context we're using for this encryption state. */
535                 if (!(*pparam = SMB_MALLOC_ARRAY(unsigned char, 2))) {
536                         return NT_STATUS_NO_MEMORY;
537                 }
538                 SSVAL(*pparam,0,partial_srv_trans_enc_ctx->enc_ctx_num);
539                 *p_param_size = 2;
540         }
541
542         return status;
543 }
544
545 /******************************************************************************
546  Complete a SPNEGO encryption negotiation. Parameters are in/out.
547  We only get this for a NTLM auth second stage.
548 ******************************************************************************/
549
550 static NTSTATUS srv_enc_spnego_ntlm_auth(connection_struct *conn,
551                                         unsigned char **ppdata,
552                                         size_t *p_data_size,
553                                         unsigned char **pparam,
554                                         size_t *p_param_size)
555 {
556         NTSTATUS status;
557         DATA_BLOB blob = data_blob_null;
558         DATA_BLOB auth = data_blob_null;
559         DATA_BLOB auth_reply = data_blob_null;
560         DATA_BLOB response = data_blob_null;
561         struct smb_trans_enc_state *es = partial_srv_trans_enc_ctx;
562
563         /* We must have a partial context here. */
564
565         if (!es || es->s.gensec_security == NULL || es->smb_enc_type != SMB_TRANS_ENC_NTLM) {
566                 srv_free_encryption_context(&partial_srv_trans_enc_ctx);
567                 return NT_STATUS_INVALID_PARAMETER;
568         }
569
570         blob = data_blob_const(*ppdata, *p_data_size);
571         if (!spnego_parse_auth(talloc_tos(), blob, &auth)) {
572                 srv_free_encryption_context(&partial_srv_trans_enc_ctx);
573                 return NT_STATUS_INVALID_PARAMETER;
574         }
575
576         status = gensec_update(es->s.gensec_security, talloc_tos(), NULL, auth, &auth_reply);
577         data_blob_free(&auth);
578
579         /* From RFC4178.
580          *
581          *    supportedMech
582          *
583          *          This field SHALL only be present in the first reply from the
584          *                target.
585          * So set mechOID to NULL here.
586          */
587
588         response = spnego_gen_auth_response(talloc_tos(), &auth_reply, status, NULL);
589         data_blob_free(&auth_reply);
590
591         if (NT_STATUS_IS_OK(status)) {
592                 /* Return the context we're using for this encryption state. */
593                 if (!(*pparam = SMB_MALLOC_ARRAY(unsigned char, 2))) {
594                         return NT_STATUS_NO_MEMORY;
595                 }
596                 SSVAL(*pparam,0,es->enc_ctx_num);
597                 *p_param_size = 2;
598         }
599
600         SAFE_FREE(*ppdata);
601         *ppdata = (unsigned char *)memdup(response.data, response.length);
602         if ((*ppdata) == NULL && response.length > 0)
603                 return NT_STATUS_NO_MEMORY;
604         *p_data_size = response.length;
605         data_blob_free(&response);
606         return status;
607 }
608
609 /******************************************************************************
610  Raw NTLM encryption negotiation. Parameters are in/out.
611  This function does both steps.
612 ******************************************************************************/
613
614 static NTSTATUS srv_enc_raw_ntlm_auth(connection_struct *conn,
615                                         unsigned char **ppdata,
616                                         size_t *p_data_size,
617                                         unsigned char **pparam,
618                                         size_t *p_param_size)
619 {
620         NTSTATUS status;
621         DATA_BLOB blob = data_blob_const(*ppdata, *p_data_size);
622         DATA_BLOB response = data_blob_null;
623         struct smb_trans_enc_state *es;
624
625         if (!partial_srv_trans_enc_ctx) {
626                 /* This is the initial step. */
627                 status = srv_enc_ntlm_negotiate(conn->sconn->remote_address,
628                                                 ppdata,
629                                                 p_data_size,
630                                                 blob,
631                                                 false);
632                 if (!NT_STATUS_EQUAL(status,NT_STATUS_MORE_PROCESSING_REQUIRED) && !NT_STATUS_IS_OK(status)) {
633                         srv_free_encryption_context(&partial_srv_trans_enc_ctx);
634                         return nt_status_squash(status);
635                 }
636                 return status;
637         }
638
639         es = partial_srv_trans_enc_ctx;
640         if (!es || es->s.gensec_security == NULL || es->smb_enc_type != SMB_TRANS_ENC_NTLM) {
641                 srv_free_encryption_context(&partial_srv_trans_enc_ctx);
642                 return NT_STATUS_INVALID_PARAMETER;
643         }
644
645         /* Second step. */
646         status = gensec_update(partial_srv_trans_enc_ctx->s.gensec_security,
647                                talloc_tos(), NULL,
648                                blob, &response);
649
650         if (NT_STATUS_IS_OK(status)) {
651                 /* Return the context we're using for this encryption state. */
652                 if (!(*pparam = SMB_MALLOC_ARRAY(unsigned char, 2))) {
653                         return NT_STATUS_NO_MEMORY;
654                 }
655                 SSVAL(*pparam, 0, es->enc_ctx_num);
656                 *p_param_size = 2;
657         }
658
659         /* Return the raw blob. */
660         SAFE_FREE(*ppdata);
661         *ppdata = (unsigned char *)memdup(response.data, response.length);
662         if ((*ppdata) == NULL && response.length > 0)
663                 return NT_STATUS_NO_MEMORY;
664         *p_data_size = response.length;
665         data_blob_free(&response);
666         return status;
667 }
668
669 /******************************************************************************
670  Do the SPNEGO encryption negotiation. Parameters are in/out.
671 ******************************************************************************/
672
673 NTSTATUS srv_request_encryption_setup(connection_struct *conn,
674                                         unsigned char **ppdata,
675                                         size_t *p_data_size,
676                                         unsigned char **pparam,
677                                         size_t *p_param_size)
678 {
679         unsigned char *pdata = *ppdata;
680
681         SAFE_FREE(*pparam);
682         *p_param_size = 0;
683
684         if (*p_data_size < 1) {
685                 return NT_STATUS_INVALID_PARAMETER;
686         }
687
688         if (pdata[0] == ASN1_APPLICATION(0)) {
689                 /* its a negTokenTarg packet */
690                 return srv_enc_spnego_negotiate(conn, ppdata, p_data_size, pparam, p_param_size);
691         }
692
693         if (pdata[0] == ASN1_CONTEXT(1)) {
694                 /* It's an auth packet */
695                 return srv_enc_spnego_ntlm_auth(conn, ppdata, p_data_size, pparam, p_param_size);
696         }
697
698         /* Maybe it's a raw unwrapped auth ? */
699         if (*p_data_size < 7) {
700                 return NT_STATUS_INVALID_PARAMETER;
701         }
702
703         if (strncmp((char *)pdata, "NTLMSSP", 7) == 0) {
704                 return srv_enc_raw_ntlm_auth(conn, ppdata, p_data_size, pparam, p_param_size);
705         }
706
707         DEBUG(1,("srv_request_encryption_setup: Unknown packet\n"));
708
709         return NT_STATUS_LOGON_FAILURE;
710 }
711
712 /******************************************************************************
713  Negotiation was successful - turn on server-side encryption.
714 ******************************************************************************/
715
716 static NTSTATUS check_enc_good(struct smb_trans_enc_state *es)
717 {
718         if (!es) {
719                 return NT_STATUS_LOGON_FAILURE;
720         }
721
722         if (es->smb_enc_type == SMB_TRANS_ENC_NTLM) {
723                 if (!gensec_have_feature(es->s.gensec_security, GENSEC_FEATURE_SIGN)) {
724                         return NT_STATUS_INVALID_PARAMETER;
725                 }
726
727                 if (!gensec_have_feature(es->s.gensec_security, GENSEC_FEATURE_SEAL)) {
728                         return NT_STATUS_INVALID_PARAMETER;
729                 }
730         }
731         /* Todo - check gssapi case. */
732
733         return NT_STATUS_OK;
734 }
735
736 /******************************************************************************
737  Negotiation was successful - turn on server-side encryption.
738 ******************************************************************************/
739
740 NTSTATUS srv_encryption_start(connection_struct *conn)
741 {
742         NTSTATUS status;
743
744         /* Check that we are really doing sign+seal. */
745         status = check_enc_good(partial_srv_trans_enc_ctx);
746         if (!NT_STATUS_IS_OK(status)) {
747                 return status;
748         }
749         /* Throw away the context we're using currently (if any). */
750         srv_free_encryption_context(&srv_trans_enc_ctx);
751
752         /* Steal the partial pointer. Deliberate shallow copy. */
753         srv_trans_enc_ctx = partial_srv_trans_enc_ctx;
754         srv_trans_enc_ctx->enc_on = true;
755
756         partial_srv_trans_enc_ctx = NULL;
757
758         DEBUG(1,("srv_encryption_start: context negotiated\n"));
759         return NT_STATUS_OK;
760 }
761
762 /******************************************************************************
763  Shutdown all server contexts.
764 ******************************************************************************/
765
766 void server_encryption_shutdown(struct smbd_server_connection *sconn)
767 {
768         srv_free_encryption_context(&partial_srv_trans_enc_ctx);
769         srv_free_encryption_context(&srv_trans_enc_ctx);
770 }