r21882: The server part of the code has to use an AUTH_NTLMSSP struct,
[samba.git] / source / 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 2 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, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include "includes.h"
22
23 /******************************************************************************
24  Server side encryption.
25 ******************************************************************************/
26
27 /******************************************************************************
28  Global server state.
29 ******************************************************************************/
30
31 struct smb_srv_trans_enc_ctx {
32         struct smb_trans_enc_state *es;
33         AUTH_NTLMSSP_STATE *auth_ntlmssp_state; /* Must be kept in sync with pointer in ec->ntlmssp_state. */
34 };
35
36 static struct smb_srv_trans_enc_ctx *partial_srv_trans_enc_ctx;
37 static struct smb_srv_trans_enc_ctx *srv_trans_enc_ctx;
38
39 /******************************************************************************
40  Is server encryption on ?
41 ******************************************************************************/
42
43 BOOL srv_encryption_on(void)
44 {
45         if (srv_trans_enc_ctx) {
46                 return common_encryption_on(srv_trans_enc_ctx->es);
47         }
48         return False;
49 }
50
51 /******************************************************************************
52  Shutdown a server encryption state.
53 ******************************************************************************/
54
55 static void srv_free_encryption_context(struct smb_srv_trans_enc_ctx **pp_ec)
56 {
57         struct smb_srv_trans_enc_ctx *ec = *pp_ec;
58
59         if (!ec) {
60                 return;
61         }
62
63         if (ec->es) {
64                 struct smb_trans_enc_state *es = ec->es;
65                 if (es->smb_enc_type == SMB_TRANS_ENC_NTLM &&
66                                 ec->auth_ntlmssp_state) {
67                         auth_ntlmssp_end(&ec->auth_ntlmssp_state);
68                         /* The auth_ntlmssp_end killed this already. */
69                         es->ntlmssp_state = NULL;
70                 }
71                 common_free_encryption_state(&ec->es);
72         }
73
74         SAFE_FREE(ec);
75         *pp_ec = NULL;
76 }
77
78 /******************************************************************************
79  Free an encryption-allocated buffer.
80 ******************************************************************************/
81
82 void srv_free_enc_buffer(char *buf)
83 {
84         if (srv_trans_enc_ctx) {
85                 return common_free_enc_buffer(srv_trans_enc_ctx->es, buf);
86         }
87 }
88
89 /******************************************************************************
90  Decrypt an incoming buffer.
91 ******************************************************************************/
92
93 NTSTATUS srv_decrypt_buffer(char *buf)
94 {
95         if (srv_trans_enc_ctx) {
96                 return common_decrypt_buffer(srv_trans_enc_ctx->es, buf);
97         }
98         return NT_STATUS_OK;
99 }
100
101 /******************************************************************************
102  Encrypt an outgoing buffer. Return the encrypted pointer in buf_out.
103 ******************************************************************************/
104
105 NTSTATUS srv_encrypt_buffer(char *buffer, char **buf_out)
106 {
107         if (srv_trans_enc_ctx) {
108                 return common_encrypt_buffer(srv_trans_enc_ctx->es, buffer, buf_out);
109         }
110         /* Not encrypting. */
111         *buf_out = buffer;
112         return NT_STATUS_OK;
113 }
114
115 /******************************************************************************
116  Do the gss encryption negotiation. Parameters are in/out.
117  Until success we do everything on the partial enc ctx.
118 ******************************************************************************/
119
120 #if defined(HAVE_GSSAPI_SUPPORT) && defined(HAVE_KRB5)
121 static NTSTATUS srv_enc_spnego_gss_negotiate(char **ppdata, size_t *p_data_size, DATA_BLOB *psecblob)
122 {
123         return NT_STATUS_NOT_SUPPORTED;
124 }
125 #endif
126
127 /******************************************************************************
128  Do the SPNEGO encryption negotiation. Parameters are in/out.
129  Covers the NTLM case. Based off code in smbd/sesssionsetup.c
130  Until success we do everything on the partial enc ctx.
131 ******************************************************************************/
132
133 static NTSTATUS srv_enc_spnego_negotiate(unsigned char **ppdata, size_t *p_data_size)
134 {
135         NTSTATUS status;
136         DATA_BLOB blob = data_blob(NULL,0);
137         DATA_BLOB secblob = data_blob(NULL, 0);
138         DATA_BLOB chal = data_blob(NULL, 0);
139         DATA_BLOB response = data_blob(NULL, 0);
140         BOOL got_kerberos_mechanism = False;
141         struct smb_srv_trans_enc_ctx *ec = NULL;
142
143         blob = data_blob_const(*ppdata, *p_data_size);
144
145         status = parse_spnego_mechanisms(blob, &secblob, &got_kerberos_mechanism);
146         if (!NT_STATUS_IS_OK(status)) {
147                 return nt_status_squash(status);
148         }
149
150         /* We should have no partial context at this point. */
151
152         srv_free_encryption_context(&partial_srv_trans_enc_ctx);
153
154         partial_srv_trans_enc_ctx = SMB_MALLOC_P(struct smb_srv_trans_enc_ctx);
155         if (!partial_srv_trans_enc_ctx) {
156                 data_blob_free(&secblob);
157                 return NT_STATUS_NO_MEMORY;
158         }
159         ZERO_STRUCTP(partial_srv_trans_enc_ctx);
160
161 #if defined(HAVE_GSSAPI_SUPPORT) && defined(HAVE_KRB5)
162         if (got_kerberos_mechanism && lp_use_kerberos_keytab()) ) {
163                 status = srv_enc_spnego_gss_negotiate(ppdata, p_data_size, &secblob);
164                 if (!NT_STATUS_IS_OK(status)) {
165                         data_blob_free(&secblob);
166                         srv_free_encryption_context(&partial_srv_trans_enc_ctx);
167                 }
168                 return status;
169         }
170 #endif
171
172         /* Deal with an NTLM enc. setup. */
173         ec = partial_srv_trans_enc_ctx;
174
175         status = auth_ntlmssp_start(&ec->auth_ntlmssp_state);
176         if (!NT_STATUS_IS_OK(status)) {
177                 srv_free_encryption_context(&partial_srv_trans_enc_ctx);
178                 return nt_status_squash(status);
179         }
180
181         status = auth_ntlmssp_update(ec->auth_ntlmssp_state, secblob, &chal);
182         data_blob_free(&secblob);
183
184         /* status here should be NT_STATUS_MORE_PROCESSING_REQUIRED
185          * for success ... */
186
187         response = spnego_gen_auth_response(&chal, status, OID_NTLMSSP);
188         data_blob_free(&chal);
189
190         SAFE_FREE(*ppdata);
191         *ppdata = response.data;
192         *p_data_size = response.length;
193
194         return status;
195 }
196
197 /******************************************************************************
198  Complete a SPNEGO encryption negotiation. Parameters are in/out.
199 ******************************************************************************/
200
201 static NTSTATUS srv_enc_spnego_auth(unsigned char **ppdata, size_t *p_data_size)
202 {
203         return NT_STATUS_NOT_SUPPORTED;
204 }
205
206 /******************************************************************************
207  Do the SPNEGO encryption negotiation. Parameters are in/out.
208 ******************************************************************************/
209
210 NTSTATUS srv_request_encryption_setup(unsigned char **ppdata, size_t *p_data_size)
211 {
212         unsigned char *pdata = *ppdata;
213
214         if (*p_data_size < 1) {
215                 return NT_STATUS_INVALID_PARAMETER;
216         }
217
218         if (pdata[0] == ASN1_APPLICATION(0)) {
219                 /* 
220                  * Until success we do everything on the partial
221                  * enc state.
222                  */
223                 /* its a negTokenTarg packet */
224                 return srv_enc_spnego_negotiate(ppdata, p_data_size);
225         }
226
227         if (pdata[0] == ASN1_CONTEXT(1)) {
228                 /* Its a auth packet */
229                 return srv_enc_spnego_auth(ppdata, p_data_size);
230         }
231
232         return NT_STATUS_INVALID_PARAMETER;
233 }
234
235 /******************************************************************************
236  Negotiation was successful - turn on server-side encryption.
237 ******************************************************************************/
238
239 void srv_encryption_start(void)
240 {
241         srv_free_encryption_context(&srv_trans_enc_ctx);
242         /* Steal the partial pointer. Deliberate shallow copy. */
243         srv_trans_enc_ctx = partial_srv_trans_enc_ctx;
244         srv_trans_enc_ctx->es->enc_on = True;
245
246         partial_srv_trans_enc_ctx = NULL;
247 }
248
249 /******************************************************************************
250  Shutdown all server contexts.
251 ******************************************************************************/
252
253 void server_encryption_shutdown(void)
254 {
255         srv_free_encryption_context(&partial_srv_trans_enc_ctx);
256         srv_free_encryption_context(&srv_trans_enc_ctx);
257 }