diff options
author | Volker Lendecke <vlendec@samba.org> | 2004-04-01 12:31:50 +0000 |
---|---|---|
committer | Volker Lendecke <vlendec@samba.org> | 2004-04-01 12:31:50 +0000 |
commit | 56e7c149babcf41e5c510104a8e0cdca56f227f0 (patch) | |
tree | 17e87dc5db42586bd072db1b47bc2ae11dcf1c30 /source3/lib | |
parent | e2f355c7eae4f1fda705cc223575193535b91da5 (diff) | |
download | samba-56e7c149babcf41e5c510104a8e0cdca56f227f0.tar.gz samba-56e7c149babcf41e5c510104a8e0cdca56f227f0.tar.xz samba-56e7c149babcf41e5c510104a8e0cdca56f227f0.zip |
This restructures lib/afs.c so that the token data can be but into a
stream. This is to implement wbinfo -k that asks winbind for authentication
which then creates the AFS token for the authenticated user.
Volker
(This used to be commit 2df6750a079820826013360fb9e47f90bc8223a5)
Diffstat (limited to 'source3/lib')
-rw-r--r-- | source3/lib/afs.c | 361 |
1 files changed, 294 insertions, 67 deletions
diff --git a/source3/lib/afs.c b/source3/lib/afs.c index 789afcdd837..ce972ec27b7 100644 --- a/source3/lib/afs.c +++ b/source3/lib/afs.c @@ -43,6 +43,130 @@ struct ClearToken { uint32 EndTimestamp; }; +static char *afs_encode_token(const char *cell, const DATA_BLOB ticket, + const struct ClearToken *ct) +{ + char *base64_ticket; + char *result; + + DATA_BLOB key = data_blob(ct->HandShakeKey, 8); + char *base64_key; + + base64_ticket = base64_encode_data_blob(ticket); + if (base64_ticket == NULL) + return NULL; + + base64_key = base64_encode_data_blob(key); + if (base64_key == NULL) { + free(base64_ticket); + return NULL; + } + + asprintf(&result, "%s\n%u\n%s\n%u\n%u\n%u\n%s\n", cell, + ct->AuthHandle, base64_key, ct->ViceId, ct->BeginTimestamp, + ct->EndTimestamp, base64_ticket); + + DEBUG(10, ("Got ticket string:\n%s\n", result)); + + free(base64_ticket); + free(base64_key); + + return result; +} + +static BOOL afs_decode_token(const char *string, char **cell, + DATA_BLOB *ticket, struct ClearToken *ct) +{ + DATA_BLOB blob; + struct ClearToken result_ct; + + char *s = strdup(string); + + char *t; + + if ((t = strtok(s, "\n")) == NULL) { + DEBUG(10, ("strtok failed\n")); + return False; + } + + *cell = strdup(t); + + if ((t = strtok(NULL, "\n")) == NULL) { + DEBUG(10, ("strtok failed\n")); + return False; + } + + if (sscanf(t, "%u", &result_ct.AuthHandle) != 1) { + DEBUG(10, ("sscanf AuthHandle failed\n")); + return False; + } + + if ((t = strtok(NULL, "\n")) == NULL) { + DEBUG(10, ("strtok failed\n")); + return False; + } + + blob = base64_decode_data_blob(t); + + if ( (blob.data == NULL) || + (blob.length != sizeof(result_ct.HandShakeKey) )) { + DEBUG(10, ("invalid key: %x/%d\n", (uint32)blob.data, + blob.length)); + return False; + } + + memcpy(result_ct.HandShakeKey, blob.data, blob.length); + + data_blob_free(&blob); + + if ((t = strtok(NULL, "\n")) == NULL) { + DEBUG(10, ("strtok failed\n")); + return False; + } + + if (sscanf(t, "%u", &result_ct.ViceId) != 1) { + DEBUG(10, ("sscanf ViceId failed\n")); + return False; + } + + if ((t = strtok(NULL, "\n")) == NULL) { + DEBUG(10, ("strtok failed\n")); + return False; + } + + if (sscanf(t, "%u", &result_ct.BeginTimestamp) != 1) { + DEBUG(10, ("sscanf BeginTimestamp failed\n")); + return False; + } + + if ((t = strtok(NULL, "\n")) == NULL) { + DEBUG(10, ("strtok failed\n")); + return False; + } + + if (sscanf(t, "%u", &result_ct.EndTimestamp) != 1) { + DEBUG(10, ("sscanf EndTimestamp failed\n")); + return False; + } + + if ((t = strtok(NULL, "\n")) == NULL) { + DEBUG(10, ("strtok failed\n")); + return False; + } + + blob = base64_decode_data_blob(t); + + if (blob.data == NULL) { + DEBUG(10, ("Could not get ticket\n")); + return False; + } + + *ticket = blob; + *ct = result_ct; + + return True; +} + /* Put an AFS token into the Kernel so that it can authenticate against the AFS server. This assumes correct local uid settings. @@ -53,9 +177,9 @@ struct ClearToken { to avoid. */ -static BOOL afs_settoken(const char *username, const char *cell, +static BOOL afs_settoken(const char *cell, const struct ClearToken *ctok, - char *v4tkt_data, int v4tkt_length) + DATA_BLOB ticket) { int ret; struct { @@ -67,10 +191,10 @@ static BOOL afs_settoken(const char *username, const char *cell, char *p = buf; int tmp; - memcpy(p, &v4tkt_length, sizeof(uint32)); + memcpy(p, &ticket.length, sizeof(uint32)); p += sizeof(uint32); - memcpy(p, v4tkt_data, v4tkt_length); - p += v4tkt_length; + memcpy(p, ticket.data, ticket.length); + p += ticket.length; tmp = sizeof(struct ClearToken); memcpy(p, &tmp, sizeof(uint32)); @@ -109,90 +233,69 @@ static BOOL afs_settoken(const char *username, const char *cell, return (ret == 0); } -/* - This routine takes a radical approach completely defeating the - Kerberos idea of security and using AFS simply as an intelligent - file backend. Samba has persuaded itself somehow that the user is - actually correctly identified and then we create a ticket that the - AFS server hopefully accepts using its KeyFile that the admin has - kindly stored to our secrets.tdb. - - Thanks to the book "Network Security -- PRIVATE Communication in a - PUBLIC World" by Charlie Kaufman, Radia Perlman and Mike Speciner - Kerberos 4 tickets are not really hard to construct. - - For the comments "Alice" is the User to be auth'ed, and "Bob" is the - AFS server. */ - -BOOL afs_login(connection_struct *conn) +BOOL afs_settoken_str(const char *token_string) { - fstring ticket; - char *p = ticket; - uint32 len; - struct afs_key key; - pstring afs_username; - char *cell; - + DATA_BLOB ticket; struct ClearToken ct; + BOOL result; + char *cell; - uint32 now; /* I assume time() returns 32 bit */ + if (!afs_decode_token(token_string, &cell, &ticket, &ct)) + return False; - des_key_schedule key_schedule; + if (geteuid() != 0) + ct.ViceId = getuid(); - pstrcpy(afs_username, lp_afs_username_map()); - standard_sub_conn(conn, afs_username, sizeof(afs_username)); + result = afs_settoken(cell, &ct, ticket); - /* The pts command always generates completely lower-case user - * names. */ - strlower_m(afs_username); + SAFE_FREE(cell); + data_blob_free(&ticket); - cell = strchr(afs_username, '@'); - - if (cell == NULL) { - DEBUG(1, ("AFS username doesn't contain a @, " - "could not find cell\n")); - return False; + return result; } - *cell = '\0'; - cell += 1; +/* Create a ClearToken and an encrypted ticket. ClearToken has not yet the + * ViceId set, this should be set by the caller. */ - DEBUG(10, ("Trying to log into AFS for user %s@%s\n", - afs_username, cell)); +static BOOL afs_createtoken(const char *username, const char *cell, + DATA_BLOB *ticket, struct ClearToken *ct) +{ + fstring clear_ticket; + char *p = clear_ticket; + uint32 len; + uint32 now; + + struct afs_key key; + des_key_schedule key_schedule; if (!secrets_init()) return False; if (!secrets_fetch_afs_key(cell, &key)) { - DEBUG(5, ("Could not fetch AFS service key\n")); + DEBUG(1, ("Could not fetch AFS service key\n")); return False; } - ct.AuthHandle = key.kvno; + ct->AuthHandle = key.kvno; /* Build the ticket. This is going to be encrypted, so in our way we fill in ct while we still have the unencrypted form. */ - p = ticket; + p = clear_ticket; /* The byte-order */ *p = 1; p += 1; /* "Alice", the client username */ - strncpy(p, afs_username, sizeof(ticket)-PTR_DIFF(p,ticket)-1); + strncpy(p, username, sizeof(clear_ticket)-PTR_DIFF(p,clear_ticket)-1); p += strlen(p)+1; - strncpy(p, "", sizeof(ticket)-PTR_DIFF(p,ticket)-1); + strncpy(p, "", sizeof(clear_ticket)-PTR_DIFF(p,clear_ticket)-1); p += strlen(p)+1; - strncpy(p, cell, sizeof(ticket)-PTR_DIFF(p,ticket)-1); + strncpy(p, cell, sizeof(clear_ticket)-PTR_DIFF(p,clear_ticket)-1); p += strlen(p)+1; - /* This assumes that we have setresuid and set the real uid as well as - the effective uid in set_effective_uid(). */ - ct.ViceId = getuid(); - DEBUG(10, ("Creating Token for uid %d\n", ct.ViceId)); - /* Alice's network layer address. At least Openafs-1.2.10 ignores this, so we fill in a dummy value here. */ SIVAL(p, 0, 0); @@ -203,7 +306,7 @@ BOOL afs_login(connection_struct *conn) /* Our client code needs the the key in the clear, it does not know the server-key ... */ - memcpy(ct.HandShakeKey, p, 8); + memcpy(ct->HandShakeKey, p, 8); p += 8; @@ -216,37 +319,151 @@ BOOL afs_login(connection_struct *conn) /* Ticket creation time */ now = time(NULL); SIVAL(p, 0, now); - ct.BeginTimestamp = now; + ct->BeginTimestamp = now; - ct.EndTimestamp = now + (255*60*5); - if (((ct.EndTimestamp - ct.BeginTimestamp) & 1) == 1) { - ct.BeginTimestamp += 1; /* Lifetime must be even */ + ct->EndTimestamp = now + (255*60*5); + if (((ct->EndTimestamp - ct->BeginTimestamp) & 1) == 1) { + ct->BeginTimestamp += 1; /* Lifetime must be even */ } p += 4; /* And here comes Bob's name and instance, in this case the AFS server. */ - strncpy(p, "afs", sizeof(ticket)-PTR_DIFF(p,ticket)-1); + strncpy(p, "afs", sizeof(clear_ticket)-PTR_DIFF(p,clear_ticket)-1); p += strlen(p)+1; - strncpy(p, "", sizeof(ticket)-PTR_DIFF(p,ticket)-1); + strncpy(p, "", sizeof(clear_ticket)-PTR_DIFF(p,clear_ticket)-1); p += strlen(p)+1; /* And zero-pad to a multiple of 8 bytes */ - len = PTR_DIFF(p, ticket); + len = PTR_DIFF(p, clear_ticket); if (len & 7) { uint32 extra_space = 8-(len & 7); memset(p, 0, extra_space); p+=extra_space; } - len = PTR_DIFF(p, ticket); + len = PTR_DIFF(p, clear_ticket); des_key_sched((const_des_cblock *)key.key, key_schedule); - des_pcbc_encrypt(ticket, ticket, + des_pcbc_encrypt(clear_ticket, clear_ticket, len, key_schedule, (C_Block *)key.key, 1); ZERO_STRUCT(key); - return afs_settoken(afs_username, cell, &ct, ticket, len); + *ticket = data_blob(clear_ticket, len); + + return True; +} + +char *afs_createtoken_str(const char *username, const char *cell) +{ + DATA_BLOB ticket; + struct ClearToken ct; + char *result; + + if (!afs_createtoken(username, cell, &ticket, &ct)) + return NULL; + + result = afs_encode_token(cell, ticket, &ct); + + data_blob_free(&ticket); + + return result; +} + +/* + This routine takes a radical approach completely bypassing the + Kerberos idea of security and using AFS simply as an intelligent + file backend. Samba has persuaded itself somehow that the user is + actually correctly identified and then we create a ticket that the + AFS server hopefully accepts using its KeyFile that the admin has + kindly stored to our secrets.tdb. + + Thanks to the book "Network Security -- PRIVATE Communication in a + PUBLIC World" by Charlie Kaufman, Radia Perlman and Mike Speciner + Kerberos 4 tickets are not really hard to construct. + + For the comments "Alice" is the User to be auth'ed, and "Bob" is the + AFS server. */ + +BOOL afs_login(connection_struct *conn) +{ + DATA_BLOB ticket; + pstring afs_username; + char *cell; + BOOL result; + + struct ClearToken ct; + + pstrcpy(afs_username, lp_afs_username_map()); + standard_sub_conn(conn, afs_username, sizeof(afs_username)); + + /* The pts command always generates completely lower-case user + * names. */ + strlower_m(afs_username); + + cell = strchr(afs_username, '@'); + + if (cell == NULL) { + DEBUG(1, ("AFS username doesn't contain a @, " + "could not find cell\n")); + return False; + } + + *cell = '\0'; + cell += 1; + + DEBUG(10, ("Trying to log into AFS for user %s@%s\n", + afs_username, cell)); + + if (!afs_createtoken(afs_username, cell, &ticket, &ct)) + return False; + + /* For which Unix-UID do we want to set the token? */ + ct.ViceId = getuid(); + + { + char *str, *new_cell; + DATA_BLOB test_ticket; + struct ClearToken test_ct; + + hex_encode(ct.HandShakeKey, sizeof(ct.HandShakeKey), &str); + DEBUG(10, ("Key: %s\n", str)); + free(str); + + str = afs_encode_token(cell, ticket, &ct); + + if (!afs_decode_token(str, &new_cell, &test_ticket, + &test_ct)) { + DEBUG(0, ("Could not decode token")); + goto decode_failed; + } + + if (strcmp(cell, new_cell) != 0) { + DEBUG(0, ("cell changed\n")); + } + + if ((ticket.length != test_ticket.length) || + (memcmp(ticket.data, test_ticket.data, + ticket.length) != 0)) { + DEBUG(0, ("Ticket changed\n")); + } + + if (memcmp(&ct, &test_ct, sizeof(ct)) != 0) { + DEBUG(0, ("ClearToken changed\n")); + } + + data_blob_free(&test_ticket); + + decode_failed: + SAFE_FREE(str); + SAFE_FREE(new_cell); + } + + result = afs_settoken(cell, &ct, ticket); + + data_blob_free(&ticket); + + return result; } #else @@ -256,4 +473,14 @@ BOOL afs_login(connection_struct *conn) return True; } +BOOL afs_settoken_str(const char *token_string) +{ + return False; +} + +char *afs_createtoken_str(const char *username, const char *cell) +{ + return False; +} + #endif /* WITH_FAKE_KASERVER */ |