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