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; }
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; }
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; }
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; }
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; }
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; }
/* 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; }
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; }
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; }
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); }
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; }
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; }
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; }
/** * 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; }
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; }
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 *)¶ms, 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, ¶ms, 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); }
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 *)¶ms, 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, ¶ms, 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); }
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; }
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; }
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; }
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); }
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; }
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; }