s3-gse: Use the session key type, not the lucid context to set NEW_SPNEGO
[ab/samba.git/.git] / source3 / librpc / crypto / cli_spnego.c
1 /*
2  *  SPNEGO Encapsulation
3  *  Client functions
4  *  Copyright (C) Simo Sorce 2010.
5  *  Copyright (C) Andrew Bartlett 2011.
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License as published by
9  *  the Free Software Foundation; either version 3 of the License, or
10  *  (at your option) any later version.
11  *
12  *  This program is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU General Public License for more details.
16  *
17  *  You should have received a copy of the GNU General Public License
18  *  along with this program; if not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #include "includes.h"
22 #include "../libcli/auth/spnego.h"
23 #include "include/auth_generic.h"
24 #include "librpc/gen_ndr/ntlmssp.h"
25 #include "auth/ntlmssp/ntlmssp.h"
26 #include "librpc/crypto/gse.h"
27 #include "librpc/crypto/spnego.h"
28 #include "auth/gensec/gensec.h"
29
30 static NTSTATUS spnego_context_init(TALLOC_CTX *mem_ctx,
31                                     bool do_sign, bool do_seal,
32                                     struct spnego_context **spnego_ctx)
33 {
34         struct spnego_context *sp_ctx;
35
36         sp_ctx = talloc_zero(mem_ctx, struct spnego_context);
37         if (!sp_ctx) {
38                 return NT_STATUS_NO_MEMORY;
39         }
40
41         sp_ctx->do_sign = do_sign;
42         sp_ctx->do_seal = do_seal;
43         sp_ctx->state = SPNEGO_CONV_INIT;
44
45         *spnego_ctx = sp_ctx;
46         return NT_STATUS_OK;
47 }
48
49 NTSTATUS spnego_generic_init_client(TALLOC_CTX *mem_ctx,
50                                     const char *oid,
51                                     bool do_sign, bool do_seal,
52                                     bool is_dcerpc,
53                                     const char *server,
54                                     const char *target_service,
55                                     const char *domain,
56                                     const char *username,
57                                     const char *password,
58                                     struct spnego_context **spnego_ctx)
59 {
60         struct spnego_context *sp_ctx = NULL;
61         struct auth_generic_state *auth_generic_state;
62         NTSTATUS status;
63
64         status = spnego_context_init(mem_ctx, do_sign, do_seal, &sp_ctx);
65         if (!NT_STATUS_IS_OK(status)) {
66                 return status;
67         }
68         if (strcmp(oid, GENSEC_OID_NTLMSSP) == 0) {
69                 sp_ctx->mech = SPNEGO_NTLMSSP;
70         } else if (strcmp(oid, GENSEC_OID_KERBEROS5) == 0) {
71                 sp_ctx->mech = SPNEGO_KRB5;
72         } else {
73                 return NT_STATUS_INVALID_PARAMETER;
74         }
75
76         status = auth_generic_client_prepare(sp_ctx,
77                                         &auth_generic_state);
78         if (!NT_STATUS_IS_OK(status)) {
79                 TALLOC_FREE(sp_ctx);
80                 return status;
81         }
82
83         status = auth_generic_set_username(auth_generic_state,
84                                            username);
85         if (!NT_STATUS_IS_OK(status)) {
86                 TALLOC_FREE(sp_ctx);
87                 return status;
88         }
89
90         status = auth_generic_set_domain(auth_generic_state,
91                                          domain);
92         if (!NT_STATUS_IS_OK(status)) {
93                 TALLOC_FREE(sp_ctx);
94                 return status;
95         }
96
97         status = auth_generic_set_password(auth_generic_state,
98                                            password);
99         if (!NT_STATUS_IS_OK(status)) {
100                 TALLOC_FREE(sp_ctx);
101                 return status;
102         }
103
104         if (do_sign) {
105                 gensec_want_feature(auth_generic_state->gensec_security,
106                                           GENSEC_FEATURE_SIGN);
107         } else if (do_seal) {
108                 gensec_want_feature(auth_generic_state->gensec_security,
109                                           GENSEC_FEATURE_SEAL);
110         }
111
112         if (is_dcerpc) {
113                 gensec_want_feature(auth_generic_state->gensec_security,
114                                     GENSEC_FEATURE_DCE_STYLE);
115         }
116
117         status = gensec_set_target_service(auth_generic_state->gensec_security, target_service);
118         if (!NT_STATUS_IS_OK(status)) {
119                 TALLOC_FREE(sp_ctx);
120                 return status;
121         }
122
123         status = gensec_set_target_hostname(auth_generic_state->gensec_security, server);
124         if (!NT_STATUS_IS_OK(status)) {
125                 TALLOC_FREE(sp_ctx);
126                 return status;
127         }
128
129         status = auth_generic_client_start(auth_generic_state, oid);
130         if (!NT_STATUS_IS_OK(status)) {
131                 TALLOC_FREE(sp_ctx);
132                 return status;
133         }
134
135         sp_ctx->gensec_security = talloc_move(sp_ctx, &auth_generic_state->gensec_security);
136         TALLOC_FREE(auth_generic_state);
137         *spnego_ctx = sp_ctx;
138         return NT_STATUS_OK;
139 }
140
141 NTSTATUS spnego_get_client_auth_token(TALLOC_CTX *mem_ctx,
142                                       struct spnego_context *sp_ctx,
143                                       DATA_BLOB *spnego_in,
144                                       DATA_BLOB *spnego_out)
145 {
146         struct gensec_security *gensec_security;
147         struct spnego_data sp_in, sp_out;
148         DATA_BLOB token_in = data_blob_null;
149         DATA_BLOB token_out = data_blob_null;
150         const char *mech_oids[2] = { NULL, NULL };
151         char *principal = NULL;
152         ssize_t len_in = 0;
153         ssize_t len_out = 0;
154         NTSTATUS status;
155
156         if (!spnego_in->length) {
157                 /* server didn't send anything, is init ? */
158                 if (sp_ctx->state != SPNEGO_CONV_INIT) {
159                         return NT_STATUS_INVALID_PARAMETER;
160                 }
161         } else {
162                 len_in = spnego_read_data(mem_ctx, *spnego_in, &sp_in);
163                 if (len_in == -1) {
164                         status = NT_STATUS_INVALID_PARAMETER;
165                         goto done;
166                 }
167                 if (sp_in.type != SPNEGO_NEG_TOKEN_TARG) {
168                         status = NT_STATUS_INVALID_PARAMETER;
169                         goto done;
170                 }
171                 if (sp_in.negTokenTarg.negResult == SPNEGO_REJECT) {
172                         status = NT_STATUS_ACCESS_DENIED;
173                         goto done;
174                 }
175                 token_in = sp_in.negTokenTarg.responseToken;
176         }
177
178         if (sp_ctx->state == SPNEGO_CONV_AUTH_CONFIRM) {
179                 if (sp_in.negTokenTarg.negResult == SPNEGO_ACCEPT_COMPLETED) {
180                         sp_ctx->state = SPNEGO_CONV_AUTH_DONE;
181                         *spnego_out = data_blob_null;
182                         status = NT_STATUS_OK;
183                 } else {
184                         status = NT_STATUS_ACCESS_DENIED;
185                 }
186                 goto done;
187         }
188
189         switch (sp_ctx->mech) {
190         case SPNEGO_KRB5:
191                 mech_oids[0] = OID_KERBEROS5;
192                 break;
193
194         case SPNEGO_NTLMSSP:
195                 mech_oids[0] = OID_NTLMSSP;
196                 break;
197
198         default:
199                 status = NT_STATUS_INTERNAL_ERROR;
200                 goto done;
201         }
202
203         gensec_security = sp_ctx->gensec_security;
204         status = gensec_update(gensec_security, mem_ctx, NULL,
205                                token_in, &token_out);
206         sp_ctx->more_processing = false;
207         if (NT_STATUS_EQUAL(status,
208                             NT_STATUS_MORE_PROCESSING_REQUIRED)) {
209                 sp_ctx->more_processing = true;
210         } else if (!NT_STATUS_IS_OK(status)) {
211                 goto done;
212         }
213
214         switch (sp_ctx->state) {
215         case SPNEGO_CONV_INIT:
216                 *spnego_out = spnego_gen_negTokenInit(mem_ctx, mech_oids,
217                                                       &token_out, principal);
218                 if (!spnego_out->data) {
219                         status = NT_STATUS_INTERNAL_ERROR;
220                         goto done;
221                 }
222                 sp_ctx->state = SPNEGO_CONV_AUTH_MORE;
223                 break;
224
225         case SPNEGO_CONV_AUTH_MORE:
226                 /* server says it's done and we do not seem to agree */
227                 if (sp_in.negTokenTarg.negResult ==
228                                                 SPNEGO_ACCEPT_COMPLETED) {
229                         status = NT_STATUS_INVALID_PARAMETER;
230                         goto done;
231                 }
232
233                 sp_out.type = SPNEGO_NEG_TOKEN_TARG;
234                 sp_out.negTokenTarg.negResult = SPNEGO_NONE_RESULT;
235                 sp_out.negTokenTarg.supportedMech = NULL;
236                 sp_out.negTokenTarg.responseToken = token_out;
237                 sp_out.negTokenTarg.mechListMIC = data_blob_null;
238
239                 len_out = spnego_write_data(mem_ctx, spnego_out, &sp_out);
240                 if (len_out == -1) {
241                         status = NT_STATUS_INTERNAL_ERROR;
242                         goto done;
243                 }
244
245                 if (!sp_ctx->more_processing) {
246                         /* we still need to get an ack from the server */
247                         sp_ctx->state = SPNEGO_CONV_AUTH_CONFIRM;
248                 }
249
250                 break;
251
252         default:
253                 status = NT_STATUS_INTERNAL_ERROR;
254                 goto done;
255         }
256
257         status = NT_STATUS_OK;
258
259 done:
260         if (len_in > 0) {
261                 spnego_free_data(&sp_in);
262         }
263         data_blob_free(&token_out);
264         return status;
265 }
266
267 bool spnego_require_more_processing(struct spnego_context *sp_ctx)
268 {
269
270         /* see if spnego processing itself requires more */
271         if (sp_ctx->state == SPNEGO_CONV_AUTH_MORE ||
272             sp_ctx->state == SPNEGO_CONV_AUTH_CONFIRM) {
273                 return true;
274         }
275
276         return sp_ctx->more_processing;
277 }
278
279 NTSTATUS spnego_get_negotiated_mech(struct spnego_context *sp_ctx,
280                                     struct gensec_security **auth_context)
281 {
282         *auth_context = sp_ctx->gensec_security;
283         return NT_STATUS_OK;
284 }
285
286 NTSTATUS spnego_sign(TALLOC_CTX *mem_ctx,
287                         struct spnego_context *sp_ctx,
288                         DATA_BLOB *data, DATA_BLOB *full_data,
289                         DATA_BLOB *signature)
290 {
291         return gensec_sign_packet(
292                 sp_ctx->gensec_security,
293                 mem_ctx,
294                 data->data, data->length,
295                 full_data->data, full_data->length,
296                 signature);
297 }
298
299 NTSTATUS spnego_sigcheck(TALLOC_CTX *mem_ctx,
300                          struct spnego_context *sp_ctx,
301                          DATA_BLOB *data, DATA_BLOB *full_data,
302                          DATA_BLOB *signature)
303 {
304         return gensec_check_packet(
305                 sp_ctx->gensec_security,
306                 data->data, data->length,
307                 full_data->data, full_data->length,
308                 signature);
309 }
310
311 NTSTATUS spnego_seal(TALLOC_CTX *mem_ctx,
312                         struct spnego_context *sp_ctx,
313                         DATA_BLOB *data, DATA_BLOB *full_data,
314                         DATA_BLOB *signature)
315 {
316         return gensec_seal_packet(
317                 sp_ctx->gensec_security,
318                 mem_ctx,
319                 data->data, data->length,
320                 full_data->data, full_data->length,
321                 signature);
322 }
323
324 NTSTATUS spnego_unseal(TALLOC_CTX *mem_ctx,
325                         struct spnego_context *sp_ctx,
326                         DATA_BLOB *data, DATA_BLOB *full_data,
327                         DATA_BLOB *signature)
328 {
329         return gensec_unseal_packet(
330                 sp_ctx->gensec_security,
331                 data->data, data->length,
332                 full_data->data, full_data->length,
333                 signature);
334 }