From af105268217bc5d8b93c3c0c66eca087ffb10085 Mon Sep 17 00:00:00 2001 From: Greg Hudson Date: Wed, 21 Sep 2011 16:29:00 +0000 Subject: [PATCH] Add kadmin functionality for string attributes git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@25215 dc483132-0cff-0310-8789-dd5450dbe970 --- .../admin_commands/kadmin_local.rst | 37 +++++ src/include/kdb.h | 2 +- src/kadmin/cli/kadmin.M | 22 +++ src/kadmin/cli/kadmin.c | 127 ++++++++++++++++++ src/kadmin/cli/kadmin.h | 3 + src/kadmin/cli/kadmin_ct.ct | 9 ++ src/kadmin/server/kadm_rpc_svc.c | 12 ++ src/kadmin/server/ovsec_kadmd.c | 4 +- src/kadmin/server/server_stubs.c | 112 +++++++++++++++ src/lib/kadm5/admin.h | 14 ++ src/lib/kadm5/admin_xdr.h | 4 + src/lib/kadm5/clnt/client_principal.c | 48 +++++++ src/lib/kadm5/clnt/client_rpc.c | 30 +++++ src/lib/kadm5/clnt/libkadm5clnt_mit.exports | 3 + src/lib/kadm5/kadm_rpc.h | 32 +++++ src/lib/kadm5/kadm_rpc_xdr.c | 69 ++++++++++ src/lib/kadm5/misc_free.c | 19 +++ src/lib/kadm5/srv/libkadm5srv_mit.exports | 7 + src/lib/kadm5/srv/svr_principal.c | 52 +++++++ src/tests/Makefile.in | 1 + src/tests/t_stringattr.py | 56 ++++++++ 21 files changed, 661 insertions(+), 2 deletions(-) create mode 100644 src/tests/t_stringattr.py diff --git a/doc/rst_source/krb_admins/admin_commands/kadmin_local.rst b/doc/rst_source/krb_admins/admin_commands/kadmin_local.rst index eab77e0c3..ae6b1434c 100644 --- a/doc/rst_source/krb_admins/admin_commands/kadmin_local.rst +++ b/doc/rst_source/krb_admins/admin_commands/kadmin_local.rst @@ -562,6 +562,43 @@ list_principals .. _list_principals_end: +.. _get_strings: + +get_strings +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + **get_strings** *principal* + Displays string attributes on *principal*. + String attributes are used to supply per-principal configuration to some KDC plugin modules. + + Alias:: + + getstr + +.. _set_string: + +set_string +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + **set_string** *principal* *key* *value* + Sets a string attribute on *principal*. + + Alias:: + + setstr + +.. _del_string: + +del_string +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + **del_string** *principal* *key* + Deletes a string attribute from *principal*. + + Alias:: + + delstr + .. _add_policy: add_policy diff --git a/src/include/kdb.h b/src/include/kdb.h index 31f48b151..809722eda 100644 --- a/src/include/kdb.h +++ b/src/include/kdb.h @@ -243,7 +243,7 @@ typedef struct __krb5_key_salt_tuple { #define KRB5_TL_MKEY_AUX 0x000a /* String attributes may not always be represented in tl-data. kadmin clients - * must use the modify_strings and get_strings RPCs. */ + * must use the get_strings and set_string RPCs. */ #define KRB5_TL_STRING_ATTRS 0x000b #define KRB5_TL_PAC_LOGON_INFO 0x0100 /* NDR encoded validation info */ diff --git a/src/kadmin/cli/kadmin.M b/src/kadmin/cli/kadmin.M index f847c8235..4dd10e6d3 100644 --- a/src/kadmin/cli/kadmin.M +++ b/src/kadmin/cli/kadmin.M @@ -672,6 +672,28 @@ kadmin: .RE .fi .TP +\fBget_strings\fP \fIprincipal\fP +displays string attributes on +.IR principal . +String attributes are used to supply per-principal configuration to +some KDC plugin modules. Alias +.BR getstrs . +.fi +.TP +\fBset_string\fP \fIprincipal\fP \fIkey\fP \fIvalue\fP +sets a string attribute on +.IR principal . +Alias +.BR setstr . +.fi +.TP +\fBdel_string\fP \fIprincipal\fP \fIkey\fP +deletes a string attribute from +.IR principal . +Alias +.BR delstr . +.fi +.TP \fBadd_policy\fP [\fIoptions\fP] \fIpolicy\fP adds the named policy to the policy database. Requires the .I add diff --git a/src/kadmin/cli/kadmin.c b/src/kadmin/cli/kadmin.c index baaac0bab..539091f84 100644 --- a/src/kadmin/cli/kadmin.c +++ b/src/kadmin/cli/kadmin.c @@ -1898,3 +1898,130 @@ cleanup: free(canon); return; } + +void +kadmin_getstrings(int argc, char *argv[]) +{ + kadm5_ret_t retval; + char *pname, *canon = NULL; + krb5_principal princ = NULL; + krb5_string_attr *strings = NULL; + int count, i; + + if (argc != 2) { + fprintf(stderr, _("usage: get_strings principal\n")); + return; + } + pname = argv[1]; + + retval = kadmin_parse_name(pname, &princ); + if (retval) { + com_err("get_strings", retval, _("while parsing principal")); + return; + } + + retval = krb5_unparse_name(context, princ, &canon); + if (retval) { + com_err("get_strings", retval, _("while canonicalizing principal")); + goto cleanup; + } + + retval = kadm5_get_strings(handle, princ, &strings, &count); + if (retval) { + com_err("get_strings", retval, + _("while getting attributes for principal \"%s\""), canon); + goto cleanup; + } + + if (count == 0) + printf(_("(No string attributes.)\n")); + for (i = 0; i < count; i++) + printf("%s: %s\n", strings[i].key, strings[i].value); + kadm5_free_strings(handle, strings, count); + +cleanup: + krb5_free_principal(context, princ); + free(canon); + return; +} + +void +kadmin_setstring(int argc, char *argv[]) +{ + kadm5_ret_t retval; + char *pname, *canon = NULL, *key, *value; + krb5_principal princ = NULL; + + if (argc != 4) { + fprintf(stderr, _("usage: set_string principal key value\n")); + return; + } + pname = argv[1]; + key = argv[2]; + value = argv[3]; + + retval = kadmin_parse_name(pname, &princ); + if (retval) { + com_err("set_string", retval, _("while parsing principal")); + return; + } + + retval = krb5_unparse_name(context, princ, &canon); + if (retval) { + com_err("set_string", retval, _("while canonicalizing principal")); + goto cleanup; + } + + retval = kadm5_set_string(handle, princ, key, value); + if (retval) { + com_err("set_string", retval, + _("while setting attribute on principal \"%s\""), canon); + goto cleanup; + } + + printf(_("Attribute set for principal \"%s\".\n"), canon); +cleanup: + krb5_free_principal(context, princ); + free(canon); + return; +} + +void +kadmin_delstring(int argc, char *argv[]) +{ + kadm5_ret_t retval; + char *pname, *canon = NULL, *key; + krb5_principal princ = NULL; + + if (argc != 3) { + fprintf(stderr, _("usage: del_string principal key\n")); + return; + } + pname = argv[1]; + key = argv[2]; + + retval = kadmin_parse_name(pname, &princ); + if (retval) { + com_err("delstring", retval, _("while parsing principal")); + return; + } + + retval = krb5_unparse_name(context, princ, &canon); + if (retval) { + com_err("del_string", retval, _("while canonicalizing principal")); + goto cleanup; + } + + retval = kadm5_set_string(handle, princ, key, NULL); + if (retval) { + com_err("del_string", retval, + _("while deleting attribute from principal \"%s\""), canon); + goto cleanup; + } + + printf(_("Attribute removed from principal \"%s\".\n"), canon); +cleanup: + krb5_free_principal(context, princ); + free(canon); + return; +} diff --git a/src/kadmin/cli/kadmin.h b/src/kadmin/cli/kadmin.h index 6d8704035..7afa0c928 100644 --- a/src/kadmin/cli/kadmin.h +++ b/src/kadmin/cli/kadmin.h @@ -53,6 +53,9 @@ extern void kadmin_getprivs(int argc, char *argv[]); extern void kadmin_keytab_add(int argc, char *argv[]); extern void kadmin_keytab_remove(int argc, char *argv[]); extern void kadmin_purgekeys(int argc, char *argv[]); +extern void kadmin_getstrings(int argc, char *argv[]); +extern void kadmin_setstring(int argc, char *argv[]); +extern void kadmin_delstring(int argc, char *argv[]); #include "autoconf.h" diff --git a/src/kadmin/cli/kadmin_ct.ct b/src/kadmin/cli/kadmin_ct.ct index 86ac96e70..705e41840 100644 --- a/src/kadmin/cli/kadmin_ct.ct +++ b/src/kadmin/cli/kadmin_ct.ct @@ -80,6 +80,15 @@ request kadmin_unlock, "Release exclusive database lock", request kadmin_purgekeys, "Purge previously retained old keys from a principal", purgekeys; +request kadmin_getstrings, "Show string attributes on a principal", + get_strings, getstrs; + +request kadmin_setstring, "Set a string attribute on a principal", + set_string, setstr; + +request kadmin_delstring, "Delete a string attribute on a principal", + del_string, delstr; + # list_requests is generic -- unrelated to Kerberos request ss_list_requests, "List available requests.", list_requests, lr, "?"; diff --git a/src/kadmin/server/kadm_rpc_svc.c b/src/kadmin/server/kadm_rpc_svc.c index a9bccf599..a75bdb89d 100644 --- a/src/kadmin/server/kadm_rpc_svc.c +++ b/src/kadmin/server/kadm_rpc_svc.c @@ -213,6 +213,18 @@ void kadm_1(rqstp, transp) local = (char *(*)()) purgekeys_2_svc; break; + case GET_STRINGS: + xdr_argument = xdr_gstrings_arg; + xdr_result = xdr_gstrings_ret; + local = (char *(*)()) get_strings_2_svc; + break; + + case SET_STRING: + xdr_argument = xdr_sstring_arg; + xdr_result = xdr_generic_ret; + local = (char *(*)()) set_string_2_svc; + break; + default: krb5_klog_syslog(LOG_ERR, "Invalid KADM5 procedure number: %s, %d", inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr), diff --git a/src/kadmin/server/ovsec_kadmd.c b/src/kadmin/server/ovsec_kadmd.c index 63d1787cb..f38f209f1 100644 --- a/src/kadmin/server/ovsec_kadmd.c +++ b/src/kadmin/server/ovsec_kadmd.c @@ -746,7 +746,9 @@ void log_badverf(gss_name_t client_name, gss_name_t server_name, {19, "CHPASS_PRINCIPAL3"}, {20, "CHRAND_PRINCIPAL3"}, {21, "SETKEY_PRINCIPAL3"}, - {22, "PURGEKEYS"} + {22, "PURGEKEYS"}, + {23, "GET_STRINGS"}, + {24, "SET_STRING"} }; #define NPROCNAMES (sizeof (proc_names) / sizeof (struct procnames)) OM_uint32 minor; diff --git a/src/kadmin/server/server_stubs.c b/src/kadmin/server/server_stubs.c index 6a2ed7551..8dbe756d6 100644 --- a/src/kadmin/server/server_stubs.c +++ b/src/kadmin/server/server_stubs.c @@ -1604,6 +1604,118 @@ exit_func: return &ret; } +gstrings_ret * +get_strings_2_svc(gstrings_arg *arg, struct svc_req *rqstp) +{ + static gstrings_ret ret; + char *prime_arg; + gss_buffer_desc client_name, + service_name; + OM_uint32 minor_stat; + kadm5_server_handle_t handle; + const char *errmsg = NULL; + + xdr_free(xdr_gstrings_ret, &ret); + + if ((ret.code = new_server_handle(arg->api_version, rqstp, &handle))) + goto exit_func; + + if ((ret.code = check_handle((void *)handle))) + goto exit_func; + + ret.api_version = handle->api_version; + + if (setup_gss_names(rqstp, &client_name, &service_name) < 0) { + ret.code = KADM5_FAILURE; + goto exit_func; + } + if (krb5_unparse_name(handle->context, arg->princ, &prime_arg)) { + ret.code = KADM5_BAD_PRINCIPAL; + goto exit_func; + } + + if (CHANGEPW_SERVICE(rqstp) || !kadm5int_acl_check(handle->context, + rqst2name(rqstp), + ACL_LIST, NULL, NULL)) { + ret.code = KADM5_AUTH_LIST; + log_unauth("kadm5_get_strings", prime_arg, + &client_name, &service_name, rqstp); + } else { + ret.code = kadm5_get_strings((void *)handle, arg->princ, &ret.strings, + &ret.count); + if (ret.code != 0) + errmsg = krb5_get_error_message(handle->context, ret.code); + + log_done("kadm5_get_strings", prime_arg, errmsg, + &client_name, &service_name, rqstp); + + if (errmsg != NULL) + krb5_free_error_message(handle->context, errmsg); + } + free(prime_arg); + gss_release_buffer(&minor_stat, &client_name); + gss_release_buffer(&minor_stat, &service_name); +exit_func: + free_server_handle(handle); + return &ret; +} + +generic_ret * +set_string_2_svc(sstring_arg *arg, struct svc_req *rqstp) +{ + static generic_ret ret; + char *prime_arg; + gss_buffer_desc client_name, + service_name; + OM_uint32 minor_stat; + kadm5_server_handle_t handle; + const char *errmsg = NULL; + + xdr_free(xdr_generic_ret, &ret); + + if ((ret.code = new_server_handle(arg->api_version, rqstp, &handle))) + goto exit_func; + + if ((ret.code = check_handle((void *)handle))) + goto exit_func; + + ret.api_version = handle->api_version; + + if (setup_gss_names(rqstp, &client_name, &service_name) < 0) { + ret.code = KADM5_FAILURE; + goto exit_func; + } + if (krb5_unparse_name(handle->context, arg->princ, &prime_arg)) { + ret.code = KADM5_BAD_PRINCIPAL; + goto exit_func; + } + + if (CHANGEPW_SERVICE(rqstp) || !kadm5int_acl_check(handle->context, + rqst2name(rqstp), + ACL_LIST, NULL, NULL)) { + ret.code = KADM5_AUTH_LIST; + log_unauth("kadm5_mod_strings", prime_arg, + &client_name, &service_name, rqstp); + } else { + ret.code = kadm5_set_string((void *)handle, arg->princ, arg->key, + arg->value); + if (ret.code != 0) + errmsg = krb5_get_error_message(handle->context, ret.code); + + log_done("kadm5_mod_strings", prime_arg, errmsg, + &client_name, &service_name, rqstp); + + if (errmsg != NULL) + krb5_free_error_message(handle->context, errmsg); + } + free(prime_arg); + gss_release_buffer(&minor_stat, &client_name); + gss_release_buffer(&minor_stat, &service_name); +exit_func: + free_server_handle(handle); + return &ret; +} + generic_ret *init_2_svc(krb5_ui_4 *arg, struct svc_req *rqstp) { static generic_ret ret; diff --git a/src/lib/kadm5/admin.h b/src/lib/kadm5/admin.h index 7bcc7fcbc..d1a76f737 100644 --- a/src/lib/kadm5/admin.h +++ b/src/lib/kadm5/admin.h @@ -513,6 +513,20 @@ kadm5_ret_t kadm5_purgekeys(void *server_handle, krb5_principal principal, int keepkvno); +kadm5_ret_t kadm5_get_strings(void *server_handle, + krb5_principal principal, + krb5_string_attr **strings_out, + int *count_out); + +kadm5_ret_t kadm5_set_string(void *server_handle, + krb5_principal principal, + const char *key, + const char *value); + +kadm5_ret_t kadm5_free_strings(void *server_handle, + krb5_string_attr *strings, + int count); + KADM5INT_END_DECLS #endif /* __KADM5_ADMIN_H__ */ diff --git a/src/lib/kadm5/admin_xdr.h b/src/lib/kadm5/admin_xdr.h index 927a0e5b0..e46d5429d 100644 --- a/src/lib/kadm5/admin_xdr.h +++ b/src/lib/kadm5/admin_xdr.h @@ -56,6 +56,9 @@ bool_t xdr_gpols_arg(XDR *xdrs, gpols_arg *objp); bool_t xdr_gpols_ret(XDR *xdrs, gpols_ret *objp); bool_t xdr_getprivs_ret(XDR *xdrs, getprivs_ret *objp); bool_t xdr_purgekeys_arg(XDR *xdrs, purgekeys_arg *objp); +bool_t xdr_gstrings_arg(XDR *xdrs, gstrings_arg *objp); +bool_t xdr_gstrings_ret(XDR *xdrs, gstrings_ret *objp); +bool_t xdr_sstring_arg(XDR *xdrs, sstring_arg *objp); bool_t xdr_krb5_principal(XDR *xdrs, krb5_principal *objp); bool_t xdr_krb5_octet(XDR *xdrs, krb5_octet *objp); bool_t xdr_krb5_int32(XDR *xdrs, krb5_int32 *objp); @@ -63,4 +66,5 @@ bool_t xdr_krb5_enctype(XDR *xdrs, krb5_enctype *objp); bool_t xdr_krb5_salttype(XDR *xdrs, krb5_int32 *objp); bool_t xdr_krb5_keyblock(XDR *xdrs, krb5_keyblock *objp); bool_t xdr_krb5_key_data(XDR *xdrs, krb5_key_data *objp); +bool_t xdr_krb5_string_attr(XDR *xdrs, krb5_string_attr *objp); bool_t xdr_osa_pw_hist_ent(XDR *xdrs, osa_pw_hist_ent *objp); diff --git a/src/lib/kadm5/clnt/client_principal.c b/src/lib/kadm5/clnt/client_principal.c index 41324be80..6af2a1751 100644 --- a/src/lib/kadm5/clnt/client_principal.c +++ b/src/lib/kadm5/clnt/client_principal.c @@ -482,3 +482,51 @@ kadm5_purgekeys(void *server_handle, eret(); return r->code; } + +kadm5_ret_t +kadm5_get_strings(void *server_handle, krb5_principal principal, + krb5_string_attr **strings_out, int *count_out) +{ + gstrings_arg arg; + gstrings_ret *r; + kadm5_server_handle_t handle = server_handle; + + *strings_out = NULL; + *count_out = 0; + CHECK_HANDLE(server_handle); + if (principal == NULL) + return EINVAL; + + arg.princ = principal; + arg.api_version = handle->api_version; + r = get_strings_2(&arg, handle->clnt); + if (r == NULL) + eret(); + if (r->code == 0) { + *strings_out = r->strings; + *count_out = r->count; + } + return r->code; +} + +kadm5_ret_t +kadm5_set_string(void *server_handle, krb5_principal principal, + const char *key, const char *value) +{ + sstring_arg arg; + generic_ret *r; + kadm5_server_handle_t handle = server_handle; + + CHECK_HANDLE(server_handle); + if (principal == NULL || key == NULL) + return EINVAL; + + arg.princ = principal; + arg.key = (char *)key; + arg.value = (char *)value; + arg.api_version = handle->api_version; + r = set_string_2(&arg, handle->clnt); + if (r == NULL) + eret(); + return r->code; +} diff --git a/src/lib/kadm5/clnt/client_rpc.c b/src/lib/kadm5/clnt/client_rpc.c index 95417a60c..e11346d82 100644 --- a/src/lib/kadm5/clnt/client_rpc.c +++ b/src/lib/kadm5/clnt/client_rpc.c @@ -341,3 +341,33 @@ purgekeys_2(purgekeys_arg *argp, CLIENT *clnt) } return (&clnt_res); } + +gstrings_ret * +get_strings_2(gstrings_arg *argp, CLIENT *clnt) +{ + static gstrings_ret clnt_res; + + memset(&clnt_res, 0, sizeof(clnt_res)); + if (clnt_call(clnt, GET_STRINGS, + (xdrproc_t) xdr_gstrings_arg, (caddr_t) argp, + (xdrproc_t) xdr_gstrings_ret, (caddr_t) &clnt_res, + TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&clnt_res); +} + +generic_ret * +set_string_2(sstring_arg *argp, CLIENT *clnt) +{ + static generic_ret clnt_res; + + memset(&clnt_res, 0, sizeof(clnt_res)); + if (clnt_call(clnt, SET_STRING, + (xdrproc_t) xdr_sstring_arg, (caddr_t) argp, + (xdrproc_t) xdr_generic_ret, (caddr_t) &clnt_res, + TIMEOUT) != RPC_SUCCESS) { + return (NULL); + } + return (&clnt_res); +} diff --git a/src/lib/kadm5/clnt/libkadm5clnt_mit.exports b/src/lib/kadm5/clnt/libkadm5clnt_mit.exports index 249a3c774..4732766ae 100644 --- a/src/lib/kadm5/clnt/libkadm5clnt_mit.exports +++ b/src/lib/kadm5/clnt/libkadm5clnt_mit.exports @@ -16,6 +16,7 @@ kadm5_free_key_data kadm5_free_name_list kadm5_free_policy_ent kadm5_free_principal_ent +kadm5_free_strings kadm5_get_admin_service_name kadm5_get_config_params kadm5_get_policies @@ -23,6 +24,7 @@ kadm5_get_policy kadm5_get_principal kadm5_get_principals kadm5_get_privs +kadm5_get_strings kadm5_init kadm5_init_anonymous kadm5_init_krb5_context @@ -36,6 +38,7 @@ kadm5_purgekeys kadm5_randkey_principal kadm5_randkey_principal_3 kadm5_rename_principal +kadm5_set_string kadm5_setkey_principal kadm5_setkey_principal_3 kadm5_setv4key_principal diff --git a/src/lib/kadm5/kadm_rpc.h b/src/lib/kadm5/kadm_rpc.h index 1aa98d0fd..d5e9e7f07 100644 --- a/src/lib/kadm5/kadm_rpc.h +++ b/src/lib/kadm5/kadm_rpc.h @@ -207,6 +207,28 @@ struct purgekeys_arg { }; typedef struct purgekeys_arg purgekeys_arg; +struct gstrings_arg { + krb5_ui_4 api_version; + krb5_principal princ; +}; +typedef struct gstrings_arg gstrings_arg; + +struct gstrings_ret { + krb5_ui_4 api_version; + kadm5_ret_t code; + krb5_string_attr *strings; + int count; +}; +typedef struct gstrings_ret gstrings_ret; + +struct sstring_arg { + krb5_ui_4 api_version; + krb5_principal princ; + char *key; + char *value; +}; +typedef struct sstring_arg sstring_arg; + #define KADM 2112 #define KADMVERS 2 #define CREATE_PRINCIPAL 1 @@ -275,6 +297,12 @@ extern generic_ret * setkey_principal3_2_svc(setkey3_arg *, struct svc_req *); #define PURGEKEYS 22 extern generic_ret * purgekeys_2(purgekeys_arg *, CLIENT *); extern generic_ret * purgekeys_2_svc(purgekeys_arg *, struct svc_req *); +#define GET_STRINGS 23 +extern gstrings_ret * get_strings_2(gstrings_arg *, CLIENT *); +extern gstrings_ret * get_strings_2_svc(gstrings_arg *, struct svc_req *); +#define SET_STRING 24 +extern generic_ret * set_string_2(sstring_arg *, CLIENT *); +extern generic_ret * set_string_2_svc(sstring_arg *, struct svc_req *); extern bool_t xdr_cprinc_arg (); extern bool_t xdr_cprinc3_arg (); @@ -312,6 +340,10 @@ extern bool_t xdr_gpols_arg (); extern bool_t xdr_gpols_ret (); extern bool_t xdr_getprivs_ret (); extern bool_t xdr_purgekeys_arg (); +extern bool_t xdr_gstrings_arg (); +extern bool_t xdr_gstrings_ret (); +extern bool_t xdr_sstring_arg (); +extern bool_t xdr_krb5_string_attr (); #endif /* __KADM_RPC_H__ */ diff --git a/src/lib/kadm5/kadm_rpc_xdr.c b/src/lib/kadm5/kadm_rpc_xdr.c index 0b14ff8f5..0b0253a5c 100644 --- a/src/lib/kadm5/kadm_rpc_xdr.c +++ b/src/lib/kadm5/kadm_rpc_xdr.c @@ -971,6 +971,62 @@ xdr_purgekeys_arg(XDR *xdrs, purgekeys_arg *objp) return (TRUE); } +bool_t +xdr_gstrings_arg(XDR *xdrs, gstrings_arg *objp) +{ + if (!xdr_ui_4(xdrs, &objp->api_version)) { + return (FALSE); + } + if (!xdr_krb5_principal(xdrs, &objp->princ)) { + return (FALSE); + } + + return (TRUE); +} + +bool_t +xdr_gstrings_ret(XDR *xdrs, gstrings_ret *objp) +{ + if (!xdr_ui_4(xdrs, &objp->api_version)) { + return (FALSE); + } + if (!xdr_kadm5_ret_t(xdrs, &objp->code)) { + return (FALSE); + } + if (objp->code == KADM5_OK) { + if (!xdr_int(xdrs, &objp->count)) { + return (FALSE); + } + if (!xdr_array(xdrs, (caddr_t *) &objp->strings, + (unsigned int *) &objp->count, ~0, + sizeof(krb5_string_attr), + xdr_krb5_string_attr)) { + return (FALSE); + } + } + + return (TRUE); +} + +bool_t +xdr_sstring_arg(XDR *xdrs, sstring_arg *objp) +{ + if (!xdr_ui_4(xdrs, &objp->api_version)) { + return (FALSE); + } + if (!xdr_krb5_principal(xdrs, &objp->princ)) { + return (FALSE); + } + if (!xdr_nullstring(xdrs, &objp->key)) { + return (FALSE); + } + if (!xdr_nullstring(xdrs, &objp->value)) { + return (FALSE); + } + + return (TRUE); +} + bool_t xdr_krb5_principal(XDR *xdrs, krb5_principal *objp) { @@ -1063,3 +1119,16 @@ xdr_krb5_keyblock(XDR *xdrs, krb5_keyblock *objp) return FALSE; return TRUE; } + +bool_t +xdr_krb5_string_attr(XDR *xdrs, krb5_string_attr *objp) +{ + if (!xdr_nullstring(xdrs, &objp->key)) + return FALSE; + if (!xdr_nullstring(xdrs, &objp->value)) + return FALSE; + if (xdrs->x_op == XDR_DECODE && + (objp->key == NULL || objp->value == NULL)) + return FALSE; + return TRUE; +} diff --git a/src/lib/kadm5/misc_free.c b/src/lib/kadm5/misc_free.c index 4d38c0f99..1d7079199 100644 --- a/src/lib/kadm5/misc_free.c +++ b/src/lib/kadm5/misc_free.c @@ -89,3 +89,22 @@ kadm5_free_principal_ent(void *server_handle, kadm5_principal_ent_t val) } return KADM5_OK; } + +kadm5_ret_t +kadm5_free_strings(void *server_handle, krb5_string_attr *strings, + int count) +{ + int i; + + _KADM5_CHECK_HANDLE(server_handle); + + if (!strings) + return KADM5_OK; + + for (i = 0; i < count; i++) { + free(strings[i].key); + free(strings[i].value); + } + free(strings); + return KADM5_OK; +} diff --git a/src/lib/kadm5/srv/libkadm5srv_mit.exports b/src/lib/kadm5/srv/libkadm5srv_mit.exports index 49a1b8803..44311ee26 100644 --- a/src/lib/kadm5/srv/libkadm5srv_mit.exports +++ b/src/lib/kadm5/srv/libkadm5srv_mit.exports @@ -26,6 +26,7 @@ kadm5_free_key_data kadm5_free_name_list kadm5_free_policy_ent kadm5_free_principal_ent +kadm5_free_strings kadm5_get_config_params kadm5_get_policies kadm5_get_policy @@ -33,6 +34,7 @@ kadm5_get_principal kadm5_get_principal_keys kadm5_get_principals kadm5_get_privs +kadm5_get_strings kadm5_init kadm5_init_anonymous kadm5_init_krb5_context @@ -47,6 +49,7 @@ kadm5_purgekeys kadm5_randkey_principal kadm5_randkey_principal_3 kadm5_rename_principal +kadm5_set_string kadm5_setkey_principal kadm5_setkey_principal_3 kadm5_setv4key_principal @@ -105,6 +108,8 @@ xdr_gprinc_arg xdr_gprinc_ret xdr_gprincs_arg xdr_gprincs_ret +xdr_gstrings_arg +xdr_gstrings_ret xdr_kadm5_policy_ent_rec xdr_kadm5_principal_ent_rec xdr_kadm5_ret_t @@ -120,6 +125,7 @@ xdr_krb5_kvno xdr_krb5_octet xdr_krb5_principal xdr_krb5_salttype +xdr_krb5_string_attr xdr_krb5_timestamp xdr_krb5_tl_data xdr_krb5_ui_2 @@ -135,5 +141,6 @@ xdr_rprinc_arg xdr_setkey3_arg xdr_setkey_arg xdr_setv4key_arg +xdr_sstring_arg xdr_ui_4 kadm5_init_iprop diff --git a/src/lib/kadm5/srv/svr_principal.c b/src/lib/kadm5/srv/svr_principal.c index 464d5e8e4..a9d0cdb88 100644 --- a/src/lib/kadm5/srv/svr_principal.c +++ b/src/lib/kadm5/srv/svr_principal.c @@ -2307,3 +2307,55 @@ done: kdb_free_entry(handle, kdb, &adb); return ret; } + +kadm5_ret_t +kadm5_get_strings(void *server_handle, krb5_principal principal, + krb5_string_attr **strings_out, int *count_out) +{ + kadm5_server_handle_t handle = server_handle; + kadm5_ret_t ret; + krb5_db_entry *kdb = NULL; + + *strings_out = NULL; + *count_out = 0; + CHECK_HANDLE(server_handle); + if (principal == NULL) + return EINVAL; + + ret = kdb_get_entry(handle, principal, &kdb, NULL); + if (ret) + return ret; + + ret = krb5_dbe_get_strings(handle->context, kdb, strings_out, count_out); + kdb_free_entry(handle, kdb, NULL); + return ret; +} + +kadm5_ret_t +kadm5_set_string(void *server_handle, krb5_principal principal, + const char *key, const char *value) +{ + kadm5_server_handle_t handle = server_handle; + kadm5_ret_t ret; + krb5_db_entry *kdb; + osa_princ_ent_rec adb; + + CHECK_HANDLE(server_handle); + if (principal == NULL || key == NULL) + return EINVAL; + + ret = kdb_get_entry(handle, principal, &kdb, &adb); + if (ret) + return ret; + + ret = krb5_dbe_set_string(handle->context, kdb, key, value); + if (ret) + goto done; + + kdb->mask = KADM5_TL_DATA; + ret = kdb_put_entry(handle, kdb, &adb); + +done: + kdb_free_entry(handle, kdb, &adb); + return ret; +} diff --git a/src/tests/Makefile.in b/src/tests/Makefile.in index 0d6f0b795..6578d3309 100644 --- a/src/tests/Makefile.in +++ b/src/tests/Makefile.in @@ -69,6 +69,7 @@ check-pytests:: $(RUNPYTEST) $(srcdir)/t_renew.py $(PYTESTFLAGS) $(RUNPYTEST) $(srcdir)/t_renprinc.py $(PYTESTFLAGS) $(RUNPYTEST) $(srcdir)/t_cccol.py $(PYTESTFLAGS) + $(RUNPYTEST) $(srcdir)/t_stringattr.py $(PYTESTFLAGS) clean:: $(RM) kdc.conf diff --git a/src/tests/t_stringattr.py b/src/tests/t_stringattr.py new file mode 100644 index 000000000..392ab6c98 --- /dev/null +++ b/src/tests/t_stringattr.py @@ -0,0 +1,56 @@ +# Copyright (C) 2011 by the Massachusetts Institute of Technology. +# All rights reserved. + +# Export of this software from the United States of America may +# require a specific license from the United States Government. +# It is the responsibility of any person or organization contemplating +# export to obtain such a license before exporting. +# +# WITHIN THAT CONSTRAINT, permission to use, copy, modify, and +# distribute this software and its documentation for any purpose and +# without fee is hereby granted, provided that the above copyright +# notice appear in all copies and that both that copyright notice and +# this permission notice appear in supporting documentation, and that +# the name of M.I.T. not be used in advertising or publicity pertaining +# to distribution of the software without specific, written prior +# permission. Furthermore if you modify this software you must label +# your software as modified software and not distribute it in such a +# fashion that it might be confused with the original M.I.T. software. +# M.I.T. makes no representations about the suitability of +# this software for any purpose. It is provided "as is" without express +# or implied warranty. + +#!/usr/bin/python +from k5test import * + +def run_kadmin(query): + global realm + return realm.run_as_master([kadmin, '-c', realm.ccache, '-q', query]) + +realm = K5Realm(create_host=False, get_creds=False) + +realm.kinit(realm.admin_princ, password('admin'), flags=['-S', 'kadmin/admin']) + +output = run_kadmin('getstrs user') +if '(No string attributes.)' not in output: + fail('Empty attribute query') + +output = run_kadmin('setstr user attr1 value1') +if 'Attribute set for principal' not in output: + fail('Setting attr1') +output = run_kadmin('setstr user attr2 value2') +if 'Attribute set for principal' not in output: + fail('Setting attr2') +output = run_kadmin('delstr user attr1') +if 'Attribute removed from principal' not in output: + fail('Deleting attr1') +output = run_kadmin('setstr user attr3 value3') +if 'Attribute set for principal' not in output: + fail('Setting attr3') + +output = run_kadmin('getstrs user') +if 'attr2: value2' not in output or 'attr3: value3' not in output or \ + 'attr1:' in output: + fail('Final attribute query') + +success('KDB string attributes.') -- 2.26.2