root/source4/kdc/kdc.c

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

DEFINITIONS

This source file includes following definitions.
  1. kdc_send_handler
  2. kdc_recv_handler
  3. kdc_socket_handler
  4. kdc_tcp_terminate_connection
  5. kdc_tcp_recv
  6. kdc_tcp_recv_handler
  7. kdc_tcp_recv_error
  8. kdc_tcp_send
  9. kdc_process
  10. kdc_tcp_generic_accept
  11. kdc_tcp_accept
  12. kpasswdd_tcp_accept
  13. kdc_add_socket
  14. kdc_startup_interfaces
  15. kdc_check_generic_kerberos
  16. kdc_task_init
  17. server_service_kdc_init

   1 /* 
   2    Unix SMB/CIFS implementation.
   3 
   4    KDC Server startup
   5 
   6    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2008
   7    Copyright (C) Andrew Tridgell        2005
   8    Copyright (C) Stefan Metzmacher      2005
   9 
  10    This program is free software; you can redistribute it and/or modify
  11    it under the terms of the GNU General Public License as published by
  12    the Free Software Foundation; either version 3 of the License, or
  13    (at your option) any later version.
  14    
  15    This program is distributed in the hope that it will be useful,
  16    but WITHOUT ANY WARRANTY; without even the implied warranty of
  17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18    GNU General Public License for more details.
  19    
  20    You should have received a copy of the GNU General Public License
  21    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  22 */
  23 
  24 #include "includes.h"
  25 #include "smbd/service_task.h"
  26 #include "smbd/service.h"
  27 #include "smbd/service_stream.h"
  28 #include "smbd/process_model.h"
  29 #include "lib/events/events.h"
  30 #include "lib/socket/socket.h"
  31 #include "system/network.h"
  32 #include "../lib/util/dlinklist.h"
  33 #include "lib/messaging/irpc.h"
  34 #include "lib/stream/packet.h"
  35 #include "librpc/gen_ndr/samr.h"
  36 #include "librpc/gen_ndr/ndr_irpc.h"
  37 #include "librpc/gen_ndr/ndr_krb5pac.h"
  38 #include "lib/socket/netif.h"
  39 #include "param/param.h"
  40 #include "kdc/kdc.h"
  41 #include "librpc/gen_ndr/ndr_misc.h"
  42 
  43 
  44 /* Disgusting hack to get a mem_ctx and lp_ctx into the hdb plugin, when 
  45  * used as a keytab */
  46 TALLOC_CTX *kdc_mem_ctx;
  47 struct tevent_context *kdc_ev_ctx;
  48 struct loadparm_context *kdc_lp_ctx;
  49 
  50 /* hold all the info needed to send a reply */
  51 struct kdc_reply {
  52         struct kdc_reply *next, *prev;
  53         struct socket_address *dest;
  54         DATA_BLOB packet;
  55 };
  56 
  57 typedef bool (*kdc_process_fn_t)(struct kdc_server *kdc,
  58                                  TALLOC_CTX *mem_ctx, 
  59                                  DATA_BLOB *input, 
  60                                  DATA_BLOB *reply,
  61                                  struct socket_address *peer_addr, 
  62                                  struct socket_address *my_addr, 
  63                                  int datagram);
  64 
  65 /* hold information about one kdc socket */
  66 struct kdc_socket {
  67         struct socket_context *sock;
  68         struct kdc_server *kdc;
  69         struct tevent_fd *fde;
  70 
  71         /* a queue of outgoing replies that have been deferred */
  72         struct kdc_reply *send_queue;
  73 
  74         kdc_process_fn_t process;
  75 };
  76 /*
  77   state of an open tcp connection
  78 */
  79 struct kdc_tcp_connection {
  80         /* stream connection we belong to */
  81         struct stream_connection *conn;
  82 
  83         /* the kdc_server the connection belongs to */
  84         struct kdc_server *kdc;
  85 
  86         struct packet_context *packet;
  87 
  88         kdc_process_fn_t process;
  89 };
  90 
  91 /*
  92   handle fd send events on a KDC socket
  93 */
  94 static void kdc_send_handler(struct kdc_socket *kdc_socket)
     /* [<][>][^][v][top][bottom][index][help] */
  95 {
  96         while (kdc_socket->send_queue) {
  97                 struct kdc_reply *rep = kdc_socket->send_queue;
  98                 NTSTATUS status;
  99                 size_t sendlen;
 100 
 101                 status = socket_sendto(kdc_socket->sock, &rep->packet, &sendlen,
 102                                        rep->dest);
 103                 if (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
 104                         break;
 105                 }
 106                 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_BUFFER_SIZE)) {
 107                         /* Replace with a krb err, response to big */
 108                 }
 109                 
 110                 DLIST_REMOVE(kdc_socket->send_queue, rep);
 111                 talloc_free(rep);
 112         }
 113 
 114         if (kdc_socket->send_queue == NULL) {
 115                 EVENT_FD_NOT_WRITEABLE(kdc_socket->fde);
 116         }
 117 }
 118 
 119 
 120 /*
 121   handle fd recv events on a KDC socket
 122 */
 123 static void kdc_recv_handler(struct kdc_socket *kdc_socket)
     /* [<][>][^][v][top][bottom][index][help] */
 124 {
 125         NTSTATUS status;
 126         TALLOC_CTX *tmp_ctx = talloc_new(kdc_socket);
 127         DATA_BLOB blob;
 128         struct kdc_reply *rep;
 129         DATA_BLOB reply;
 130         size_t nread, dsize;
 131         struct socket_address *src;
 132         struct socket_address *my_addr;
 133         int ret;
 134 
 135         status = socket_pending(kdc_socket->sock, &dsize);
 136         if (!NT_STATUS_IS_OK(status)) {
 137                 talloc_free(tmp_ctx);
 138                 return;
 139         }
 140 
 141         blob = data_blob_talloc(tmp_ctx, NULL, dsize);
 142         if (blob.data == NULL) {
 143                 /* hope this is a temporary low memory condition */
 144                 talloc_free(tmp_ctx);
 145                 return;
 146         }
 147 
 148         status = socket_recvfrom(kdc_socket->sock, blob.data, blob.length, &nread,
 149                                  tmp_ctx, &src);
 150         if (!NT_STATUS_IS_OK(status)) {
 151                 talloc_free(tmp_ctx);
 152                 return;
 153         }
 154         blob.length = nread;
 155         
 156         DEBUG(10,("Received krb5 UDP packet of length %lu from %s:%u\n", 
 157                  (long)blob.length, src->addr, (uint16_t)src->port));
 158         
 159         my_addr = socket_get_my_addr(kdc_socket->sock, tmp_ctx);
 160         if (!my_addr) {
 161                 talloc_free(tmp_ctx);
 162                 return;
 163         }
 164 
 165 
 166         /* Call krb5 */
 167         ret = kdc_socket->process(kdc_socket->kdc, 
 168                                   tmp_ctx, 
 169                                   &blob,  
 170                                   &reply,
 171                                   src, my_addr,
 172                                   1 /* Datagram */);
 173         if (!ret) {
 174                 talloc_free(tmp_ctx);
 175                 return;
 176         }
 177 
 178         /* queue a pending reply */
 179         rep = talloc(kdc_socket, struct kdc_reply);
 180         if (rep == NULL) {
 181                 talloc_free(tmp_ctx);
 182                 return;
 183         }
 184         rep->dest         = talloc_steal(rep, src);
 185         rep->packet       = reply;
 186         talloc_steal(rep, reply.data);
 187 
 188         if (rep->packet.data == NULL) {
 189                 talloc_free(rep);
 190                 talloc_free(tmp_ctx);
 191                 return;
 192         }
 193 
 194         DLIST_ADD_END(kdc_socket->send_queue, rep, struct kdc_reply *);
 195         EVENT_FD_WRITEABLE(kdc_socket->fde);
 196         talloc_free(tmp_ctx);
 197 }
 198 
 199 /*
 200   handle fd events on a KDC socket
 201 */
 202 static void kdc_socket_handler(struct tevent_context *ev, struct tevent_fd *fde,
     /* [<][>][^][v][top][bottom][index][help] */
 203                                uint16_t flags, void *private_data)
 204 {
 205         struct kdc_socket *kdc_socket = talloc_get_type(private_data, struct kdc_socket);
 206         if (flags & EVENT_FD_WRITE) {
 207                 kdc_send_handler(kdc_socket);
 208         } 
 209         if (flags & EVENT_FD_READ) {
 210                 kdc_recv_handler(kdc_socket);
 211         }
 212 }
 213 
 214 static void kdc_tcp_terminate_connection(struct kdc_tcp_connection *kdcconn, const char *reason)
     /* [<][>][^][v][top][bottom][index][help] */
 215 {
 216         stream_terminate_connection(kdcconn->conn, reason);
 217 }
 218 
 219 /*
 220   receive a full packet on a KDC connection
 221 */
 222 static NTSTATUS kdc_tcp_recv(void *private_data, DATA_BLOB blob)
     /* [<][>][^][v][top][bottom][index][help] */
 223 {
 224         struct kdc_tcp_connection *kdcconn = talloc_get_type(private_data,
 225                                                              struct kdc_tcp_connection);
 226         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
 227         TALLOC_CTX *tmp_ctx = talloc_new(kdcconn);
 228         int ret;
 229         DATA_BLOB input, reply;
 230         struct socket_address *src_addr;
 231         struct socket_address *my_addr;
 232 
 233         talloc_steal(tmp_ctx, blob.data);
 234 
 235         src_addr = socket_get_peer_addr(kdcconn->conn->socket, tmp_ctx);
 236         if (!src_addr) {
 237                 talloc_free(tmp_ctx);
 238                 return NT_STATUS_NO_MEMORY;
 239         }
 240 
 241         my_addr = socket_get_my_addr(kdcconn->conn->socket, tmp_ctx);
 242         if (!my_addr) {
 243                 talloc_free(tmp_ctx);
 244                 return NT_STATUS_NO_MEMORY;
 245         }
 246 
 247         /* Call krb5 */
 248         input = data_blob_const(blob.data + 4, blob.length - 4); 
 249 
 250         ret = kdcconn->process(kdcconn->kdc, 
 251                                tmp_ctx,
 252                                &input,
 253                                &reply,
 254                                src_addr,
 255                                my_addr,
 256                                0 /* Not datagram */);
 257         if (!ret) {
 258                 talloc_free(tmp_ctx);
 259                 return NT_STATUS_INTERNAL_ERROR;
 260         }
 261 
 262         /* and now encode the reply */
 263         blob = data_blob_talloc(kdcconn, NULL, reply.length + 4);
 264         if (!blob.data) {
 265                 talloc_free(tmp_ctx);
 266                 return NT_STATUS_NO_MEMORY;
 267         }
 268 
 269         RSIVAL(blob.data, 0, reply.length);
 270         memcpy(blob.data + 4, reply.data, reply.length);        
 271 
 272         status = packet_send(kdcconn->packet, blob);
 273         if (!NT_STATUS_IS_OK(status)) {
 274                 talloc_free(tmp_ctx);
 275                 return status;
 276         }
 277 
 278         /* the call isn't needed any more */
 279         talloc_free(tmp_ctx);
 280         return NT_STATUS_OK;
 281 }
 282 
 283 /*
 284   receive some data on a KDC connection
 285 */
 286 static void kdc_tcp_recv_handler(struct stream_connection *conn, uint16_t flags)
     /* [<][>][^][v][top][bottom][index][help] */
 287 {
 288         struct kdc_tcp_connection *kdcconn = talloc_get_type(conn->private_data,
 289                                                              struct kdc_tcp_connection);
 290         packet_recv(kdcconn->packet);
 291 }
 292 
 293 /*
 294   called on a tcp recv error
 295 */
 296 static void kdc_tcp_recv_error(void *private_data, NTSTATUS status)
     /* [<][>][^][v][top][bottom][index][help] */
 297 {
 298         struct kdc_tcp_connection *kdcconn = talloc_get_type(private_data,
 299                                              struct kdc_tcp_connection);
 300         kdc_tcp_terminate_connection(kdcconn, nt_errstr(status));
 301 }
 302 
 303 /*
 304   called when we can write to a connection
 305 */
 306 static void kdc_tcp_send(struct stream_connection *conn, uint16_t flags)
     /* [<][>][^][v][top][bottom][index][help] */
 307 {
 308         struct kdc_tcp_connection *kdcconn = talloc_get_type(conn->private_data,
 309                                                              struct kdc_tcp_connection);
 310         packet_queue_run(kdcconn->packet);
 311 }
 312 
 313 /**
 314    Wrapper for krb5_kdc_process_krb5_request, converting to/from Samba
 315    calling conventions
 316 */
 317 
 318 static bool kdc_process(struct kdc_server *kdc,
     /* [<][>][^][v][top][bottom][index][help] */
 319                         TALLOC_CTX *mem_ctx, 
 320                         DATA_BLOB *input, 
 321                         DATA_BLOB *reply,
 322                         struct socket_address *peer_addr, 
 323                         struct socket_address *my_addr,
 324                         int datagram_reply)
 325 {
 326         int ret;        
 327         krb5_data k5_reply;
 328         krb5_data_zero(&k5_reply);
 329 
 330         krb5_kdc_update_time(NULL);
 331 
 332         DEBUG(10,("Received KDC packet of length %lu from %s:%d\n", 
 333                   (long)input->length - 4, peer_addr->addr, peer_addr->port));
 334 
 335         ret = krb5_kdc_process_krb5_request(kdc->smb_krb5_context->krb5_context, 
 336                                             kdc->config,
 337                                             input->data, input->length,
 338                                             &k5_reply,
 339                                             peer_addr->addr,
 340                                             peer_addr->sockaddr,
 341                                             datagram_reply);
 342         if (ret == -1) {
 343                 *reply = data_blob(NULL, 0);
 344                 return false;
 345         }
 346         if (k5_reply.length) {
 347                 *reply = data_blob_talloc(mem_ctx, k5_reply.data, k5_reply.length);
 348                 krb5_free_data_contents(kdc->smb_krb5_context->krb5_context, &k5_reply);
 349         } else {
 350                 *reply = data_blob(NULL, 0);    
 351         }
 352         return true;
 353 }
 354 
 355 /*
 356   called when we get a new connection
 357 */
 358 static void kdc_tcp_generic_accept(struct stream_connection *conn, kdc_process_fn_t process_fn)
     /* [<][>][^][v][top][bottom][index][help] */
 359 {
 360         struct kdc_server *kdc = talloc_get_type(conn->private_data, struct kdc_server);
 361         struct kdc_tcp_connection *kdcconn;
 362 
 363         kdcconn = talloc_zero(conn, struct kdc_tcp_connection);
 364         if (!kdcconn) {
 365                 stream_terminate_connection(conn, "kdc_tcp_accept: out of memory");
 366                 return;
 367         }
 368         kdcconn->conn    = conn;
 369         kdcconn->kdc     = kdc;
 370         kdcconn->process = process_fn;
 371         conn->private_data    = kdcconn;
 372 
 373         kdcconn->packet = packet_init(kdcconn);
 374         if (kdcconn->packet == NULL) {
 375                 kdc_tcp_terminate_connection(kdcconn, "kdc_tcp_accept: out of memory");
 376                 return;
 377         }
 378         packet_set_private(kdcconn->packet, kdcconn);
 379         packet_set_socket(kdcconn->packet, conn->socket);
 380         packet_set_callback(kdcconn->packet, kdc_tcp_recv);
 381         packet_set_full_request(kdcconn->packet, packet_full_request_u32);
 382         packet_set_error_handler(kdcconn->packet, kdc_tcp_recv_error);
 383         packet_set_event_context(kdcconn->packet, conn->event.ctx);
 384         packet_set_fde(kdcconn->packet, conn->event.fde);
 385         packet_set_serialise(kdcconn->packet);
 386 }
 387 
 388 static void kdc_tcp_accept(struct stream_connection *conn)
     /* [<][>][^][v][top][bottom][index][help] */
 389 {
 390         kdc_tcp_generic_accept(conn, kdc_process);
 391 }
 392 
 393 static const struct stream_server_ops kdc_tcp_stream_ops = {
 394         .name                   = "kdc_tcp",
 395         .accept_connection      = kdc_tcp_accept,
 396         .recv_handler           = kdc_tcp_recv_handler,
 397         .send_handler           = kdc_tcp_send
 398 };
 399 
 400 static void kpasswdd_tcp_accept(struct stream_connection *conn)
     /* [<][>][^][v][top][bottom][index][help] */
 401 {
 402         kdc_tcp_generic_accept(conn, kpasswdd_process);
 403 }
 404 
 405 static const struct stream_server_ops kpasswdd_tcp_stream_ops = {
 406         .name                   = "kpasswdd_tcp",
 407         .accept_connection      = kpasswdd_tcp_accept,
 408         .recv_handler           = kdc_tcp_recv_handler,
 409         .send_handler           = kdc_tcp_send
 410 };
 411 
 412 /*
 413   start listening on the given address
 414 */
 415 static NTSTATUS kdc_add_socket(struct kdc_server *kdc, const char *address,
     /* [<][>][^][v][top][bottom][index][help] */
 416                                uint16_t kdc_port, uint16_t kpasswd_port)
 417 {
 418         const struct model_ops *model_ops;
 419         struct kdc_socket *kdc_socket;
 420         struct kdc_socket *kpasswd_socket;
 421         struct socket_address *kdc_address, *kpasswd_address;
 422         NTSTATUS status;
 423 
 424         kdc_socket = talloc(kdc, struct kdc_socket);
 425         NT_STATUS_HAVE_NO_MEMORY(kdc_socket);
 426 
 427         kpasswd_socket = talloc(kdc, struct kdc_socket);
 428         NT_STATUS_HAVE_NO_MEMORY(kpasswd_socket);
 429 
 430         status = socket_create("ip", SOCKET_TYPE_DGRAM, &kdc_socket->sock, 0);
 431         if (!NT_STATUS_IS_OK(status)) {
 432                 talloc_free(kdc_socket);
 433                 return status;
 434         }
 435 
 436         status = socket_create("ip", SOCKET_TYPE_DGRAM, &kpasswd_socket->sock, 0);
 437         if (!NT_STATUS_IS_OK(status)) {
 438                 talloc_free(kpasswd_socket);
 439                 return status;
 440         }
 441 
 442         kdc_socket->kdc = kdc;
 443         kdc_socket->send_queue = NULL;
 444         kdc_socket->process = kdc_process;
 445 
 446         talloc_steal(kdc_socket, kdc_socket->sock);
 447 
 448         kdc_socket->fde = event_add_fd(kdc->task->event_ctx, kdc, 
 449                                        socket_get_fd(kdc_socket->sock), EVENT_FD_READ,
 450                                        kdc_socket_handler, kdc_socket);
 451 
 452         kdc_address = socket_address_from_strings(kdc_socket, kdc_socket->sock->backend_name, 
 453                                                   address, kdc_port);
 454         NT_STATUS_HAVE_NO_MEMORY(kdc_address);
 455 
 456         status = socket_listen(kdc_socket->sock, kdc_address, 0, 0);
 457         if (!NT_STATUS_IS_OK(status)) {
 458                 DEBUG(0,("Failed to bind to %s:%d UDP for kdc - %s\n", 
 459                          address, kdc_port, nt_errstr(status)));
 460                 talloc_free(kdc_socket);
 461                 return status;
 462         }
 463 
 464         kpasswd_socket->kdc = kdc;
 465         kpasswd_socket->send_queue = NULL;
 466         kpasswd_socket->process = kpasswdd_process;
 467 
 468         talloc_steal(kpasswd_socket, kpasswd_socket->sock);
 469 
 470         kpasswd_socket->fde = event_add_fd(kdc->task->event_ctx, kdc, 
 471                                            socket_get_fd(kpasswd_socket->sock), EVENT_FD_READ,
 472                                            kdc_socket_handler, kpasswd_socket);
 473         
 474         kpasswd_address = socket_address_from_strings(kpasswd_socket, kpasswd_socket->sock->backend_name, 
 475                                                       address, kpasswd_port);
 476         NT_STATUS_HAVE_NO_MEMORY(kpasswd_address);
 477 
 478         status = socket_listen(kpasswd_socket->sock, kpasswd_address, 0, 0);
 479         if (!NT_STATUS_IS_OK(status)) {
 480                 DEBUG(0,("Failed to bind to %s:%d UDP for kpasswd - %s\n", 
 481                          address, kpasswd_port, nt_errstr(status)));
 482                 talloc_free(kpasswd_socket);
 483                 return status;
 484         }
 485 
 486         /* within the kdc task we want to be a single process, so
 487            ask for the single process model ops and pass these to the
 488            stream_setup_socket() call. */
 489         model_ops = process_model_startup(kdc->task->event_ctx, "single");
 490         if (!model_ops) {
 491                 DEBUG(0,("Can't find 'single' process model_ops\n"));
 492                 talloc_free(kdc_socket);
 493                 return NT_STATUS_INTERNAL_ERROR;
 494         }
 495 
 496         status = stream_setup_socket(kdc->task->event_ctx, 
 497                                      kdc->task->lp_ctx,
 498                                      model_ops, 
 499                                      &kdc_tcp_stream_ops, 
 500                                      "ip", address, &kdc_port, 
 501                                      lp_socket_options(kdc->task->lp_ctx), 
 502                                      kdc);
 503         if (!NT_STATUS_IS_OK(status)) {
 504                 DEBUG(0,("Failed to bind to %s:%u TCP - %s\n",
 505                          address, kdc_port, nt_errstr(status)));
 506                 talloc_free(kdc_socket);
 507                 return status;
 508         }
 509 
 510         status = stream_setup_socket(kdc->task->event_ctx, 
 511                                      kdc->task->lp_ctx,
 512                                      model_ops, 
 513                                      &kpasswdd_tcp_stream_ops, 
 514                                      "ip", address, &kpasswd_port, 
 515                                      lp_socket_options(kdc->task->lp_ctx), 
 516                                      kdc);
 517         if (!NT_STATUS_IS_OK(status)) {
 518                 DEBUG(0,("Failed to bind to %s:%u TCP - %s\n",
 519                          address, kpasswd_port, nt_errstr(status)));
 520                 talloc_free(kdc_socket);
 521                 return status;
 522         }
 523 
 524         return NT_STATUS_OK;
 525 }
 526 
 527 
 528 /*
 529   setup our listening sockets on the configured network interfaces
 530 */
 531 static NTSTATUS kdc_startup_interfaces(struct kdc_server *kdc, struct loadparm_context *lp_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 532                                        struct interface *ifaces)
 533 {
 534         int num_interfaces;
 535         TALLOC_CTX *tmp_ctx = talloc_new(kdc);
 536         NTSTATUS status;
 537         int i;
 538 
 539         num_interfaces = iface_count(ifaces);
 540         
 541         for (i=0; i<num_interfaces; i++) {
 542                 const char *address = talloc_strdup(tmp_ctx, iface_n_ip(ifaces, i));
 543                 status = kdc_add_socket(kdc, address, lp_krb5_port(lp_ctx), 
 544                                         lp_kpasswd_port(lp_ctx));
 545                 NT_STATUS_NOT_OK_RETURN(status);
 546         }
 547 
 548         talloc_free(tmp_ctx);
 549 
 550         return NT_STATUS_OK;
 551 }
 552 
 553 static struct krb5plugin_windc_ftable windc_plugin_table = {
 554         .minor_version = KRB5_WINDC_PLUGING_MINOR,
 555         .init = samba_kdc_plugin_init,
 556         .fini = samba_kdc_plugin_fini,
 557         .pac_generate = samba_kdc_get_pac,
 558         .pac_verify = samba_kdc_reget_pac,
 559         .client_access = samba_kdc_check_client_access,
 560 };
 561 
 562 
 563 static NTSTATUS kdc_check_generic_kerberos(struct irpc_message *msg, 
     /* [<][>][^][v][top][bottom][index][help] */
 564                                  struct kdc_check_generic_kerberos *r)
 565 {
 566         struct PAC_Validate pac_validate;
 567         DATA_BLOB srv_sig;
 568         struct PAC_SIGNATURE_DATA kdc_sig;
 569         struct kdc_server *kdc = talloc_get_type(msg->private_data, struct kdc_server);
 570         enum ndr_err_code ndr_err;
 571         krb5_enctype etype;
 572         int ret;
 573         hdb_entry_ex ent;
 574         krb5_principal principal;
 575         krb5_keyblock keyblock;
 576         Key *key;
 577 
 578         /* There is no reply to this request */
 579         r->out.generic_reply = data_blob(NULL, 0);
 580 
 581         ndr_err = ndr_pull_struct_blob(&r->in.generic_request, msg, 
 582                                        lp_iconv_convenience(kdc->task->lp_ctx), 
 583                                        &pac_validate,
 584                                        (ndr_pull_flags_fn_t)ndr_pull_PAC_Validate);
 585         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
 586                 return NT_STATUS_INVALID_PARAMETER;
 587         }
 588         
 589         if (pac_validate.MessageType != 3) {
 590                 /* We don't implement any other message types - such as certificate validation - yet */
 591                 return NT_STATUS_INVALID_PARAMETER;
 592         }
 593 
 594         if (pac_validate.ChecksumAndSignature.length != (pac_validate.ChecksumLength + pac_validate.SignatureLength)
 595             || pac_validate.ChecksumAndSignature.length < pac_validate.ChecksumLength
 596             || pac_validate.ChecksumAndSignature.length < pac_validate.SignatureLength ) {
 597                 return NT_STATUS_INVALID_PARAMETER;
 598         }
 599         
 600         srv_sig = data_blob_const(pac_validate.ChecksumAndSignature.data, 
 601                                   pac_validate.ChecksumLength);
 602         
 603         if (pac_validate.SignatureType == CKSUMTYPE_HMAC_MD5) {
 604                 etype = ETYPE_ARCFOUR_HMAC_MD5;
 605         } else {
 606                 ret = krb5_cksumtype_to_enctype(kdc->smb_krb5_context->krb5_context, pac_validate.SignatureType,
 607                                                 &etype);
 608                 if (ret != 0) {
 609                         return NT_STATUS_LOGON_FAILURE;
 610                 }
 611         }
 612 
 613         ret = krb5_make_principal(kdc->smb_krb5_context->krb5_context, &principal, 
 614                                   lp_realm(kdc->task->lp_ctx), 
 615                                   "krbtgt", lp_realm(kdc->task->lp_ctx), 
 616                                   NULL);
 617 
 618         if (ret != 0) {
 619                 return NT_STATUS_NO_MEMORY;
 620         }
 621 
 622         ret = kdc->config->db[0]->hdb_fetch(kdc->smb_krb5_context->krb5_context, 
 623                                             kdc->config->db[0],
 624                                             principal,
 625                                             HDB_F_GET_KRBTGT | HDB_F_DECRYPT,
 626                                             &ent);
 627 
 628         if (ret != 0) {
 629                 hdb_free_entry(kdc->smb_krb5_context->krb5_context, &ent);
 630                 krb5_free_principal(kdc->smb_krb5_context->krb5_context, principal);
 631         
 632                 return NT_STATUS_LOGON_FAILURE;
 633         }
 634         
 635         ret = hdb_enctype2key(kdc->smb_krb5_context->krb5_context, &ent.entry, etype, &key);
 636 
 637         if (ret != 0) {
 638                 hdb_free_entry(kdc->smb_krb5_context->krb5_context, &ent);
 639                 krb5_free_principal(kdc->smb_krb5_context->krb5_context, principal);
 640                 return NT_STATUS_LOGON_FAILURE;
 641         }
 642 
 643         keyblock = key->key;
 644         
 645         kdc_sig.type = pac_validate.SignatureType;
 646         kdc_sig.signature = data_blob_const(&pac_validate.ChecksumAndSignature.data[pac_validate.ChecksumLength],
 647                                             pac_validate.SignatureLength);
 648         ret = check_pac_checksum(msg, srv_sig, &kdc_sig, 
 649                            kdc->smb_krb5_context->krb5_context, &keyblock);
 650 
 651         hdb_free_entry(kdc->smb_krb5_context->krb5_context, &ent);
 652         krb5_free_principal(kdc->smb_krb5_context->krb5_context, principal);
 653 
 654         if (ret != 0) {
 655                 return NT_STATUS_LOGON_FAILURE;
 656         }
 657         
 658         return NT_STATUS_OK;
 659 }
 660 
 661 
 662 static struct hdb_method hdb_samba4 = {
 663         .interface_version = HDB_INTERFACE_VERSION,
 664         .prefix = "samba4:",
 665         .create = hdb_samba4_create
 666 };
 667 
 668 /*
 669   startup the kdc task
 670 */
 671 static void kdc_task_init(struct task_server *task)
     /* [<][>][^][v][top][bottom][index][help] */
 672 {
 673         struct kdc_server *kdc;
 674         NTSTATUS status;
 675         krb5_error_code ret;
 676         struct interface *ifaces;
 677 
 678         switch (lp_server_role(task->lp_ctx)) {
 679         case ROLE_STANDALONE:
 680                 task_server_terminate(task, "kdc: no KDC required in standalone configuration");
 681                 return;
 682         case ROLE_DOMAIN_MEMBER:
 683                 task_server_terminate(task, "kdc: no KDC required in member server configuration");
 684                 return;
 685         case ROLE_DOMAIN_CONTROLLER:
 686                 /* Yes, we want a KDC */
 687                 break;
 688         }
 689 
 690         load_interfaces(task, lp_interfaces(task->lp_ctx), &ifaces);
 691 
 692         if (iface_count(ifaces) == 0) {
 693                 task_server_terminate(task, "kdc: no network interfaces configured");
 694                 return;
 695         }
 696 
 697         task_server_set_title(task, "task[kdc]");
 698 
 699         kdc = talloc(task, struct kdc_server);
 700         if (kdc == NULL) {
 701                 task_server_terminate(task, "kdc: out of memory");
 702                 return;
 703         }
 704 
 705         kdc->task = task;
 706 
 707         initialize_krb5_error_table();
 708 
 709         ret = smb_krb5_init_context(kdc, task->event_ctx, task->lp_ctx, &kdc->smb_krb5_context);
 710         if (ret) {
 711                 DEBUG(1,("kdc_task_init: krb5_init_context failed (%s)\n", 
 712                          error_message(ret)));
 713                 task_server_terminate(task, "kdc: krb5_init_context failed");
 714                 return; 
 715         }
 716 
 717         krb5_add_et_list(kdc->smb_krb5_context->krb5_context, initialize_hdb_error_table_r);
 718 
 719         ret = krb5_kdc_get_config(kdc->smb_krb5_context->krb5_context, 
 720                                   &kdc->config);
 721         if(ret) {
 722                 task_server_terminate(task, "kdc: failed to get KDC configuration");
 723                 return;
 724         }
 725 
 726         kdc->config->logf = kdc->smb_krb5_context->logf;
 727         kdc->config->db = talloc(kdc, struct HDB *);
 728         if (!kdc->config->db) {
 729                 task_server_terminate(task, "kdc: out of memory");
 730                 return;
 731         }
 732         kdc->config->num_db = 1;
 733                 
 734         status = kdc_hdb_samba4_create(kdc, task->event_ctx, task->lp_ctx, 
 735                                     kdc->smb_krb5_context->krb5_context, 
 736                                     &kdc->config->db[0], NULL);
 737         if (!NT_STATUS_IS_OK(status)) {
 738                 task_server_terminate(task, "kdc: hdb_ldb_create (setup KDC database) failed");
 739                 return; 
 740         }
 741 
 742 
 743         /* Register hdb-samba4 hooks */
 744         ret = krb5_plugin_register(kdc->smb_krb5_context->krb5_context, 
 745                                    PLUGIN_TYPE_DATA, "hdb",
 746                                    &hdb_samba4);
 747         if(ret) {
 748                 task_server_terminate(task, "kdc: failed to register hdb keytab");
 749                 return;
 750         }
 751 
 752         ret = krb5_kt_register(kdc->smb_krb5_context->krb5_context, &hdb_kt_ops);
 753         if(ret) {
 754                 task_server_terminate(task, "kdc: failed to register hdb keytab");
 755                 return;
 756         }
 757 
 758         /* Registar WinDC hooks */
 759         ret = krb5_plugin_register(kdc->smb_krb5_context->krb5_context, 
 760                                    PLUGIN_TYPE_DATA, "windc",
 761                                    &windc_plugin_table);
 762         if(ret) {
 763                 task_server_terminate(task, "kdc: failed to register hdb keytab");
 764                 return;
 765         }
 766 
 767         krb5_kdc_windc_init(kdc->smb_krb5_context->krb5_context);
 768 
 769         kdc_mem_ctx = kdc->smb_krb5_context;
 770         kdc_ev_ctx = task->event_ctx;
 771         kdc_lp_ctx = task->lp_ctx;
 772 
 773         /* start listening on the configured network interfaces */
 774         status = kdc_startup_interfaces(kdc, task->lp_ctx, ifaces);
 775         if (!NT_STATUS_IS_OK(status)) {
 776                 task_server_terminate(task, "kdc failed to setup interfaces");
 777                 return;
 778         }
 779 
 780         status = IRPC_REGISTER(task->msg_ctx, irpc, KDC_CHECK_GENERIC_KERBEROS, 
 781                                kdc_check_generic_kerberos, kdc);
 782         if (!NT_STATUS_IS_OK(status)) {
 783                 task_server_terminate(task, "nbtd failed to setup monitoring");
 784                 return;
 785         }
 786 
 787         irpc_add_name(task->msg_ctx, "kdc_server");
 788 }
 789 
 790 
 791 /* called at smbd startup - register ourselves as a server service */
 792 NTSTATUS server_service_kdc_init(void)
     /* [<][>][^][v][top][bottom][index][help] */
 793 {
 794         return register_server_service("kdc", kdc_task_init);
 795 }

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