summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/Makefile.in4
-rw-r--r--source3/configure.in16
-rw-r--r--source3/include/secrets.h17
-rw-r--r--source3/lib/afs.c248
-rw-r--r--source3/passdb/secrets.c53
-rw-r--r--source3/smbd/service.c4
-rw-r--r--source3/utils/net.c47
-rw-r--r--source3/utils/net_help.c3
8 files changed, 390 insertions, 2 deletions
diff --git a/source3/Makefile.in b/source3/Makefile.in
index 00b98e79b2..f79af7cb4e 100644
--- a/source3/Makefile.in
+++ b/source3/Makefile.in
@@ -347,7 +347,7 @@ SMBD_OBJ_SRV = smbd/files.o smbd/chgpasswd.o smbd/connection.o \
smbd/process.o smbd/service.o smbd/error.o \
printing/printfsp.o lib/util_seaccess.o \
lib/sysquotas.o smbd/change_trust_pw.o smbd/fake_file.o \
- smbd/quotas.o smbd/ntquotas.o \
+ smbd/quotas.o smbd/ntquotas.o lib/afs.o \
$(MANGLE_OBJ) @VFS_STATIC@
SMBD_OBJ_BASE = $(PARAM_OBJ) $(SMBD_OBJ_SRV) $(MSDFS_OBJ) $(LIBSMB_OBJ) \
@@ -492,7 +492,7 @@ NET_OBJ = $(NET_OBJ1) $(PARAM_OBJ) $(SECRETS_OBJ) $(LIBSMB_OBJ) \
$(KRBCLIENT_OBJ) $(UBIQX_OBJ) $(LIB_OBJ) \
$(LIBMSRPC_OBJ) $(IDMAP_OBJ) \
$(LIBADS_OBJ) $(LIBADS_SERVER_OBJ) $(POPT_LIB_OBJ) \
- $(SMBLDAP_OBJ) $(DCUTIL_OBJ) lib/dummyroot.o lib/server_mutex.o
+ $(SMBLDAP_OBJ) $(DCUTIL_OBJ) lib/dummyroot.o lib/server_mutex.o lib/afs.o
CUPS_OBJ = client/smbspool.o $(PARAM_OBJ) $(LIBSMB_OBJ) $(UBIQX_OBJ) \
$(LIB_OBJ) $(KRBCLIENT_OBJ) $(SECRETS_OBJ)
diff --git a/source3/configure.in b/source3/configure.in
index 92fdfc10cd..27eeaaeab1 100644
--- a/source3/configure.in
+++ b/source3/configure.in
@@ -2181,6 +2181,22 @@ AC_ARG_WITH(afs,
AC_MSG_RESULT(no)
)
+####################################################
+# check for Linux-specific AFS fake-kaserver support
+AC_MSG_CHECKING(whether to use AFS fake-kaserver)
+AC_ARG_WITH(fake-kaserver,
+[ --with-fake-kaserver Include AFS fake-kaserver support (default=no) ],
+[ case "$withval" in
+ yes)
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(WITH_FAKE_KASERVER,1,[Whether to include AFS fake-kaserver support])
+ ;;
+ *)
+ AC_MSG_RESULT(no)
+ ;;
+ esac ],
+ AC_MSG_RESULT(no)
+)
#################################################
# check for the DFS clear-text auth system
diff --git a/source3/include/secrets.h b/source3/include/secrets.h
index dacfef26ea..cb4fbd043a 100644
--- a/source3/include/secrets.h
+++ b/source3/include/secrets.h
@@ -77,5 +77,22 @@ typedef struct trustdom {
DOM_SID sid;
} TRUSTDOM;
+/*
+ * Format of an OpenAFS keyfile
+ */
+
+#define SECRETS_AFS_MAXKEYS 8
+
+struct afs_key {
+ uint32 kvno;
+ char key[8];
+};
+
+struct afs_keyfile {
+ uint32 nkeys;
+ struct afs_key entry[SECRETS_AFS_MAXKEYS];
+};
+
+#define SECRETS_AFS_KEYFILE "SECRETS/AFS_KEYFILE"
#endif /* _SECRETS_H */
diff --git a/source3/lib/afs.c b/source3/lib/afs.c
new file mode 100644
index 0000000000..b96703e986
--- /dev/null
+++ b/source3/lib/afs.c
@@ -0,0 +1,248 @@
+/*
+ * 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 2 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, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "includes.h"
+
+#ifdef WITH_FAKE_KASERVER
+
+#include <afs/stds.h>
+#include <afs/afs.h>
+#include <afs/auth.h>
+#include <afs/venus.h>
+#include <asm/unistd.h>
+#include <openssl/des.h>
+
+_syscall5(int, afs_syscall, int, subcall,
+ char *, path,
+ int, cmd,
+ char *, cmarg,
+ int, follow);
+
+char *afs_cell(void)
+{
+ static char *cell = NULL;
+
+ if (cell == NULL) {
+ cell = strdup(lp_realm());
+ strlower_m(cell);
+ }
+
+ return cell;
+}
+
+struct ClearToken {
+ uint32 AuthHandle;
+ char HandShakeKey[8];
+ uint32 ViceId;
+ uint32 BeginTimestamp;
+ 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(char *username, const struct ClearToken *ctok,
+ char *v4tkt_data, int v4tkt_length)
+{
+ 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(afs_cell());
+ if (tmp >= MAXKTCREALMLEN) {
+ DEBUG(1, ("Realm too long\n"));
+ return False;
+ }
+
+ strncpy(p, afs_cell(), tmp);
+ p += tmp;
+ *p = 0;
+ p +=1;
+
+ iob.in = buf;
+ iob.in_size = PTR_DIFF(p,buf);
+ iob.out = buf;
+ iob.out_size = sizeof(buf);
+
+#if 0
+ file_save("/tmp/ioctlbuf", iob.in, iob.in_size);
+#endif
+
+ ret = afs_syscall(AFSCALL_PIOCTL, 0, VIOCSETTOK, (char *)&iob, 0);
+
+ DEBUG(10, ("afs VIOCSETTOK returned %d\n", ret));
+ 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(char *username)
+{
+ fstring ticket;
+ char *p = ticket;
+ uint32 len;
+ struct afs_key key;
+
+ struct ClearToken ct;
+
+ uint32 now; /* I assume time() returns 32 bit */
+
+ des_key_schedule key_schedule;
+
+ DEBUG(10, ("Trying to log into AFS for user %s@%s\n",
+ username, afs_cell()));
+
+ if (!secrets_init())
+ return False;
+
+ if (!secrets_fetch_afs_key(afs_cell(), &key)) {
+ DEBUG(5, ("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 = ticket;
+
+ /* The byte-order */
+ *p = 1;
+ p += 1;
+
+ /* "Alice", the client username */
+ strncpy(p, username, sizeof(ticket)-PTR_DIFF(p,ticket)-1);
+ p += strlen(p)+1;
+ strncpy(p, "", sizeof(ticket)-PTR_DIFF(p,ticket)-1);
+ p += strlen(p)+1;
+ strncpy(p, afs_cell(), sizeof(ticket)-PTR_DIFF(p,ticket)-1);
+ p += strlen(p)+1;
+
+ 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);
+
+ /* Our client code needs the the key in the clear, it does not
+ know the server-key ... */
+ 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.*/
+ *p = 255;
+ p += 1;
+
+ /* Ticket creation time */
+ now = time(NULL);
+ SIVAL(p, 0, now);
+ ct.BeginTimestamp = now;
+
+ 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);
+ p += strlen(p)+1;
+ strncpy(p, "", sizeof(ticket)-PTR_DIFF(p,ticket)-1);
+ p += strlen(p)+1;
+
+ /* And zero-pad to a multiple of 8 bytes */
+ len = PTR_DIFF(p, ticket);
+ if (len & 7) {
+ uint32 extra_space = 8-(len & 7);
+ memset(p, 0, extra_space);
+ p+=extra_space;
+ }
+ len = PTR_DIFF(p, ticket);
+
+ des_key_sched((const_des_cblock *)key.key, key_schedule);
+ des_pcbc_encrypt(ticket, ticket,
+ len, key_schedule, (C_Block *)key.key, 1);
+
+ ZERO_STRUCT(key);
+
+ return afs_settoken(username, &ct, ticket, len);
+}
+
+#else
+
+BOOL afs_login(char *username)
+{
+ return True;
+}
+
+#endif /* WITH_FAKE_KASERVER */
diff --git a/source3/passdb/secrets.c b/source3/passdb/secrets.c
index 2c99631e13..8a146f0d68 100644
--- a/source3/passdb/secrets.c
+++ b/source3/passdb/secrets.c
@@ -738,3 +738,56 @@ BOOL must_use_pdc( const char *domain )
}
+/*******************************************************************************
+ Store a complete AFS keyfile into secrets.tdb.
+*******************************************************************************/
+
+BOOL secrets_store_afs_keyfile(const char *cell, const struct afs_keyfile *keyfile)
+{
+ fstring key;
+
+ if ((cell == NULL) || (keyfile == NULL))
+ return False;
+
+ if (ntohl(keyfile->nkeys) > SECRETS_AFS_MAXKEYS)
+ return False;
+
+ slprintf(key, sizeof(key)-1, "%s/%s", SECRETS_AFS_KEYFILE, cell);
+ return secrets_store(key, keyfile, sizeof(struct afs_keyfile));
+}
+
+/*******************************************************************************
+ Fetch the current (highest) AFS key from secrets.tdb
+*******************************************************************************/
+BOOL secrets_fetch_afs_key(const char *cell, struct afs_key *result)
+{
+ fstring key;
+ struct afs_keyfile *keyfile;
+ size_t size;
+ uint32 i;
+
+ slprintf(key, sizeof(key)-1, "%s/%s", SECRETS_AFS_KEYFILE, cell);
+
+ keyfile = (struct afs_keyfile *)secrets_fetch(key, &size);
+
+ if (keyfile == NULL)
+ return False;
+
+ if (size != sizeof(struct afs_keyfile)) {
+ SAFE_FREE(keyfile);
+ return False;
+ }
+
+ i = ntohl(keyfile->nkeys);
+
+ if (i > SECRETS_AFS_MAXKEYS) {
+ SAFE_FREE(keyfile);
+ return False;
+ }
+
+ *result = keyfile->entry[i-1];
+
+ result->kvno = ntohl(result->kvno);
+
+ return True;
+}
diff --git a/source3/smbd/service.c b/source3/smbd/service.c
index f75c920069..f9f264c270 100644
--- a/source3/smbd/service.c
+++ b/source3/smbd/service.c
@@ -642,6 +642,10 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser,
return NULL;
}
}
+
+#ifdef WITH_FAKE_KASERVER
+ afs_login(user);
+#endif
#if CHECK_PATH_ON_TCONX
/* win2000 does not check the permissions on the directory
diff --git a/source3/utils/net.c b/source3/utils/net.c
index 080b0f4c8a..e5c078da29 100644
--- a/source3/utils/net.c
+++ b/source3/utils/net.c
@@ -462,6 +462,50 @@ static int net_getdomainsid(int argc, const char **argv)
return 0;
}
+#ifdef WITH_FAKE_KASERVER
+
+int net_afskey_usage(int argc, const char **argv)
+{
+ d_printf(" net afskey filename\n"
+ "\tImports a OpenAFS KeyFile into our secrets.tdb\n\n");
+ return -1;
+}
+
+static int net_afskey(int argc, const char **argv)
+{
+ int fd;
+ struct afs_keyfile keyfile;
+
+ if (argc != 1) {
+ d_printf("usage: 'net afskey <keyfile>'\n");
+ return -1;
+ }
+
+ if (!secrets_init()) {
+ d_printf("Could not open secrets.tdb\n");
+ return -1;
+ }
+
+ if ((fd = open(argv[0], O_RDONLY, 0)) < 0) {
+ d_printf("Could not open %s\n", argv[0]);
+ return -1;
+ }
+
+ if (read(fd, &keyfile, sizeof(keyfile)) != sizeof(keyfile)) {
+ d_printf("Could not read keyfile\n");
+ return -1;
+ }
+
+ if (!secrets_store_afs_keyfile(afs_cell(), &keyfile)) {
+ d_printf("Could not write keyfile to secrets.tdb\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+#endif /* WITH_FAKE_KASERVER */
+
static uint32 get_maxrid(void)
{
SAM_ACCOUNT *pwd = NULL;
@@ -572,6 +616,9 @@ static struct functable net_func[] = {
{"GETDOMAINSID", net_getdomainsid},
{"MAXRID", net_maxrid},
{"IDMAP", net_idmap},
+#ifdef WITH_FAKE_KASERVER
+ {"AFSKEY", net_afskey},
+#endif
{"HELP", net_help},
{NULL, NULL}
diff --git a/source3/utils/net_help.c b/source3/utils/net_help.c
index 272a06bc90..95116a4d2a 100644
--- a/source3/utils/net_help.c
+++ b/source3/utils/net_help.c
@@ -196,6 +196,9 @@ int net_help(int argc, const char **argv)
{"PASSWORD", net_rap_password_usage},
{"TIME", net_time_usage},
{"LOOKUP", net_lookup_usage},
+#ifdef WITH_FAKE_KASERVER
+ {"AFSKEY", net_afskey_usage},
+#endif
{"HELP", help_usage},
{NULL, NULL}};