root/source4/auth/gensec/gensec_krb5.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. gensec_krb5_destroy
  2. gensec_krb5_start
  3. gensec_krb5_server_start
  4. gensec_fake_gssapi_krb5_server_start
  5. gensec_krb5_client_start
  6. gensec_fake_gssapi_krb5_client_start
  7. gensec_fake_gssapi_krb5_magic
  8. gensec_krb5_update
  9. gensec_krb5_session_key
  10. gensec_krb5_session_info
  11. gensec_krb5_wrap
  12. gensec_krb5_unwrap
  13. gensec_krb5_have_feature
  14. gensec_krb5_init

   1 /* 
   2    Unix SMB/CIFS implementation.
   3 
   4    Kerberos backend for GENSEC
   5    
   6    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004
   7    Copyright (C) Andrew Tridgell 2001
   8    Copyright (C) Luke Howard 2002-2003
   9    Copyright (C) Stefan Metzmacher 2004-2005
  10 
  11    This program is free software; you can redistribute it and/or modify
  12    it under the terms of the GNU General Public License as published by
  13    the Free Software Foundation; either version 3 of the License, or
  14    (at your option) any later version.
  15    
  16    This program is distributed in the hope that it will be useful,
  17    but WITHOUT ANY WARRANTY; without even the implied warranty of
  18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19    GNU General Public License for more details.
  20 
  21    
  22    You should have received a copy of the GNU General Public License
  23    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  24 */
  25 
  26 #include "includes.h"
  27 #include "system/kerberos.h"
  28 #include "auth/kerberos/kerberos.h"
  29 #include "librpc/gen_ndr/krb5pac.h"
  30 #include "auth/auth.h"
  31 #include "lib/ldb/include/ldb.h"
  32 #include "auth/auth_sam.h"
  33 #include "lib/socket/socket.h"
  34 #include "librpc/rpc/dcerpc.h"
  35 #include "auth/credentials/credentials.h"
  36 #include "auth/credentials/credentials_krb5.h"
  37 #include "auth/gensec/gensec.h"
  38 #include "auth/gensec/gensec_proto.h"
  39 #include "param/param.h"
  40 #include "auth/session_proto.h"
  41 #include "auth/auth_sam_reply.h"
  42 
  43 enum GENSEC_KRB5_STATE {
  44         GENSEC_KRB5_SERVER_START,
  45         GENSEC_KRB5_CLIENT_START,
  46         GENSEC_KRB5_CLIENT_MUTUAL_AUTH,
  47         GENSEC_KRB5_DONE
  48 };
  49 
  50 struct gensec_krb5_state {
  51         DATA_BLOB session_key;
  52         DATA_BLOB pac;
  53         enum GENSEC_KRB5_STATE state_position;
  54         struct smb_krb5_context *smb_krb5_context;
  55         krb5_auth_context auth_context;
  56         krb5_data enc_ticket;
  57         krb5_keyblock *keyblock;
  58         krb5_ticket *ticket;
  59         bool gssapi;
  60 };
  61 
  62 static int gensec_krb5_destroy(struct gensec_krb5_state *gensec_krb5_state)
     /* [<][>][^][v][top][bottom][index][help] */
  63 {
  64         if (!gensec_krb5_state->smb_krb5_context) {
  65                 /* We can't clean anything else up unless we started up this far */
  66                 return 0;
  67         }
  68         if (gensec_krb5_state->enc_ticket.length) { 
  69                 kerberos_free_data_contents(gensec_krb5_state->smb_krb5_context->krb5_context, 
  70                                             &gensec_krb5_state->enc_ticket); 
  71         }
  72 
  73         if (gensec_krb5_state->ticket) {
  74                 krb5_free_ticket(gensec_krb5_state->smb_krb5_context->krb5_context, 
  75                                  gensec_krb5_state->ticket);
  76         }
  77 
  78         /* ccache freed in a child destructor */
  79 
  80         krb5_free_keyblock(gensec_krb5_state->smb_krb5_context->krb5_context, 
  81                            gensec_krb5_state->keyblock);
  82                 
  83         if (gensec_krb5_state->auth_context) {
  84                 krb5_auth_con_free(gensec_krb5_state->smb_krb5_context->krb5_context, 
  85                                    gensec_krb5_state->auth_context);
  86         }
  87 
  88         return 0;
  89 }
  90 
  91 static NTSTATUS gensec_krb5_start(struct gensec_security *gensec_security)
     /* [<][>][^][v][top][bottom][index][help] */
  92 {
  93         krb5_error_code ret;
  94         struct gensec_krb5_state *gensec_krb5_state;
  95         struct cli_credentials *creds;
  96         const struct socket_address *my_addr, *peer_addr;
  97         krb5_address my_krb5_addr, peer_krb5_addr;
  98         
  99         creds = gensec_get_credentials(gensec_security);
 100         if (!creds) {
 101                 return NT_STATUS_INVALID_PARAMETER;
 102         }
 103 
 104         gensec_krb5_state = talloc(gensec_security, struct gensec_krb5_state);
 105         if (!gensec_krb5_state) {
 106                 return NT_STATUS_NO_MEMORY;
 107         }
 108 
 109         gensec_security->private_data = gensec_krb5_state;
 110         gensec_krb5_state->smb_krb5_context = NULL;
 111         gensec_krb5_state->auth_context = NULL;
 112         gensec_krb5_state->ticket = NULL;
 113         ZERO_STRUCT(gensec_krb5_state->enc_ticket);
 114         gensec_krb5_state->keyblock = NULL;
 115         gensec_krb5_state->session_key = data_blob(NULL, 0);
 116         gensec_krb5_state->pac = data_blob(NULL, 0);
 117         gensec_krb5_state->gssapi = false;
 118 
 119         talloc_set_destructor(gensec_krb5_state, gensec_krb5_destroy); 
 120 
 121         if (cli_credentials_get_krb5_context(creds, 
 122                                              gensec_security->event_ctx, 
 123                                              gensec_security->settings->lp_ctx, &gensec_krb5_state->smb_krb5_context)) {
 124                 talloc_free(gensec_krb5_state);
 125                 return NT_STATUS_INTERNAL_ERROR;
 126         }
 127 
 128         ret = krb5_auth_con_init(gensec_krb5_state->smb_krb5_context->krb5_context, &gensec_krb5_state->auth_context);
 129         if (ret) {
 130                 DEBUG(1,("gensec_krb5_start: krb5_auth_con_init failed (%s)\n", 
 131                          smb_get_krb5_error_message(gensec_krb5_state->smb_krb5_context->krb5_context, 
 132                                                     ret, gensec_krb5_state)));
 133                 talloc_free(gensec_krb5_state);
 134                 return NT_STATUS_INTERNAL_ERROR;
 135         }
 136 
 137         ret = krb5_auth_con_setflags(gensec_krb5_state->smb_krb5_context->krb5_context, 
 138                                      gensec_krb5_state->auth_context,
 139                                      KRB5_AUTH_CONTEXT_DO_SEQUENCE);
 140         if (ret) {
 141                 DEBUG(1,("gensec_krb5_start: krb5_auth_con_setflags failed (%s)\n", 
 142                          smb_get_krb5_error_message(gensec_krb5_state->smb_krb5_context->krb5_context, 
 143                                                     ret, gensec_krb5_state)));
 144                 talloc_free(gensec_krb5_state);
 145                 return NT_STATUS_INTERNAL_ERROR;
 146         }
 147 
 148         my_addr = gensec_get_my_addr(gensec_security);
 149         if (my_addr && my_addr->sockaddr) {
 150                 ret = krb5_sockaddr2address(gensec_krb5_state->smb_krb5_context->krb5_context, 
 151                                             my_addr->sockaddr, &my_krb5_addr);
 152                 if (ret) {
 153                         DEBUG(1,("gensec_krb5_start: krb5_sockaddr2address (local) failed (%s)\n", 
 154                                  smb_get_krb5_error_message(gensec_krb5_state->smb_krb5_context->krb5_context, 
 155                                                             ret, gensec_krb5_state)));
 156                         talloc_free(gensec_krb5_state);
 157                         return NT_STATUS_INTERNAL_ERROR;
 158                 }
 159         }
 160 
 161         peer_addr = gensec_get_peer_addr(gensec_security);
 162         if (peer_addr && peer_addr->sockaddr) {
 163                 ret = krb5_sockaddr2address(gensec_krb5_state->smb_krb5_context->krb5_context, 
 164                                             peer_addr->sockaddr, &peer_krb5_addr);
 165                 if (ret) {
 166                         DEBUG(1,("gensec_krb5_start: krb5_sockaddr2address (local) failed (%s)\n", 
 167                                  smb_get_krb5_error_message(gensec_krb5_state->smb_krb5_context->krb5_context, 
 168                                                             ret, gensec_krb5_state)));
 169                         talloc_free(gensec_krb5_state);
 170                         return NT_STATUS_INTERNAL_ERROR;
 171                 }
 172         }
 173 
 174         ret = krb5_auth_con_setaddrs(gensec_krb5_state->smb_krb5_context->krb5_context, 
 175                                      gensec_krb5_state->auth_context,
 176                                      my_addr ? &my_krb5_addr : NULL, 
 177                                      peer_addr ? &peer_krb5_addr : NULL);
 178         if (ret) {
 179                 DEBUG(1,("gensec_krb5_start: krb5_auth_con_setaddrs failed (%s)\n", 
 180                          smb_get_krb5_error_message(gensec_krb5_state->smb_krb5_context->krb5_context, 
 181                                                     ret, gensec_krb5_state)));
 182                 talloc_free(gensec_krb5_state);
 183                 return NT_STATUS_INTERNAL_ERROR;
 184         }
 185 
 186         return NT_STATUS_OK;
 187 }
 188 
 189 static NTSTATUS gensec_krb5_server_start(struct gensec_security *gensec_security)
     /* [<][>][^][v][top][bottom][index][help] */
 190 {
 191         NTSTATUS nt_status;
 192         struct gensec_krb5_state *gensec_krb5_state;
 193 
 194         nt_status = gensec_krb5_start(gensec_security);
 195         if (!NT_STATUS_IS_OK(nt_status)) {
 196                 return nt_status;
 197         }
 198         
 199         gensec_krb5_state = (struct gensec_krb5_state *)gensec_security->private_data;
 200         gensec_krb5_state->state_position = GENSEC_KRB5_SERVER_START;
 201 
 202         return NT_STATUS_OK;
 203 }
 204 
 205 static NTSTATUS gensec_fake_gssapi_krb5_server_start(struct gensec_security *gensec_security)
     /* [<][>][^][v][top][bottom][index][help] */
 206 {
 207         NTSTATUS nt_status = gensec_krb5_server_start(gensec_security);
 208 
 209         if (NT_STATUS_IS_OK(nt_status)) {
 210                 struct gensec_krb5_state *gensec_krb5_state;
 211                 gensec_krb5_state = (struct gensec_krb5_state *)gensec_security->private_data;
 212                 gensec_krb5_state->gssapi = true;
 213         }
 214         return nt_status;
 215 }
 216 
 217 static NTSTATUS gensec_krb5_client_start(struct gensec_security *gensec_security)
     /* [<][>][^][v][top][bottom][index][help] */
 218 {
 219         struct gensec_krb5_state *gensec_krb5_state;
 220         krb5_error_code ret;
 221         NTSTATUS nt_status;
 222         struct ccache_container *ccache_container;
 223         const char *hostname;
 224         krb5_flags ap_req_options = AP_OPTS_USE_SUBKEY | AP_OPTS_MUTUAL_REQUIRED;
 225 
 226         const char *principal;
 227         krb5_data in_data;
 228 
 229         hostname = gensec_get_target_hostname(gensec_security);
 230         if (!hostname) {
 231                 DEBUG(1, ("Could not determine hostname for target computer, cannot use kerberos\n"));
 232                 return NT_STATUS_INVALID_PARAMETER;
 233         }
 234         if (is_ipaddress(hostname)) {
 235                 DEBUG(2, ("Cannot do krb5 to an IP address"));
 236                 return NT_STATUS_INVALID_PARAMETER;
 237         }
 238         if (strcmp(hostname, "localhost") == 0) {
 239                 DEBUG(2, ("krb5 to 'localhost' does not make sense"));
 240                 return NT_STATUS_INVALID_PARAMETER;
 241         }
 242                         
 243         nt_status = gensec_krb5_start(gensec_security);
 244         if (!NT_STATUS_IS_OK(nt_status)) {
 245                 return nt_status;
 246         }
 247 
 248         gensec_krb5_state = (struct gensec_krb5_state *)gensec_security->private_data;
 249         gensec_krb5_state->state_position = GENSEC_KRB5_CLIENT_START;
 250 
 251         principal = gensec_get_target_principal(gensec_security);
 252 
 253         ret = cli_credentials_get_ccache(gensec_get_credentials(gensec_security), 
 254                                          gensec_security->event_ctx, 
 255                                          gensec_security->settings->lp_ctx, &ccache_container);
 256         switch (ret) {
 257         case 0:
 258                 break;
 259         case KRB5KDC_ERR_PREAUTH_FAILED:
 260                 return NT_STATUS_LOGON_FAILURE;
 261         case KRB5_KDC_UNREACH:
 262                 DEBUG(3, ("Cannot reach a KDC we require to contact %s\n", principal));
 263                 return NT_STATUS_INVALID_PARAMETER; /* Make SPNEGO ignore us, we can't go any further here */
 264         default:
 265                 DEBUG(1, ("gensec_krb5_start: Aquiring initiator credentials failed: %s\n", error_message(ret)));
 266                 return NT_STATUS_UNSUCCESSFUL;
 267         }
 268         in_data.length = 0;
 269         
 270         if (principal && lp_client_use_spnego_principal(gensec_security->settings->lp_ctx)) {
 271                 krb5_principal target_principal;
 272                 ret = krb5_parse_name(gensec_krb5_state->smb_krb5_context->krb5_context, principal,
 273                                       &target_principal);
 274                 if (ret == 0) {
 275                         ret = krb5_mk_req_exact(gensec_krb5_state->smb_krb5_context->krb5_context, 
 276                                                 &gensec_krb5_state->auth_context,
 277                                                 ap_req_options, 
 278                                                 target_principal,
 279                                                 &in_data, ccache_container->ccache, 
 280                                                 &gensec_krb5_state->enc_ticket);
 281                         krb5_free_principal(gensec_krb5_state->smb_krb5_context->krb5_context, 
 282                                             target_principal);
 283                 }
 284         } else {
 285                 ret = krb5_mk_req(gensec_krb5_state->smb_krb5_context->krb5_context, 
 286                                   &gensec_krb5_state->auth_context,
 287                                   ap_req_options,
 288                                   gensec_get_target_service(gensec_security),
 289                                   hostname,
 290                                   &in_data, ccache_container->ccache, 
 291                                   &gensec_krb5_state->enc_ticket);
 292         }
 293         switch (ret) {
 294         case 0:
 295                 return NT_STATUS_OK;
 296         case KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN:
 297                 DEBUG(3, ("Server [%s] is not registered with our KDC: %s\n", 
 298                           hostname, smb_get_krb5_error_message(gensec_krb5_state->smb_krb5_context->krb5_context, ret, gensec_krb5_state)));
 299                 return NT_STATUS_INVALID_PARAMETER; /* Make SPNEGO ignore us, we can't go any further here */
 300         case KRB5_KDC_UNREACH:
 301                 DEBUG(3, ("Cannot reach a KDC we require to contact host [%s]: %s\n",
 302                           hostname, smb_get_krb5_error_message(gensec_krb5_state->smb_krb5_context->krb5_context, ret, gensec_krb5_state)));
 303                 return NT_STATUS_INVALID_PARAMETER; /* Make SPNEGO ignore us, we can't go any further here */
 304         case KRB5KDC_ERR_PREAUTH_FAILED:
 305         case KRB5KRB_AP_ERR_TKT_EXPIRED:
 306         case KRB5_CC_END:
 307                 /* Too much clock skew - we will need to kinit to re-skew the clock */
 308         case KRB5KRB_AP_ERR_SKEW:
 309         case KRB5_KDCREP_SKEW:
 310         {
 311                 DEBUG(3, ("kerberos (mk_req) failed: %s\n", 
 312                           smb_get_krb5_error_message(gensec_krb5_state->smb_krb5_context->krb5_context, ret, gensec_krb5_state)));
 313                 /*fall through*/
 314         }
 315         
 316         /* just don't print a message for these really ordinary messages */
 317         case KRB5_FCC_NOFILE:
 318         case KRB5_CC_NOTFOUND:
 319         case ENOENT:
 320                 
 321                 return NT_STATUS_UNSUCCESSFUL;
 322                 break;
 323                 
 324         default:
 325                 DEBUG(0, ("kerberos: %s\n", 
 326                           smb_get_krb5_error_message(gensec_krb5_state->smb_krb5_context->krb5_context, ret, gensec_krb5_state)));
 327                 return NT_STATUS_UNSUCCESSFUL;
 328         }
 329 }
 330 
 331 static NTSTATUS gensec_fake_gssapi_krb5_client_start(struct gensec_security *gensec_security)
     /* [<][>][^][v][top][bottom][index][help] */
 332 {
 333         NTSTATUS nt_status = gensec_krb5_client_start(gensec_security);
 334 
 335         if (NT_STATUS_IS_OK(nt_status)) {
 336                 struct gensec_krb5_state *gensec_krb5_state;
 337                 gensec_krb5_state = (struct gensec_krb5_state *)gensec_security->private_data;
 338                 gensec_krb5_state->gssapi = true;
 339         }
 340         return nt_status;
 341 }
 342 
 343 /**
 344  * Check if the packet is one for this mechansim
 345  * 
 346  * @param gensec_security GENSEC state
 347  * @param in The request, as a DATA_BLOB
 348  * @return Error, INVALID_PARAMETER if it's not a packet for us
 349  *                or NT_STATUS_OK if the packet is ok. 
 350  */
 351 
 352 static NTSTATUS gensec_fake_gssapi_krb5_magic(struct gensec_security *gensec_security, 
     /* [<][>][^][v][top][bottom][index][help] */
 353                                   const DATA_BLOB *in) 
 354 {
 355         if (gensec_gssapi_check_oid(in, GENSEC_OID_KERBEROS5)) {
 356                 return NT_STATUS_OK;
 357         } else {
 358                 return NT_STATUS_INVALID_PARAMETER;
 359         }
 360 }
 361 
 362 
 363 /**
 364  * Next state function for the Krb5 GENSEC mechanism
 365  * 
 366  * @param gensec_krb5_state KRB5 State
 367  * @param out_mem_ctx The TALLOC_CTX for *out to be allocated on
 368  * @param in The request, as a DATA_BLOB
 369  * @param out The reply, as an talloc()ed DATA_BLOB, on *out_mem_ctx
 370  * @return Error, MORE_PROCESSING_REQUIRED if a reply is sent, 
 371  *                or NT_STATUS_OK if the user is authenticated. 
 372  */
 373 
 374 static NTSTATUS gensec_krb5_update(struct gensec_security *gensec_security, 
     /* [<][>][^][v][top][bottom][index][help] */
 375                                    TALLOC_CTX *out_mem_ctx, 
 376                                    const DATA_BLOB in, DATA_BLOB *out) 
 377 {
 378         struct gensec_krb5_state *gensec_krb5_state = (struct gensec_krb5_state *)gensec_security->private_data;
 379         krb5_error_code ret = 0;
 380         NTSTATUS nt_status;
 381 
 382         switch (gensec_krb5_state->state_position) {
 383         case GENSEC_KRB5_CLIENT_START:
 384         {
 385                 DATA_BLOB unwrapped_out;
 386                 
 387                 if (gensec_krb5_state->gssapi) {
 388                         unwrapped_out = data_blob_talloc(out_mem_ctx, gensec_krb5_state->enc_ticket.data, gensec_krb5_state->enc_ticket.length);
 389                         
 390                         /* wrap that up in a nice GSS-API wrapping */
 391                         *out = gensec_gssapi_gen_krb5_wrap(out_mem_ctx, &unwrapped_out, TOK_ID_KRB_AP_REQ);
 392                 } else {
 393                         *out = data_blob_talloc(out_mem_ctx, gensec_krb5_state->enc_ticket.data, gensec_krb5_state->enc_ticket.length);
 394                 }
 395                 gensec_krb5_state->state_position = GENSEC_KRB5_CLIENT_MUTUAL_AUTH;
 396                 nt_status = NT_STATUS_MORE_PROCESSING_REQUIRED;
 397                 return nt_status;
 398         }
 399                 
 400         case GENSEC_KRB5_CLIENT_MUTUAL_AUTH:
 401         {
 402                 DATA_BLOB unwrapped_in;
 403                 krb5_data inbuf;
 404                 krb5_ap_rep_enc_part *repl = NULL;
 405                 uint8_t tok_id[2];
 406 
 407                 if (gensec_krb5_state->gssapi) {
 408                         if (!gensec_gssapi_parse_krb5_wrap(out_mem_ctx, &in, &unwrapped_in, tok_id)) {
 409                                 DEBUG(1,("gensec_gssapi_parse_krb5_wrap(mutual authentication) failed to parse\n"));
 410                                 dump_data_pw("Mutual authentication message:\n", in.data, in.length);
 411                                 return NT_STATUS_INVALID_PARAMETER;
 412                         }
 413                 } else {
 414                         unwrapped_in = in;
 415                 }
 416                 /* TODO: check the tok_id */
 417 
 418                 inbuf.data = unwrapped_in.data;
 419                 inbuf.length = unwrapped_in.length;
 420                 ret = krb5_rd_rep(gensec_krb5_state->smb_krb5_context->krb5_context, 
 421                                   gensec_krb5_state->auth_context,
 422                                   &inbuf, &repl);
 423                 if (ret) {
 424                         DEBUG(1,("krb5_rd_rep (mutual authentication) failed (%s)\n",
 425                                  smb_get_krb5_error_message(gensec_krb5_state->smb_krb5_context->krb5_context, ret, out_mem_ctx)));
 426                         dump_data_pw("Mutual authentication message:\n", (uint8_t *)inbuf.data, inbuf.length);
 427                         nt_status = NT_STATUS_ACCESS_DENIED;
 428                 } else {
 429                         *out = data_blob(NULL, 0);
 430                         nt_status = NT_STATUS_OK;
 431                         gensec_krb5_state->state_position = GENSEC_KRB5_DONE;
 432                 }
 433                 if (repl) {
 434                         krb5_free_ap_rep_enc_part(gensec_krb5_state->smb_krb5_context->krb5_context, repl);
 435                 }
 436                 return nt_status;
 437         }
 438 
 439         case GENSEC_KRB5_SERVER_START:
 440         {
 441                 DATA_BLOB unwrapped_in;
 442                 DATA_BLOB unwrapped_out = data_blob(NULL, 0);
 443                 krb5_data inbuf, outbuf;
 444                 uint8_t tok_id[2];
 445                 struct keytab_container *keytab;
 446                 krb5_principal server_in_keytab;
 447 
 448                 if (!in.data) {
 449                         return NT_STATUS_INVALID_PARAMETER;
 450                 }       
 451 
 452                 /* Grab the keytab, however generated */
 453                 ret = cli_credentials_get_keytab(gensec_get_credentials(gensec_security), 
 454                                                  gensec_security->event_ctx, 
 455                                                  gensec_security->settings->lp_ctx, &keytab);
 456                 if (ret) {
 457                         return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
 458                 }
 459                 
 460                 /* This ensures we lookup the correct entry in that keytab */
 461                 ret = principal_from_credentials(out_mem_ctx, gensec_get_credentials(gensec_security), 
 462                                                  gensec_krb5_state->smb_krb5_context, 
 463                                                  &server_in_keytab);
 464 
 465                 if (ret) {
 466                         return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
 467                 }
 468 
 469                 /* Parse the GSSAPI wrapping, if it's there... (win2k3 allows it to be omited) */
 470                 if (gensec_krb5_state->gssapi
 471                     && gensec_gssapi_parse_krb5_wrap(out_mem_ctx, &in, &unwrapped_in, tok_id)) {
 472                         inbuf.data = unwrapped_in.data;
 473                         inbuf.length = unwrapped_in.length;
 474                 } else {
 475                         inbuf.data = in.data;
 476                         inbuf.length = in.length;
 477                 }
 478 
 479                 ret = smb_rd_req_return_stuff(gensec_krb5_state->smb_krb5_context->krb5_context,
 480                                               &gensec_krb5_state->auth_context, 
 481                                               &inbuf, keytab->keytab, server_in_keytab,  
 482                                               &outbuf, 
 483                                               &gensec_krb5_state->ticket, 
 484                                               &gensec_krb5_state->keyblock);
 485 
 486                 if (ret) {
 487                         return NT_STATUS_LOGON_FAILURE;
 488                 }
 489                 unwrapped_out.data = (uint8_t *)outbuf.data;
 490                 unwrapped_out.length = outbuf.length;
 491                 gensec_krb5_state->state_position = GENSEC_KRB5_DONE;
 492                 /* wrap that up in a nice GSS-API wrapping */
 493                 if (gensec_krb5_state->gssapi) {
 494                         *out = gensec_gssapi_gen_krb5_wrap(out_mem_ctx, &unwrapped_out, TOK_ID_KRB_AP_REP);
 495                 } else {
 496                         *out = data_blob_talloc(out_mem_ctx, outbuf.data, outbuf.length);
 497                 }
 498                 krb5_data_free(&outbuf);
 499                 return NT_STATUS_OK;
 500         }
 501 
 502         case GENSEC_KRB5_DONE:
 503         default:
 504                 /* Asking too many times... */
 505                 return NT_STATUS_INVALID_PARAMETER;
 506         }
 507 }
 508 
 509 static NTSTATUS gensec_krb5_session_key(struct gensec_security *gensec_security, 
     /* [<][>][^][v][top][bottom][index][help] */
 510                                         DATA_BLOB *session_key) 
 511 {
 512         struct gensec_krb5_state *gensec_krb5_state = (struct gensec_krb5_state *)gensec_security->private_data;
 513         krb5_context context = gensec_krb5_state->smb_krb5_context->krb5_context;
 514         krb5_auth_context auth_context = gensec_krb5_state->auth_context;
 515         krb5_keyblock *skey;
 516         krb5_error_code err = -1;
 517 
 518         if (gensec_krb5_state->state_position != GENSEC_KRB5_DONE) {
 519                 return NT_STATUS_NO_USER_SESSION_KEY;
 520         }
 521 
 522         if (gensec_krb5_state->session_key.data) {
 523                 *session_key = gensec_krb5_state->session_key;
 524                 return NT_STATUS_OK;
 525         }
 526 
 527         switch (gensec_security->gensec_role) {
 528         case GENSEC_CLIENT:
 529                 err = krb5_auth_con_getlocalsubkey(context, auth_context, &skey);
 530                 break;
 531         case GENSEC_SERVER:
 532                 err = krb5_auth_con_getremotesubkey(context, auth_context, &skey);
 533                 break;
 534         }
 535         if (err == 0 && skey != NULL) {
 536                 DEBUG(10, ("Got KRB5 session key of length %d\n",  
 537                            (int)KRB5_KEY_LENGTH(skey)));
 538                 gensec_krb5_state->session_key = data_blob_talloc(gensec_krb5_state, 
 539                                                 KRB5_KEY_DATA(skey), KRB5_KEY_LENGTH(skey));
 540                 *session_key = gensec_krb5_state->session_key;
 541                 dump_data_pw("KRB5 Session Key:\n", session_key->data, session_key->length);
 542 
 543                 krb5_free_keyblock(context, skey);
 544                 return NT_STATUS_OK;
 545         } else {
 546                 DEBUG(10, ("KRB5 error getting session key %d\n", err));
 547                 return NT_STATUS_NO_USER_SESSION_KEY;
 548         }
 549 }
 550 
 551 static NTSTATUS gensec_krb5_session_info(struct gensec_security *gensec_security,
     /* [<][>][^][v][top][bottom][index][help] */
 552                                          struct auth_session_info **_session_info) 
 553 {
 554         NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
 555         struct gensec_krb5_state *gensec_krb5_state = (struct gensec_krb5_state *)gensec_security->private_data;
 556         krb5_context context = gensec_krb5_state->smb_krb5_context->krb5_context;
 557         struct auth_serversupplied_info *server_info = NULL;
 558         struct auth_session_info *session_info = NULL;
 559         struct PAC_LOGON_INFO *logon_info;
 560 
 561         krb5_principal client_principal;
 562         char *principal_string;
 563         
 564         DATA_BLOB pac;
 565         krb5_data pac_data;
 566 
 567         krb5_error_code ret;
 568 
 569         TALLOC_CTX *mem_ctx = talloc_new(gensec_security);
 570         if (!mem_ctx) {
 571                 return NT_STATUS_NO_MEMORY;
 572         }
 573         
 574         ret = krb5_ticket_get_client(context, gensec_krb5_state->ticket, &client_principal);
 575         if (ret) {
 576                 DEBUG(5, ("krb5_ticket_get_client failed to get cleint principal: %s\n", 
 577                           smb_get_krb5_error_message(context, 
 578                                                      ret, mem_ctx)));
 579                 talloc_free(mem_ctx);
 580                 return NT_STATUS_NO_MEMORY;
 581         }
 582         
 583         ret = krb5_unparse_name(gensec_krb5_state->smb_krb5_context->krb5_context, 
 584                                 client_principal, &principal_string);
 585         if (ret) {
 586                 DEBUG(1, ("Unable to parse client principal: %s\n",
 587                           smb_get_krb5_error_message(context, 
 588                                                      ret, mem_ctx)));
 589                 talloc_free(mem_ctx);
 590                 return NT_STATUS_NO_MEMORY;
 591         }
 592 
 593         ret = krb5_ticket_get_authorization_data_type(context, gensec_krb5_state->ticket, 
 594                                                       KRB5_AUTHDATA_WIN2K_PAC, 
 595                                                       &pac_data);
 596         
 597         if (ret && gensec_setting_bool(gensec_security->settings, "gensec", "require_pac", false)) {
 598                 DEBUG(1, ("Unable to find PAC in ticket from %s, failing to allow access: %s \n",
 599                           principal_string,
 600                           smb_get_krb5_error_message(context, 
 601                                                      ret, mem_ctx)));
 602                 krb5_free_principal(context, client_principal);
 603                 free(principal_string);
 604                 return NT_STATUS_ACCESS_DENIED;
 605         } else if (ret) {
 606                 /* NO pac */
 607                 DEBUG(5, ("krb5_ticket_get_authorization_data_type failed to find PAC: %s\n", 
 608                           smb_get_krb5_error_message(context, 
 609                                                      ret, mem_ctx)));
 610                 if (gensec_security->auth_context && 
 611                     !gensec_setting_bool(gensec_security->settings, "gensec", "require_pac", false)) {
 612                         DEBUG(1, ("Unable to find PAC, resorting to local user lookup: %s"));
 613                         nt_status = gensec_security->auth_context->get_server_info_principal(mem_ctx, 
 614                                                                                              gensec_security->auth_context, 
 615                                                                                              principal_string,
 616                                                                                              &server_info);
 617                         if (!NT_STATUS_IS_OK(nt_status)) {
 618                                 talloc_free(mem_ctx);
 619                                 return nt_status;
 620                         }
 621                 } else {
 622                         DEBUG(1, ("Unable to find PAC in ticket from %s, failing to allow access\n",
 623                                   principal_string));
 624                         return NT_STATUS_ACCESS_DENIED;
 625                 }
 626 
 627                 krb5_free_principal(context, client_principal);
 628                 free(principal_string);
 629                 
 630                 if (!NT_STATUS_IS_OK(nt_status)) {
 631                         talloc_free(mem_ctx);
 632                         return nt_status;
 633                 }
 634         } else {
 635                 /* Found pac */
 636                 union netr_Validation validation;
 637                 free(principal_string);
 638 
 639                 pac = data_blob_talloc(mem_ctx, pac_data.data, pac_data.length);
 640                 if (!pac.data) {
 641                         krb5_free_principal(context, client_principal);
 642                         talloc_free(mem_ctx);
 643                         return NT_STATUS_NO_MEMORY;
 644                 }
 645 
 646                 /* decode and verify the pac */
 647                 nt_status = kerberos_pac_logon_info(gensec_krb5_state, 
 648                                                     gensec_security->settings->iconv_convenience,
 649                                                     &logon_info, pac,
 650                                                     gensec_krb5_state->smb_krb5_context->krb5_context,
 651                                                     NULL, gensec_krb5_state->keyblock,
 652                                                     client_principal,
 653                                                     gensec_krb5_state->ticket->ticket.authtime, NULL);
 654                 krb5_free_principal(context, client_principal);
 655 
 656                 if (!NT_STATUS_IS_OK(nt_status)) {
 657                         talloc_free(mem_ctx);
 658                         return nt_status;
 659                 }
 660 
 661                 validation.sam3 = &logon_info->info3;
 662                 nt_status = make_server_info_netlogon_validation(mem_ctx, 
 663                                                                  NULL,
 664                                                                  3, &validation,
 665                                                                  &server_info); 
 666                 if (!NT_STATUS_IS_OK(nt_status)) {
 667                         talloc_free(mem_ctx);
 668                         return nt_status;
 669                 }
 670         }
 671 
 672         /* references the server_info into the session_info */
 673         nt_status = auth_generate_session_info(mem_ctx, gensec_security->event_ctx, gensec_security->settings->lp_ctx, server_info, &session_info);
 674 
 675         if (!NT_STATUS_IS_OK(nt_status)) {
 676                 talloc_free(mem_ctx);
 677                 return nt_status;
 678         }
 679 
 680         nt_status = gensec_krb5_session_key(gensec_security, &session_info->session_key);
 681 
 682         if (!NT_STATUS_IS_OK(nt_status)) {
 683                 talloc_free(mem_ctx);
 684                 return nt_status;
 685         }
 686 
 687         *_session_info = session_info;
 688 
 689         talloc_steal(gensec_krb5_state, session_info);
 690         talloc_free(mem_ctx);
 691         return NT_STATUS_OK;
 692 }
 693 
 694 static NTSTATUS gensec_krb5_wrap(struct gensec_security *gensec_security, 
     /* [<][>][^][v][top][bottom][index][help] */
 695                                    TALLOC_CTX *mem_ctx, 
 696                                    const DATA_BLOB *in, 
 697                                    DATA_BLOB *out)
 698 {
 699         struct gensec_krb5_state *gensec_krb5_state = (struct gensec_krb5_state *)gensec_security->private_data;
 700         krb5_context context = gensec_krb5_state->smb_krb5_context->krb5_context;
 701         krb5_auth_context auth_context = gensec_krb5_state->auth_context;
 702         krb5_error_code ret;
 703         krb5_data input, output;
 704         input.length = in->length;
 705         input.data = in->data;
 706         
 707         if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
 708                 ret = krb5_mk_priv(context, auth_context, &input, &output, NULL);
 709                 if (ret) {
 710                         DEBUG(1, ("krb5_mk_priv failed: %s\n", 
 711                                   smb_get_krb5_error_message(gensec_krb5_state->smb_krb5_context->krb5_context, 
 712                                                              ret, mem_ctx)));
 713                         return NT_STATUS_ACCESS_DENIED;
 714                 }
 715                 *out = data_blob_talloc(mem_ctx, output.data, output.length);
 716                 
 717                 krb5_data_free(&output);
 718         } else {
 719                 return NT_STATUS_ACCESS_DENIED;
 720         }
 721         return NT_STATUS_OK;
 722 }
 723 
 724 static NTSTATUS gensec_krb5_unwrap(struct gensec_security *gensec_security, 
     /* [<][>][^][v][top][bottom][index][help] */
 725                                      TALLOC_CTX *mem_ctx, 
 726                                      const DATA_BLOB *in, 
 727                                      DATA_BLOB *out)
 728 {
 729         struct gensec_krb5_state *gensec_krb5_state = (struct gensec_krb5_state *)gensec_security->private_data;
 730         krb5_context context = gensec_krb5_state->smb_krb5_context->krb5_context;
 731         krb5_auth_context auth_context = gensec_krb5_state->auth_context;
 732         krb5_error_code ret;
 733         krb5_data input, output;
 734         krb5_replay_data replay;
 735         input.length = in->length;
 736         input.data = in->data;
 737         
 738         if (gensec_have_feature(gensec_security, GENSEC_FEATURE_SEAL)) {
 739                 ret = krb5_rd_priv(context, auth_context, &input, &output, &replay);
 740                 if (ret) {
 741                         DEBUG(1, ("krb5_rd_priv failed: %s\n", 
 742                                   smb_get_krb5_error_message(gensec_krb5_state->smb_krb5_context->krb5_context, 
 743                                                              ret, mem_ctx)));
 744                         return NT_STATUS_ACCESS_DENIED;
 745                 }
 746                 *out = data_blob_talloc(mem_ctx, output.data, output.length);
 747                 
 748                 krb5_data_free(&output);
 749         } else {
 750                 return NT_STATUS_ACCESS_DENIED;
 751         }
 752         return NT_STATUS_OK;
 753 }
 754 
 755 static bool gensec_krb5_have_feature(struct gensec_security *gensec_security,
     /* [<][>][^][v][top][bottom][index][help] */
 756                                      uint32_t feature)
 757 {
 758         struct gensec_krb5_state *gensec_krb5_state = (struct gensec_krb5_state *)gensec_security->private_data;
 759         if (feature & GENSEC_FEATURE_SESSION_KEY) {
 760                 return true;
 761         } 
 762         if (!gensec_krb5_state->gssapi && 
 763             (feature & GENSEC_FEATURE_SEAL)) {
 764                 return true;
 765         } 
 766         
 767         return false;
 768 }
 769 
 770 static const char *gensec_krb5_oids[] = { 
 771         GENSEC_OID_KERBEROS5,
 772         GENSEC_OID_KERBEROS5_OLD,
 773         NULL 
 774 };
 775 
 776 static const struct gensec_security_ops gensec_fake_gssapi_krb5_security_ops = {
 777         .name           = "fake_gssapi_krb5",
 778         .auth_type      = DCERPC_AUTH_TYPE_KRB5,
 779         .oid            = gensec_krb5_oids,
 780         .client_start   = gensec_fake_gssapi_krb5_client_start,
 781         .server_start   = gensec_fake_gssapi_krb5_server_start,
 782         .update         = gensec_krb5_update,
 783         .magic          = gensec_fake_gssapi_krb5_magic,
 784         .session_key    = gensec_krb5_session_key,
 785         .session_info   = gensec_krb5_session_info,
 786         .have_feature   = gensec_krb5_have_feature,
 787         .enabled        = false,
 788         .kerberos       = true,
 789         .priority       = GENSEC_KRB5
 790 };
 791 
 792 static const struct gensec_security_ops gensec_krb5_security_ops = {
 793         .name           = "krb5",
 794         .client_start   = gensec_krb5_client_start,
 795         .server_start   = gensec_krb5_server_start,
 796         .update         = gensec_krb5_update,
 797         .session_key    = gensec_krb5_session_key,
 798         .session_info   = gensec_krb5_session_info,
 799         .have_feature   = gensec_krb5_have_feature,
 800         .wrap           = gensec_krb5_wrap,
 801         .unwrap         = gensec_krb5_unwrap,
 802         .enabled        = true,
 803         .kerberos       = true,
 804         .priority       = GENSEC_KRB5
 805 };
 806 
 807 _PUBLIC_ NTSTATUS gensec_krb5_init(void)
     /* [<][>][^][v][top][bottom][index][help] */
 808 {
 809         NTSTATUS ret;
 810 
 811         ret = gensec_register(&gensec_krb5_security_ops);
 812         if (!NT_STATUS_IS_OK(ret)) {
 813                 DEBUG(0,("Failed to register '%s' gensec backend!\n",
 814                         gensec_krb5_security_ops.name));
 815                 return ret;
 816         }
 817 
 818         ret = gensec_register(&gensec_fake_gssapi_krb5_security_ops);
 819         if (!NT_STATUS_IS_OK(ret)) {
 820                 DEBUG(0,("Failed to register '%s' gensec backend!\n",
 821                         gensec_krb5_security_ops.name));
 822                 return ret;
 823         }
 824 
 825         return ret;
 826 }

/* [<][>][^][v][top][bottom][index][help] */