Exemplo n.º 1
0
static krb5_error_code
LDAP_addmod_generalized_time(LDAPMod *** mods, int modop,
			     const char *attribute, KerberosTime * time)
{
    char buf[22];
    struct tm *tm;

    /* XXX not threadsafe */
    tm = gmtime(time);
    strftime(buf, sizeof(buf), "%Y%m%d%H%M%SZ", tm);

    return LDAP_addmod(mods, modop, attribute, buf);
}
Exemplo n.º 2
0
static krb5_error_code
LDAP_addmod_integer(krb5_context context,
		    LDAPMod *** mods, int modop,
		    const char *attribute, unsigned long l)
{
    krb5_error_code ret;
    char *buf;

    ret = asprintf(&buf, "%ld", l);
    if (ret < 0) {
	krb5_set_error_string(context, "asprintf: out of memory:");
	return ret;
    }
    ret = LDAP_addmod(mods, modop, attribute, buf);
    free (buf);
    return ret;
}
Exemplo n.º 3
0
static krb5_error_code
LDAP_entry2mods(krb5_context context, HDB * db, hdb_entry_ex * ent,
		LDAPMessage * msg, LDAPMod *** pmods)
{
    krb5_error_code ret;
    krb5_boolean is_new_entry;
    char *tmp = NULL;
    LDAPMod **mods = NULL;
    hdb_entry_ex orig;
    unsigned long oflags, nflags;
    int i;

    krb5_boolean is_samba_account = FALSE;
    krb5_boolean is_account = FALSE;
    krb5_boolean is_heimdal_entry = FALSE;
    krb5_boolean is_heimdal_principal = FALSE;

    struct berval **vals;

    *pmods = NULL;

    if (msg != NULL) {

	ret = LDAP_message2entry(context, db, msg, 0, &orig);
	if (ret)
	    goto out;

	is_new_entry = FALSE;

	vals = ldap_get_values_len(HDB2LDAP(db), msg, "objectClass");
	if (vals) {
	    int num_objectclasses = ldap_count_values_len(vals);
	    for (i=0; i < num_objectclasses; i++) {
		if (bervalstrcmp(vals[i], "sambaSamAccount"))
		    is_samba_account = TRUE;
		else if (bervalstrcmp(vals[i], structural_object))
		    is_account = TRUE;
		else if (bervalstrcmp(vals[i], "krb5Principal"))
		    is_heimdal_principal = TRUE;
		else if (bervalstrcmp(vals[i], "krb5KDCEntry"))
		    is_heimdal_entry = TRUE;
	    }
	    ldap_value_free_len(vals);
	}

	/*
	 * If this is just a "account" entry and no other objectclass
	 * is hanging on this entry, it's really a new entry.
	 */
	if (is_samba_account == FALSE && is_heimdal_principal == FALSE &&
	    is_heimdal_entry == FALSE) {
	    if (is_account == TRUE) {
		is_new_entry = TRUE;
	    } else {
		ret = HDB_ERR_NOENTRY;
		goto out;
	    }
	}
    } else
	is_new_entry = TRUE;

    if (is_new_entry) {

	/* to make it perfectly obvious we're depending on
	 * orig being intiialized to zero */
	memset(&orig, 0, sizeof(orig));

	ret = LDAP_addmod(&mods, LDAP_MOD_ADD, "objectClass", "top");
	if (ret)
	    goto out;

	/* account is the structural object class */
	if (is_account == FALSE) {
	    ret = LDAP_addmod(&mods, LDAP_MOD_ADD, "objectClass",
			      structural_object);
	    is_account = TRUE;
	    if (ret)
		goto out;
	}

	ret = LDAP_addmod(&mods, LDAP_MOD_ADD, "objectClass", "krb5Principal");
	is_heimdal_principal = TRUE;
	if (ret)
	    goto out;

	ret = LDAP_addmod(&mods, LDAP_MOD_ADD, "objectClass", "krb5KDCEntry");
	is_heimdal_entry = TRUE;
	if (ret)
	    goto out;
    }

    if (is_new_entry ||
	krb5_principal_compare(context, ent->entry.principal, orig.entry.principal)
	== FALSE)
    {
	if (is_heimdal_principal || is_heimdal_entry) {

	    ret = krb5_unparse_name(context, ent->entry.principal, &tmp);
	    if (ret)
		goto out;

	    ret = LDAP_addmod(&mods, LDAP_MOD_REPLACE,
			      "krb5PrincipalName", tmp);
	    if (ret) {
		free(tmp);
		goto out;
	    }
	    free(tmp);
	}

	if (is_account || is_samba_account) {
	    ret = krb5_unparse_name_short(context, ent->entry.principal, &tmp);
	    if (ret)
		goto out;
	    ret = LDAP_addmod(&mods, LDAP_MOD_REPLACE, "uid", tmp);
	    if (ret) {
		free(tmp);
		goto out;
	    }
	    free(tmp);
	}
    }

    if (is_heimdal_entry && (ent->entry.kvno != orig.entry.kvno || is_new_entry)) {
	ret = LDAP_addmod_integer(context, &mods, LDAP_MOD_REPLACE,
			    "krb5KeyVersionNumber",
			    ent->entry.kvno);
	if (ret)
	    goto out;
    }

    if (is_heimdal_entry && ent->entry.valid_start) {
	if (orig.entry.valid_end == NULL
	    || (*(ent->entry.valid_start) != *(orig.entry.valid_start))) {
	    ret = LDAP_addmod_generalized_time(&mods, LDAP_MOD_REPLACE,
					       "krb5ValidStart",
					       ent->entry.valid_start);
	    if (ret)
		goto out;
	}
    }

    if (ent->entry.valid_end) {
 	if (orig.entry.valid_end == NULL || (*(ent->entry.valid_end) != *(orig.entry.valid_end))) {
	    if (is_heimdal_entry) {
		ret = LDAP_addmod_generalized_time(&mods, LDAP_MOD_REPLACE,
						   "krb5ValidEnd",
						   ent->entry.valid_end);
		if (ret)
		    goto out;
            }
	    if (is_samba_account) {
		ret = LDAP_addmod_integer(context, &mods,  LDAP_MOD_REPLACE,
					  "sambaKickoffTime",
					  *(ent->entry.valid_end));
		if (ret)
		    goto out;
	    }
   	}
    }

    if (ent->entry.pw_end) {
	if (orig.entry.pw_end == NULL || (*(ent->entry.pw_end) != *(orig.entry.pw_end))) {
	    if (is_heimdal_entry) {
		ret = LDAP_addmod_generalized_time(&mods, LDAP_MOD_REPLACE,
						   "krb5PasswordEnd",
						   ent->entry.pw_end);
		if (ret)
		    goto out;
	    }

	    if (is_samba_account) {
		ret = LDAP_addmod_integer(context, &mods, LDAP_MOD_REPLACE,
					  "sambaPwdMustChange",
					  *(ent->entry.pw_end));
		if (ret)
		    goto out;
	    }
	}
    }


#if 0 /* we we have last_pw_change */
    if (is_samba_account && ent->entry.last_pw_change) {
	if (orig.entry.last_pw_change == NULL || (*(ent->entry.last_pw_change) != *(orig.entry.last_pw_change))) {
	    ret = LDAP_addmod_integer(context, &mods, LDAP_MOD_REPLACE,
				      "sambaPwdLastSet",
				      *(ent->entry.last_pw_change));
	    if (ret)
		goto out;
	}
    }
#endif

    if (is_heimdal_entry && ent->entry.max_life) {
	if (orig.entry.max_life == NULL
	    || (*(ent->entry.max_life) != *(orig.entry.max_life))) {

	    ret = LDAP_addmod_integer(context, &mods, LDAP_MOD_REPLACE,
				      "krb5MaxLife",
				      *(ent->entry.max_life));
	    if (ret)
		goto out;
	}
    }

    if (is_heimdal_entry && ent->entry.max_renew) {
	if (orig.entry.max_renew == NULL
	    || (*(ent->entry.max_renew) != *(orig.entry.max_renew))) {

	    ret = LDAP_addmod_integer(context, &mods, LDAP_MOD_REPLACE,
				      "krb5MaxRenew",
				      *(ent->entry.max_renew));
	    if (ret)
		goto out;
	}
    }

    oflags = HDBFlags2int(orig.entry.flags);
    nflags = HDBFlags2int(ent->entry.flags);

    if (is_heimdal_entry && oflags != nflags) {

	ret = LDAP_addmod_integer(context, &mods, LDAP_MOD_REPLACE,
				  "krb5KDCFlags",
				  nflags);
	if (ret)
	    goto out;
    }

    /* Remove keys if they exists, and then replace keys. */
    if (!is_new_entry && orig.entry.keys.len > 0) {
	vals = ldap_get_values_len(HDB2LDAP(db), msg, "krb5Key");
	if (vals) {
	    ldap_value_free_len(vals);

	    ret = LDAP_addmod(&mods, LDAP_MOD_DELETE, "krb5Key", NULL);
	    if (ret)
		goto out;
	}
    }

    for (i = 0; i < ent->entry.keys.len; i++) {

	if (is_samba_account
	    && ent->entry.keys.val[i].key.keytype == ETYPE_ARCFOUR_HMAC_MD5) {
	    char *ntHexPassword;
	    char *nt;
	    time_t now = time(NULL);

	    /* the key might have been 'sealed', but samba passwords
	       are clear in the directory */
	    ret = hdb_unseal_key(context, db, &ent->entry.keys.val[i]);
	    if (ret)
		goto out;

	    nt = ent->entry.keys.val[i].key.keyvalue.data;
	    /* store in ntPassword, not krb5key */
	    ret = hex_encode(nt, 16, &ntHexPassword);
	    if (ret < 0) {
		ret = ENOMEM;
		krb5_set_error_message(context, ret, "hdb-ldap: failed to "
				      "hex encode key");
		goto out;
	    }
	    ret = LDAP_addmod(&mods, LDAP_MOD_REPLACE, "sambaNTPassword",
			      ntHexPassword);
	    free(ntHexPassword);
	    if (ret)
		goto out;
	    ret = LDAP_addmod_integer(context, &mods, LDAP_MOD_REPLACE,
				      "sambaPwdLastSet", now);
	    if (ret)
		goto out;

	    /* have to kill the LM passwod if it exists */
	    vals = ldap_get_values_len(HDB2LDAP(db), msg, "sambaLMPassword");
	    if (vals) {
		ldap_value_free_len(vals);
		ret = LDAP_addmod(&mods, LDAP_MOD_DELETE,
				  "sambaLMPassword", NULL);
		if (ret)
		    goto out;
	    }

	} else if (is_heimdal_entry) {
	    unsigned char *buf;
	    size_t len, buf_size;

	    ASN1_MALLOC_ENCODE(Key, buf, buf_size, &ent->entry.keys.val[i], &len, ret);
	    if (ret)
		goto out;
	    if(buf_size != len)
		krb5_abortx(context, "internal error in ASN.1 encoder");

	    /* addmod_len _owns_ the key, doesn't need to copy it */
	    ret = LDAP_addmod_len(&mods, LDAP_MOD_ADD, "krb5Key", buf, len);
	    if (ret)
		goto out;
	}
    }

    if (ent->entry.etypes) {
	int add_krb5EncryptionType = 0;

	/*
	 * Only add/modify krb5EncryptionType if it's a new heimdal
	 * entry or krb5EncryptionType already exists on the entry.
	 */

	if (!is_new_entry) {
	    vals = ldap_get_values_len(HDB2LDAP(db), msg, "krb5EncryptionType");
	    if (vals) {
		ldap_value_free_len(vals);
		ret = LDAP_addmod(&mods, LDAP_MOD_DELETE, "krb5EncryptionType",
				  NULL);
		if (ret)
		    goto out;
		add_krb5EncryptionType = 1;
	    }
	} else if (is_heimdal_entry)
	    add_krb5EncryptionType = 1;

	if (add_krb5EncryptionType) {
	    for (i = 0; i < ent->entry.etypes->len; i++) {
		if (is_samba_account &&
		    ent->entry.keys.val[i].key.keytype == ETYPE_ARCFOUR_HMAC_MD5)
		{
		    ;
		} else if (is_heimdal_entry) {
		    ret = LDAP_addmod_integer(context, &mods, LDAP_MOD_ADD,
					      "krb5EncryptionType",
					      ent->entry.etypes->val[i]);
		    if (ret)
			goto out;
		}
	    }
	}
    }

    /* for clarity */
    ret = 0;

 out:

    if (ret == 0)
	*pmods = mods;
    else if (mods != NULL) {
	ldap_mods_free(mods, 1);
	*pmods = NULL;
    }

    if (msg)
	hdb_free_entry(context, &orig);

    return ret;
}