s4:heimdal: import lorikeet-heimdal-200906080040 (commit 904d0124b46eed7a8ad6e5b73e89...
[amitay/samba.git] / source4 / heimdal / lib / krb5 / kcm.c
index 8a8f1efc11a09334db2498adf12d8bb240675b73..f0343419725f5aa0a8569f328ba478128f6a2537 100644 (file)
 
 #include "kcm.h"
 
-RCSID("$Id$");
-
 typedef struct krb5_kcmcache {
     char *name;
     struct sockaddr_un path;
     char *door_path;
 } krb5_kcmcache;
 
+typedef struct krb5_kcm_cursor {
+    unsigned long offset;
+    unsigned long length;
+    kcmuuid_t *uuids;
+} *krb5_kcm_cursor;
+
+
 #define KCMCACHE(X)    ((krb5_kcmcache *)(X)->data.data)
 #define CACHENAME(X)   (KCMCACHE(X)->name)
-#define KCMCURSOR(C)   (*(uint32_t *)(C))
+#define KCMCURSOR(C)   ((krb5_kcm_cursor)(C))
+
+#ifdef HAVE_DOOR_CREATE
 
 static krb5_error_code
 try_door(krb5_context context,
@@ -61,7 +68,6 @@ try_door(krb5_context context,
         krb5_data *request_data,
         krb5_data *response_data)
 {
-#ifdef HAVE_DOOR_CREATE
     door_arg_t arg;
     int fd;
     int ret;
@@ -91,10 +97,8 @@ try_door(krb5_context context,
        return ret;
 
     return 0;
-#else
-    return KRB5_CC_IO;
-#endif
 }
+#endif /* HAVE_DOOR_CREATE */
 
 static krb5_error_code
 try_unix_socket(krb5_context context,
@@ -143,9 +147,11 @@ kcm_send_request(krb5_context context,
     ret = KRB5_CC_NOSUPP;
 
     for (i = 0; i < context->max_retries; i++) {
+#ifdef HAVE_DOOR_CREATE
        ret = try_door(context, k, &request_data, response_data);
        if (ret == 0 && response_data->length != 0)
            break;
+#endif
        ret = try_unix_socket(context, k, &request_data, response_data);
        if (ret == 0 && response_data->length != 0)
            break;
@@ -207,7 +213,8 @@ kcm_alloc(krb5_context context, const char *name, krb5_ccache *id)
 
     k = malloc(sizeof(*k));
     if (k == NULL) {
-       krb5_set_error_message(context, KRB5_CC_NOMEM, N_("malloc: out of memory", ""));
+       krb5_set_error_message(context, KRB5_CC_NOMEM,
+                              N_("malloc: out of memory", ""));
        return KRB5_CC_NOMEM;
     }
 
@@ -309,8 +316,6 @@ kcm_free(krb5_context context, krb5_ccache *id)
        memset(k, 0, sizeof(*k));
        krb5_data_free(&(*id)->data);
     }
-
-    *id = NULL;
 }
 
 static const char *
@@ -609,10 +614,10 @@ kcm_get_first (krb5_context context,
               krb5_cc_cursor *cursor)
 {
     krb5_error_code ret;
+    krb5_kcm_cursor c;
     krb5_kcmcache *k = KCMCACHE(id);
     krb5_storage *request, *response;
     krb5_data response_data;
-    int32_t tmp;
 
     ret = kcm_storage_request(context, KCM_OP_GET_FIRST, &request);
     if (ret)
@@ -625,27 +630,56 @@ kcm_get_first (krb5_context context,
     }
 
     ret = kcm_call(context, k, request, &response, &response_data);
-    if (ret) {
-       krb5_storage_free(request);
+    krb5_storage_free(request);
+    if (ret)
+       return ret;
+
+    c = calloc(1, sizeof(*c));
+    if (c == NULL) {
+       ret = ENOMEM;
+       krb5_set_error_message(context, ret, 
+                              N_("malloc: out of memory", ""));
        return ret;
     }
 
-    ret = krb5_ret_int32(response, &tmp);
-    if (ret || tmp < 0)
-       ret = KRB5_CC_IO;
+    while (1) {
+       ssize_t sret;
+       kcmuuid_t uuid;
+       void *ptr;
+
+       sret = krb5_storage_read(response, &uuid, sizeof(uuid));
+       if (sret == 0) {
+           ret = 0;
+           break;
+       } else if (sret != sizeof(uuid)) {
+           ret = EINVAL;
+           break;
+       }
+
+       ptr = realloc(c->uuids, sizeof(c->uuids[0]) * (c->length + 1));
+       if (ptr == NULL) {
+           free(c->uuids);
+           free(c);
+           krb5_set_error_message(context, ENOMEM, 
+                                  N_("malloc: out of memory", ""));
+           return ENOMEM;
+       }
+       c->uuids = ptr;
+
+       memcpy(&c->uuids[c->length], &uuid, sizeof(uuid));
+       c->length += 1;
+    }
 
-    krb5_storage_free(request);
     krb5_storage_free(response);
     krb5_data_free(&response_data);
 
-    if (ret)
+    if (ret) {
+        free(c->uuids);
+        free(c);
        return ret;
+    }
 
-    *cursor = malloc(sizeof(tmp));
-    if (*cursor == NULL)
-       return KRB5_CC_NOMEM;
-
-    KCMCURSOR(*cursor) = tmp;
+    *cursor = c;
 
     return 0;
 }
@@ -666,8 +700,15 @@ kcm_get_next (krb5_context context,
 {
     krb5_error_code ret;
     krb5_kcmcache *k = KCMCACHE(id);
+    krb5_kcm_cursor c = KCMCURSOR(*cursor);
     krb5_storage *request, *response;
     krb5_data response_data;
+    ssize_t sret;
+
+ again:
+
+    if (c->offset >= c->length)
+       return KRB5_CC_END;
 
     ret = kcm_storage_request(context, KCM_OP_GET_NEXT, &request);
     if (ret)
@@ -679,23 +720,26 @@ kcm_get_next (krb5_context context,
        return ret;
     }
 
-    ret = krb5_store_int32(request, KCMCURSOR(*cursor));
-    if (ret) {
+    sret = krb5_storage_write(request, 
+                             &c->uuids[c->offset],
+                             sizeof(c->uuids[c->offset]));
+    c->offset++;
+    if (sret != sizeof(c->uuids[c->offset])) {
        krb5_storage_free(request);
-       return ret;
+       krb5_clear_error_message(context);
+       return ENOMEM;
     }
 
     ret = kcm_call(context, k, request, &response, &response_data);
-    if (ret) {
-       krb5_storage_free(request);
-       return ret;
+    krb5_storage_free(request);
+    if (ret == KRB5_CC_END) {
+       goto again;
     }
 
     ret = krb5_ret_creds(response, creds);
     if (ret)
        ret = KRB5_CC_IO;
 
-    krb5_storage_free(request);
     krb5_storage_free(response);
     krb5_data_free(&response_data);
 
@@ -717,6 +761,7 @@ kcm_end_get (krb5_context context,
 {
     krb5_error_code ret;
     krb5_kcmcache *k = KCMCACHE(id);
+    krb5_kcm_cursor c = KCMCURSOR(*cursor);
     krb5_storage *request;
 
     ret = kcm_storage_request(context, KCM_OP_END_GET, &request);
@@ -729,22 +774,14 @@ kcm_end_get (krb5_context context,
        return ret;
     }
 
-    ret = krb5_store_int32(request, KCMCURSOR(*cursor));
-    if (ret) {
-       krb5_storage_free(request);
-       return ret;
-    }
-
     ret = kcm_call(context, k, request, NULL, NULL);
-    if (ret) {
-       krb5_storage_free(request);
+    krb5_storage_free(request);
+    if (ret)
        return ret;
-    }
 
-    krb5_storage_free(request);
+    free(c->uuids);
+    free(c);
 
-    KCMCURSOR(*cursor) = 0;
-    free(*cursor);
     *cursor = NULL;
 
     return ret;