This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
+ the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "includes.h"
#include "lib/socket/socket.h"
#include "kdc/kdc.h"
#include "system/network.h"
-#include "dlinklist.h"
+#include "lib/util/dlinklist.h"
#include "lib/messaging/irpc.h"
#include "lib/stream/packet.h"
#include "librpc/gen_ndr/samr.h"
-#include "netif/netif.h"
+#include "lib/socket/netif.h"
+#include "heimdal/kdc/windc_plugin.h"
+#include "heimdal/lib/krb5/krb5_locl.h"
+#include "heimdal/kdc/kdc_locl.h"
+#include "param/param.h"
+
+
+/* Disgusting hack to get a mem_ctx into the hdb plugin, when used as a keytab */
+TALLOC_CTX *kdc_mem_ctx;
/* hold all the info needed to send a reply */
struct kdc_reply {
DATA_BLOB packet;
};
-typedef BOOL (*kdc_process_fn_t)(struct kdc_server *kdc,
+typedef bool (*kdc_process_fn_t)(struct kdc_server *kdc,
TALLOC_CTX *mem_ctx,
DATA_BLOB *input,
DATA_BLOB *reply,
struct socket_address *peer_addr,
- struct socket_address *my_addr);
+ struct socket_address *my_addr,
+ int datagram);
/* hold information about one kdc socket */
struct kdc_socket {
NTSTATUS status;
size_t sendlen;
- status = socket_sendto(kdc_socket->sock, &rep->packet, &sendlen, 0,
+ status = socket_sendto(kdc_socket->sock, &rep->packet, &sendlen,
rep->dest);
if (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
break;
return;
}
- blob = data_blob_talloc(kdc_socket, NULL, dsize);
+ blob = data_blob_talloc(tmp_ctx, NULL, dsize);
if (blob.data == NULL) {
/* hope this is a temporary low memory condition */
talloc_free(tmp_ctx);
return;
}
- status = socket_recvfrom(kdc_socket->sock, blob.data, blob.length, &nread, 0,
+ status = socket_recvfrom(kdc_socket->sock, blob.data, blob.length, &nread,
tmp_ctx, &src);
if (!NT_STATUS_IS_OK(status)) {
talloc_free(tmp_ctx);
tmp_ctx,
&blob,
&reply,
- src, my_addr);
+ src, my_addr,
+ 1 /* Datagram */);
if (!ret) {
talloc_free(tmp_ctx);
return;
&input,
&reply,
src_addr,
- my_addr);
+ my_addr,
+ 0 /* Not datagram */);
if (!ret) {
talloc_free(tmp_ctx);
return NT_STATUS_INTERNAL_ERROR;
calling conventions
*/
-static BOOL kdc_process(struct kdc_server *kdc,
+static bool kdc_process(struct kdc_server *kdc,
TALLOC_CTX *mem_ctx,
DATA_BLOB *input,
DATA_BLOB *reply,
struct socket_address *peer_addr,
- struct socket_address *my_addr)
+ struct socket_address *my_addr,
+ int datagram_reply)
{
int ret;
krb5_data k5_reply;
+ krb5_data_zero(&k5_reply);
+
+ krb5_kdc_update_time(NULL);
DEBUG(10,("Received KDC packet of length %lu from %s:%d\n",
(long)input->length - 4, peer_addr->addr, peer_addr->port));
input->data, input->length,
&k5_reply,
peer_addr->addr,
- peer_addr->sockaddr);
+ peer_addr->sockaddr,
+ datagram_reply);
if (ret == -1) {
*reply = data_blob(NULL, 0);
- return False;
+ return false;
}
- *reply = data_blob_talloc(mem_ctx, k5_reply.data, k5_reply.length);
- krb5_data_free(&k5_reply);
- return True;
+ if (k5_reply.length) {
+ *reply = data_blob_talloc(mem_ctx, k5_reply.data, k5_reply.length);
+ krb5_free_data_contents(kdc->smb_krb5_context->krb5_context, &k5_reply);
+ } else {
+ *reply = data_blob(NULL, 0);
+ }
+ return true;
}
/*
/*
start listening on the given address
*/
-static NTSTATUS kdc_add_socket(struct kdc_server *kdc, const char *address)
+static NTSTATUS kdc_add_socket(struct kdc_server *kdc, const char *address,
+ uint16_t kdc_port, uint16_t kpasswd_port)
{
const struct model_ops *model_ops;
struct kdc_socket *kdc_socket;
struct kdc_socket *kpasswd_socket;
struct socket_address *kdc_address, *kpasswd_address;
NTSTATUS status;
- uint16_t kdc_port = lp_krb5_port();
- uint16_t kpasswd_port = lp_kpasswd_port();
kdc_socket = talloc(kdc, struct kdc_socket);
NT_STATUS_HAVE_NO_MEMORY(kdc_socket);
/*
setup our listening sockets on the configured network interfaces
*/
-static NTSTATUS kdc_startup_interfaces(struct kdc_server *kdc)
+static NTSTATUS kdc_startup_interfaces(struct kdc_server *kdc, struct loadparm_context *lp_ctx)
{
int num_interfaces = iface_count();
TALLOC_CTX *tmp_ctx = talloc_new(kdc);
for (i=0; i<num_interfaces; i++) {
const char *address = talloc_strdup(tmp_ctx, iface_n_ip(i));
- status = kdc_add_socket(kdc, address);
+ status = kdc_add_socket(kdc, address, lp_krb5_port(lp_ctx),
+ lp_kpasswd_port(lp_ctx));
NT_STATUS_NOT_OK_RETURN(status);
}
return NT_STATUS_OK;
}
+static struct krb5plugin_windc_ftable windc_plugin_table = {
+ .minor_version = KRB5_WINDC_PLUGING_MINOR,
+ .init = samba_kdc_plugin_init,
+ .fini = samba_kdc_plugin_fini,
+ .pac_generate = samba_kdc_get_pac,
+ .pac_verify = samba_kdc_reget_pac,
+ .client_access = samba_kdc_check_client_access,
+};
+
+
/*
startup the kdc task
*/
NTSTATUS status;
krb5_error_code ret;
- switch (lp_server_role()) {
+ switch (lp_server_role(task->lp_ctx)) {
case ROLE_STANDALONE:
task_server_terminate(task, "kdc: no KDC required in standalone configuration");
return;
case ROLE_DOMAIN_MEMBER:
task_server_terminate(task, "kdc: no KDC required in member server configuration");
return;
- case ROLE_DOMAIN_PDC:
- case ROLE_DOMAIN_BDC:
+ case ROLE_DOMAIN_CONTROLLER:
/* Yes, we want a KDC */
break;
}
kdc->task = task;
- /* Setup the KDC configuration */
- kdc->config = talloc(kdc, krb5_kdc_configuration);
- if (!kdc->config) {
- task_server_terminate(task, "kdc: out of memory");
- return;
- }
- krb5_kdc_default_config(kdc->config);
-
initialize_krb5_error_table();
- ret = smb_krb5_init_context(kdc, &kdc->smb_krb5_context);
+ ret = smb_krb5_init_context(kdc, task->event_ctx, task->lp_ctx, &kdc->smb_krb5_context);
if (ret) {
DEBUG(1,("kdc_task_init: krb5_init_context failed (%s)\n",
error_message(ret)));
krb5_add_et_list(kdc->smb_krb5_context->krb5_context, initialize_hdb_error_table_r);
+ ret = krb5_kdc_get_config(kdc->smb_krb5_context->krb5_context,
+ &kdc->config);
+ if(ret) {
+ task_server_terminate(task, "kdc: failed to get KDC configuration");
+ return;
+ }
+
kdc->config->logf = kdc->smb_krb5_context->logf;
- kdc->config->db = talloc(kdc->config, struct HDB *);
+ kdc->config->db = talloc(kdc, struct HDB *);
if (!kdc->config->db) {
task_server_terminate(task, "kdc: out of memory");
return;
task_server_terminate(task, "kdc: failed to register hdb keytab");
return;
}
+
+ /* Registar WinDC hooks */
+ ret = _krb5_plugin_register(kdc->smb_krb5_context->krb5_context,
+ PLUGIN_TYPE_DATA, "windc",
+ &windc_plugin_table);
+ if(ret) {
+ task_server_terminate(task, "kdc: failed to register hdb keytab");
+ return;
+ }
+
+ krb5_kdc_windc_init(kdc->smb_krb5_context->krb5_context);
+
+ kdc_mem_ctx = kdc->smb_krb5_context;
+
/* start listening on the configured network interfaces */
- status = kdc_startup_interfaces(kdc);
+ status = kdc_startup_interfaces(kdc, task->lp_ctx);
if (!NT_STATUS_IS_OK(status)) {
task_server_terminate(task, "kdc failed to setup interfaces");
return;