diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 17:20:00 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 17:20:00 +0000 |
commit | 8daa83a594a2e98f39d764422bfbdbc62c9efd44 (patch) | |
tree | 4099e8021376c7d8c05bdf8503093d80e9c7bad0 /lib/afs/afs_funcs.c | |
parent | Initial commit. (diff) | |
download | samba-8daa83a594a2e98f39d764422bfbdbc62c9efd44.tar.xz samba-8daa83a594a2e98f39d764422bfbdbc62c9efd44.zip |
Adding upstream version 2:4.20.0+dfsg.upstream/2%4.20.0+dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'lib/afs/afs_funcs.c')
-rw-r--r-- | lib/afs/afs_funcs.c | 313 |
1 files changed, 313 insertions, 0 deletions
diff --git a/lib/afs/afs_funcs.c b/lib/afs/afs_funcs.c new file mode 100644 index 0000000..4360f54 --- /dev/null +++ b/lib/afs/afs_funcs.c @@ -0,0 +1,313 @@ +/* + * Unix SMB/CIFS implementation. + * Generate AFS tickets + * Copyright (C) Volker Lendecke 2003 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "includes.h" +#include "lib/afs/afs_funcs.h" + +#ifdef WITH_FAKE_KASERVER + +#define NO_ASN1_TYPEDEFS 1 + +#include "secrets.h" +#include "passdb.h" +#include "auth.h" +#include "../librpc/gen_ndr/ndr_netlogon.h" +#include "lib/afs/afs_settoken.h" + +#include <afs/param.h> +#include <afs/stds.h> +#include <afs/auth.h> +#include <afs/venus.h> +#include <asm/unistd.h> +#include <openssl/des.h> + +struct ClearToken { + uint32 AuthHandle; + char HandShakeKey[8]; + uint32 ViceId; + uint32 BeginTimestamp; + uint32 EndTimestamp; +}; + +static char *afs_encode_token(const char *cell, const DATA_BLOB ticket, + const struct ClearToken *ct) +{ + char *base64_ticket; + char *result = NULL; + + DATA_BLOB key = data_blob(ct->HandShakeKey, 8); + char *base64_key; + TALLOC_CTX *mem_ctx; + + mem_ctx = talloc_stackframe(); + if (mem_ctx == NULL) + goto done; + + base64_ticket = base64_encode_data_blob(mem_ctx, ticket); + if (base64_ticket == NULL) + goto done; + + base64_key = base64_encode_data_blob(mem_ctx, key); + if (base64_key == NULL) + goto done; + + 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)); + +done: + TALLOC_FREE(mem_ctx); + + return result; +} + +/* Create a ClearToken and an encrypted ticket. ClearToken has not yet the + * ViceId set, this should be set by the caller. */ + +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(1, ("Could not fetch AFS service key\n")); + return false; + } + + 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 = clear_ticket; + + /* The byte-order */ + *p = 1; + p += 1; + + /* "Alice", the client username */ + strncpy(p, username, sizeof(clear_ticket)-PTR_DIFF(p,clear_ticket)-1); + p += strlen(p)+1; + strncpy(p, "", sizeof(clear_ticket)-PTR_DIFF(p,clear_ticket)-1); + p += strlen(p)+1; + strncpy(p, cell, sizeof(clear_ticket)-PTR_DIFF(p,clear_ticket)-1); + p += strlen(p)+1; + + /* 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); + p += 4; + + /* We need to create a session key */ + generate_random_buffer((uint8_t *)p, 8); + + /* Our client code needs the the key in the clear, it does not + know the server-key ... */ + memcpy(ct->HandShakeKey, p, 8); + + p += 8; + + /* This is a kerberos 4 life time. The life time is expressed + * in units of 5 minute intervals up to 38400 seconds, after + * that a table is used up to lifetime 0xBF. Values between + * 0xC0 and 0xFF is undefined. 0xFF is defined to be the + * infinite time that never expire. + * + * So here we cheat and use the infinite time */ + *p = 255; + p += 1; + + /* Ticket creation time */ + now = time(NULL); + SIVAL(p, 0, now); + ct->BeginTimestamp = now; + + if(lp_afs_token_lifetime() == 0) + ct->EndTimestamp = NEVERDATE; + else + ct->EndTimestamp = now + lp_afs_token_lifetime(); + + 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(clear_ticket)-PTR_DIFF(p,clear_ticket)-1); + p += strlen(p)+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, clear_ticket); + if (len & 7) { + uint32 extra_space = 8-(len & 7); + memset(p, 0, extra_space); + p+=extra_space; + } + len = PTR_DIFF(p, clear_ticket); + + des_key_sched((const_des_cblock *)key.key, key_schedule); + des_pcbc_encrypt((const unsigned char*) clear_ticket, + (unsigned char*) clear_ticket, + len, key_schedule, (C_Block *)key.key, 1); + + ZERO_STRUCT(key); + + *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) +{ + const struct loadparm_substitution *lp_sub = + loadparm_s3_global_substitution(); + DATA_BLOB ticket; + char *afs_username = NULL; + char *cell = NULL; + bool result; + char *ticket_str = NULL; + const struct dom_sid *user_sid; + TALLOC_CTX *ctx = talloc_tos(); + struct dom_sid_buf buf; + + struct ClearToken ct; + + afs_username = talloc_strdup(ctx, + lp_afs_username_map()); + if (!afs_username) { + return false; + } + + afs_username = talloc_sub_advanced(ctx, + lp_servicename(ctx, lp_sub, SNUM(conn)), + conn->session_info->unix_info->unix_name, + conn->connectpath, + conn->session_info->unix_token->gid, + conn->session_info->unix_info->sanitized_username, + conn->session_info->info->domain_name, + afs_username); + if (!afs_username) { + return false; + } + + user_sid = &conn->session_info->security_token->sids[PRIMARY_USER_SID_INDEX]; + afs_username = talloc_string_sub(talloc_tos(), + afs_username, + "%s", + dom_sid_str_buf(user_sid, &buf)); + if (!afs_username) { + return false; + } + + /* The pts command always generates completely lower-case user + * names. */ + if (!strlower_m(afs_username)) { + return false; + } + + 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(); + + ticket_str = afs_encode_token(cell, ticket, &ct); + + result = afs_settoken_str(ticket_str); + + SAFE_FREE(ticket_str); + + data_blob_free(&ticket); + + return result; +} + +#else + +bool afs_login(connection_struct *conn) +{ + return true; +} + +char *afs_createtoken_str(const char *username, const char *cell) +{ + return NULL; +} + +#endif /* WITH_FAKE_KASERVER */ |