ntlmssp: Move ntlmssp code to auth/ntlmssp
[metze/samba/wip.git] / source3 / librpc / crypto / cli_spnego.c
1 /*
2  *  SPNEGO Encapsulation
3  *  Client functions
4  *  Copyright (C) Simo Sorce 2010.
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 "../libcli/auth/spnego.h"
22 #include "include/ntlmssp_wrap.h"
23 #include "librpc/gen_ndr/ntlmssp.h"
24 #include "auth/ntlmssp/ntlmssp.h"
25 #include "librpc/crypto/gse.h"
26 #include "librpc/crypto/spnego.h"
27
28 static NTSTATUS spnego_context_init(TALLOC_CTX *mem_ctx,
29                                     bool do_sign, bool do_seal,
30                                     struct spnego_context **spnego_ctx)
31 {
32         struct spnego_context *sp_ctx;
33
34         sp_ctx = talloc_zero(mem_ctx, struct spnego_context);
35         if (!sp_ctx) {
36                 return NT_STATUS_NO_MEMORY;
37         }
38
39         sp_ctx->do_sign = do_sign;
40         sp_ctx->do_seal = do_seal;
41         sp_ctx->state = SPNEGO_CONV_INIT;
42
43         *spnego_ctx = sp_ctx;
44         return NT_STATUS_OK;
45 }
46
47 NTSTATUS spnego_gssapi_init_client(TALLOC_CTX *mem_ctx,
48                                    bool do_sign, bool do_seal,
49                                    bool is_dcerpc,
50                                    const char *ccache_name,
51                                    const char *server,
52                                    const char *service,
53                                    const char *username,
54                                    const char *password,
55                                    struct spnego_context **spnego_ctx)
56 {
57         struct spnego_context *sp_ctx = NULL;
58         uint32_t add_gss_c_flags = 0;
59         NTSTATUS status;
60
61         status = spnego_context_init(mem_ctx, do_sign, do_seal, &sp_ctx);
62         if (!NT_STATUS_IS_OK(status)) {
63                 return status;
64         }
65         sp_ctx->mech = SPNEGO_KRB5;
66
67         if (is_dcerpc) {
68                 add_gss_c_flags = GSS_C_DCE_STYLE;
69         }
70
71         status = gse_init_client(sp_ctx,
72                                  do_sign, do_seal,
73                                  ccache_name, server, service,
74                                  username, password, add_gss_c_flags,
75                                  &sp_ctx->mech_ctx.gssapi_state);
76         if (!NT_STATUS_IS_OK(status)) {
77                 TALLOC_FREE(sp_ctx);
78                 return status;
79         }
80
81         *spnego_ctx = sp_ctx;
82         return NT_STATUS_OK;
83 }
84
85 NTSTATUS spnego_ntlmssp_init_client(TALLOC_CTX *mem_ctx,
86                                     bool do_sign, bool do_seal,
87                                     bool is_dcerpc,
88                                     const char *domain,
89                                     const char *username,
90                                     const char *password,
91                                     struct spnego_context **spnego_ctx)
92 {
93         struct spnego_context *sp_ctx = NULL;
94         NTSTATUS status;
95
96         status = spnego_context_init(mem_ctx, do_sign, do_seal, &sp_ctx);
97         if (!NT_STATUS_IS_OK(status)) {
98                 return status;
99         }
100         sp_ctx->mech = SPNEGO_NTLMSSP;
101
102         status = auth_ntlmssp_client_start(sp_ctx,
103                                         lp_netbios_name(),
104                                         lp_workgroup(),
105                                         lp_client_ntlmv2_auth(),
106                                         &sp_ctx->mech_ctx.ntlmssp_state);
107         if (!NT_STATUS_IS_OK(status)) {
108                 TALLOC_FREE(sp_ctx);
109                 return status;
110         }
111
112         status = auth_ntlmssp_set_username(sp_ctx->mech_ctx.ntlmssp_state,
113                                            username);
114         if (!NT_STATUS_IS_OK(status)) {
115                 TALLOC_FREE(sp_ctx);
116                 return status;
117         }
118
119         status = auth_ntlmssp_set_domain(sp_ctx->mech_ctx.ntlmssp_state,
120                                          domain);
121         if (!NT_STATUS_IS_OK(status)) {
122                 TALLOC_FREE(sp_ctx);
123                 return status;
124         }
125
126         status = auth_ntlmssp_set_password(sp_ctx->mech_ctx.ntlmssp_state,
127                                            password);
128         if (!NT_STATUS_IS_OK(status)) {
129                 TALLOC_FREE(sp_ctx);
130                 return status;
131         }
132
133         if (do_sign) {
134                 auth_ntlmssp_want_feature(sp_ctx->mech_ctx.ntlmssp_state,
135                                           NTLMSSP_FEATURE_SIGN);
136         } else if (do_seal) {
137                 auth_ntlmssp_want_feature(sp_ctx->mech_ctx.ntlmssp_state,
138                                           NTLMSSP_FEATURE_SEAL);
139         }
140
141         *spnego_ctx = sp_ctx;
142         return NT_STATUS_OK;
143 }
144
145 NTSTATUS spnego_get_client_auth_token(TALLOC_CTX *mem_ctx,
146                                       struct spnego_context *sp_ctx,
147                                       DATA_BLOB *spnego_in,
148                                       DATA_BLOB *spnego_out)
149 {
150         struct gse_context *gse_ctx;
151         struct auth_ntlmssp_state *ntlmssp_ctx;
152         struct spnego_data sp_in, sp_out;
153         DATA_BLOB token_in = data_blob_null;
154         DATA_BLOB token_out = data_blob_null;
155         const char *mech_oids[2] = { NULL, NULL };
156         char *principal = NULL;
157         ssize_t len_in = 0;
158         ssize_t len_out = 0;
159         bool mech_wants_more = false;
160         NTSTATUS status;
161
162         if (!spnego_in->length) {
163                 /* server didn't send anything, is init ? */
164                 if (sp_ctx->state != SPNEGO_CONV_INIT) {
165                         return NT_STATUS_INVALID_PARAMETER;
166                 }
167         } else {
168                 len_in = spnego_read_data(mem_ctx, *spnego_in, &sp_in);
169                 if (len_in == -1) {
170                         status = NT_STATUS_INVALID_PARAMETER;
171                         goto done;
172                 }
173                 if (sp_in.type != SPNEGO_NEG_TOKEN_TARG) {
174                         status = NT_STATUS_INVALID_PARAMETER;
175                         goto done;
176                 }
177                 if (sp_in.negTokenTarg.negResult == SPNEGO_REJECT) {
178                         status = NT_STATUS_ACCESS_DENIED;
179                         goto done;
180                 }
181                 token_in = sp_in.negTokenTarg.responseToken;
182         }
183
184         if (sp_ctx->state == SPNEGO_CONV_AUTH_CONFIRM) {
185                 if (sp_in.negTokenTarg.negResult == SPNEGO_ACCEPT_COMPLETED) {
186                         sp_ctx->state = SPNEGO_CONV_AUTH_DONE;
187                         *spnego_out = data_blob_null;
188                         status = NT_STATUS_OK;
189                 } else {
190                         status = NT_STATUS_ACCESS_DENIED;
191                 }
192                 goto done;
193         }
194
195         switch (sp_ctx->mech) {
196         case SPNEGO_KRB5:
197
198                 gse_ctx = sp_ctx->mech_ctx.gssapi_state;
199                 status = gse_get_client_auth_token(mem_ctx, gse_ctx,
200                                                    &token_in, &token_out);
201                 if (!NT_STATUS_IS_OK(status)) {
202                         goto done;
203                 }
204
205                 mech_oids[0] = OID_KERBEROS5;
206                 mech_wants_more = gse_require_more_processing(gse_ctx);
207
208                 break;
209
210         case SPNEGO_NTLMSSP:
211
212                 ntlmssp_ctx = sp_ctx->mech_ctx.ntlmssp_state;
213                 status = auth_ntlmssp_update(ntlmssp_ctx, mem_ctx,
214                                              token_in, &token_out);
215                 if (NT_STATUS_EQUAL(status,
216                                     NT_STATUS_MORE_PROCESSING_REQUIRED)) {
217                         mech_wants_more = true;
218                 } else if (!NT_STATUS_IS_OK(status)) {
219                         goto done;
220                 }
221
222                 mech_oids[0] = OID_NTLMSSP;
223
224                 break;
225
226         default:
227                 status = NT_STATUS_INTERNAL_ERROR;
228                 goto done;
229         }
230
231         switch (sp_ctx->state) {
232         case SPNEGO_CONV_INIT:
233                 *spnego_out = spnego_gen_negTokenInit(mem_ctx, mech_oids,
234                                                       &token_out, principal);
235                 if (!spnego_out->data) {
236                         status = NT_STATUS_INTERNAL_ERROR;
237                         goto done;
238                 }
239                 sp_ctx->state = SPNEGO_CONV_AUTH_MORE;
240                 break;
241
242         case SPNEGO_CONV_AUTH_MORE:
243                 /* server says it's done and we do not seem to agree */
244                 if (sp_in.negTokenTarg.negResult ==
245                                                 SPNEGO_ACCEPT_COMPLETED) {
246                         status = NT_STATUS_INVALID_PARAMETER;
247                         goto done;
248                 }
249
250                 sp_out.type = SPNEGO_NEG_TOKEN_TARG;
251                 sp_out.negTokenTarg.negResult = SPNEGO_NONE_RESULT;
252                 sp_out.negTokenTarg.supportedMech = NULL;
253                 sp_out.negTokenTarg.responseToken = token_out;
254                 sp_out.negTokenTarg.mechListMIC = data_blob_null;
255
256                 len_out = spnego_write_data(mem_ctx, spnego_out, &sp_out);
257                 if (len_out == -1) {
258                         status = NT_STATUS_INTERNAL_ERROR;
259                         goto done;
260                 }
261
262                 if (!mech_wants_more) {
263                         /* we still need to get an ack from the server */
264                         sp_ctx->state = SPNEGO_CONV_AUTH_CONFIRM;
265                 }
266
267                 break;
268
269         default:
270                 status = NT_STATUS_INTERNAL_ERROR;
271                 goto done;
272         }
273
274         status = NT_STATUS_OK;
275
276 done:
277         if (len_in > 0) {
278                 spnego_free_data(&sp_in);
279         }
280         data_blob_free(&token_out);
281         return status;
282 }
283
284 bool spnego_require_more_processing(struct spnego_context *sp_ctx)
285 {
286         struct gse_context *gse_ctx;
287
288         /* see if spnego processing itself requires more */
289         if (sp_ctx->state == SPNEGO_CONV_AUTH_MORE ||
290             sp_ctx->state == SPNEGO_CONV_AUTH_CONFIRM) {
291                 return true;
292         }
293
294         /* otherwise see if underlying mechnism does */
295         switch (sp_ctx->mech) {
296         case SPNEGO_KRB5:
297                 gse_ctx = sp_ctx->mech_ctx.gssapi_state;
298                 return gse_require_more_processing(gse_ctx);
299         case SPNEGO_NTLMSSP:
300                 return false;
301         default:
302                 DEBUG(0, ("Unsupported type in request!\n"));
303                 return false;
304         }
305 }
306
307 NTSTATUS spnego_get_negotiated_mech(struct spnego_context *sp_ctx,
308                                     enum spnego_mech *type,
309                                     void **auth_context)
310 {
311         switch (sp_ctx->mech) {
312         case SPNEGO_KRB5:
313                 *auth_context = sp_ctx->mech_ctx.gssapi_state;
314                 break;
315         case SPNEGO_NTLMSSP:
316                 *auth_context = sp_ctx->mech_ctx.ntlmssp_state;
317                 break;
318         default:
319                 return NT_STATUS_INTERNAL_ERROR;
320         }
321
322         *type = sp_ctx->mech;
323         return NT_STATUS_OK;
324 }
325
326 DATA_BLOB spnego_get_session_key(TALLOC_CTX *mem_ctx,
327                                  struct spnego_context *sp_ctx)
328 {
329         switch (sp_ctx->mech) {
330         case SPNEGO_KRB5:
331                 return gse_get_session_key(mem_ctx,
332                                            sp_ctx->mech_ctx.gssapi_state);
333         case SPNEGO_NTLMSSP:
334                 return auth_ntlmssp_get_session_key(
335                         sp_ctx->mech_ctx.ntlmssp_state, mem_ctx);
336         default:
337                 DEBUG(0, ("Unsupported type in request!\n"));
338                 return data_blob_null;
339         }
340 }
341
342 NTSTATUS spnego_sign(TALLOC_CTX *mem_ctx,
343                         struct spnego_context *sp_ctx,
344                         DATA_BLOB *data, DATA_BLOB *full_data,
345                         DATA_BLOB *signature)
346 {
347         switch(sp_ctx->mech) {
348         case SPNEGO_KRB5:
349                 return gse_sign(mem_ctx,
350                                 sp_ctx->mech_ctx.gssapi_state,
351                                 data, signature);
352         case SPNEGO_NTLMSSP:
353                 return auth_ntlmssp_sign_packet(
354                                         sp_ctx->mech_ctx.ntlmssp_state,
355                                         mem_ctx,
356                                         data->data, data->length,
357                                         full_data->data, full_data->length,
358                                         signature);
359         default:
360                 return NT_STATUS_INVALID_PARAMETER;
361         }
362 }
363
364 NTSTATUS spnego_sigcheck(TALLOC_CTX *mem_ctx,
365                          struct spnego_context *sp_ctx,
366                          DATA_BLOB *data, DATA_BLOB *full_data,
367                          DATA_BLOB *signature)
368 {
369         switch(sp_ctx->mech) {
370         case SPNEGO_KRB5:
371                 return gse_sigcheck(mem_ctx,
372                                     sp_ctx->mech_ctx.gssapi_state,
373                                     data, signature);
374         case SPNEGO_NTLMSSP:
375                 return auth_ntlmssp_check_packet(
376                                         sp_ctx->mech_ctx.ntlmssp_state,
377                                         data->data, data->length,
378                                         full_data->data, full_data->length,
379                                         signature);
380         default:
381                 return NT_STATUS_INVALID_PARAMETER;
382         }
383 }
384
385 NTSTATUS spnego_seal(TALLOC_CTX *mem_ctx,
386                         struct spnego_context *sp_ctx,
387                         DATA_BLOB *data, DATA_BLOB *full_data,
388                         DATA_BLOB *signature)
389 {
390         switch(sp_ctx->mech) {
391         case SPNEGO_KRB5:
392                 return gse_seal(mem_ctx,
393                                 sp_ctx->mech_ctx.gssapi_state,
394                                 data, signature);
395         case SPNEGO_NTLMSSP:
396                 return auth_ntlmssp_seal_packet(
397                                         sp_ctx->mech_ctx.ntlmssp_state,
398                                         mem_ctx,
399                                         data->data, data->length,
400                                         full_data->data, full_data->length,
401                                         signature);
402         default:
403                 return NT_STATUS_INVALID_PARAMETER;
404         }
405 }
406
407 NTSTATUS spnego_unseal(TALLOC_CTX *mem_ctx,
408                         struct spnego_context *sp_ctx,
409                         DATA_BLOB *data, DATA_BLOB *full_data,
410                         DATA_BLOB *signature)
411 {
412         switch(sp_ctx->mech) {
413         case SPNEGO_KRB5:
414                 return gse_unseal(mem_ctx,
415                                     sp_ctx->mech_ctx.gssapi_state,
416                                     data, signature);
417         case SPNEGO_NTLMSSP:
418                 return auth_ntlmssp_unseal_packet(
419                                         sp_ctx->mech_ctx.ntlmssp_state,
420                                         data->data, data->length,
421                                         full_data->data, full_data->length,
422                                         signature);
423         default:
424                 return NT_STATUS_INVALID_PARAMETER;
425         }
426 }