summaryrefslogtreecommitdiffstats
path: root/ipa-server
diff options
context:
space:
mode:
authorSimo Sorce <ssorce@redhat.com>2007-10-31 10:52:44 -0400
committerSimo Sorce <ssorce@redhat.com>2007-10-31 10:52:44 -0400
commit51a51302273ad7b2c83ad37bb182096835cb87e5 (patch)
tree285f7f52bdfe54859df2262b98cabb77454d4ba6 /ipa-server
parent45346ee3ab09405212631f5c6ca3753d1615a950 (diff)
downloadfreeipa-51a51302273ad7b2c83ad37bb182096835cb87e5.tar.gz
freeipa-51a51302273ad7b2c83ad37bb182096835cb87e5.tar.xz
freeipa-51a51302273ad7b2c83ad37bb182096835cb87e5.zip
Properly increment kvno and keep recent key material around
This is necessary for services that need to be able to respond to requests from client that acquired a service ticket just before a password change.
Diffstat (limited to 'ipa-server')
-rw-r--r--ipa-server/ipa-slapi-plugins/ipa-pwd-extop/ipa_pwd_extop.c175
1 files changed, 162 insertions, 13 deletions
diff --git a/ipa-server/ipa-slapi-plugins/ipa-pwd-extop/ipa_pwd_extop.c b/ipa-server/ipa-slapi-plugins/ipa-pwd-extop/ipa_pwd_extop.c
index e920cec7b..e4e9d4615 100644
--- a/ipa-server/ipa-slapi-plugins/ipa-pwd-extop/ipa_pwd_extop.c
+++ b/ipa-server/ipa-slapi-plugins/ipa-pwd-extop/ipa_pwd_extop.c
@@ -162,6 +162,21 @@ int n_keysalts;
*/
+struct kbvals {
+ ber_int_t kvno;
+ struct berval *bval;
+};
+
+static int cmpkbvals(const void *p1, const void *p2)
+{
+ const struct kbvals *k1, *k2;
+
+ k1 = (struct kbvals *)p1;
+ k2 = (struct kbvals *)p2;
+
+ return (((int)k1->kvno) - ((int)k2->kvno));
+}
+
static inline void encode_int16(unsigned int val, unsigned char *p)
{
p[1] = (val >> 8) & 0xff;
@@ -170,35 +185,166 @@ static inline void encode_int16(unsigned int val, unsigned char *p)
static Slapi_Value **encrypt_encode_key(krb5_context krbctx, Slapi_Entry *e, const char *newPasswd)
{
+ const char *krbPrincipalName;
+ const char *krbLastPwdChange;
+ uint32_t krbMaxTicketLife;
+ Slapi_Attr *krbPrincipalKey = NULL;
+ struct kbvals *kbvals = NULL;
+ time_t lastpwchange;
+ time_t time_now;
+ int kvno;
+ int num_versions, num_keys;
+ int krbTicketFlags;
+ BerElement *be;
struct berval *bval = NULL;
Slapi_Value **svals = NULL;
- BerElement *be = NULL;
- int num_versions;
- int krbTicketFlags;
- const char *krbPrincipalName;
+ int svals_no;
krb5_principal princ;
krb5_error_code krberr;
krb5_data pwd;
int ret, i;
+ time_now = time(NULL);
+
krbPrincipalName = slapi_entry_attr_get_charptr(e, "krbPrincipalName");
if (!krbPrincipalName) {
slapi_log_error(SLAPI_LOG_FATAL, "ipa_pwd_extop", "no krbPrincipalName present in this entry\n");
return NULL;
}
- /* TODO: retrieve current kvno and increment it */
- /* TODO: keep previous version */
+ krbMaxTicketLife = slapi_entry_attr_get_uint(e, "krbMaxTicketLife");
+ if (krbMaxTicketLife == 0) {
+ /* FIXME: retrieve the default from config (max_life from kdc.conf) */
+ krbMaxTicketLife = 86400; /* just set the default 24h for now */
+ }
+
+ krbLastPwdChange = slapi_entry_attr_get_charptr(e, "krbLastPwdChange");
+ if (!krbLastPwdChange) {
+ lastpwchange = -1;
+ } else {
+ struct tm tm;
+
+ memset(&tm, 0, sizeof(struct tm));
+ ret = sscanf(krbLastPwdChange,
+ "%04u%02u%02u%02u%02u%02u",
+ &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
+ &tm.tm_hour, &tm.tm_min, &tm.tm_sec);
+
+ if (ret == 6) {
+ tm.tm_year -= 1900;
+ tm.tm_mon -= 1;
+ lastpwchange = timegm(&tm);
+ } else {
+ /* FIXME: report an error ? */
+ lastpwchange = -1;
+ }
+ }
+ /* FIXME: warn if lastpwchange == -1 ? */
+
+ kvno = 0;
+ num_keys = 0;
num_versions = 1;
+ /* retrieve current kvno and and keys */
+ ret = slapi_entry_attr_find(e, "krbPrincipalKey", &krbPrincipalKey);
+ if (ret == 0) {
+ int i, n, count, idx;
+ ber_int_t tkvno;
+ Slapi_ValueSet *svs;
+ Slapi_Value *sv;
+ ber_tag_t tag, tmp;
+
+ slapi_attr_get_valueset(krbPrincipalKey, &svs);
+ count = slapi_valueset_count(svs);
+ if (count > 0) {
+ kbvals = (struct kbvals *)calloc(count, sizeof(struct kbvals));
+ }
+ n = 0;
+ for (i = 0; count > 0 && i < count; i++) {
+ if (i == 0) {
+ idx = slapi_valueset_first_value(svs, &sv);
+ } else {
+ idx = slapi_valueset_next_value(svs, idx, &sv);
+ }
+ if (idx == -1) {
+ slapi_log_error(SLAPI_LOG_TRACE, "ipa_pwd_extop",
+ "Array of stored keys shorter than expected\n");
+ break;
+ }
+ bval = slapi_value_get_berval(sv);
+ if (!bval) {
+ slapi_log_error(SLAPI_LOG_TRACE, "ipa_pwd_extop",
+ "Error retrieving berval from Slapi_Value\n");
+ continue;
+ }
+ be = ber_init(bval);
+ if (!be) {
+ slapi_log_error(SLAPI_LOG_TRACE, "ipa_pwd_extop",
+ "ber_init() failed!\n");
+ continue;
+ }
+
+ tag = ber_scanf(be, "{xxt[i]", &tmp, &tkvno);
+ if (tag == LBER_ERROR) {
+ slapi_log_error(SLAPI_LOG_TRACE, "ipa_pwd_extop",
+ "Bad OLD key encoding ?!\n");
+ ber_free(be, 1);
+ continue;
+ }
+
+ kbvals[n].kvno = tkvno;
+ kbvals[n].bval = bval;
+ n++;
+
+ if (tkvno > kvno) {
+ kvno = tkvno;
+ }
+
+ ber_free(be, 1);
+ }
+ num_keys = n;
+
+ /* now verify how many keys we need to keep around */
+ if (num_keys > 0 && lastpwchange != -1) {
+ if (time_now > lastpwchange + krbMaxTicketLife) {
+ /* the last password change was long ago,
+ * at most only the last entry need to be kept */
+ num_versions = 2;
+ } else {
+ /* we don't know how many changes have happened since
+ * the oldest krbtgt was release, keep all + new */
+ num_versions = num_keys + 1;
+ }
+
+ /* now reorder by kvno */
+ if (num_keys > 1) {
+ qsort(kbvals, num_keys, sizeof(struct kbvals), cmpkbvals);
+ }
+ }
+ }
+
+ /* increment kvno (will be 1 if this is a new entry) */
+ kvno++;
+
svals = (Slapi_Value **)calloc(num_versions + 1, sizeof(Slapi_Value *));
if (!svals) {
slapi_log_error(SLAPI_LOG_FATAL, "ipa_pwd_extop", "memory allocation failed\n");
return NULL;
}
- svals[1] = NULL;
-
+ /* set all old keys to save */
+ for (svals_no = 0; svals_no < (num_versions - 1); svals_no++) {
+ int idx;
+
+ idx = num_keys - (num_versions - 1) + svals_no;
+ svals[svals_no] = slapi_value_new_berval(kbvals[idx].bval);
+ if (!svals[svals_no]) {
+ slapi_log_error(SLAPI_LOG_FATAL, "ipa_pwd_extop",
+ "Converting berval to Slapi_Value\n");
+ goto enc_error;
+ }
+ }
+
krberr = krb5_parse_name(krbctx, krbPrincipalName, &princ);
if (krberr) {
slapi_log_error(SLAPI_LOG_FATAL, "ipa_pwd_extop",
@@ -220,13 +366,13 @@ static Slapi_Value **encrypt_encode_key(krb5_context krbctx, Slapi_Entry *e, con
goto enc_error;
}
- /* major-vno = 1 and minor-von = 1 */
- /* this encoding assumes all keys have the same kvno (currently set at 1) */
+ /* major-vno = 1 and minor-vno = 1 */
+ /* this encoding assumes all keys have the same kvno */
/* we also assum mkvno is 0 */
ret = ber_printf(be, "{t[i]t[i]t[i]t[i]t[{",
(ber_tag_t)(LBER_CONSTRUCTED | LBER_CLASS_CONTEXT | 0), 1,
(ber_tag_t)(LBER_CONSTRUCTED | LBER_CLASS_CONTEXT | 1), 1,
- (ber_tag_t)(LBER_CONSTRUCTED | LBER_CLASS_CONTEXT | 2), 1,
+ (ber_tag_t)(LBER_CONSTRUCTED | LBER_CLASS_CONTEXT | 2), kvno,
(ber_tag_t)(LBER_CONSTRUCTED | LBER_CLASS_CONTEXT | 3), 0,
(ber_tag_t)(LBER_CONSTRUCTED | LBER_CLASS_CONTEXT | 4));
if (ret == -1) {
@@ -435,13 +581,16 @@ static Slapi_Value **encrypt_encode_key(krb5_context krbctx, Slapi_Entry *e, con
goto enc_error;
}
- svals[0] = slapi_value_new_berval(bval);
- if (!svals[0]) {
+ svals[svals_no] = slapi_value_new_berval(bval);
+ if (!svals[svals_no]) {
slapi_log_error(SLAPI_LOG_FATAL, "ipa_pwd_extop",
"Converting berval to Slapi_Value\n");
goto enc_error;
}
+ svals_no++;
+ svals[svals_no] = NULL;
+
krb5_free_principal(krbctx, princ);
ber_bvfree(bval);
ber_free(be, 1);