summaryrefslogtreecommitdiffstats
path: root/src/lib/krb5
diff options
context:
space:
mode:
authorSimo Sorce <simo@redhat.com>2013-08-02 17:53:27 -0400
committerGreg Hudson <ghudson@mit.edu>2013-08-15 14:30:29 -0400
commit7c48819629390927c89f13e2f6c976dc9a2d0ff6 (patch)
tree54c59c98cd98729b3b571130a299d03fb08d9257 /src/lib/krb5
parent2721a662a3d88601bff991599928c1566be7485a (diff)
downloadkrb5-7c48819629390927c89f13e2f6c976dc9a2d0ff6.tar.gz
krb5-7c48819629390927c89f13e2f6c976dc9a2d0ff6.tar.xz
krb5-7c48819629390927c89f13e2f6c976dc9a2d0ff6.zip
Use dry-run unparses in keyring ccache
Support credentials larger than 4K in cc_keyring.c by calculating the payload size in one pass, allocating a buffer of precisely the right size, and then unparsing into that buffer. [ghudson@mit.edu: squashed two commits; rewrote message; added length field instead of doing pointer arithmetic on null pointers; used proper English comments and clarified what code they apply to.]
Diffstat (limited to 'src/lib/krb5')
-rw-r--r--src/lib/krb5/ccache/cc_keyring.c118
1 files changed, 78 insertions, 40 deletions
diff --git a/src/lib/krb5/ccache/cc_keyring.c b/src/lib/krb5/ccache/cc_keyring.c
index 9c04415ce2..8b376e6fd0 100644
--- a/src/lib/krb5/ccache/cc_keyring.c
+++ b/src/lib/krb5/ccache/cc_keyring.c
@@ -142,7 +142,7 @@ debug_print(char *fmt, ...)
#define KRB5_OK 0
/* Hopefully big enough to hold a serialized credential */
-#define GUESS_CRED_SIZE 4096
+#define MAX_CRED_SIZE (1024*1024)
#define CHECK_N_GO(ret, errdest) if (ret != KRB5_OK) goto errdest
#define CHECK(ret) if (ret != KRB5_OK) goto errout
@@ -185,6 +185,7 @@ typedef struct _krb5_krcc_buffer_cursor
{
char *bpp;
char *endp;
+ size_t size; /* For dry-run length calculation */
} krb5_krcc_bc;
/* Global mutex */
@@ -303,9 +304,11 @@ static krb5_error_code krb5_krcc_parse_ui_2
/* Routines to unparse a cred structure into keyring key */
static krb5_error_code krb5_krcc_unparse
(krb5_context, krb5_pointer buf, unsigned int len, krb5_krcc_bc * bc);
-static krb5_error_code krb5_krcc_unparse_cred
+static krb5_error_code krb5_krcc_unparse_cred_alloc
(krb5_context context, krb5_creds * creds,
char **datapp, unsigned int *lenptr);
+static krb5_error_code krb5_krcc_unparse_cred
+(krb5_context context, krb5_creds * creds, krb5_krcc_bc * bc);
static krb5_error_code krb5_krcc_unparse_principal
(krb5_context, krb5_principal princ, krb5_krcc_bc * bc);
static krb5_error_code krb5_krcc_unparse_keyblock
@@ -1009,7 +1012,7 @@ krb5_krcc_store(krb5_context context, krb5_ccache id, krb5_creds * creds)
}
/* Serialize credential into memory */
- kret = krb5_krcc_unparse_cred(context, creds, &payload, &payloadlen);
+ kret = krb5_krcc_unparse_cred_alloc(context, creds, &payload, &payloadlen);
if (kret != KRB5_OK)
goto errout;
@@ -1075,7 +1078,7 @@ krb5_krcc_save_principal(krb5_context context, krb5_ccache id,
{
krb5_krcc_data *d;
krb5_error_code kret;
- char *payload;
+ char *payload = NULL;
key_serial_t newkey;
unsigned int payloadsize;
krb5_krcc_bc bc;
@@ -1084,13 +1087,18 @@ krb5_krcc_save_principal(krb5_context context, krb5_ccache id,
d = (krb5_krcc_data *) id->data;
- payload = malloc(GUESS_CRED_SIZE);
+ /* Do a dry run first to calculate the size. */
+ bc.bpp = bc.endp = NULL;
+ bc.size = 0;
+ kret = krb5_krcc_unparse_principal(context, princ, &bc);
+ CHECK_N_GO(kret, errout);
+
+ /* Allocate a buffer and serialize for real. */
+ payload = malloc(bc.size);
if (payload == NULL)
return KRB5_CC_NOMEM;
-
bc.bpp = payload;
- bc.endp = payload + GUESS_CRED_SIZE;
-
+ bc.endp = payload + bc.size;
kret = krb5_krcc_unparse_principal(context, princ, &bc);
CHECK_N_GO(kret, errout);
@@ -1688,6 +1696,12 @@ static krb5_error_code
krb5_krcc_unparse(krb5_context context, krb5_pointer buf, unsigned int len,
krb5_krcc_bc * bc)
{
+ if (bc->bpp == NULL) {
+ /* This is a dry run; just increase size and return. */
+ bc->size += len;
+ return KRB5_OK;
+ }
+
if (bc->bpp + len > bc->endp)
return KRB5_CC_WRITE;
@@ -1888,54 +1902,78 @@ krb5_krcc_unparse_ui_2(krb5_context context, krb5_int32 i, krb5_krcc_bc * bc)
*/
static krb5_error_code
krb5_krcc_unparse_cred(krb5_context context, krb5_creds * creds,
- char **datapp, unsigned int *lenptr)
+ krb5_krcc_bc *bc)
{
krb5_error_code kret;
- char *buf = NULL;
- krb5_krcc_bc bc;
- if (!creds || !datapp || !lenptr)
- return EINVAL;
+ kret = krb5_krcc_unparse_principal(context, creds->client, bc);
+ CHECK_OUT(kret);
- *datapp = NULL;
- *lenptr = 0;
+ kret = krb5_krcc_unparse_principal(context, creds->server, bc);
+ CHECK_OUT(kret);
- buf = malloc(GUESS_CRED_SIZE);
- if (buf == NULL)
- return KRB5_CC_NOMEM;
+ kret = krb5_krcc_unparse_keyblock(context, &creds->keyblock, bc);
+ CHECK_OUT(kret);
- bc.bpp = buf;
- bc.endp = buf + GUESS_CRED_SIZE;
+ kret = krb5_krcc_unparse_times(context, &creds->times, bc);
+ CHECK_OUT(kret);
- kret = krb5_krcc_unparse_principal(context, creds->client, &bc);
- CHECK_N_GO(kret, errout);
+ kret = krb5_krcc_unparse_octet(context, (krb5_int32) creds->is_skey, bc);
+ CHECK_OUT(kret);
- kret = krb5_krcc_unparse_principal(context, creds->server, &bc);
- CHECK_N_GO(kret, errout);
+ kret = krb5_krcc_unparse_int32(context, creds->ticket_flags, bc);
+ CHECK_OUT(kret);
- kret = krb5_krcc_unparse_keyblock(context, &creds->keyblock, &bc);
- CHECK_N_GO(kret, errout);
+ kret = krb5_krcc_unparse_addrs(context, creds->addresses, bc);
+ CHECK_OUT(kret);
- kret = krb5_krcc_unparse_times(context, &creds->times, &bc);
- CHECK_N_GO(kret, errout);
+ kret = krb5_krcc_unparse_authdata(context, creds->authdata, bc);
+ CHECK_OUT(kret);
- kret = krb5_krcc_unparse_octet(context, (krb5_int32) creds->is_skey, &bc);
- CHECK_N_GO(kret, errout);
+ kret = krb5_krcc_unparse_krb5data(context, &creds->ticket, bc);
+ CHECK_OUT(kret);
+ CHECK(kret);
- kret = krb5_krcc_unparse_int32(context, creds->ticket_flags, &bc);
- CHECK_N_GO(kret, errout);
+ kret = krb5_krcc_unparse_krb5data(context, &creds->second_ticket, bc);
+ CHECK_OUT(kret);
- kret = krb5_krcc_unparse_addrs(context, creds->addresses, &bc);
- CHECK_N_GO(kret, errout);
+ /* Success! */
+ kret = KRB5_OK;
- kret = krb5_krcc_unparse_authdata(context, creds->authdata, &bc);
- CHECK_N_GO(kret, errout);
+errout:
+ return kret;
+}
- kret = krb5_krcc_unparse_krb5data(context, &creds->ticket, &bc);
- CHECK_N_GO(kret, errout);
+static krb5_error_code
+krb5_krcc_unparse_cred_alloc(krb5_context context, krb5_creds * creds,
+ char **datapp, unsigned int *lenptr)
+{
+ krb5_error_code kret;
+ char *buf = NULL;
+ krb5_krcc_bc bc;
- kret = krb5_krcc_unparse_krb5data(context, &creds->second_ticket, &bc);
- CHECK_N_GO(kret, errout);
+ if (!creds || !datapp || !lenptr)
+ return EINVAL;
+
+ *datapp = NULL;
+ *lenptr = 0;
+
+ /* Do a dry run first to calculate the size. */
+ bc.bpp = bc.endp = NULL;
+ bc.size = 0;
+ kret = krb5_krcc_unparse_cred(context, creds, &bc);
+ CHECK(kret);
+ if (bc.size > MAX_CRED_SIZE)
+ return KRB5_CC_WRITE;
+
+ /* Allocate a buffer and unparse for real. */
+ buf = malloc(bc.size);
+ if (buf == NULL)
+ return KRB5_CC_NOMEM;
+ bc.bpp = buf;
+ bc.endp = buf + bc.size;
+ kret = krb5_krcc_unparse_cred(context, creds, &bc);
+ CHECK(kret);
/* Success! */
*datapp = buf;