*
* 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 2 of the License, or
+ * 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,
* 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, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include "includes.h"
#ifdef WITH_FAKE_KASERVER
+#define NO_ASN1_TYPEDEFS 1
+
#include <afs/stds.h>
#include <afs/afs.h>
#include <afs/auth.h>
#include <asm/unistd.h>
#include <openssl/des.h>
-_syscall5(int, afs_syscall, int, subcall,
- char *, path,
- int, cmd,
- char *, cmarg,
- int, follow);
-
struct ClearToken {
uint32 AuthHandle;
char HandShakeKey[8];
uint32 EndTimestamp;
};
-/*
- Put an AFS token into the Kernel so that it can authenticate against
- the AFS server. This assumes correct local uid settings.
-
- This is currently highly Linux and OpenAFS-specific. The correct API
- call for this would be ktc_SetToken. But to do that we would have to
- import a REALLY big bunch of libraries which I would currently like
- to avoid.
-*/
-
-static BOOL afs_settoken(const char *username, const char *cell,
- const struct ClearToken *ctok,
- char *v4tkt_data, int v4tkt_length)
+static char *afs_encode_token(const char *cell, const DATA_BLOB ticket,
+ const struct ClearToken *ct)
{
- int ret;
- struct {
- char *in, *out;
- uint16 in_size, out_size;
- } iob;
-
- char buf[1024];
- char *p = buf;
- int tmp;
-
- memcpy(p, &v4tkt_length, sizeof(uint32));
- p += sizeof(uint32);
- memcpy(p, v4tkt_data, v4tkt_length);
- p += v4tkt_length;
-
- tmp = sizeof(struct ClearToken);
- memcpy(p, &tmp, sizeof(uint32));
- p += sizeof(uint32);
- memcpy(p, ctok, tmp);
- p += tmp;
-
- tmp = 0;
-
- memcpy(p, &tmp, sizeof(uint32));
- p += sizeof(uint32);
-
- tmp = strlen(cell);
- if (tmp >= MAXKTCREALMLEN) {
- DEBUG(1, ("Realm too long\n"));
- return False;
- }
+ char *base64_ticket;
+ char *result = NULL;
- strncpy(p, cell, tmp);
- p += tmp;
- *p = 0;
- p +=1;
+ DATA_BLOB key = data_blob(ct->HandShakeKey, 8);
+ char *base64_key;
+ TALLOC_CTX *mem_ctx;
- iob.in = buf;
- iob.in_size = PTR_DIFF(p,buf);
- iob.out = buf;
- iob.out_size = sizeof(buf);
+ mem_ctx = talloc_init("afs_encode_token");
+ if (mem_ctx == NULL)
+ goto done;
-#if 0
- file_save("/tmp/ioctlbuf", iob.in, iob.in_size);
-#endif
+ base64_ticket = base64_encode_data_blob(mem_ctx, ticket);
+ if (base64_ticket == NULL)
+ goto done;
- ret = afs_syscall(AFSCALL_PIOCTL, 0, VIOCSETTOK, (char *)&iob, 0);
+ base64_key = base64_encode_data_blob(mem_ctx, key);
+ if (base64_key == NULL)
+ goto done;
- DEBUG(10, ("afs VIOCSETTOK returned %d\n", ret));
- return (ret == 0);
-}
+ 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);
-/*
- 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.
+ DEBUG(10, ("Got ticket string:\n%s\n", result));
- 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.
+done:
+ TALLOC_FREE(mem_ctx);
- For the comments "Alice" is the User to be auth'ed, and "Bob" is the
- AFS server. */
+ return result;
+}
+
+/* Create a ClearToken and an encrypted ticket. ClearToken has not yet the
+ * ViceId set, this should be set by the caller. */
-BOOL afs_login(connection_struct *conn)
+static bool afs_createtoken(const char *username, const char *cell,
+ DATA_BLOB *ticket, struct ClearToken *ct)
{
- fstring ticket;
- char *p = ticket;
+ fstring clear_ticket;
+ char *p = clear_ticket;
uint32 len;
- struct afs_key key;
- pstring afs_username;
- char *cell;
-
- struct ClearToken ct;
-
- uint32 now; /* I assume time() returns 32 bit */
+ uint32 now;
+ struct afs_key key;
des_key_schedule key_schedule;
- pstrcpy(afs_username, lp_afs_username_map());
- standard_sub_conn(conn, afs_username, sizeof(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;
- strlower_m(cell);
-
- DEBUG(10, ("Trying to log into AFS for user %s@%s\n",
- afs_username, cell));
-
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);
p += 4;
/* We need to create a session key */
- generate_random_buffer(p, 8, False);
+ generate_random_buffer(p, 8);
/* 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;
- /* Ticket lifetime. We fake everything here, so go as long as
- possible. This is in 5-minute intervals, so 255 is 21 hours
- and 15 minutes.*/
+ /* 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;
+ ct->BeginTimestamp = now;
+
+ if(lp_afs_token_lifetime() == 0)
+ ct->EndTimestamp = NEVERDATE;
+ else
+ ct->EndTimestamp = now + lp_afs_token_lifetime();
- ct.EndTimestamp = now + (255*60*5);
- if (((ct.EndTimestamp - ct.BeginTimestamp) & 1) == 1) {
- ct.BeginTimestamp += 1; /* Lifetime must be even */
+ 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)
+{
+ extern userdom_struct current_user_info;
+ extern struct current_user current_user;
+ DATA_BLOB ticket;
+ char *afs_username = NULL;
+ char *cell = NULL;
+ bool result;
+ char *ticket_str = NULL;
+ const DOM_SID *user_sid;
+ TALLOC_CTX *ctx = talloc_tos();
+
+ struct ClearToken ct;
+
+ afs_username = talloc_strdup(ctx,
+ lp_afs_username_map());
+ if (!afs_username) {
+ return false;
+ }
+
+ afs_username = talloc_sub_advanced(ctx,
+ SNUM(conn), conn->user,
+ conn->connectpath, conn->gid,
+ get_current_username(),
+ current_user_info.domain,
+ afs_username);
+ if (!afs_username) {
+ return false;
+ }
+
+ user_sid = ¤t_user.nt_user_token->user_sids[0];
+ afs_username = talloc_string_sub(talloc_tos(),
+ afs_username,
+ "%s",
+ sid_string_tos(user_sid));
+ if (!afs_username) {
+ return false;
+ }
+
+ /* 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();
+
+ 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)
+bool afs_login(connection_struct *conn)
{
return True;
}
+char *afs_createtoken_str(const char *username, const char *cell)
+{
+ return False;
+}
+
#endif /* WITH_FAKE_KASERVER */