diff options
author | Andrew Bartlett <abartlet@samba.org> | 2005-11-06 14:15:34 +0000 |
---|---|---|
committer | Gerald (Jerry) Carter <jerry@samba.org> | 2007-10-10 13:45:50 -0500 |
commit | fb2394d309f33bdccde3a4e17f6fd994d452b425 (patch) | |
tree | f1caf0a70e1fb2729b15f03564d1b68dbaa412e3 | |
parent | df5b70db2c228bd781d8472440858dcdf502f9f9 (diff) | |
download | samba-fb2394d309f33bdccde3a4e17f6fd994d452b425.tar.gz samba-fb2394d309f33bdccde3a4e17f6fd994d452b425.tar.bz2 samba-fb2394d309f33bdccde3a4e17f6fd994d452b425.zip |
r11536: Add a hook for client-principal access control to hdb-ldb, re-using
the code in auth/auth_sam.c for consistancy. This will also allow us
to have one place for a backend directory hook.
I will use a very similar hook to add the PAC.
Andrew Bartlett
(This used to be commit 4315836cd8c94eb8340c4050804face4d0066810)
-rw-r--r-- | source4/heimdal/kdc/kdc_locl.h | 9 | ||||
-rw-r--r-- | source4/heimdal/kdc/kerberos5.c | 72 | ||||
-rw-r--r-- | source4/heimdal/kdc/misc.c | 56 | ||||
-rw-r--r-- | source4/heimdal/lib/hdb/hdb-protos.h | 3 | ||||
-rw-r--r-- | source4/heimdal/lib/hdb/hdb.c | 10 | ||||
-rw-r--r-- | source4/heimdal/lib/hdb/hdb.h | 21 | ||||
-rw-r--r-- | source4/kdc/hdb-ldb.c | 104 |
7 files changed, 231 insertions, 44 deletions
diff --git a/source4/heimdal/kdc/kdc_locl.h b/source4/heimdal/kdc/kdc_locl.h index b0501abb8d..8658d33b68 100644 --- a/source4/heimdal/kdc/kdc_locl.h +++ b/source4/heimdal/kdc/kdc_locl.h @@ -71,10 +71,19 @@ krb5_error_code _kdc_db_fetch(krb5_context, krb5_kdc_configuration *, krb5_principal, enum hdb_ent_type, hdb_entry **); +krb5_error_code +_kdc_db_fetch_ex(krb5_context context, + krb5_kdc_configuration *config, + krb5_principal principal, enum hdb_ent_type ent_type, + hdb_entry_ex **h); + void _kdc_free_ent(krb5_context context, hdb_entry *); void +_kdc_free_ent_ex(krb5_context context, hdb_entry_ex *ent); + +void loop(krb5_context context, krb5_kdc_configuration *config); krb5_error_code diff --git a/source4/heimdal/kdc/kerberos5.c b/source4/heimdal/kdc/kerberos5.c index 1c02e66211..0df090eef3 100644 --- a/source4/heimdal/kdc/kerberos5.c +++ b/source4/heimdal/kdc/kerberos5.c @@ -767,7 +767,8 @@ _kdc_as_rep(krb5_context context, KDC_REQ_BODY *b = &req->req_body; AS_REP rep; KDCOptions f = b->kdc_options; - hdb_entry *client = NULL, *server = NULL; + hdb_entry_ex *client = NULL; + hdb_entry *server = NULL; krb5_enctype cetype, setype; EncTicketPart et; EncKDCRepPart ek; @@ -813,7 +814,7 @@ _kdc_as_rep(krb5_context context, kdc_log(context, config, 0, "AS-REQ %s from %s for %s", client_name, from, server_name); - ret = _kdc_db_fetch(context, config, client_princ, HDB_ENT_TYPE_CLIENT, &client); + ret = _kdc_db_fetch_ex(context, config, client_princ, HDB_ENT_TYPE_CLIENT, &client); if(ret){ kdc_log(context, config, 0, "UNKNOWN -- %s: %s", client_name, krb5_get_err_text(context, ret)); @@ -830,12 +831,19 @@ _kdc_as_rep(krb5_context context, } ret = _kdc_check_flags(context, config, - client, client_name, + &client->entry, client_name, server, server_name, TRUE); if(ret) goto out; + if (client->check_client_access) { + ret = client->check_client_access(context, client, + b->addresses); + if(ret) + goto out; + } + memset(&et, 0, sizeof(et)); memset(&ek, 0, sizeof(ek)); @@ -875,7 +883,7 @@ _kdc_as_rep(krb5_context context, ret = _kdc_pk_check_client(context, config, client_princ, - client, + &client->entry, pkp, &client_cert); if (ret) { @@ -924,7 +932,7 @@ _kdc_as_rep(krb5_context context, goto out; } - ret = hdb_enctype2key(context, client, enc_data.etype, &pa_key); + ret = hdb_enctype2key(context, &client->entry, enc_data.etype, &pa_key); if(ret){ char *estr; e_text = "No key matches pa-data"; @@ -974,7 +982,7 @@ _kdc_as_rep(krb5_context context, krb5_get_err_text(context, ret)); free(str); - if(hdb_next_enctype2key(context, client, + if(hdb_next_enctype2key(context, &client->entry, enc_data.etype, &pa_key) == 0) goto try_next_key; e_text = "Failed to decrypt PA-DATA"; @@ -1030,7 +1038,7 @@ _kdc_as_rep(krb5_context context, goto out; } }else if (config->require_preauth - || client->flags.require_preauth + || client->entry.flags.require_preauth || server->flags.require_preauth) { METHOD_DATA method_data; PA_DATA *pa; @@ -1058,10 +1066,10 @@ _kdc_as_rep(krb5_context context, /* XXX check ret */ if (only_older_enctype_p(req)) - ret = get_pa_etype_info(context, config, &method_data, client, + ret = get_pa_etype_info(context, config, &method_data, &client->entry, b->etype.val, b->etype.len); /* XXX check ret */ - ret = get_pa_etype_info2(context, config, &method_data, client, + ret = get_pa_etype_info2(context, config, &method_data, &client->entry, b->etype.val, b->etype.len); @@ -1089,7 +1097,7 @@ _kdc_as_rep(krb5_context context, } ret = find_keys(context, config, - client, server, &ckey, &cetype, &skey, &setype, + &client->entry, server, &ckey, &cetype, &skey, &setype, b->etype.val, b->etype.len); if(ret) { kdc_log(context, config, 0, "Server/client has no support for etypes"); @@ -1154,19 +1162,19 @@ _kdc_as_rep(krb5_context context, rep.pvno = 5; rep.msg_type = krb_as_rep; - copy_Realm(&client->principal->realm, &rep.crealm); + copy_Realm(&client->entry.principal->realm, &rep.crealm); if (f.request_anonymous) make_anonymous_principalname (&rep.cname); else _krb5_principal2principalname(&rep.cname, - client->principal); + client->entry.principal); rep.ticket.tkt_vno = 5; copy_Realm(&server->principal->realm, &rep.ticket.realm); _krb5_principal2principalname(&rep.ticket.sname, server->principal); et.flags.initial = 1; - if(client->flags.forwardable && server->flags.forwardable) + if(client->entry.flags.forwardable && server->flags.forwardable) et.flags.forwardable = f.forwardable; else if (f.forwardable) { ret = KRB5KDC_ERR_POLICY; @@ -1174,7 +1182,7 @@ _kdc_as_rep(krb5_context context, "Ticket may not be forwardable -- %s", client_name); goto out; } - if(client->flags.proxiable && server->flags.proxiable) + if(client->entry.flags.proxiable && server->flags.proxiable) et.flags.proxiable = f.proxiable; else if (f.proxiable) { ret = KRB5KDC_ERR_POLICY; @@ -1182,7 +1190,7 @@ _kdc_as_rep(krb5_context context, "Ticket may not be proxiable -- %s", client_name); goto out; } - if(client->flags.postdate && server->flags.postdate) + if(client->entry.flags.postdate && server->flags.postdate) et.flags.may_postdate = f.allow_postdate; else if (f.allow_postdate){ ret = KRB5KDC_ERR_POLICY; @@ -1220,8 +1228,8 @@ _kdc_as_rep(krb5_context context, /* be careful not overflowing */ - if(client->max_life) - t = start + min(t - start, *client->max_life); + if(client->entry.max_life) + t = start + min(t - start, *client->entry.max_life); if(server->max_life) t = start + min(t - start, *server->max_life); #if 0 @@ -1241,8 +1249,8 @@ _kdc_as_rep(krb5_context context, t = *b->rtime; if(t == 0) t = MAX_TIME; - if(client->max_renew) - t = start + min(t - start, *client->max_renew); + if(client->entry.max_renew) + t = start + min(t - start, *client->entry.max_renew); if(server->max_renew) t = start + min(t - start, *server->max_renew); #if 0 @@ -1278,16 +1286,16 @@ _kdc_as_rep(krb5_context context, */ ek.last_req.val = malloc(2 * sizeof(*ek.last_req.val)); ek.last_req.len = 0; - if (client->pw_end + if (client->entry.pw_end && (config->kdc_warn_pwexpire == 0 - || kdc_time + config->kdc_warn_pwexpire <= *client->pw_end)) { + || kdc_time + config->kdc_warn_pwexpire <= *client->entry.pw_end)) { ek.last_req.val[ek.last_req.len].lr_type = LR_PW_EXPTIME; - ek.last_req.val[ek.last_req.len].lr_value = *client->pw_end; + ek.last_req.val[ek.last_req.len].lr_value = *client->entry.pw_end; ++ek.last_req.len; } - if (client->valid_end) { + if (client->entry.valid_end) { ek.last_req.val[ek.last_req.len].lr_type = LR_ACCT_EXPTIME; - ek.last_req.val[ek.last_req.len].lr_value = *client->valid_end; + ek.last_req.val[ek.last_req.len].lr_value = *client->entry.valid_end; ++ek.last_req.len; } if (ek.last_req.len == 0) { @@ -1296,15 +1304,15 @@ _kdc_as_rep(krb5_context context, ++ek.last_req.len; } ek.nonce = b->nonce; - if (client->valid_end || client->pw_end) { + if (client->entry.valid_end || client->entry.pw_end) { ALLOC(ek.key_expiration); - if (client->valid_end) { - if (client->pw_end) - *ek.key_expiration = min(*client->valid_end, *client->pw_end); + if (client->entry.valid_end) { + if (client->entry.pw_end) + *ek.key_expiration = min(*client->entry.valid_end, *client->entry.pw_end); else - *ek.key_expiration = *client->valid_end; + *ek.key_expiration = *client->entry.valid_end; } else - *ek.key_expiration = *client->pw_end; + *ek.key_expiration = *client->entry.pw_end; } else ek.key_expiration = NULL; ek.flags = et.flags; @@ -1352,7 +1360,7 @@ _kdc_as_rep(krb5_context context, ret = encode_reply(context, config, &rep, &et, &ek, setype, server->kvno, &skey->key, - client->kvno, reply_key, &e_text, reply); + client->entry.kvno, reply_key, &e_text, reply); free_EncTicketPart(&et); free_EncKDCRepPart(&ek); out: @@ -1381,7 +1389,7 @@ _kdc_as_rep(krb5_context context, krb5_free_principal(context, server_princ); free(server_name); if(client) - _kdc_free_ent(context, client); + _kdc_free_ent_ex(context, client); if(server) _kdc_free_ent(context, server); return ret; diff --git a/source4/heimdal/kdc/misc.c b/source4/heimdal/kdc/misc.c index 5a251607b6..b14bb50ea5 100644 --- a/source4/heimdal/kdc/misc.c +++ b/source4/heimdal/kdc/misc.c @@ -82,3 +82,59 @@ _kdc_free_ent(krb5_context context, hdb_entry *ent) free (ent); } +krb5_error_code +_kdc_db_fetch_ex(krb5_context context, + krb5_kdc_configuration *config, + krb5_principal principal, enum hdb_ent_type ent_type, + hdb_entry_ex **h) +{ + hdb_entry_ex *ent; + krb5_error_code ret = HDB_ERR_NOENTRY; + int i; + + ent = malloc (sizeof (*ent)); + if (ent == NULL) + return ENOMEM; + memset(ent, '\0', sizeof(*ent)); + + ent->entry.principal = principal; + + for(i = 0; i < config->num_db; i++) { + ret = config->db[i]->hdb_open(context, config->db[i], O_RDONLY, 0); + if (ret) { + kdc_log(context, config, 0, "Failed to open database: %s", + krb5_get_err_text(context, ret)); + continue; + } + if (config->db[i]->hdb_fetch_ex) { + ret = config->db[i]->hdb_fetch_ex(context, + config->db[i], + HDB_F_DECRYPT, + principal, + ent_type, + ent); + } else { + ret = config->db[i]->hdb_fetch(context, + config->db[i], + HDB_F_DECRYPT, + principal, + ent_type, + &ent->entry); + } + config->db[i]->hdb_close(context, config->db[i]); + if(ret == 0) { + *h = ent; + return 0; + } + } + free(ent); + return ret; +} + +void +_kdc_free_ent_ex(krb5_context context, hdb_entry_ex *ent) +{ + hdb_free_entry_ex (context, ent); + free (ent); +} + diff --git a/source4/heimdal/lib/hdb/hdb-protos.h b/source4/heimdal/lib/hdb/hdb-protos.h index 799f013eba..7557b46bff 100644 --- a/source4/heimdal/lib/hdb/hdb-protos.h +++ b/source4/heimdal/lib/hdb/hdb-protos.h @@ -120,6 +120,9 @@ hdb_free_entry ( hdb_entry */*ent*/); void +hdb_free_entry_ex(krb5_context context, hdb_entry_ex *ent); + +void hdb_free_key (Key */*key*/); void diff --git a/source4/heimdal/lib/hdb/hdb.c b/source4/heimdal/lib/hdb/hdb.c index c66579fab0..e8161afbc1 100644 --- a/source4/heimdal/lib/hdb/hdb.c +++ b/source4/heimdal/lib/hdb/hdb.c @@ -144,6 +144,16 @@ hdb_free_entry(krb5_context context, hdb_entry *ent) free_hdb_entry(ent); } +void +hdb_free_entry_ex(krb5_context context, hdb_entry_ex *ent) +{ + if (ent->free_private) { + ent->free_private(context, ent); + } + + free_hdb_entry(&ent->entry); +} + krb5_error_code hdb_foreach(krb5_context context, HDB *db, diff --git a/source4/heimdal/lib/hdb/hdb.h b/source4/heimdal/lib/hdb/hdb.h index fe86f0ae72..41cc03cf36 100644 --- a/source4/heimdal/lib/hdb/hdb.h +++ b/source4/heimdal/lib/hdb/hdb.h @@ -54,6 +54,23 @@ enum hdb_ent_type{ HDB_ENT_TYPE_CLIENT, HDB_ENT_TYPE_SERVER, HDB_ENT_TYPE_ANY }; typedef struct hdb_master_key_data *hdb_master_key; +typedef struct hdb_entry_ex { + struct hdb_entry entry; + void *private; + + krb5_error_code (*free_private)(krb5_context, struct hdb_entry_ex *); + krb5_error_code (*check_client_access)(krb5_context, struct hdb_entry_ex *, HostAddresses *); + krb5_error_code (*authz_data_as_req)(krb5_context, struct hdb_entry_ex *, + AuthorizationData *in, + EncryptionKey *tgtkey, + AuthorizationData *out); + krb5_error_code (*authz_data_tgs_req)(krb5_context, struct hdb_entry_ex *, + AuthorizationData *in, + EncryptionKey *tgtkey, + EncryptionKey *servicekey, + AuthorizationData *out); +} hdb_entry_ex; + typedef struct HDB{ void *hdb_db; void *hdb_dbc; @@ -66,6 +83,8 @@ typedef struct HDB{ krb5_error_code (*hdb_close)(krb5_context, struct HDB*); krb5_error_code (*hdb_fetch)(krb5_context,struct HDB*,unsigned hdb_flags, krb5_const_principal principal, enum hdb_ent_type ent_type, hdb_entry*); + krb5_error_code (*hdb_fetch_ex)(krb5_context,struct HDB*,unsigned hdb_flags, krb5_const_principal principal, + enum hdb_ent_type ent_type, hdb_entry_ex*); krb5_error_code (*hdb_store)(krb5_context,struct HDB*,unsigned,hdb_entry*); krb5_error_code (*hdb_remove)(krb5_context, struct HDB*, hdb_entry*); krb5_error_code (*hdb_firstkey)(krb5_context, struct HDB*, @@ -82,7 +101,7 @@ typedef struct HDB{ krb5_error_code (*hdb_destroy)(krb5_context, struct HDB*); }HDB; -#define HDB_INTERFACE_VERSION 2 +#define HDB_INTERFACE_VERSION 3 struct hdb_so_method { int version; diff --git a/source4/kdc/hdb-ldb.c b/source4/kdc/hdb-ldb.c index 80e8cdc74e..87e8273898 100644 --- a/source4/kdc/hdb-ldb.c +++ b/source4/kdc/hdb-ldb.c @@ -38,6 +38,7 @@ #include "hdb.h" #include "lib/ldb/include/ldb.h" #include "system/iconv.h" +#include "librpc/gen_ndr/netlogon.h" enum hdb_ldb_ent_type { HDB_LDB_ENT_TYPE_CLIENT, HDB_LDB_ENT_TYPE_SERVER, @@ -72,6 +73,12 @@ static const char *realm_ref_attrs[] = { NULL }; +struct hdb_ldb_private { + struct ldb_context *samdb; + struct ldb_message **msg; + struct ldb_message **realm_ref_msg; +}; + static KerberosTime ldb_msg_find_krb5time_ldap_time(struct ldb_message *msg, const char *attr, KerberosTime default_val) { const char *tmp; @@ -611,10 +618,48 @@ static krb5_error_code LDB_rename(krb5_context context, HDB *db, const char *new return HDB_ERR_DB_INUSE; } -static krb5_error_code LDB_fetch(krb5_context context, HDB *db, unsigned flags, - krb5_const_principal principal, - enum hdb_ent_type ent_type, - hdb_entry *entry) +static krb5_error_code hdb_ldb_free_private(krb5_context context, hdb_entry_ex *entry_ex) +{ + talloc_free(entry_ex->private); + return 0; +} + +static krb5_error_code hdb_ldb_check_client_access(krb5_context context, hdb_entry_ex *entry_ex, + HostAddresses *addresses) +{ + krb5_error_code ret; + NTSTATUS nt_status; + TALLOC_CTX *tmp_ctx = talloc_new(entry_ex->private); + struct hdb_ldb_private *private = entry_ex->private; + char *name, *workstation = NULL; + if (!tmp_ctx) { + return ENOMEM; + } + + ret = krb5_unparse_name(context, entry_ex->entry.principal, &name); + if (ret != 0) { + talloc_free(tmp_ctx); + } + nt_status = authsam_account_ok(tmp_ctx, + private->samdb, + MSV1_0_ALLOW_SERVER_TRUST_ACCOUNT | MSV1_0_ALLOW_WORKSTATION_TRUST_ACCOUNT, + private->msg, + private->realm_ref_msg, + workstation, + name); + free(name); + + if (!NT_STATUS_IS_OK(nt_status)) { + return KRB5KDC_ERR_POLICY; + } + return 0; +} + + +static krb5_error_code LDB_fetch_ex(krb5_context context, HDB *db, unsigned flags, + krb5_const_principal principal, + enum hdb_ent_type ent_type, + hdb_entry_ex *entry_ex) { struct ldb_message **msg = NULL; struct ldb_message **realm_ref_msg = NULL; @@ -631,10 +676,6 @@ static krb5_error_code LDB_fetch(krb5_context context, HDB *db, unsigned flags, return ENOMEM; } - /* Cludge, cludge cludge. If the realm part of krbtgt/realm, - * is in our db, then direct the caller at our primary - * krgtgt */ - switch (ent_type) { case HDB_ENT_TYPE_CLIENT: { @@ -662,7 +703,23 @@ static krb5_error_code LDB_fetch(krb5_context context, HDB *db, unsigned flags, ret = LDB_message2entry(context, db, mem_ctx, principal, ldb_ent_type, - msg[0], realm_ref_msg[0], entry); + msg[0], realm_ref_msg[0], &entry_ex->entry); + + if (ret == 0) { + struct hdb_ldb_private *private = talloc(db, struct hdb_ldb_private); + if (!private) { + hdb_free_entry(context, &entry_ex->entry); + ret = ENOMEM; + } + private->msg = talloc_steal(private, msg); + private->realm_ref_msg = talloc_steal(private, realm_ref_msg); + private->samdb = (struct ldb_context *)db->hdb_db; + + entry_ex->private = private; + entry_ex->free_private = hdb_ldb_free_private; + entry_ex->check_client_access = hdb_ldb_check_client_access; + } + talloc_free(mem_ctx); return ret; } @@ -673,6 +730,10 @@ static krb5_error_code LDB_fetch(krb5_context context, HDB *db, unsigned flags, if ((LDB_lookup_realm(context, (struct ldb_context *)db->hdb_db, mem_ctx, principal->name.name_string.val[1], &realm_fixed_msg) == 0)) { /* us */ + /* Cludge, cludge cludge. If the realm part of krbtgt/realm, + * is in our db, then direct the caller at our primary + * krgtgt */ + const char *dnsdomain = ldb_msg_find_string(realm_fixed_msg[0], "dnsRoot", NULL); char *realm_fixed = strupper_talloc(mem_ctx, dnsdomain); if (!realm_fixed) { @@ -741,7 +802,7 @@ static krb5_error_code LDB_fetch(krb5_context context, HDB *db, unsigned flags, ret = LDB_message2entry(context, db, mem_ctx, principal, ldb_ent_type, - msg[0], realm_ref_msg[0], entry); + msg[0], realm_ref_msg[0], &entry_ex->entry); talloc_free(mem_ctx); return ret; @@ -784,7 +845,7 @@ static krb5_error_code LDB_fetch(krb5_context context, HDB *db, unsigned flags, } else { ret = LDB_message2entry(context, db, mem_ctx, principal, ldb_ent_type, - msg[0], realm_ref_msg[0], entry); + msg[0], realm_ref_msg[0], &entry_ex->entry); if (ret != 0) { krb5_warnx(context, "LDB_fetch: message2entry failed\n"); } @@ -794,6 +855,26 @@ static krb5_error_code LDB_fetch(krb5_context context, HDB *db, unsigned flags, return ret; } +static krb5_error_code LDB_fetch(krb5_context context, HDB *db, unsigned flags, + krb5_const_principal principal, + enum hdb_ent_type ent_type, + hdb_entry *entry) +{ + struct hdb_entry_ex entry_ex; + krb5_error_code ret; + + memset(&entry_ex, '\0', sizeof(entry_ex)); + ret = LDB_fetch_ex(context, db, flags, principal, ent_type, &entry_ex); + + if (ret == 0) { + if (entry_ex.free_private) { + entry_ex.free_private(context, &entry_ex); + } + *entry = entry_ex.entry; + } + return ret; +} + static krb5_error_code LDB_store(krb5_context context, HDB *db, unsigned flags, hdb_entry *entry) { return HDB_ERR_DB_INUSE; @@ -967,6 +1048,7 @@ krb5_error_code hdb_ldb_create(TALLOC_CTX *mem_ctx, (*db)->hdb_open = LDB_open; (*db)->hdb_close = LDB_close; (*db)->hdb_fetch = LDB_fetch; + (*db)->hdb_fetch_ex = LDB_fetch_ex; (*db)->hdb_store = LDB_store; (*db)->hdb_remove = LDB_remove; (*db)->hdb_firstkey = LDB_firstkey; |