summaryrefslogtreecommitdiff
path: root/third_party/heimdal/lib/kadm5/get_princs_c.c
diff options
context:
space:
mode:
authorAndrew Bartlett <abartlet@samba.org>2022-10-31 14:33:09 +1300
committerAndrew Bartlett <abartlet@samba.org>2022-11-02 04:23:34 +0000
commitef28247f3bbbd7cf9daed7a4dba28855496ce38e (patch)
treef97d5b9b41ebbfb7e52269486b3c41d9a0fd9575 /third_party/heimdal/lib/kadm5/get_princs_c.c
parentab4c7bda8daccdb99adaf6ec7fddf8b5f84be09a (diff)
downloadsamba-ef28247f3bbbd7cf9daed7a4dba28855496ce38e.tar.gz
third_party/heimdal: import lorikeet-heimdal-202210310104 (commit 0fc20ff4144973047e6aaaeb2fc8708bd75be222)
This commit won't compile on it's own, as we need to fix the build system to cope in the next commit. The purpose of this commit is to update to a new lorikeet-heimdal tree that includes the previous two patches and is rebased on a current Heimdal master snapshot. Signed-off-by: Andrew Bartlett <abartlet@samba.org> Reviewed-by: Joseph Sutton <josephsutton@catalyst.net.nz>
Diffstat (limited to 'third_party/heimdal/lib/kadm5/get_princs_c.c')
-rw-r--r--third_party/heimdal/lib/kadm5/get_princs_c.c186
1 files changed, 185 insertions, 1 deletions
diff --git a/third_party/heimdal/lib/kadm5/get_princs_c.c b/third_party/heimdal/lib/kadm5/get_princs_c.c
index 4998223d260..93d7ce7ed1b 100644
--- a/third_party/heimdal/lib/kadm5/get_princs_c.c
+++ b/third_party/heimdal/lib/kadm5/get_princs_c.c
@@ -66,7 +66,7 @@ kadm5_c_get_principals(void *server_handle,
ret = krb5_store_int32(sp, kadm_get_princs);
if (ret)
goto out;
- ret = krb5_store_int32(sp, expression != NULL);
+ ret = krb5_store_int32(sp, expression != NULL ? 1 : 0);
if (ret)
goto out;
if (expression) {
@@ -117,3 +117,187 @@ kadm5_c_get_principals(void *server_handle,
krb5_data_free(&reply);
return ret;
}
+
+kadm5_ret_t
+kadm5_c_iter_principals(void *server_handle,
+ const char *expression,
+ int (*cb)(void *, const char *),
+ void *cbdata)
+{
+ kadm5_client_context *context = server_handle;
+ kadm5_ret_t ret;
+ krb5_storage *sp;
+ unsigned char buf[1024];
+ int32_t tmp;
+ krb5_data reply;
+ size_t i;
+
+ ret = _kadm5_connect(server_handle, 0 /* want_write */);
+ if (ret)
+ return ret;
+
+ krb5_data_zero(&reply);
+
+ sp = krb5_storage_from_mem(buf, sizeof(buf));
+ if (sp == NULL) {
+ ret = krb5_enomem(context->context);
+ goto out_keep_error;
+ }
+ ret = krb5_store_int32(sp, kadm_get_princs);
+ if (ret)
+ goto out;
+
+ /*
+ * Our protocol has an int boolean for this operation to indicate whether
+ * there's an expression. What we'll do here is that instead of sending
+ * just false or trueish, for online iteration we'll send a number other
+ * than 0 or 1 -- a magic value > 0 and < INT_MAX.
+ *
+ * In response we'll expect multiple replies, each with up to some small
+ * number of principal names. See kadmin/server.c.
+ */
+ ret = krb5_store_int32(sp, 0x55555555);
+ if (ret)
+ goto out;
+ ret = krb5_store_string(sp, expression ? expression : "");
+ if (ret)
+ goto out;
+ ret = _kadm5_client_send(context, sp);
+ if (ret)
+ goto out_keep_error;
+ ret = _kadm5_client_recv(context, &reply);
+ if (ret)
+ goto out_keep_error;
+ krb5_storage_free(sp);
+ sp = krb5_storage_from_data (&reply);
+ if (sp == NULL) {
+ ret = krb5_enomem(context->context);
+ goto out_keep_error;
+ }
+ ret = krb5_ret_int32(sp, &tmp);
+ if (ret == 0)
+ ret = tmp;
+
+ if (ret)
+ goto out;
+
+ ret = krb5_ret_int32(sp, &tmp);
+ if (ret)
+ goto out;
+
+ if (tmp < 0) {
+ size_t n = -tmp;
+ int more = 1;
+ int stop = 0;
+
+ /* The server supports online iteration, hooray! */
+
+ while (more) {
+ /*
+ * We expect any number of chunks, each having `n' names, except
+ * the last one would have fewer than `n' (possibly zero, even).
+ *
+ * After that we expect one more reply with just a final return
+ * code.
+ */
+ krb5_data_free(&reply);
+ krb5_storage_free(sp);
+ sp = NULL;
+ ret = _kadm5_client_recv(context, &reply);
+ if (ret == 0 && (sp = krb5_storage_from_data(&reply)) == NULL)
+ ret = krb5_enomem(context->context);
+ if (ret)
+ goto out;
+
+ /* Every chunk begins with a status code */
+ ret = krb5_ret_int32(sp, &tmp);
+ if (ret == 0)
+ ret = tmp;
+ if (ret)
+ goto out;
+
+ /* We expect up to -tmp principals per reply */
+ for (i = 0; i < n; i++) {
+ char *princ = NULL;
+
+ ret = krb5_ret_string(sp, &princ);
+ if (ret == HEIM_ERR_EOF) {
+ /* This was the last reply */
+ more = 0;
+ ret = 0;
+ break;
+ }
+ if (ret)
+ goto out;
+ if (!stop) {
+ stop = cb(cbdata, princ);
+ if (stop) {
+ /*
+ * Tell the server to stop.
+ *
+ * We use a NOP for this, but with a payload that says
+ * "don't reply to the NOP" just in case the NOP
+ * arrives and is processed _after_ the LISTing has
+ * finished.
+ */
+ krb5_storage_free(sp);
+ if ((sp = krb5_storage_emem()) &&
+ krb5_store_int32(sp, kadm_nop) == 0 &&
+ krb5_store_int32(sp, 0))
+ (void) _kadm5_client_send(context, sp);
+ }
+ }
+ free(princ);
+ }
+
+ if (!more) {
+ if (ret == 0)
+ ret = stop;
+ break;
+ }
+ }
+ /* Get the final result code */
+ krb5_data_free(&reply);
+ krb5_storage_free(sp);
+ sp = NULL;
+ ret = _kadm5_client_recv(context, &reply);
+ if (ret == 0 && (sp = krb5_storage_from_data(&reply)) == NULL)
+ ret = krb5_enomem(context->context);
+ if (ret)
+ goto out;
+ ret = krb5_ret_int32(sp, &tmp);
+ if (ret == 0)
+ ret = tmp;
+ if (!stop) {
+ /*
+ * Send our "interrupt" after the last chunk if we hand't
+ * interrupted already.
+ */
+ krb5_storage_free(sp);
+ if ((sp = krb5_storage_emem()) &&
+ krb5_store_int32(sp, kadm_nop) == 0)
+ (void) _kadm5_client_send(context, sp);
+ }
+ } else {
+ size_t n = tmp;
+
+ /* Old server -- listing not online */
+ for (i = 0; i < n; i++) {
+ char *princ = NULL;
+
+ ret = krb5_ret_string(sp, &princ);
+ if (ret)
+ goto out;
+ cb(cbdata, princ);
+ free(princ);
+ }
+ }
+
+ out:
+ krb5_clear_error_message(context->context);
+
+ out_keep_error:
+ krb5_storage_free(sp);
+ krb5_data_free(&reply);
+ return ret;
+}