Example #1
0
int add_admin_princ(void *handle, krb5_context context,
		    char *name, char *realm, int attrs, int lifetime)
{
     char *fullname;
     krb5_error_code ret;
     kadm5_principal_ent_rec ent;

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

     fullname = build_name_with_realm(name, realm);
     ret = krb5_parse_name(context, fullname, &ent.principal);
     if (ret) {
	  com_err(progname, ret, str_PARSE_NAME);
	  return(ERR);
     }
     ent.max_life = lifetime;
     ent.attributes = attrs | KRB5_KDB_DISALLOW_ALL_TIX;
     
     ret = kadm5_create_principal(handle, &ent,
				  (KADM5_PRINCIPAL | KADM5_MAX_LIFE |
				   KADM5_ATTRIBUTES),
				  "to-be-random");
     if (ret) {
	  if (ret != KADM5_DUP) {
	       com_err(progname, ret, str_PUT_PRINC, fullname);
	       krb5_free_principal(context, ent.principal);
	       free(fullname);
	       return ERR;
	  }
     } else {
	  /* only randomize key if we created the principal */
	  ret = kadm5_randkey_principal(handle, ent.principal, NULL, NULL);
	  if (ret) {
	       com_err(progname, ret, str_RANDOM_KEY, fullname);
	       krb5_free_principal(context, ent.principal);
	       free(fullname);
	       return ERR;
	  }
	  
	  ent.attributes = attrs;
	  ret = kadm5_modify_principal(handle, &ent, KADM5_ATTRIBUTES);
	  if (ret) {
	       com_err(progname, ret, str_PUT_PRINC, fullname);
	       krb5_free_principal(context, ent.principal);
	       free(fullname);
	       return ERR;
	  }
     }
     
     krb5_free_principal(context, ent.principal);
     free(fullname);

     return OK;
}
Example #2
0
void
krb5_modprinc(krb5_context ctx, kadm5_handle hndl, kadm5_principal_ent_rec p,
              long mask)
{
	kadm5_ret_t	ret;
	char		croakstr[256] = "";

	K5BAIL(kadm5_modify_principal(hndl, &p, mask));

done:
	if (ret)
		croak("%s", croakstr);
}
static PyObject *PyKAdminPrincipal_commit(PyKAdminPrincipalObject *self) {

    kadm5_ret_t retval = KADM5_OK; 

    if (self && self->mask) {

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

        self->mask = 0;
    }

    Py_RETURN_TRUE;
}
Example #4
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;
}
Example #5
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;
}
Example #6
0
File: mod.c Project: InvLim/heimdal
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;
}
Example #7
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;
}
Example #8
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;
}
Example #9
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;
}
Example #10
0
bool
kerberos_expire_password(const char *principal, time_t expires)
{
    char *path, *user;
    const char *realm;
    krb5_context ctx;
    krb5_principal admin = NULL;
    krb5_principal princ = NULL;
    krb5_error_code code;
    kadm5_config_params params;
    kadm5_principal_ent_rec ent;
    void *handle;
    bool okay = false;

    /* Set up for making our call. */
    path = test_file_path("config/admin-keytab");
    if (path == NULL)
        return false;
    code = krb5_init_context(&ctx);
    if (code != 0)
        bail_krb5(ctx, code, "error initializing Kerberos");
    admin = kerberos_keytab_principal(ctx, path);
    realm = krb5_principal_get_realm(ctx, admin);
    code = krb5_set_default_realm(ctx, realm);
    if (code != 0)
        bail_krb5(ctx, code, "cannot set default realm");
    code = krb5_unparse_name(ctx, admin, &user);
    if (code != 0)
        bail_krb5(ctx, code, "cannot unparse admin principal");
    code = krb5_parse_name(ctx, principal, &princ);
    if (code != 0)
        bail_krb5(ctx, code, "cannot parse principal %s", principal);

    /*
     * If the actual kadmin calls fail, we may be built with MIT Kerberos
     * against a Heimdal server or vice versa.  Return false to skip the
     * tests.
     */
    memset(&params, 0, sizeof(params));
    params.realm = (char *) realm;
    params.mask = KADM5_CONFIG_REALM;
    code = kadm5_init_with_skey_ctx(ctx, user, path, KADM5_ADMIN_SERVICE,
                                    &params, KADM5_STRUCT_VERSION,
                                    KADM5_API_VERSION, &handle);
    if (code != 0) {
        diag_krb5(ctx, code, "error initializing kadmin");
        goto done;
    }
    memset(&ent, 0, sizeof(ent));
    ent.principal = princ;
    ent.pw_expiration = expires;
    code = kadm5_modify_principal(handle, &ent, KADM5_PW_EXPIRATION);
    if (code == 0)
        okay = true;
    else
        diag_krb5(ctx, code, "error setting password expiration");

done:
    kadm5_destroy(handle);
    krb5_free_unparsed_name(ctx, user);
    krb5_free_principal(ctx, admin);
    krb5_free_principal(ctx, princ);
    krb5_free_context(ctx);
    test_file_path_free(path);
    return okay;
}
Example #11
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;
}
Example #12
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;
}
Example #13
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;
}
Example #14
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;
}