static PyObject *PyKAdminPrincipal_reload(PyKAdminPrincipalObject *self) {

    krb5_error_code ret = 0;
    kadm5_ret_t retval = KADM5_OK; 

    krb5_principal temp = NULL;

    if (self) {

        // we need to free prior to fetching otherwise we leak memory since principal and policy are pointers, alternitively we could manually free those
        ret = krb5_copy_principal(self->kadmin->context, self->entry.principal, &temp);
        if (ret) {}

        retval = kadm5_free_principal_ent(self->kadmin->server_handle, &self->entry);
        if (retval != KADM5_OK) { PyKAdminError_raise_error(retval, "kadm5_free_principal_ent"); } 

        if (retval == KADM5_OK) {
            retval = kadm5_get_principal(self->kadmin->server_handle, temp, &self->entry, KADM5_PRINCIPAL_NORMAL_MASK);
            if (retval != KADM5_OK) { PyKAdminError_raise_error(retval, "kadm5_get_principal"); }
        }

        krb5_free_principal(self->kadmin->context, temp);

        if (retval != KADM5_OK) { return NULL; }        
    }

    Py_RETURN_TRUE;
}
PyKAdminPrincipalObject *PyKAdminPrincipalObject_principal_with_name(PyKAdminObject *kadmin, char *client_name) {
        
    krb5_error_code errno;
    kadm5_ret_t retval = KADM5_OK;

    PyKAdminPrincipalObject *principal = (PyKAdminPrincipalObject *)Py_None;
    krb5_principal temp = NULL;

    if (kadmin && client_name) {

        principal = (PyKAdminPrincipalObject *)PyKAdminPrincipal_new(&PyKAdminPrincipalObject_Type, NULL, NULL);

        if (principal) {

            Py_INCREF(kadmin);
            principal->kadmin = kadmin;

            errno = krb5_parse_name(kadmin->context, client_name, &temp);
            retval = kadm5_get_principal(kadmin->server_handle, temp, &principal->entry, (KADM5_PRINCIPAL_NORMAL_MASK | KADM5_KEY_DATA));

            krb5_free_principal(kadmin->context, temp);

            if ((retval != KADM5_OK) || errno) {
                PyKAdminPrincipal_dealloc(principal);
                principal = (PyKAdminPrincipalObject *)Py_None;
            }

        }
    }

    Py_INCREF(principal);
    return principal;
}
Exemple #3
0
static krb5_error_code
get_default (kadm5_server_context *context,
	     krb5_principal princ,
	     kadm5_principal_ent_t default_ent)
{
    krb5_error_code ret;
    krb5_principal def_principal;
    krb5_const_realm realm = krb5_principal_get_realm(context->context, princ);

    ret = krb5_make_principal (context->context, &def_principal,
			       realm, "default", NULL);
    if (ret)
	return ret;
    ret = kadm5_get_principal (context, def_principal, default_ent,
			       KADM5_PRINCIPAL_NORMAL_MASK);
    krb5_free_principal (context->context, def_principal);
    return ret;
}
Exemple #4
0
static int
do_get_entry(krb5_principal principal, void *data)
{
    kadm5_principal_ent_rec princ;
    krb5_error_code ret;
    struct get_entry_data *e = data;

    memset(&princ, 0, sizeof(princ));
    ret = kadm5_get_principal(kadm_handle, principal,
			      &princ,
			      e->mask | e->extra_mask);
    if(ret)
	return ret;
    else {
	(e->format)(e, &princ);
	kadm5_free_principal_ent(kadm_handle, &princ);
    }
    return 0;
}
Exemple #5
0
static int
get_check_entry(const char *name, kadm5_principal_ent_rec *ent)
{
    krb5_error_code ret;
    krb5_principal principal;

    ret = krb5_parse_name(context, name, &principal);
    if (ret) {
	krb5_warn(context, ret, "krb5_unparse_name: %s", name);
	return 1;
    }

    memset(ent, 0, sizeof(*ent));
    ret = kadm5_get_principal(kadm_handle, principal, ent, 0);
    krb5_free_principal(context, principal);
    if(ret)
	return 1;

    return 0;
}
Exemple #6
0
static int
do_check_entry(krb5_principal principal, void *data)
{
    krb5_error_code ret;
    kadm5_principal_ent_rec princ;
    char *name;
    int i;

    ret = krb5_unparse_name(context, principal, &name);
    if (ret)
	return 1;

    memset (&princ, 0, sizeof(princ));
    ret = kadm5_get_principal(kadm_handle, principal, &princ,
			      KADM5_PRINCIPAL | KADM5_KEY_DATA);
    if(ret) {
	krb5_warn(context, ret, "Failed to get principal: %s", name);
	free(name);
	return 0;
    }

    for (i = 0; i < princ.n_key_data; i++) {
	size_t keysize;
	ret = krb5_enctype_keysize(context,
				   princ.key_data[i].key_data_type[0],
				   &keysize);
	if (ret == 0 && keysize != princ.key_data[i].key_data_length[0]) {
	    krb5_warnx(context,
		       "Principal %s enctype %d, wrong length: %lu\n",
		       name, princ.key_data[i].key_data_type[0],
		       (unsigned long)princ.key_data[i].key_data_length);
	}
    }

    free(name);
    kadm5_free_principal_ent(kadm_handle, &princ);

    return 0;
}
Exemple #7
0
kadm5_principal_ent_rec
krb5_query_princ(krb5_context ctx, kadm5_handle hndl, char *in)
{
	kadm5_principal_ent_rec	 dprinc;
	krb5_principal		 princ = NULL;
	kadm5_ret_t		 ret;
	char			 croakstr[2048] = "";

	memset(&dprinc, 0, sizeof(dprinc));

	K5BAIL(krb5_parse_name(ctx, in, &princ));
	K5BAIL(kadm5_get_principal(hndl, princ, &dprinc, 
	    KADM5_PRINCIPAL_NORMAL_MASK));

done:
	if (princ)
		krb5_free_principal(ctx, princ);
	/* XXXrcd: free dprinc */

	if (ret)
		croak("%s", croakstr);

	return dprinc;
}
Exemple #8
0
/* Modify Kerberos principal */
long modify_kerberos(char *username, int activate)
{ 
  void *kadm_server_handle = NULL;
  krb5_context context = NULL;
  kadm5_ret_t status;
  krb5_principal princ;
  kadm5_principal_ent_rec dprinc;
  kadm5_policy_ent_rec defpol;
  kadm5_config_params realm_params;
  char admin_princ[256];
  long mask = 0;
#ifdef KERBEROS_TEST_REALM
  char ubuf[256];

  sprintf(admin_princ, "moira/%s@%s", hostname, KERBEROS_TEST_REALM);
  sprintf(ubuf, "%s@%s", username, KERBEROS_TEST_REALM);
  username = ubuf;
  realm_params.realm = KERBEROS_TEST_REALM;
  realm_params.mask = KADM5_CONFIG_REALM;
#else
  strcpy(admin_princ, MOIRA_SVR_PRINCIPAL);
  realm_params.mask = 0;
#endif

  status = krb5_init_context(&context);
  if (status)
    return status;

  memset(&princ, 0, sizeof(princ));
  memset(&dprinc, 0, sizeof(dprinc));

  status = krb5_parse_name(context, username, &princ);
  if (status)
    return status;

  status = kadm5_init_with_skey(admin_princ, NULL, KADM5_ADMIN_SERVICE,
                                &realm_params, KADM5_STRUCT_VERSION,
                                KADM5_API_VERSION_2, NULL,
                                &kadm_server_handle);
  if (status)
    goto cleanup;

  status = kadm5_get_principal(kadm_server_handle, princ, &dprinc, KADM5_PRINCIPAL_NORMAL_MASK);
  if (status)
    goto cleanup;

  mask |= KADM5_ATTRIBUTES;
  if (activate == 2)
    {
      /* Force password change */
      dprinc.attributes |= KRB5_KDB_REQUIRES_PWCHANGE;
      dprinc.attributes &= ~KRB5_KDB_DISALLOW_ALL_TIX;
    }
  else if (activate == 1)
    {
      /* Enable principal */
      dprinc.attributes &= ~KRB5_KDB_DISALLOW_ALL_TIX;
      dprinc.attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE;
    }
  else
    {
      /* Disable principal */
      dprinc.attributes |= KRB5_KDB_DISALLOW_ALL_TIX;
      dprinc.attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE;
    }

  status = kadm5_modify_principal(kadm_server_handle, &dprinc, mask);

 cleanup:
  krb5_free_principal(context, princ);
  kadm5_free_principal_ent(kadm_server_handle, &dprinc);
  if (kadm_server_handle)
    kadm5_destroy(kadm_server_handle);

  return status;
}
Exemple #9
0
static krb5_error_code
add_one_principal (const char *name,
		   int rand_key,
		   int rand_password,
		   int use_defaults,
		   char *password,
		   krb5_key_data *key_data,
		   const char *max_ticket_life,
		   const char *max_renewable_life,
		   const char *attributes,
		   const char *expiration,
		   const char *pw_expiration)
{
    krb5_error_code ret;
    kadm5_principal_ent_rec princ, defrec;
    kadm5_principal_ent_rec *default_ent = NULL;
    krb5_principal princ_ent = NULL;
    int mask = 0;
    int default_mask = 0;
    char pwbuf[1024];

    memset(&princ, 0, sizeof(princ));
    ret = krb5_parse_name(context, name, &princ_ent);
    if (ret) {
	krb5_warn(context, ret, "krb5_parse_name");
	return ret;
    }
    princ.principal = princ_ent;
    mask |= KADM5_PRINCIPAL;

    ret = set_entry(context, &princ, &mask,
		    max_ticket_life, max_renewable_life,
		    expiration, pw_expiration, attributes);
    if (ret)
	goto out;

    default_ent = &defrec;
    ret = get_default (kadm_handle, princ_ent, default_ent);
    if (ret) {
	default_ent  = NULL;
	default_mask = 0;
    } else {
	default_mask = KADM5_ATTRIBUTES | KADM5_MAX_LIFE | KADM5_MAX_RLIFE |
	    KADM5_PRINC_EXPIRE_TIME | KADM5_PW_EXPIRATION;
    }

    if(use_defaults)
	set_defaults(&princ, &mask, default_ent, default_mask);
    else
	if(edit_entry(&princ, &mask, default_ent, default_mask))
	    goto out;
    if(rand_key || key_data) {
	princ.attributes |= KRB5_KDB_DISALLOW_ALL_TIX;
	mask |= KADM5_ATTRIBUTES;
	random_password (pwbuf, sizeof(pwbuf));
	password = pwbuf;
    } else if (rand_password) {
	random_password (pwbuf, sizeof(pwbuf));
	password = pwbuf;
    } else if(password == NULL) {
	char *princ_name;
	char *prompt;

	krb5_unparse_name(context, princ_ent, &princ_name);
	asprintf (&prompt, "%s's Password: "******"failed to verify password");
	    goto out;
	}
	password = pwbuf;
    }

    ret = kadm5_create_principal(kadm_handle, &princ, mask, password);
    if(ret) {
	krb5_warn(context, ret, "kadm5_create_principal");
	goto out;
    }
    if(rand_key) {
	krb5_keyblock *new_keys;
	int n_keys, i;
	ret = kadm5_randkey_principal(kadm_handle, princ_ent,
				      &new_keys, &n_keys);
	if(ret){
	    krb5_warn(context, ret, "kadm5_randkey_principal");
	    n_keys = 0;
	}
	for(i = 0; i < n_keys; i++)
	    krb5_free_keyblock_contents(context, &new_keys[i]);
	if (n_keys > 0)
	    free(new_keys);
	kadm5_get_principal(kadm_handle, princ_ent, &princ,
			    KADM5_PRINCIPAL | KADM5_KVNO | KADM5_ATTRIBUTES);
	princ.attributes &= (~KRB5_KDB_DISALLOW_ALL_TIX);
	princ.kvno = 1;
	kadm5_modify_principal(kadm_handle, &princ,
			       KADM5_ATTRIBUTES | KADM5_KVNO);
	kadm5_free_principal_ent(kadm_handle, &princ);
    } else if (key_data) {
	ret = kadm5_chpass_principal_with_key (kadm_handle, princ_ent,
					       3, key_data);
	if (ret) {
	    krb5_warn(context, ret, "kadm5_chpass_principal_with_key");
	}
	kadm5_get_principal(kadm_handle, princ_ent, &princ,
			    KADM5_PRINCIPAL | KADM5_ATTRIBUTES);
	princ.attributes &= (~KRB5_KDB_DISALLOW_ALL_TIX);
	kadm5_modify_principal(kadm_handle, &princ, KADM5_ATTRIBUTES);
	kadm5_free_principal_ent(kadm_handle, &princ);
    } else if (rand_password) {
	char *princ_name;

	krb5_unparse_name(context, princ_ent, &princ_name);
	printf ("added %s with password \"%s\"\n", princ_name, password);
	free (princ_name);
    }
out:
    if (princ_ent)
	krb5_free_principal (context, princ_ent);
    if(default_ent)
	kadm5_free_principal_ent (kadm_handle, default_ent);
    if (password != NULL)
	memset (password, 0, strlen(password));
    return ret;
}
Exemple #10
0
static kadm5_ret_t
kadmind_dispatch(void *kadm_handlep, krb5_boolean initial,
		 krb5_data *in, krb5_data *out)
{
    kadm5_ret_t ret;
    int32_t cmd, mask, tmp;
    kadm5_server_context *contextp = kadm_handlep;
    char client[128], name[128], name2[128];
    const char *op = "";
    krb5_principal princ, princ2;
    kadm5_principal_ent_rec ent;
    char *password, *expression;
    krb5_keyblock *new_keys;
    krb5_key_salt_tuple *ks_tuple = NULL;
    krb5_boolean keepold = FALSE;
    int n_ks_tuple = 0;
    int n_keys;
    char **princs;
    int n_princs;
    int keys_ok = 0;
    krb5_storage *sp;

    krb5_unparse_name_fixed(contextp->context, contextp->caller,
			    client, sizeof(client));

    sp = krb5_storage_from_data(in);
    if (sp == NULL)
	krb5_errx(contextp->context, 1, "out of memory");

    krb5_ret_int32(sp, &cmd);
    switch(cmd){
    case kadm_get:{
	op = "GET";
	ret = krb5_ret_principal(sp, &princ);
	if(ret)
	    goto fail;
	ret = krb5_ret_int32(sp, &mask);
	if(ret){
	    krb5_free_principal(contextp->context, princ);
	    goto fail;
	}
	mask |= KADM5_PRINCIPAL;
	krb5_unparse_name_fixed(contextp->context, princ, name, sizeof(name));
	krb5_warnx(contextp->context, "%s: %s %s", client, op, name);

        /* If the caller doesn't have KADM5_PRIV_GET, we're done. */
	ret = _kadm5_acl_check_permission(contextp, KADM5_PRIV_GET, princ);
        if (ret) {
	    krb5_free_principal(contextp->context, princ);
	    goto fail;
        }

        /* Then check to see if it is ok to return keys */
        if ((mask & KADM5_KEY_DATA) != 0) {
            ret = _kadm5_acl_check_permission(contextp, KADM5_PRIV_GET_KEYS,
                                              princ);
            if (ret == 0) {
                keys_ok = 1;
            } else if ((mask == (KADM5_PRINCIPAL|KADM5_KEY_DATA)) ||
                       (mask == (KADM5_PRINCIPAL|KADM5_KVNO|KADM5_KEY_DATA))) {
                /*
                 * Requests for keys will get bogus keys, which is useful if
                 * the client just wants to see what (kvno, enctype)s the
                 * principal has keys for, but terrible if the client wants to
                 * write the keys into a keytab or modify the principal and
                 * write the bogus keys back to the server.
                 *
                 * We use a heuristic to detect which case we're handling here.
                 * If the client only asks for the flags in the above
                 * condition, then it's very likely a kadmin ext_keytab,
                 * add_enctype, or other request that should not see bogus
                 * keys.  We deny them.
                 *
                 * The kadmin get command can be coaxed into making a request
                 * with the same mask.  But the default long and terse output
                 * modes request other things too, so in all likelihood this
                 * heuristic will not hurt any kadmin get uses.
                 */
                krb5_free_principal(contextp->context, princ);
                goto fail;
            }
        }

	ret = kadm5_get_principal(kadm_handlep, princ, &ent, mask);
	krb5_storage_free(sp);
	sp = krb5_storage_emem();
	krb5_store_int32(sp, ret);
	if (ret == 0){
	    if (keys_ok)
		kadm5_store_principal_ent(sp, &ent);
	    else
		kadm5_store_principal_ent_nokeys(sp, &ent);
	    kadm5_free_principal_ent(kadm_handlep, &ent);
	}
	krb5_free_principal(contextp->context, princ);
	break;
    }
    case kadm_delete:{
	op = "DELETE";
	ret = krb5_ret_principal(sp, &princ);
	if(ret)
	    goto fail;
	krb5_unparse_name_fixed(contextp->context, princ, name, sizeof(name));
	krb5_warnx(contextp->context, "%s: %s %s", client, op, name);
	ret = _kadm5_acl_check_permission(contextp, KADM5_PRIV_DELETE, princ);
	if(ret){
	    krb5_free_principal(contextp->context, princ);
	    goto fail;
	}
	ret = kadm5_delete_principal(kadm_handlep, princ);
	krb5_free_principal(contextp->context, princ);
	krb5_storage_free(sp);
	sp = krb5_storage_emem();
	krb5_store_int32(sp, ret);
	break;
    }
    case kadm_create:{
	op = "CREATE";
	ret = kadm5_ret_principal_ent(sp, &ent);
	if(ret)
	    goto fail;
	ret = krb5_ret_int32(sp, &mask);
	if(ret){
	    kadm5_free_principal_ent(contextp->context, &ent);
	    goto fail;
	}
	ret = krb5_ret_string(sp, &password);
	if(ret){
	    kadm5_free_principal_ent(contextp->context, &ent);
	    goto fail;
	}
	krb5_unparse_name_fixed(contextp->context, ent.principal,
				name, sizeof(name));
	krb5_warnx(contextp->context, "%s: %s %s", client, op, name);
	ret = _kadm5_acl_check_permission(contextp, KADM5_PRIV_ADD,
					  ent.principal);
	if(ret){
	    kadm5_free_principal_ent(contextp->context, &ent);
	    memset(password, 0, strlen(password));
	    free(password);
	    goto fail;
	}
	ret = kadm5_create_principal(kadm_handlep, &ent,
				     mask, password);
	kadm5_free_principal_ent(kadm_handlep, &ent);
	memset(password, 0, strlen(password));
	free(password);
	krb5_storage_free(sp);
	sp = krb5_storage_emem();
	krb5_store_int32(sp, ret);
	break;
    }
    case kadm_modify:{
	op = "MODIFY";
	ret = kadm5_ret_principal_ent(sp, &ent);
	if(ret)
	    goto fail;
	ret = krb5_ret_int32(sp, &mask);
	if(ret){
	    kadm5_free_principal_ent(contextp, &ent);
	    goto fail;
	}
	krb5_unparse_name_fixed(contextp->context, ent.principal,
				name, sizeof(name));
	krb5_warnx(contextp->context, "%s: %s %s", client, op, name);
	ret = _kadm5_acl_check_permission(contextp, KADM5_PRIV_MODIFY,
					  ent.principal);
	if(ret){
	    kadm5_free_principal_ent(contextp, &ent);
	    goto fail;
	}
	ret = kadm5_modify_principal(kadm_handlep, &ent, mask);
	kadm5_free_principal_ent(kadm_handlep, &ent);
	krb5_storage_free(sp);
	sp = krb5_storage_emem();
	krb5_store_int32(sp, ret);
	break;
    }
    case kadm_rename:{
	op = "RENAME";
	ret = krb5_ret_principal(sp, &princ);
	if(ret)
	    goto fail;
	ret = krb5_ret_principal(sp, &princ2);
	if(ret){
	    krb5_free_principal(contextp->context, princ);
	    goto fail;
	}
	krb5_unparse_name_fixed(contextp->context, princ, name, sizeof(name));
	krb5_unparse_name_fixed(contextp->context, princ2, name2, sizeof(name2));
	krb5_warnx(contextp->context, "%s: %s %s -> %s",
		   client, op, name, name2);
	ret = _kadm5_acl_check_permission(contextp,
					  KADM5_PRIV_ADD,
					  princ2)
	    || _kadm5_acl_check_permission(contextp,
					   KADM5_PRIV_DELETE,
					   princ);
	if(ret){
	    krb5_free_principal(contextp->context, princ);
	    krb5_free_principal(contextp->context, princ2);
	    goto fail;
	}
	ret = kadm5_rename_principal(kadm_handlep, princ, princ2);
	krb5_free_principal(contextp->context, princ);
	krb5_free_principal(contextp->context, princ2);
	krb5_storage_free(sp);
	sp = krb5_storage_emem();
	krb5_store_int32(sp, ret);
	break;
    }
    case kadm_chpass:{
	op = "CHPASS";
	ret = krb5_ret_principal(sp, &princ);
	if (ret)
	    goto fail;
	ret = krb5_ret_string(sp, &password);
	if (ret) {
	    krb5_free_principal(contextp->context, princ);
	    goto fail;
	}
	ret = krb5_ret_int32(sp, &keepold);
	if (ret && ret != HEIM_ERR_EOF) {
	    krb5_free_principal(contextp->context, princ);
	    goto fail;
	}
	krb5_unparse_name_fixed(contextp->context, princ, name, sizeof(name));
	krb5_warnx(contextp->context, "%s: %s %s", client, op, name);

	/*
	 * The change is allowed if at least one of:
	 *
	 * a) allowed by sysadmin
	 * b) it's for the principal him/herself and this was an
	 *    initial ticket, but then, check with the password quality
	 *    function.
	 * c) the user is on the CPW ACL.
	 */

	if (krb5_config_get_bool_default(contextp->context, NULL, TRUE,
					 "kadmin", "allow_self_change_password", NULL)
	    && initial
	    && krb5_principal_compare (contextp->context, contextp->caller,
				       princ))
	{
	    krb5_data pwd_data;
	    const char *pwd_reason;

	    pwd_data.data = password;
	    pwd_data.length = strlen(password);

	    pwd_reason = kadm5_check_password_quality (contextp->context,
						       princ, &pwd_data);
	    if (pwd_reason != NULL)
		ret = KADM5_PASS_Q_DICT;
	    else
		ret = 0;
	} else
	    ret = _kadm5_acl_check_permission(contextp, KADM5_PRIV_CPW, princ);

	if(ret) {
	    krb5_free_principal(contextp->context, princ);
	    memset(password, 0, strlen(password));
	    free(password);
	    goto fail;
	}
	ret = kadm5_chpass_principal_3(kadm_handlep, princ, keepold, 0, NULL,
				       password);
	krb5_free_principal(contextp->context, princ);
	memset(password, 0, strlen(password));
	free(password);
	krb5_storage_free(sp);
	sp = krb5_storage_emem();
	krb5_store_int32(sp, ret);
	break;
    }
    case kadm_chpass_with_key:{
	int i;
	krb5_key_data *key_data;
	int n_key_data;

	op = "CHPASS_WITH_KEY";
	ret = krb5_ret_principal(sp, &princ);
	if(ret)
	    goto fail;
	ret = krb5_ret_int32(sp, &n_key_data);
	if (ret) {
	    krb5_free_principal(contextp->context, princ);
	    goto fail;
	}
	ret = krb5_ret_int32(sp, &keepold);
	if (ret && ret != HEIM_ERR_EOF) {
	    krb5_free_principal(contextp->context, princ);
	    goto fail;
	}
	/* n_key_data will be squeezed into an int16_t below. */
	if (n_key_data < 0 || n_key_data >= 1 << 16 ||
	    (size_t)n_key_data > UINT_MAX/sizeof(*key_data)) {
	    ret = ERANGE;
	    krb5_free_principal(contextp->context, princ);
	    goto fail;
	}

	key_data = malloc (n_key_data * sizeof(*key_data));
	if (key_data == NULL && n_key_data != 0) {
	    ret = ENOMEM;
	    krb5_free_principal(contextp->context, princ);
	    goto fail;
	}

	for (i = 0; i < n_key_data; ++i) {
	    ret = kadm5_ret_key_data (sp, &key_data[i]);
	    if (ret) {
		int16_t dummy = i;

		kadm5_free_key_data (contextp, &dummy, key_data);
		free (key_data);
		krb5_free_principal(contextp->context, princ);
		goto fail;
	    }
	}

	krb5_unparse_name_fixed(contextp->context, princ, name, sizeof(name));
	krb5_warnx(contextp->context, "%s: %s %s", client, op, name);

	/*
	 * The change is only allowed if the user is on the CPW ACL,
	 * this it to force password quality check on the user.
	 */

	ret = _kadm5_acl_check_permission(contextp, KADM5_PRIV_CPW, princ);
	if(ret) {
	    int16_t dummy = n_key_data;

	    kadm5_free_key_data (contextp, &dummy, key_data);
	    free (key_data);
	    krb5_free_principal(contextp->context, princ);
	    goto fail;
	}
	ret = kadm5_chpass_principal_with_key_3(kadm_handlep, princ, keepold,
					        n_key_data, key_data);
	{
	    int16_t dummy = n_key_data;
	    kadm5_free_key_data (contextp, &dummy, key_data);
	}
	free (key_data);
	krb5_free_principal(contextp->context, princ);
	krb5_storage_free(sp);
	sp = krb5_storage_emem();
	krb5_store_int32(sp, ret);
	break;
    }
    case kadm_randkey:{
	op = "RANDKEY";
	ret = krb5_ret_principal(sp, &princ);
	if(ret)
	    goto fail;
	krb5_unparse_name_fixed(contextp->context, princ, name, sizeof(name));
	krb5_warnx(contextp->context, "%s: %s %s", client, op, name);
	/*
	 * The change is allowed if at least one of:
	 * a) it's for the principal him/herself and this was an initial ticket
	 * b) the user is on the CPW ACL.
	 */

	if (initial
	    && krb5_principal_compare (contextp->context, contextp->caller,
				       princ))
	    ret = 0;
	else
	    ret = _kadm5_acl_check_permission(contextp, KADM5_PRIV_CPW, princ);

	if(ret) {
	    krb5_free_principal(contextp->context, princ);
	    goto fail;
	}

	/*
	 * See comments in kadm5_c_randkey_principal() regarding the
	 * protocol.
	 */
	ret = krb5_ret_int32(sp, &keepold);
	if (ret != 0 && ret != HEIM_ERR_EOF) {
	    krb5_free_principal(contextp->context, princ);
	    goto fail;
	}

	ret = krb5_ret_int32(sp, &n_ks_tuple);
	if (ret != 0 && ret != HEIM_ERR_EOF) {
	    krb5_free_principal(contextp->context, princ);
	    goto fail;
	} else if (ret == 0) {
	    size_t i;

	    if (n_ks_tuple < 0) {
		ret = EOVERFLOW;
		krb5_free_principal(contextp->context, princ);
		goto fail;
	    }

	    if ((ks_tuple = calloc(n_ks_tuple, sizeof (*ks_tuple))) == NULL) {
		ret = errno;
		krb5_free_principal(contextp->context, princ);
		goto fail;
	    }

	    for (i = 0; i < n_ks_tuple; i++) {
		ret = krb5_ret_int32(sp, &ks_tuple[i].ks_enctype);
		if (ret != 0) {
		    krb5_free_principal(contextp->context, princ);
		    goto fail;
		}
		ret = krb5_ret_int32(sp, &ks_tuple[i].ks_salttype);
		if (ret != 0) {
		    krb5_free_principal(contextp->context, princ);
		    goto fail;
		}
	    }
	}
	ret = kadm5_randkey_principal_3(kadm_handlep, princ, keepold,
					n_ks_tuple, ks_tuple, &new_keys,
					&n_keys);
	krb5_free_principal(contextp->context, princ);

	krb5_storage_free(sp);
	sp = krb5_storage_emem();
	krb5_store_int32(sp, ret);
	if(ret == 0){
	    int i;
	    krb5_store_int32(sp, n_keys);
	    for(i = 0; i < n_keys; i++){
		krb5_store_keyblock(sp, new_keys[i]);
		krb5_free_keyblock_contents(contextp->context, &new_keys[i]);
	    }
	    free(new_keys);
	}
	break;
    }
    case kadm_get_privs:{
	uint32_t privs;
	ret = kadm5_get_privs(kadm_handlep, &privs);
	krb5_storage_free(sp);
	sp = krb5_storage_emem();
	krb5_store_int32(sp, ret);
	if(ret == 0)
	    krb5_store_uint32(sp, privs);
	break;
    }
    case kadm_get_princs:{
	op = "LIST";
	ret = krb5_ret_int32(sp, &tmp);
	if(ret)
	    goto fail;
	if(tmp){
	    ret = krb5_ret_string(sp, &expression);
	    if(ret)
		goto fail;
	}else
	    expression = NULL;
	krb5_warnx(contextp->context, "%s: %s %s", client, op,
		   expression ? expression : "*");
	ret = _kadm5_acl_check_permission(contextp, KADM5_PRIV_LIST, NULL);
	if(ret){
	    free(expression);
	    goto fail;
	}
	ret = kadm5_get_principals(kadm_handlep, expression, &princs, &n_princs);
	free(expression);
	krb5_storage_free(sp);
	sp = krb5_storage_emem();
	krb5_store_int32(sp, ret);
	if(ret == 0){
	    int i;
	    krb5_store_int32(sp, n_princs);
	    for(i = 0; i < n_princs; i++)
		krb5_store_string(sp, princs[i]);
	    kadm5_free_name_list(kadm_handlep, princs, &n_princs);
	}
	break;
    }
    default:
	krb5_warnx(contextp->context, "%s: UNKNOWN OP %d", client, cmd);
	krb5_storage_free(sp);
	sp = krb5_storage_emem();
	krb5_store_int32(sp, KADM5_FAILURE);
	break;
    }
    krb5_storage_to_data(sp, out);
    krb5_storage_free(sp);
    return 0;
fail:
    krb5_warn(contextp->context, ret, "%s", op);
    krb5_storage_seek(sp, 0, SEEK_SET);
    krb5_store_int32(sp, ret);
    krb5_storage_to_data(sp, out);
    krb5_storage_free(sp);
    return 0;
}
Exemple #11
0
static void
add_principal(void *lhandle, char *keytab_str, krb5_keytab keytab,
              krb5_boolean keepold, int n_ks_tuple,
              krb5_key_salt_tuple *ks_tuple, char *princ_str)
{
    kadm5_principal_ent_rec princ_rec;
    krb5_principal princ = NULL;
    krb5_keytab_entry new_entry;
    krb5_keyblock *keys;
    int code, nkeys, i;

    memset(&princ_rec, 0, sizeof(princ_rec));

    princ = NULL;
    keys = NULL;
    nkeys = 0;

    code = krb5_parse_name(context, princ_str, &princ);
    if (code != 0) {
        com_err(whoami, code, "while parsing -add principal name %s",
                princ_str);
        goto cleanup;
    }

#ifdef KADMIN_LOCAL
    if (norandkey)
        code = kadm5_get_principal_keys(handle, princ, &keys, &nkeys);
    else
#endif
        if (keepold || ks_tuple != NULL) {
            code = kadm5_randkey_principal_3(lhandle, princ, keepold,
                                             n_ks_tuple, ks_tuple, &keys, &nkeys);
        } else
            code = kadm5_randkey_principal(lhandle, princ, &keys, &nkeys);
    if (code != 0) {
        if (code == KADM5_UNK_PRINC) {
            fprintf(stderr, "%s: Principal %s does not exist.\n",
                    whoami, princ_str);
        } else
            com_err(whoami, code, "while changing %s's key", princ_str);
        goto cleanup;
    }

    code = kadm5_get_principal(lhandle, princ, &princ_rec,
                               KADM5_PRINCIPAL_NORMAL_MASK);
    if (code != 0) {
        com_err(whoami, code, "while retrieving principal");
        goto cleanup;
    }

    for (i = 0; i < nkeys; i++) {
        memset(&new_entry, 0, sizeof(new_entry));
        new_entry.principal = princ;
        new_entry.key = keys[i];
        new_entry.vno = princ_rec.kvno;

        code = krb5_kt_add_entry(context, keytab, &new_entry);
        if (code != 0) {
            com_err(whoami, code, "while adding key to keytab");
            kadm5_free_principal_ent(lhandle, &princ_rec);
            goto cleanup;
        }

        if (!quiet) {
            printf("Entry for principal %s with kvno %d, "
                   "encryption type %s added to keytab %s.\n",
                   princ_str, princ_rec.kvno,
                   etype_string(keys[i].enctype), keytab_str);
        }
    }

    code = kadm5_free_principal_ent(lhandle, &princ_rec);
    if (code != 0) {
        com_err(whoami, code, "while freeing principal entry");
        goto cleanup;
    }

cleanup:
    for (i = 0; i < nkeys; i++)
        krb5_free_keyblock_contents(context, &keys[i]);
    free(keys);
    krb5_free_principal(context, princ);
}
Exemple #12
0
int
del_enctype(void *opt, int argc, char **argv)
{
    kadm5_principal_ent_rec princ;
    krb5_principal princ_ent = NULL;
    krb5_error_code ret;
    const char *princ_name;
    int i, j, k;
    krb5_key_data *new_key_data;
    int n_etypes;
    krb5_enctype *etypes;

    memset (&princ, 0, sizeof(princ));
    princ_name = argv[0];
    n_etypes   = argc - 1;
    etypes     = malloc (n_etypes * sizeof(*etypes));
    if (etypes == NULL) {
        krb5_warnx (context, "out of memory");
        return 0;
    }
    argv++;
    for (i = 0; i < n_etypes; ++i) {
        ret = krb5_string_to_enctype (context, argv[i], &etypes[i]);
        if (ret) {
            krb5_warnx (context, "bad enctype \"%s\"", argv[i]);
            goto out2;
        }
    }

    ret = krb5_parse_name(context, princ_name, &princ_ent);
    if (ret) {
        krb5_warn (context, ret, "krb5_parse_name %s", princ_name);
        goto out2;
    }

    ret = kadm5_get_principal(kadm_handle, princ_ent, &princ,
                              KADM5_PRINCIPAL | KADM5_KEY_DATA);
    if (ret) {
        krb5_free_principal (context, princ_ent);
        krb5_warnx (context, "no such principal: %s", princ_name);
        goto out2;
    }

    new_key_data   = malloc(princ.n_key_data * sizeof(*new_key_data));
    if (new_key_data == NULL && princ.n_key_data != 0) {
        krb5_warnx (context, "out of memory");
        goto out;
    }

    for (i = 0, j = 0; i < princ.n_key_data; ++i) {
        krb5_key_data *key = &princ.key_data[i];
        int docopy = 1;

        for (k = 0; k < n_etypes; ++k)
            if (etypes[k] == key->key_data_type[0]) {
                docopy = 0;
                break;
            }
        if (docopy) {
            new_key_data[j++] = *key;
        } else {
            int16_t ignore = 1;

            kadm5_free_key_data (kadm_handle, &ignore, key);
        }
    }

    free (princ.key_data);
    princ.n_key_data = j;
    princ.key_data   = new_key_data;

    ret = kadm5_modify_principal (kadm_handle, &princ, KADM5_KEY_DATA);
    if (ret)
        krb5_warn(context, ret, "kadm5_modify_principal");
out:
    krb5_free_principal (context, princ_ent);
    kadm5_free_principal_ent(kadm_handle, &princ);
out2:
    free (etypes);
    return ret != 0;
}
Exemple #13
0
int
add_enctype(struct add_enctype_options*opt, int argc, char **argv)
{
    kadm5_principal_ent_rec princ;
    krb5_principal princ_ent = NULL;
    krb5_error_code ret;
    const char *princ_name;
    int i, j;
    krb5_key_data *new_key_data;
    int n_etypes;
    krb5_enctype *etypes;

    if (!opt->random_key_flag) {
	krb5_warnx (context, "only random key is supported now");
	return 0;
    }

    memset (&princ, 0, sizeof(princ));
    princ_name = argv[0];
    n_etypes   = argc - 1;
    etypes     = malloc (n_etypes * sizeof(*etypes));
    if (etypes == NULL) {
	krb5_warnx (context, "out of memory");
	return 0;
    }
    argv++;
    for (i = 0; i < n_etypes; ++i) {
	ret = krb5_string_to_enctype (context, argv[i], &etypes[i]);
	if (ret) {
	    krb5_warnx (context, "bad enctype \"%s\"", argv[i]);
	    goto out2;
	}
    }

    ret = krb5_parse_name(context, princ_name, &princ_ent);
    if (ret) {
	krb5_warn (context, ret, "krb5_parse_name %s", princ_name);
	goto out2;
    }

    ret = kadm5_get_principal(kadm_handle, princ_ent, &princ,
			      KADM5_PRINCIPAL | KADM5_KEY_DATA);
    if (ret) {
	krb5_free_principal (context, princ_ent);
	krb5_warnx (context, "no such principal: %s", princ_name);
	goto out2;
    }

    new_key_data   = malloc((princ.n_key_data + n_etypes)
			    * sizeof(*new_key_data));
    if (new_key_data == NULL) {
	krb5_warnx (context, "out of memory");
	goto out;
    }

    for (i = 0; i < princ.n_key_data; ++i) {
	krb5_key_data *key = &princ.key_data[i];

	for (j = 0; j < n_etypes; ++j) {
	    if (etypes[j] == key->key_data_type[0]) {
		krb5_warnx(context, "enctype %d already exists",
			   (int)etypes[j]);
		free(new_key_data);
		goto out;
	    }
	}
	new_key_data[i] = *key;
    }

    for (i = 0; i < n_etypes; ++i) {
	int n = princ.n_key_data + i;
	krb5_keyblock keyblock;

	memset(&new_key_data[n], 0, sizeof(new_key_data[n]));
	new_key_data[n].key_data_ver = 2;
	new_key_data[n].key_data_kvno = 0;

	ret = krb5_generate_random_keyblock (context, etypes[i], &keyblock);
	if (ret) {
	    krb5_warnx(context, "genernate enctype %d failed", (int)etypes[i]);
	    while (--i >= 0)
		free(new_key_data[--n].key_data_contents[0]);
	    goto out;
	}

	/* key */
	new_key_data[n].key_data_type[0] = etypes[i];
	new_key_data[n].key_data_contents[0] = malloc(keyblock.keyvalue.length);
	if (new_key_data[n].key_data_contents[0] == NULL) {
	    ret = ENOMEM;
	    krb5_warn(context, ret, "out of memory");
	    while (--i >= 0)
		free(new_key_data[--n].key_data_contents[0]);
	    goto out;
	}
	new_key_data[n].key_data_length[0]   = keyblock.keyvalue.length;
	memcpy(new_key_data[n].key_data_contents[0],
	       keyblock.keyvalue.data,
	       keyblock.keyvalue.length);
	krb5_free_keyblock_contents(context, &keyblock);

	/* salt */
	new_key_data[n].key_data_type[1]     = KRB5_PW_SALT;
	new_key_data[n].key_data_length[1]   = 0;
	new_key_data[n].key_data_contents[1] = NULL;

    }

    free (princ.key_data);
    princ.n_key_data += n_etypes;
    princ.key_data   = new_key_data;
    new_key_data = NULL;

    ret = kadm5_modify_principal (kadm_handle, &princ, KADM5_KEY_DATA);
    if (ret)
	krb5_warn(context, ret, "kadm5_modify_principal");
out:
    krb5_free_principal (context, princ_ent);
    kadm5_free_principal_ent(kadm_handle, &princ);
out2:
    free (etypes);
    return ret != 0;
}
Exemple #14
0
static int
do_ext_keytab(krb5_principal principal, void *data)
{
    krb5_error_code ret;
    kadm5_principal_ent_rec princ;
    struct ext_keytab_data *e = data;
    krb5_keytab_entry *keys = NULL;
    krb5_keyblock *k = NULL;
    int i, n_k;

    ret = kadm5_get_principal(kadm_handle, principal, &princ,
			      KADM5_PRINCIPAL|KADM5_KVNO|KADM5_KEY_DATA);
    if(ret)
	return ret;

    if (princ.n_key_data) {
	keys = malloc(sizeof(*keys) * princ.n_key_data);
	if (keys == NULL) {
	    kadm5_free_principal_ent(kadm_handle, &princ);
	    krb5_clear_error_message(context);
	    return ENOMEM;
	}
	for (i = 0; i < princ.n_key_data; i++) {
	    krb5_key_data *kd = &princ.key_data[i];

	    keys[i].principal = princ.principal;
	    keys[i].vno = kd->key_data_kvno;
	    keys[i].keyblock.keytype = kd->key_data_type[0];
	    keys[i].keyblock.keyvalue.length = kd->key_data_length[0];
	    keys[i].keyblock.keyvalue.data = kd->key_data_contents[0];
	    keys[i].timestamp = time(NULL);
	}

	n_k = princ.n_key_data;
    } else {
	ret = kadm5_randkey_principal(kadm_handle, principal, &k, &n_k);
	if (ret) {
	    kadm5_free_principal_ent(kadm_handle, &princ);
	    return ret;
	}
	keys = malloc(sizeof(*keys) * n_k);
	if (keys == NULL) {
	    kadm5_free_principal_ent(kadm_handle, &princ);
	    krb5_clear_error_message(context);
	    return ENOMEM;
	}
	for (i = 0; i < n_k; i++) {
	    keys[i].principal = principal;
	    keys[i].vno = princ.kvno + 1; /* XXX get entry again */
	    keys[i].keyblock = k[i];
	    keys[i].timestamp = time(NULL);
	}
    }

    for(i = 0; i < n_k; i++) {
	ret = krb5_kt_add_entry(context, e->keytab, &keys[i]);
	if(ret)
	    krb5_warn(context, ret, "krb5_kt_add_entry(%d)", i);
    }

    if (k) {
	memset(k, 0, n_k * sizeof(*k));
	free(k);
    }
    if (keys)
	free(keys);
    kadm5_free_principal_ent(kadm_handle, &princ);
    return 0;
}
Exemple #15
0
/**
 * This function is allows the caller to set new keys for a principal.
 * This is a simple wrapper around kadm5_get_principal() and
 * kadm5_modify_principal().
 */
kadm5_ret_t
kadm5_setkey_principal_3(void *server_handle,
                         krb5_principal princ,
                         krb5_boolean keepold,
                         int n_ks_tuple, krb5_key_salt_tuple *ks_tuple,
                         krb5_keyblock *keyblocks,
                         int n_keys)
{
    kadm5_principal_ent_rec princ_ent;
    kadm5_ret_t ret;
    krb5_key_data *new_key_data = NULL;
    size_t i;

    if (n_keys < 1)
	return EINVAL;
    if (n_ks_tuple > 0 && n_ks_tuple != n_keys)
	return KADM5_SETKEY3_ETYPE_MISMATCH;

    /*
     * If setkey_principal_3 is defined in the server handle, use that.
     */
    if (__CALLABLE(setkey_principal_3))
	return __CALL(setkey_principal_3,
		      (server_handle, princ, keepold, n_ks_tuple, ks_tuple,
		       keyblocks, n_keys));

    /*
     * Otherwise, simulate it via a get, update, modify sequence.
     */
    ret = kadm5_get_principal(server_handle, princ, &princ_ent,
                              KADM5_KVNO | KADM5_PRINCIPAL | KADM5_KEY_DATA);
    if (ret)
	return ret;

    if (keepold) {
	new_key_data = malloc((n_keys + princ_ent.n_key_data) * sizeof(*new_key_data));
	if (new_key_data == NULL) {
	    ret = ENOMEM;
	    goto out;
	}

	memcpy(&new_key_data[n_keys], &princ_ent.key_data[0],
		princ_ent.n_key_data * sizeof (princ_ent.key_data[0]));
    } else {
	new_key_data = malloc(n_keys * sizeof(*new_key_data));
	if (new_key_data == NULL) {
	    ret = ENOMEM;
	    goto out;
	}
    }

    princ_ent.kvno++;
    for (i = 0; i < n_keys; i++) {
	new_key_data[i].key_data_ver = 2;

	/* Key */
	new_key_data[i].key_data_kvno = princ_ent.kvno;
	new_key_data[i].key_data_type[0] = keyblocks[i].keytype;
	new_key_data[i].key_data_length[0] = keyblocks[i].keyvalue.length;
	new_key_data[i].key_data_contents[0] =
	    malloc(keyblocks[i].keyvalue.length);
	if (new_key_data[i].key_data_contents[0] == NULL) {
	    ret = ENOMEM;
	    goto out;
	}
	memcpy(new_key_data[i].key_data_contents[0],
	       keyblocks[i].keyvalue.data,
	       keyblocks[i].keyvalue.length);

	/*
	 * Salt (but there's no salt, just salttype, which is kinda
	 * silly -- what's the point of setkey_3() then, besides
	 * keepold?!)
	 */
	new_key_data[i].key_data_type[1] = 0;
	if (n_ks_tuple > 0) {
	    if (ks_tuple[i].ks_enctype != keyblocks[i].keytype)
		return KADM5_SETKEY3_ETYPE_MISMATCH;
	    new_key_data[i].key_data_type[1] = ks_tuple[i].ks_salttype;
	}
	new_key_data[i].key_data_length[1] = 0;
	new_key_data[i].key_data_contents[1] = NULL;
    }

    /* Free old keys */
    if (!keepold) {
	for (i = 0; i < princ_ent.n_key_data; i++) {
	    free(princ_ent.key_data[i].key_data_contents[0]);
	    free(princ_ent.key_data[i].key_data_contents[1]);
	}
    }
    free(princ_ent.key_data);
    princ_ent.key_data = new_key_data;
    princ_ent.n_key_data = n_keys + (keepold ? princ_ent.n_key_data : 0);
    new_key_data = NULL;

    /* Modify the principal */
    ret = kadm5_modify_principal(server_handle, &princ_ent, KADM5_KVNO | KADM5_KEY_DATA);

out:
    if (new_key_data != NULL) {
	for (i = 0; i < n_keys; i++) {
	    free(new_key_data[i].key_data_contents[0]);
	    free(new_key_data[i].key_data_contents[1]);
	}
	free(new_key_data);
    }
    kadm5_free_principal_ent(server_handle, &princ_ent);
    return ret;
}
Exemple #16
0
static kadm5_ret_t
kadmind_dispatch(void *kadm_handle, krb5_boolean initial,
		 krb5_data *in, krb5_data *out)
{
    kadm5_ret_t ret;
    int32_t cmd, mask, tmp;
    kadm5_server_context *context = kadm_handle;
    char client[128], name[128], name2[128];
    char *op = "";
    krb5_principal princ, princ2;
    kadm5_principal_ent_rec ent;
    char *password, *expression;
    krb5_keyblock *new_keys;
    int n_keys;
    char **princs;
    int n_princs;
    krb5_storage *sp;

    krb5_unparse_name_fixed(context->context, context->caller,
			    client, sizeof(client));

    sp = krb5_storage_from_data(in);
    if (sp == NULL)
	krb5_errx(context->context, 1, "out of memory");

    krb5_ret_int32(sp, &cmd);
    switch(cmd){
    case kadm_get:{
	op = "GET";
	ret = krb5_ret_principal(sp, &princ);
	if(ret)
	    goto fail;
	ret = krb5_ret_int32(sp, &mask);
	if(ret){
	    krb5_free_principal(context->context, princ);
	    goto fail;
	}
	mask |= KADM5_PRINCIPAL;
	krb5_unparse_name_fixed(context->context, princ, name, sizeof(name));
	krb5_warnx(context->context, "%s: %s %s", client, op, name);
	ret = _kadm5_acl_check_permission(context, KADM5_PRIV_GET, princ);
	if(ret){
	    krb5_free_principal(context->context, princ);
	    goto fail;
	}
	ret = kadm5_get_principal(kadm_handle, princ, &ent, mask);
	krb5_storage_free(sp);
	sp = krb5_storage_emem();
	krb5_store_int32(sp, ret);
	if(ret == 0){
	    kadm5_store_principal_ent(sp, &ent);
	    kadm5_free_principal_ent(kadm_handle, &ent);
	}
	krb5_free_principal(context->context, princ);
	break;
    }
    case kadm_delete:{
	op = "DELETE";
	ret = krb5_ret_principal(sp, &princ);
	if(ret)
	    goto fail;
	krb5_unparse_name_fixed(context->context, princ, name, sizeof(name));
	krb5_warnx(context->context, "%s: %s %s", client, op, name);
	ret = _kadm5_acl_check_permission(context, KADM5_PRIV_DELETE, princ);
	if(ret){
	    krb5_free_principal(context->context, princ);
	    goto fail;
	}
	ret = kadm5_delete_principal(kadm_handle, princ);
	krb5_free_principal(context->context, princ);
	krb5_storage_free(sp);
	sp = krb5_storage_emem();
	krb5_store_int32(sp, ret);
	break;
    }
    case kadm_create:{
	op = "CREATE";
	ret = kadm5_ret_principal_ent(sp, &ent);
	if(ret)
	    goto fail;
	ret = krb5_ret_int32(sp, &mask);
	if(ret){
	    kadm5_free_principal_ent(context->context, &ent);
	    goto fail;
	}
	ret = krb5_ret_string(sp, &password);
	if(ret){
	    kadm5_free_principal_ent(context->context, &ent);
	    goto fail;
	}
	krb5_unparse_name_fixed(context->context, ent.principal,
				name, sizeof(name));
	krb5_warnx(context->context, "%s: %s %s", client, op, name);
	ret = _kadm5_acl_check_permission(context, KADM5_PRIV_ADD,
					  ent.principal);
	if(ret){
	    kadm5_free_principal_ent(context->context, &ent);
	    memset(password, 0, strlen(password));
	    free(password);
	    goto fail;
	}
	ret = kadm5_create_principal(kadm_handle, &ent,
				     mask, password);
	kadm5_free_principal_ent(kadm_handle, &ent);
	memset(password, 0, strlen(password));
	free(password);
	krb5_storage_free(sp);
	sp = krb5_storage_emem();
	krb5_store_int32(sp, ret);
	break;
    }
    case kadm_modify:{
	op = "MODIFY";
	ret = kadm5_ret_principal_ent(sp, &ent);
	if(ret)
	    goto fail;
	ret = krb5_ret_int32(sp, &mask);
	if(ret){
	    kadm5_free_principal_ent(context, &ent);
	    goto fail;
	}
	krb5_unparse_name_fixed(context->context, ent.principal,
				name, sizeof(name));
	krb5_warnx(context->context, "%s: %s %s", client, op, name);
	ret = _kadm5_acl_check_permission(context, KADM5_PRIV_MODIFY,
					  ent.principal);
	if(ret){
	    kadm5_free_principal_ent(context, &ent);
	    goto fail;
	}
	ret = kadm5_modify_principal(kadm_handle, &ent, mask);
	kadm5_free_principal_ent(kadm_handle, &ent);
	krb5_storage_free(sp);
	sp = krb5_storage_emem();
	krb5_store_int32(sp, ret);
	break;
    }
    case kadm_rename:{
	op = "RENAME";
	ret = krb5_ret_principal(sp, &princ);
	if(ret)
	    goto fail;
	ret = krb5_ret_principal(sp, &princ2);
	if(ret){
	    krb5_free_principal(context->context, princ);
	    goto fail;
	}
	krb5_unparse_name_fixed(context->context, princ, name, sizeof(name));
	krb5_unparse_name_fixed(context->context, princ2, name2, sizeof(name2));
	krb5_warnx(context->context, "%s: %s %s -> %s",
		   client, op, name, name2);
	ret = _kadm5_acl_check_permission(context,
					  KADM5_PRIV_ADD,
					  princ2)
	    || _kadm5_acl_check_permission(context,
					   KADM5_PRIV_DELETE,
					   princ);
	if(ret){
	    krb5_free_principal(context->context, princ);
	    krb5_free_principal(context->context, princ2);
	    goto fail;
	}
	ret = kadm5_rename_principal(kadm_handle, princ, princ2);
	krb5_free_principal(context->context, princ);
	krb5_free_principal(context->context, princ2);
	krb5_storage_free(sp);
	sp = krb5_storage_emem();
	krb5_store_int32(sp, ret);
	break;
    }
    case kadm_chpass:{
	op = "CHPASS";
	ret = krb5_ret_principal(sp, &princ);
	if(ret)
	    goto fail;
	ret = krb5_ret_string(sp, &password);
	if(ret){
	    krb5_free_principal(context->context, princ);
	    goto fail;
	}
	krb5_unparse_name_fixed(context->context, princ, name, sizeof(name));
	krb5_warnx(context->context, "%s: %s %s", client, op, name);

	/*
	 * The change is allowed if at least one of:

	 * a) it's for the principal him/herself and this was an
	 *    initial ticket, but then, check with the password quality
	 *    function.
	 * b) the user is on the CPW ACL.
	 */

	if (initial
	    && krb5_principal_compare (context->context, context->caller,
				       princ))
	{
	    krb5_data pwd_data;
	    const char *pwd_reason;

	    pwd_data.data = password;
	    pwd_data.length = strlen(password);

	    pwd_reason = kadm5_check_password_quality (context->context,
						       princ, &pwd_data);
	    if (pwd_reason != NULL)
		ret = KADM5_PASS_Q_DICT;
	    else
		ret = 0;
	} else
	    ret = _kadm5_acl_check_permission(context, KADM5_PRIV_CPW, princ);

	if(ret) {
	    krb5_free_principal(context->context, princ);
	    memset(password, 0, strlen(password));
	    free(password);
	    goto fail;
	}
	ret = kadm5_chpass_principal(kadm_handle, princ, password);
	krb5_free_principal(context->context, princ);
	memset(password, 0, strlen(password));
	free(password);
	krb5_storage_free(sp);
	sp = krb5_storage_emem();
	krb5_store_int32(sp, ret);
	break;
    }
    case kadm_chpass_with_key:{
	int i;
	krb5_key_data *key_data;
	int n_key_data;

	op = "CHPASS_WITH_KEY";
	ret = krb5_ret_principal(sp, &princ);
	if(ret)
	    goto fail;
	ret = krb5_ret_int32(sp, &n_key_data);
	if (ret) {
	    krb5_free_principal(context->context, princ);
	    goto fail;
	}
	/* n_key_data will be squeezed into an int16_t below. */
	if (n_key_data < 0 || n_key_data >= 1 << 16 ||
	    n_key_data > UINT_MAX/sizeof(*key_data)) {
	    ret = ERANGE;
	    krb5_free_principal(context->context, princ);
	    goto fail;
	}

	key_data = malloc (n_key_data * sizeof(*key_data));
	if (key_data == NULL && n_key_data != 0) {
	    ret = ENOMEM;
	    krb5_free_principal(context->context, princ);
	    goto fail;
	}

	for (i = 0; i < n_key_data; ++i) {
	    ret = kadm5_ret_key_data (sp, &key_data[i]);
	    if (ret) {
		int16_t dummy = i;

		kadm5_free_key_data (context, &dummy, key_data);
		free (key_data);
		krb5_free_principal(context->context, princ);
		goto fail;
	    }
	}

	krb5_unparse_name_fixed(context->context, princ, name, sizeof(name));
	krb5_warnx(context->context, "%s: %s %s", client, op, name);

	/*
	 * The change is only allowed if the user is on the CPW ACL,
	 * this it to force password quality check on the user.
	 */

	ret = _kadm5_acl_check_permission(context, KADM5_PRIV_CPW, princ);
	if(ret) {
	    int16_t dummy = n_key_data;

	    kadm5_free_key_data (context, &dummy, key_data);
	    free (key_data);
	    krb5_free_principal(context->context, princ);
	    goto fail;
	}
	ret = kadm5_chpass_principal_with_key(kadm_handle, princ,
					      n_key_data, key_data);
	{
	    int16_t dummy = n_key_data;
	    kadm5_free_key_data (context, &dummy, key_data);
	}
	free (key_data);
	krb5_free_principal(context->context, princ);
	krb5_storage_free(sp);
	sp = krb5_storage_emem();
	krb5_store_int32(sp, ret);
	break;
    }
    case kadm_randkey:{
	op = "RANDKEY";
	ret = krb5_ret_principal(sp, &princ);
	if(ret)
	    goto fail;
	krb5_unparse_name_fixed(context->context, princ, name, sizeof(name));
	krb5_warnx(context->context, "%s: %s %s", client, op, name);
	/*
	 * The change is allowed if at least one of:
	 * a) it's for the principal him/herself and this was an initial ticket
	 * b) the user is on the CPW ACL.
	 */

	if (initial
	    && krb5_principal_compare (context->context, context->caller,
				       princ))
	    ret = 0;
	else
	    ret = _kadm5_acl_check_permission(context, KADM5_PRIV_CPW, princ);

	if(ret) {
	    krb5_free_principal(context->context, princ);
	    goto fail;
	}
	ret = kadm5_randkey_principal(kadm_handle, princ,
				      &new_keys, &n_keys);
	krb5_free_principal(context->context, princ);
	krb5_storage_free(sp);
	sp = krb5_storage_emem();
	krb5_store_int32(sp, ret);
	if(ret == 0){
	    int i;
	    krb5_store_int32(sp, n_keys);
	    for(i = 0; i < n_keys; i++){
		krb5_store_keyblock(sp, new_keys[i]);
		krb5_free_keyblock_contents(context->context, &new_keys[i]);
	    }
	    free(new_keys);
	}
	break;
    }
    case kadm_get_privs:{
	uint32_t privs;
	ret = kadm5_get_privs(kadm_handle, &privs);
	krb5_storage_free(sp);
	sp = krb5_storage_emem();
	krb5_store_int32(sp, ret);
	if(ret == 0)
	    krb5_store_uint32(sp, privs);
	break;
    }
    case kadm_get_princs:{
	op = "LIST";
	ret = krb5_ret_int32(sp, &tmp);
	if(ret)
	    goto fail;
	if(tmp){
	    ret = krb5_ret_string(sp, &expression);
	    if(ret)
		goto fail;
	}else
	    expression = NULL;
	krb5_warnx(context->context, "%s: %s %s", client, op,
		   expression ? expression : "*");
	ret = _kadm5_acl_check_permission(context, KADM5_PRIV_LIST, NULL);
	if(ret){
	    free(expression);
	    goto fail;
	}
	ret = kadm5_get_principals(kadm_handle, expression, &princs, &n_princs);
	free(expression);
	krb5_storage_free(sp);
	sp = krb5_storage_emem();
	krb5_store_int32(sp, ret);
	if(ret == 0){
	    int i;
	    krb5_store_int32(sp, n_princs);
	    for(i = 0; i < n_princs; i++)
		krb5_store_string(sp, princs[i]);
	    kadm5_free_name_list(kadm_handle, princs, &n_princs);
	}
	break;
    }
    default:
	krb5_warnx(context->context, "%s: UNKNOWN OP %d", client, cmd);
	krb5_storage_free(sp);
	sp = krb5_storage_emem();
	krb5_store_int32(sp, KADM5_FAILURE);
	break;
    }
    krb5_storage_to_data(sp, out);
    krb5_storage_free(sp);
    return 0;
fail:
    krb5_warn(context->context, ret, "%s", op);
    krb5_storage_seek(sp, 0, SEEK_SET);
    krb5_store_int32(sp, ret);
    krb5_storage_to_data(sp, out);
    krb5_storage_free(sp);
    return 0;
}
Exemple #17
0
int
krb5_verifypw(
	pam_handle_t *pamh,
	char 	*princ_str,
	char	*old_password,
	boolean_t disp_flag,
	int debug)
{
	kadm5_ret_t		code;
	krb5_principal 		princ = 0;
	char 			admin_realm[1024];
	char			kprinc[2*MAXHOSTNAMELEN];
	char			*cpw_service;
	kadm5_principal_ent_rec principal_entry;
	kadm5_policy_ent_rec	 policy_entry;
	void 			*server_handle;
	krb5_context		context;
	kadm5_config_params	params;
#define	MSG_ROWS		5
	char			msgs[MSG_ROWS][PAM_MAX_MSG_SIZE];

	(void) memset((char *)&params, 0, sizeof (params));
	(void) memset(&principal_entry, 0, sizeof (principal_entry));
	(void) memset(&policy_entry, 0, sizeof (policy_entry));

	if (code = krb5_init_context(&context)) {
		return (6);
	}

	if ((code = get_kmd_kuser(context, (const char *)princ_str, kprinc,
		2*MAXHOSTNAMELEN)) != 0) {
		return (code);
	}

	/* Need to get a krb5_principal struct */

	code = krb5_parse_name(context, kprinc, &princ);

	if (code != 0) {
		return (MISC_EXIT_STATUS);
	}

	if (strlen(old_password) == 0) {
		krb5_free_principal(context, princ);
		return (5);
	}

	(void) strlcpy(admin_realm,
		    krb5_princ_realm(context, princ)->data,
		    sizeof (admin_realm));

	params.mask |= KADM5_CONFIG_REALM;
	params.realm = admin_realm;


	if (kadm5_get_cpw_host_srv_name(context, admin_realm, &cpw_service)) {
		syslog(LOG_ERR,
		    dgettext(TEXT_DOMAIN,
			"PAM-KRB5 (password): unable to get host based "
			"service name for realm %s\n"),
			admin_realm);
		return (3);
	}

	code = kadm5_init_with_password(kprinc, old_password, cpw_service,
					&params, KADM5_STRUCT_VERSION,
					KADM5_API_VERSION_2, &server_handle);
	if (code != 0) {
		if (debug)
			syslog(LOG_DEBUG,
			    "PAM-KRB5: krb5_verifypw: init_with_pw"
			    " failed: (%s)", error_message(code));
		krb5_free_principal(context, princ);
		return ((code == KADM5_BAD_PASSWORD) ? 2 : 3);
	}

	if (disp_flag &&
	    _kadm5_get_kpasswd_protocol(server_handle) == KRB5_CHGPWD_RPCSEC) {
		/*
		 * Note: copy of this exists in login
		 * (kverify.c/get_verified_in_tkt).
		 */

		code = kadm5_get_principal(server_handle, princ,
						&principal_entry,
						KADM5_PRINCIPAL_NORMAL_MASK);
		if (code != 0) {
			krb5_free_principal(context, princ);
			(void) kadm5_destroy(server_handle);
			return ((code == KADM5_UNK_PRINC) ? 1 :
				MISC_EXIT_STATUS);
		}

		if ((principal_entry.aux_attributes & KADM5_POLICY) != 0) {
			code = kadm5_get_policy(server_handle,
						principal_entry.policy,
						&policy_entry);
			if (code != 0) {
				/*
				 * doesn't matter which error comes back,
				 * there's no nice recovery or need to
				 * differentiate to the user
				 */
				(void) kadm5_free_principal_ent(server_handle,
							&principal_entry);
				krb5_free_principal(context, princ);
				(void) kadm5_destroy(server_handle);
				return (MISC_EXIT_STATUS);
			}

			(void) snprintf(msgs[0], PAM_MAX_MSG_SIZE,
				dgettext(TEXT_DOMAIN, "POLICY_EXPLANATION:"));
			(void) snprintf(msgs[1], PAM_MAX_MSG_SIZE,
				dgettext(TEXT_DOMAIN,
					"Principal string is %s"), princ_str);
			(void) snprintf(msgs[2], PAM_MAX_MSG_SIZE,
				dgettext(TEXT_DOMAIN, "Policy Name is  %s"),
				principal_entry.policy);
			(void) snprintf(msgs[3], PAM_MAX_MSG_SIZE,
				dgettext(TEXT_DOMAIN,
					"Minimum password length is %d"),
					policy_entry.pw_min_length);
			(void) snprintf(msgs[4], PAM_MAX_MSG_SIZE,
				dgettext(TEXT_DOMAIN,
					"Minimum password classes is %d"),
					policy_entry.pw_min_classes);
			display_msgs(pamh, PAM_TEXT_INFO, MSG_ROWS, msgs);

			if (code = kadm5_free_principal_ent(server_handle,
							    &principal_entry)) {
				(void) kadm5_free_policy_ent(server_handle,
							&policy_entry);
				krb5_free_principal(context, princ);
				(void) kadm5_destroy(server_handle);
				return (MISC_EXIT_STATUS);
			}
			if (code = kadm5_free_policy_ent(server_handle,
							&policy_entry)) {
				krb5_free_principal(context, princ);

				(void) kadm5_destroy(server_handle);
				return (MISC_EXIT_STATUS);
			}
		} else {
			/*
			 * kpasswd *COULD* output something here to encourage
			 * the choice of good passwords, in the absence of
			 * an enforced policy.
			 */
			if (code = kadm5_free_principal_ent(server_handle,
							    &principal_entry)) {
				krb5_free_principal(context, princ);
				(void) kadm5_destroy(server_handle);
				return (MISC_EXIT_STATUS);
			}
		}
	}
	krb5_free_principal(context, princ);

	(void) kadm5_destroy(server_handle);

	return (0);
}
Exemple #18
0
static int
fetch_princ_entry(
	krb5_module_data_t *kmd,
	char *princ_str,
	kadm5_principal_ent_rec *prent,	/* out */
	int debug)

{
	kadm5_ret_t		code;
	krb5_principal 		princ = 0;
	char 			admin_realm[1024];
	char			kprinc[2*MAXHOSTNAMELEN];
	char			*cpw_service, *password;
	void 			*server_handle;
	krb5_context		context;
	kadm5_config_params	params;

	password = kmd->password;
	context = kmd->kcontext;

	if ((code = get_kmd_kuser(context, (const char *)princ_str,
	    kprinc, 2*MAXHOSTNAMELEN)) != 0) {
		return (code);
	}

	code = krb5_parse_name(context, kprinc, &princ);
	if (code != 0) {
		return (PAM_SYSTEM_ERR);
	}

	if (strlen(password) == 0) {
		krb5_free_principal(context, princ);
		if (debug)
			__pam_log(LOG_AUTH | LOG_DEBUG,
			    "PAM-KRB5 (acct): fetch_princ_entry: pwlen=0");
		return (PAM_AUTH_ERR);
	}

	(void) strlcpy(admin_realm,
		    krb5_princ_realm(context, princ)->data,
		    sizeof (admin_realm));

	(void) memset((char *)&params, 0, sizeof (params));
	params.mask |= KADM5_CONFIG_REALM;
	params.realm = admin_realm;

	if (kadm5_get_cpw_host_srv_name(context, admin_realm, &cpw_service)) {
		__pam_log(LOG_AUTH | LOG_ERR,
			"PAM-KRB5 (acct):  unable to get host based "
			"service name for realm '%s'",
			admin_realm);
		krb5_free_principal(context, princ);
		return (PAM_SYSTEM_ERR);
	}

	code = kadm5_init_with_password(kprinc, password, cpw_service,
					&params, KADM5_STRUCT_VERSION,
					KADM5_API_VERSION_2, NULL,
					&server_handle);
	if (code != 0) {
		if (debug)
			__pam_log(LOG_AUTH | LOG_DEBUG,
			    "PAM-KRB5 (acct): fetch_princ_entry: "
			    "init_with_pw failed: code = %d", code);
		krb5_free_principal(context, princ);
		return ((code == KADM5_BAD_PASSWORD) ?
			PAM_AUTH_ERR : PAM_SYSTEM_ERR);
	}

	if (_kadm5_get_kpasswd_protocol(server_handle) != KRB5_CHGPWD_RPCSEC) {
		if (debug)
			__pam_log(LOG_AUTH | LOG_DEBUG,
			    "PAM-KRB5 (acct): fetch_princ_entry: "
			    "non-RPCSEC_GSS chpw server, can't get "
			    "princ entry");
		(void) kadm5_destroy(server_handle);
		krb5_free_principal(context, princ);
		return (PAM_SYSTEM_ERR);
	}

	code = kadm5_get_principal(server_handle, princ, prent,
				KADM5_PRINCIPAL_NORMAL_MASK);

	if (code != 0) {
		(void) kadm5_destroy(server_handle);
		krb5_free_principal(context, princ);
		return ((code == KADM5_UNK_PRINC) ?
			PAM_USER_UNKNOWN : PAM_SYSTEM_ERR);
	}

	(void) kadm5_destroy(server_handle);
	krb5_free_principal(context, princ);

	return (PAM_SUCCESS);
}
Exemple #19
0
static int
do_mod_entry(krb5_principal principal, void *data)
{
    krb5_error_code ret;
    kadm5_principal_ent_rec princ;
    int mask = 0;
    struct modify_options *e = data;

    memset (&princ, 0, sizeof(princ));
    ret = kadm5_get_principal(kadm_handle, principal, &princ,
			      KADM5_PRINCIPAL | KADM5_ATTRIBUTES |
			      KADM5_MAX_LIFE | KADM5_MAX_RLIFE |
			      KADM5_PRINC_EXPIRE_TIME |
			      KADM5_PW_EXPIRATION);
    if(ret)
	return ret;

    if(e->max_ticket_life_string ||
       e->max_renewable_life_string ||
       e->expiration_time_string ||
       e->pw_expiration_time_string ||
       e->attributes_string ||
       e->policy_string ||
       e->kvno_integer != -1 ||
       e->constrained_delegation_strings.num_strings ||
       e->alias_strings.num_strings ||
       e->pkinit_acl_strings.num_strings ||
       e->hist_kvno_diff_clnt_integer != -1 ||
       e->hist_kvno_diff_svc_integer != -1) {
	ret = set_entry(context, &princ, &mask,
			e->max_ticket_life_string,
			e->max_renewable_life_string,
			e->expiration_time_string,
			e->pw_expiration_time_string,
			e->attributes_string,
			e->policy_string);
	if(e->kvno_integer != -1) {
	    princ.kvno = e->kvno_integer;
	    mask |= KADM5_KVNO;
	}
	if (e->constrained_delegation_strings.num_strings) {
	    add_constrained_delegation(context, &princ,
				       &e->constrained_delegation_strings);
	    mask |= KADM5_TL_DATA;
	}
	if (e->alias_strings.num_strings) {
	    add_aliases(context, &princ, &e->alias_strings);
	    mask |= KADM5_TL_DATA;
	}
	if (e->pkinit_acl_strings.num_strings) {
	    add_pkinit_acl(context, &princ, &e->pkinit_acl_strings);
	    mask |= KADM5_TL_DATA;
	}
	if (e->hist_kvno_diff_clnt_integer != -1) {
	    add_kvno_diff(context, &princ, 0, e->hist_kvno_diff_clnt_integer);
	    mask |= KADM5_TL_DATA;
	}
	if (e->hist_kvno_diff_svc_integer != -1) {
	    add_kvno_diff(context, &princ, 1, e->hist_kvno_diff_clnt_integer);
	    mask |= KADM5_TL_DATA;
	}
    } else
	ret = edit_entry(&princ, &mask, NULL, 0);
    if(ret == 0) {
	ret = kadm5_modify_principal(kadm_handle, &princ, mask);
	if(ret)
	    krb5_warn(context, ret, "kadm5_modify_principal");
    }

    kadm5_free_principal_ent(kadm_handle, &princ);
    return ret;
}
Exemple #20
0
int
main(int argc, char **argv)
{
    krb5_context context;
    krb5_keytab kt;
    krb5_keytab_entry ktent;
    krb5_encrypt_block eblock;
    krb5_creds my_creds;
    krb5_get_init_creds_opt *opt;
    kadm5_principal_ent_rec princ_ent;
    krb5_principal princ, server;
    char pw[16];
    char *whoami, *principal, *authprinc, *authpwd;
    krb5_data pwdata;
    void *handle;
    int ret, test, encnum;
    unsigned int i;

    whoami = argv[0];

    if (argc < 2 || argc > 4) {
        fprintf(stderr, "Usage: %s principal [authuser] [authpwd]\n", whoami);
        exit(1);
    }
    principal = argv[1];
    authprinc = (argc > 2) ? argv[2] : argv[0];
    authpwd = (argc > 3) ? argv[3] : NULL;

    /*
     * Setup.  Initialize data structures, open keytab, open connection
     * to kadm5 server.
     */

    memset(&context, 0, sizeof(context));
    kadm5_init_krb5_context(&context);

    ret = krb5_parse_name(context, principal, &princ);
    if (ret) {
        com_err(whoami, ret, "while parsing principal name %s", principal);
        exit(1);
    }

    if((ret = krb5_build_principal_ext(context, &server,
                                       krb5_princ_realm(kcontext, princ)->length,
                                       krb5_princ_realm(kcontext, princ)->data,
                                       tgtname.length, tgtname.data,
                                       krb5_princ_realm(kcontext, princ)->length,
                                       krb5_princ_realm(kcontext, princ)->data,
                                       0))) {
        com_err(whoami, ret, "while building server name");
        exit(1);
    }

    ret = krb5_kt_default(context, &kt);
    if (ret) {
        com_err(whoami, ret, "while opening keytab");
        exit(1);
    }

    ret = kadm5_init(context, authprinc, authpwd, KADM5_ADMIN_SERVICE, NULL,
                     KADM5_STRUCT_VERSION, KADM5_API_VERSION_4, NULL,
                     &handle);
    if (ret) {
        com_err(whoami, ret, "while initializing connection");
        exit(1);
    }

    /* these pw's don't need to be secure, just different every time */
    SRAND((RAND_TYPE)time((void *) NULL));
    pwdata.data = pw;
    pwdata.length = sizeof(pw);

    /*
     * For each test:
     *
     * For each enctype in the test, construct a random password/key.
     * Assign all keys to principal with kadm5_setkey_principal.  Add
     * each key to the keytab, and acquire an initial ticket with the
     * keytab (XXX can I specify the kvno explicitly?).  If
     * krb5_get_init_creds_keytab succeeds, then the keys were set
     * successfully.
     */
    for (test = 0; tests[test] != NULL; test++) {
        krb5_keyblock *testp = tests[test];
        kadm5_key_data *extracted;
        int n_extracted, match;
        printf("+ Test %d:\n", test);

        for (encnum = 0; testp[encnum].magic != -1; encnum++) {
            for (i = 0; i < sizeof(pw); i++)
                pw[i] = (RAND() % 26) + '0'; /* XXX */

            krb5_use_enctype(context, &eblock, testp[encnum].enctype);
            ret = krb5_string_to_key(context, &eblock, &testp[encnum],
                                     &pwdata, NULL);
            if (ret) {
                com_err(whoami, ret, "while converting string to key");
                exit(1);
            }
        }

        /* now, encnum == # of keyblocks in testp */
        ret = kadm5_setkey_principal(handle, princ, testp, encnum);
        if (ret) {
            com_err(whoami, ret, "while setting keys");
            exit(1);
        }

        ret = kadm5_get_principal(handle, princ, &princ_ent, KADM5_KVNO);
        if (ret) {
            com_err(whoami, ret, "while retrieving principal");
            exit(1);
        }

        ret = kadm5_get_principal_keys(handle, princ, 0, &extracted,
                                       &n_extracted);
        if (ret) {
            com_err(whoami, ret, "while extracting keys");
            exit(1);
        }

        for (encnum = 0; testp[encnum].magic != -1; encnum++) {
            printf("+   enctype %d\n", testp[encnum].enctype);

            for (match = 0; match < n_extracted; match++) {
                if (extracted[match].key.enctype == testp[encnum].enctype)
                    break;
            }
            if (match >= n_extracted) {
                com_err(whoami, KRB5_WRONG_ETYPE, "while matching enctypes");
                exit(1);
            }
            if (extracted[match].key.length != testp[encnum].length ||
                memcmp(extracted[match].key.contents, testp[encnum].contents,
                       testp[encnum].length) != 0) {
                com_err(whoami, KRB5_KDB_NO_MATCHING_KEY, "verifying keys");
                exit(1);
            }

            memset(&ktent, 0, sizeof(ktent));
            ktent.principal = princ;
            ktent.key = testp[encnum];
            ktent.vno = princ_ent.kvno;

            ret = krb5_kt_add_entry(context, kt, &ktent);
            if (ret) {
                com_err(whoami, ret, "while adding keytab entry");
                exit(1);
            }

            memset(&my_creds, 0, sizeof(my_creds));
            my_creds.client = princ;
            my_creds.server = server;

            ktypes[0] = testp[encnum].enctype;
            ret = krb5_get_init_creds_opt_alloc(context, &opt);
            if (ret) {
                com_err(whoami, ret, "while allocating gic opts");
                exit(1);
            }
            krb5_get_init_creds_opt_set_etype_list(opt, ktypes, 1);
            ret = krb5_get_init_creds_keytab(context, &my_creds, princ,
                                             kt, 0, NULL /* in_tkt_service */,
                                             opt);
            krb5_get_init_creds_opt_free(context, opt);
            if (ret) {
                com_err(whoami, ret, "while acquiring initial ticket");
                exit(1);
            }
            krb5_free_cred_contents(context, &my_creds);

            /* since I can't specify enctype explicitly ... */
            ret = krb5_kt_remove_entry(context, kt, &ktent);
            if (ret) {
                com_err(whoami, ret, "while removing keytab entry");
                exit(1);
            }
        }

        (void)kadm5_free_kadm5_key_data(context, n_extracted, extracted);
    }

    ret = krb5_kt_close(context, kt);
    if (ret) {
        com_err(whoami, ret, "while closing keytab");
        exit(1);
    }

    ret = kadm5_destroy(handle);
    if (ret) {
        com_err(whoami, ret, "while closing kadmin connection");
        exit(1);
    }

    krb5_free_principal(context, princ);
    krb5_free_principal(context, server);
    krb5_free_context(context);
    return 0;
}
Exemple #21
0
int
kt_get(struct get_options *opt, int argc, char **argv)
{
    krb5_error_code ret = 0;
    krb5_keytab keytab;
    void *kadm_handle = NULL;
    krb5_enctype *etypes = NULL;
    size_t netypes = 0;
    size_t i;
    int a, j;
    unsigned int failed = 0;

    if((keytab = ktutil_open_keytab()) == NULL)
	return 1;

    if(opt->realm_string)
	krb5_set_default_realm(context, opt->realm_string);

    if (opt->enctypes_strings.num_strings != 0) {

	etypes = malloc (opt->enctypes_strings.num_strings * sizeof(*etypes));
	if (etypes == NULL) {
	    krb5_warnx(context, "malloc failed");
	    goto out;
	}
	netypes = opt->enctypes_strings.num_strings;
	for(i = 0; i < netypes; i++) {
	    ret = krb5_string_to_enctype(context,
					 opt->enctypes_strings.strings[i],
					 &etypes[i]);
	    if(ret) {
		krb5_warnx(context, "unrecognized enctype: %s",
			   opt->enctypes_strings.strings[i]);
		goto out;
	    }
	}
    }


    for(a = 0; a < argc; a++){
	krb5_principal princ_ent;
	kadm5_principal_ent_rec princ;
	int mask = 0;
	krb5_keyblock *keys;
	int n_keys;
	int created = 0;
	krb5_keytab_entry entry;

	ret = krb5_parse_name(context, argv[a], &princ_ent);
	if (ret) {
	    krb5_warn(context, ret, "can't parse principal %s", argv[a]);
	    failed++;
	    continue;
	}
	memset(&princ, 0, sizeof(princ));
	princ.principal = princ_ent;
	mask |= KADM5_PRINCIPAL;
	princ.attributes |= KRB5_KDB_DISALLOW_ALL_TIX;
	mask |= KADM5_ATTRIBUTES;
	princ.princ_expire_time = 0;
	mask |= KADM5_PRINC_EXPIRE_TIME;

	if(kadm_handle == NULL) {
	    const char *r;
	    if(opt->realm_string != NULL)
		r = opt->realm_string;
	    else
		r = krb5_principal_get_realm(context, princ_ent);
	    kadm_handle = open_kadmin_connection(opt->principal_string,
						 r,
						 opt->admin_server_string,
						 opt->server_port_integer);
	    if(kadm_handle == NULL)
		break;
	}

	ret = kadm5_create_principal(kadm_handle, &princ, mask, "x");
	if(ret == 0)
	    created = 1;
	else if(ret != KADM5_DUP) {
	    krb5_warn(context, ret, "kadm5_create_principal(%s)", argv[a]);
	    krb5_free_principal(context, princ_ent);
	    failed++;
	    continue;
	}
	ret = kadm5_randkey_principal(kadm_handle, princ_ent, &keys, &n_keys);
	if (ret) {
	    krb5_warn(context, ret, "kadm5_randkey_principal(%s)", argv[a]);
	    krb5_free_principal(context, princ_ent);
	    failed++;
	    continue;
	}

	ret = kadm5_get_principal(kadm_handle, princ_ent, &princ,
			      KADM5_PRINCIPAL | KADM5_KVNO | KADM5_ATTRIBUTES);
	if (ret) {
	    krb5_warn(context, ret, "kadm5_get_principal(%s)", argv[a]);
	    for (j = 0; j < n_keys; j++)
		krb5_free_keyblock_contents(context, &keys[j]);
	    krb5_free_principal(context, princ_ent);
	    failed++;
	    continue;
	}
	if(!created && (princ.attributes & KRB5_KDB_DISALLOW_ALL_TIX))
	    krb5_warnx(context, "%s: disallow-all-tix flag set - clearing", argv[a]);
	princ.attributes &= (~KRB5_KDB_DISALLOW_ALL_TIX);
	mask = KADM5_ATTRIBUTES;
	if(created) {
	    princ.kvno = 1;
	    mask |= KADM5_KVNO;
	}
	ret = kadm5_modify_principal(kadm_handle, &princ, mask);
	if (ret) {
	    krb5_warn(context, ret, "kadm5_modify_principal(%s)", argv[a]);
	    for (j = 0; j < n_keys; j++)
		krb5_free_keyblock_contents(context, &keys[j]);
	    krb5_free_principal(context, princ_ent);
	    failed++;
	    continue;
	}
	for(j = 0; j < n_keys; j++) {
	    int do_add = TRUE;

	    if (netypes) {
		size_t k;

		do_add = FALSE;
		for (k = 0; k < netypes; ++k)
		    if (keys[j].keytype == etypes[k]) {
			do_add = TRUE;
			break;
		    }
	    }
	    if (do_add) {
		entry.principal = princ_ent;
		entry.vno = princ.kvno;
		entry.keyblock = keys[j];
		entry.timestamp = time (NULL);
		ret = krb5_kt_add_entry(context, keytab, &entry);
		if (ret)
		    krb5_warn(context, ret, "krb5_kt_add_entry");
	    }
	    krb5_free_keyblock_contents(context, &keys[j]);
	}

	kadm5_free_principal_ent(kadm_handle, &princ);
	krb5_free_principal(context, princ_ent);
    }
 out:
    free(etypes);
    if (kadm_handle)
	kadm5_destroy(kadm_handle);
    krb5_kt_close(context, keytab);
    return ret != 0 || failed > 0;
}
Exemple #22
0
kadm5_ret_t
check_min_life(void *server_handle, krb5_principal principal,
	       char *msg_ret, unsigned int msg_len)
{
    krb5_int32			now;
    kadm5_ret_t			ret;
    kadm5_policy_ent_rec	pol;
    kadm5_principal_ent_rec	princ;
    kadm5_server_handle_t	handle = server_handle;

    if (msg_ret != NULL)
	*msg_ret = '\0';

    ret = krb5_timeofday(handle->context, &now);
    if (ret)
	return ret;

    ret = kadm5_get_principal(handle->lhandle, principal, 
			      &princ, KADM5_PRINCIPAL_NORMAL_MASK);
    if(ret) 
	 return ret;
    if(princ.aux_attributes & KADM5_POLICY) {
	if((ret=kadm5_get_policy(handle->lhandle,
				 princ.policy, &pol)) != KADM5_OK) {
	    (void) kadm5_free_principal_ent(handle->lhandle, &princ);
	    return ret;
	}
	if((now - princ.last_pwd_change) < pol.pw_min_life &&
	   !(princ.attributes & KRB5_KDB_REQUIRES_PWCHANGE)) {
	    if (msg_ret != NULL) {
		time_t until;
		char *time_string, *ptr, *errstr;

		until = princ.last_pwd_change + pol.pw_min_life;

		time_string = ctime(&until);
		errstr = error_message(CHPASS_UTIL_PASSWORD_TOO_SOON);

		if (strlen(errstr) + strlen(time_string) >= msg_len) {
		    *errstr = '\0';
		} else {
		    if (*(ptr = &time_string[strlen(time_string)-1]) == '\n')
			*ptr = '\0';
		    snprintf(msg_ret, msg_len, errstr, time_string);
		}
	    }

	    (void) kadm5_free_policy_ent(handle->lhandle, &pol);
	    (void) kadm5_free_principal_ent(handle->lhandle, &princ);
	    return KADM5_PASS_TOOSOON;
	}

	ret = kadm5_free_policy_ent(handle->lhandle, &pol);
	if (ret) {
	    (void) kadm5_free_principal_ent(handle->lhandle, &princ);
	    return ret;
        }
    }

    return kadm5_free_principal_ent(handle->lhandle, &princ);
}
Exemple #23
0
static kadm5_ret_t
create_random_entry(krb5_principal princ,
		    unsigned max_life,
		    unsigned max_rlife,
		    uint32_t attributes)
{
    kadm5_principal_ent_rec ent;
    kadm5_ret_t ret;
    int mask = 0;
    krb5_keyblock *keys;
    int n_keys, i;
    char *name;
    const char *password;
    char pwbuf[512];

    random_password(pwbuf, sizeof(pwbuf));
    password = pwbuf;

    ret = krb5_unparse_name(context, princ, &name);
    if (ret) {
	krb5_warn(context, ret, "failed to unparse principal name");
	return ret;
    }

    memset(&ent, 0, sizeof(ent));
    ent.principal = princ;
    mask |= KADM5_PRINCIPAL;
    if (max_life) {
	ent.max_life = max_life;
	mask |= KADM5_MAX_LIFE;
    }
    if (max_rlife) {
	ent.max_renewable_life = max_rlife;
	mask |= KADM5_MAX_RLIFE;
    }
    ent.attributes |= attributes | KRB5_KDB_DISALLOW_ALL_TIX;
    mask |= KADM5_ATTRIBUTES;

    /* Create the entry with a random password */
    ret = kadm5_create_principal(kadm_handle, &ent, mask, password);
    if(ret) {
	krb5_warn(context, ret, "create_random_entry(%s): randkey failed",
		  name);
	goto out;
    }

    /* Replace the string2key based keys with real random bytes */
    ret = kadm5_randkey_principal(kadm_handle, princ, &keys, &n_keys);
    if(ret) {
	krb5_warn(context, ret, "create_random_entry(%s): randkey failed",
		  name);
	goto out;
    }
    for(i = 0; i < n_keys; i++)
	krb5_free_keyblock_contents(context, &keys[i]);
    free(keys);
    ret = kadm5_get_principal(kadm_handle, princ, &ent,
			      KADM5_PRINCIPAL | KADM5_ATTRIBUTES);
    if(ret) {
	krb5_warn(context, ret, "create_random_entry(%s): "
		  "unable to get principal", name);
	goto out;
    }
    ent.attributes &= (~KRB5_KDB_DISALLOW_ALL_TIX);
    ent.kvno = 1;
    ret = kadm5_modify_principal(kadm_handle, &ent,
				 KADM5_ATTRIBUTES|KADM5_KVNO);
    kadm5_free_principal_ent (kadm_handle, &ent);
    if(ret) {
	krb5_warn(context, ret, "create_random_entry(%s): "
		  "unable to modify principal", name);
	goto out;
    }
 out:
    free(name);
    return ret;
}
Exemple #24
0
static int
do_ext_keytab(krb5_principal principal, void *data)
{
    krb5_error_code ret;
    kadm5_principal_ent_rec princ;
    struct ext_keytab_data *e = data;
    krb5_keytab_entry *keys = NULL;
    krb5_keyblock *k = NULL;
    size_t i;
    int n_k = 0;
    uint32_t mask;
    char *unparsed = NULL;

    mask = KADM5_PRINCIPAL;
    if (!e->random_key_flag)
        mask |= KADM5_KVNO | KADM5_KEY_DATA;

    ret = kadm5_get_principal(kadm_handle, principal, &princ, mask);
    if (ret)
	return ret;

    ret = krb5_unparse_name(context, principal, &unparsed);
    if (ret)
	goto out;

    if (!e->random_key_flag) {
        if (princ.n_key_data == 0) {
            krb5_warnx(context, "principal has no keys, or user lacks "
                       "get-keys privilege for %s", unparsed);
            goto out;
        }
        /*
         * kadmin clients and servers from master between 1.5 and 1.6
         * can have corrupted a principal's keys in the HDB.  If some
         * are bogus but not all are, then that must have happened.
         *
         * If all keys are bogus then the server may be a pre-1.6,
         * post-1.5 server and the client lacks get-keys privilege, or
         * the keys are corrupted.  We can't tell here.
         */
        if (kadm5_all_keys_are_bogus(princ.n_key_data, princ.key_data)) {
            krb5_warnx(context, "user lacks get-keys privilege for %s",
                       unparsed);
            goto out;
        }
        if (kadm5_some_keys_are_bogus(princ.n_key_data, princ.key_data)) {
            krb5_warnx(context, "some keys for %s are corrupted in the HDB",
                       unparsed);
        }
	keys = calloc(sizeof(*keys), princ.n_key_data);
	if (keys == NULL) {
	    ret = krb5_enomem(context);
	    goto out;
	}
	for (i = 0; i < princ.n_key_data; i++) {
	    krb5_key_data *kd = &princ.key_data[i];

            /* Don't extract bogus keys */
            if (kadm5_all_keys_are_bogus(1, kd))
                continue;

	    keys[i].principal = princ.principal;
	    keys[i].vno = kd->key_data_kvno;
	    keys[i].keyblock.keytype = kd->key_data_type[0];
	    keys[i].keyblock.keyvalue.length = kd->key_data_length[0];
	    keys[i].keyblock.keyvalue.data = kd->key_data_contents[0];
	    keys[i].timestamp = time(NULL);
            n_k++;
	}
    } else if (e->random_key_flag) {
	ret = kadm5_randkey_principal(kadm_handle, principal, &k, &n_k);
	if (ret)
	    goto out;

	keys = calloc(sizeof(*keys), n_k);
	if (keys == NULL) {
	    ret = krb5_enomem(context);
	    goto out;
	}
	for (i = 0; i < n_k; i++) {
	    keys[i].principal = principal;
	    keys[i].vno = princ.kvno + 1; /* XXX get entry again */
	    keys[i].keyblock = k[i];
	    keys[i].timestamp = time(NULL);
	}
    }

    if (n_k == 0)
        krb5_warn(context, ret, "no keys written to keytab for %s", unparsed);

    for (i = 0; i < n_k; i++) {
	ret = krb5_kt_add_entry(context, e->keytab, &keys[i]);
	if (ret)
	    krb5_warn(context, ret, "krb5_kt_add_entry(%lu)", (unsigned long)i);
    }

  out:
    kadm5_free_principal_ent(kadm_handle, &princ);
    if (k) {
        for (i = 0; i < n_k; i++)
            memset(k[i].keyvalue.data, 0, k[i].keyvalue.length);
	free(k);
    }
    free(unparsed);
    free(keys);
    return 0;
}