diff options
-rw-r--r-- | source3/Makefile.in | 15 | ||||
-rw-r--r-- | source3/configure.in | 27 | ||||
-rw-r--r-- | source3/lib/afs.c | 232 | ||||
-rw-r--r-- | source3/lib/afs_settoken.c | 233 | ||||
-rw-r--r-- | source3/modules/vfs_afsacl.c | 730 |
5 files changed, 1002 insertions, 235 deletions
diff --git a/source3/Makefile.in b/source3/Makefile.in index 36dc0dc1a2..935dd90182 100644 --- a/source3/Makefile.in +++ b/source3/Makefile.in @@ -322,6 +322,7 @@ VFS_READONLY_OBJ = modules/vfs_readonly.o modules/getdate.o VFS_CAP_OBJ = modules/vfs_cap.o VFS_EXPAND_MSDFS_OBJ = modules/vfs_expand_msdfs.o VFS_SHADOW_COPY_OBJ = modules/vfs_shadow_copy.o +VFS_AFSACL_OBJ = modules/vfs_afsacl.o PLAINTEXT_AUTH_OBJ = auth/pampass.o auth/pass_check.o @@ -362,6 +363,7 @@ SMBD_OBJ_SRV = smbd/files.o smbd/chgpasswd.o smbd/connection.o \ lib/sysquotas_xfs.o lib/sysquotas_4A.o \ smbd/change_trust_pw.o smbd/fake_file.o \ smbd/quotas.o smbd/ntquotas.o lib/afs.o smbd/msdfs.o \ + lib/afs_settoken.o \ $(MANGLE_OBJ) @VFS_STATIC@ SMBD_OBJ_BASE = $(PARAM_OBJ) $(SMBD_OBJ_SRV) $(LIBSMB_OBJ) \ @@ -514,7 +516,8 @@ NET_OBJ = $(NET_OBJ1) $(PARAM_OBJ) $(SECRETS_OBJ) $(LIBSMB_OBJ) \ $(KRBCLIENT_OBJ) $(UBIQX_OBJ) $(LIB_NONSMBD_OBJ) \ $(LIBMSRPC_OBJ) $(IDMAP_OBJ) \ $(LIBADS_OBJ) $(LIBADS_SERVER_OBJ) $(POPT_LIB_OBJ) \ - $(SMBLDAP_OBJ) $(DCUTIL_OBJ) lib/dummyroot.o lib/server_mutex.o lib/afs.o + $(SMBLDAP_OBJ) $(DCUTIL_OBJ) lib/dummyroot.o lib/server_mutex.o \ + lib/afs.o lib/afs_settoken.o CUPS_OBJ = client/smbspool.o $(PARAM_OBJ) $(LIBSMB_OBJ) $(UBIQX_OBJ) \ $(LIB_NONSMBD_OBJ) $(KRBCLIENT_OBJ) $(SECRETS_OBJ) @@ -637,10 +640,11 @@ WINBINDD_OBJ = \ $(LIBSMB_OBJ) $(LIBMSRPC_OBJ) $(RPC_PARSE_OBJ) \ $(PROFILE_OBJ) $(SLCACHE_OBJ) $(SMBLDAP_OBJ) \ $(SECRETS_OBJ) $(LIBADS_OBJ) $(KRBCLIENT_OBJ) $(POPT_LIB_OBJ) \ - $(DCUTIL_OBJ) $(IDMAP_OBJ) lib/dummyroot.o lib/afs.o + $(DCUTIL_OBJ) $(IDMAP_OBJ) lib/dummyroot.o \ + lib/afs.o lib/afs_settoken.o WBINFO_OBJ = nsswitch/wbinfo.o $(LIBSAMBA_OBJ) $(PARAM_OBJ) $(LIB_NONSMBD_OBJ) \ - $(UBIQX_OBJ) $(SECRETS_OBJ) $(POPT_LIB_OBJ) lib/afs.o + $(UBIQX_OBJ) $(SECRETS_OBJ) $(POPT_LIB_OBJ) lib/afs_settoken.o WINBIND_NSS_OBJ = nsswitch/wb_common.o lib/replace1.o @WINBIND_NSS_EXTRA_OBJS@ @@ -1189,6 +1193,11 @@ bin/expand_msdfs.@SHLIBEXT@: $(VFS_EXPAND_MSDFS_OBJ:.o=.@PICSUFFIX@) @$(SHLD) $(LDSHFLAGS) -o $@ $(VFS_EXPAND_MSDFS_OBJ:.o=.@PICSUFFIX@) \ @SONAMEFLAG@`basename $@` +bin/afsacl.@SHLIBEXT@: $(VFS_AFSACL_OBJ:.o=.po) + @echo "Building plugin $@" + @$(SHLD) $(LDSHFLAGS) -o $@ $(VFS_AFSACL_OBJ:.o=.po) \ + @SONAMEFLAG@`basename $@` + bin/wbinfo@EXEEXT@: $(WBINFO_OBJ) @BUILD_POPT@ bin/.dummy @echo Linking $@ @$(LINK) -o $@ $(WBINFO_OBJ) $(LIBS) @POPTLIBS@ diff --git a/source3/configure.in b/source3/configure.in index 8f61241a62..f4383ea337 100644 --- a/source3/configure.in +++ b/source3/configure.in @@ -2377,13 +2377,31 @@ if test x"$samba_cv_WITH_AFS" != x"no" || fi fi -if test x"$samba_cv_WITH_FAKE_KASERVER" != x"no"; then - AC_CHECK_LIB( crypto, DES_pcbc_encrypt, LIBS="$LIBS -lcrypto" ) -fi - if test x"$samba_cv_WITH_FAKE_KASERVER" != x"no" && test x"$have_afs_headers" == x"yes"; then AC_DEFINE(WITH_FAKE_KASERVER,1,[Whether to include AFS fake-kaserver support]) fi + +################################################# +# check whether to compile AFS/NT ACL mapping module +samba_cv_WITH_VFS_AFSACL=no +AC_MSG_CHECKING(whether to use AFS fake-kaserver) +AC_ARG_WITH(vfs-afsacl, +[ --with-vfs-afsacl Include AFS to NT ACL mapping module (default=no) ], +[ case "$withval" in + yes|auto) + AC_MSG_RESULT($withval) + samba_cv_WITH_VFS_AFSACL=yes + ;; + *) + AC_MSG_RESULT(no) + ;; + esac ], + AC_MSG_RESULT(no) +) + +if test x"$samba_cv_WITH_VFS_AFSACL" == x"yes"; then + default_shared_modules="$default_shared_modules vfs_afsacl" +fi if test x"$samba_cv_WITH_AFS" != x"no" && test x"$have_afs_headers" = x"yes"; then AC_DEFINE(WITH_AFS,1,[Whether to include AFS clear-text auth support]) @@ -4337,6 +4355,7 @@ SMB_MODULE(vfs_readonly, \$(VFS_READONLY_OBJ), "bin/readonly.$SHLIBEXT", VFS) SMB_MODULE(vfs_cap, \$(VFS_CAP_OBJ), "bin/cap.$SHLIBEXT", VFS) SMB_MODULE(vfs_expand_msdfs, \$(VFS_EXPAND_MSDFS_OBJ), "bin/expand_msdfs.$SHLIBEXT", VFS) SMB_MODULE(vfs_shadow_copy, \$(VFS_SHADOW_COPY_OBJ), "bin/shadow_copy.$SHLIBEXT", VFS) +SMB_MODULE(vfs_afsacl, \$(VFS_AFSACL_OBJ), "bin/afsacl.$SHLIBEXT", VFS) SMB_SUBSYSTEM(VFS,smbd/vfs.o) AC_DEFINE_UNQUOTED(STRING_STATIC_MODULES, "$string_static_modules", [String list of builtin modules]) diff --git a/source3/lib/afs.c b/source3/lib/afs.c index ce972ec27b..0830a3a0e7 100644 --- a/source3/lib/afs.c +++ b/source3/lib/afs.c @@ -29,12 +29,6 @@ #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]; @@ -74,186 +68,6 @@ static char *afs_encode_token(const char *cell, const DATA_BLOB ticket, 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. - - 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 *cell, - const struct ClearToken *ctok, - DATA_BLOB ticket) -{ - int ret; - struct { - char *in, *out; - uint16 in_size, out_size; - } iob; - - char buf[1024]; - char *p = buf; - int tmp; - - memcpy(p, &ticket.length, sizeof(uint32)); - p += sizeof(uint32); - memcpy(p, ticket.data, ticket.length); - p += ticket.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; - } - - strncpy(p, 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); -} - -BOOL afs_settoken_str(const char *token_string) -{ - DATA_BLOB ticket; - struct ClearToken ct; - BOOL result; - char *cell; - - if (!afs_decode_token(token_string, &cell, &ticket, &ct)) - return False; - - if (geteuid() != 0) - ct.ViceId = getuid(); - - result = afs_settoken(cell, &ct, ticket); - - SAFE_FREE(cell); - data_blob_free(&ticket); - - return result; - } - /* Create a ClearToken and an encrypted ticket. ClearToken has not yet the * ViceId set, this should be set by the caller. */ @@ -391,6 +205,7 @@ BOOL afs_login(connection_struct *conn) pstring afs_username; char *cell; BOOL result; + char *ticket_str; struct ClearToken ct; @@ -421,45 +236,11 @@ BOOL afs_login(connection_struct *conn) /* 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); + ticket_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; - } + result = afs_settoken_str(ticket_str); - 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); + SAFE_FREE(ticket_str); data_blob_free(&ticket); @@ -473,11 +254,6 @@ 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; diff --git a/source3/lib/afs_settoken.c b/source3/lib/afs_settoken.c new file mode 100644 index 0000000000..eb10c4c66d --- /dev/null +++ b/source3/lib/afs_settoken.c @@ -0,0 +1,233 @@ +/* + * Unix SMB/CIFS implementation. + * Generate AFS tickets + * Copyright (C) Volker Lendecke 2004 + * + * 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); + +struct ClearToken { + uint32 AuthHandle; + char HandShakeKey[8]; + uint32 ViceId; + uint32 BeginTimestamp; + uint32 EndTimestamp; +}; + +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. + + 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 *cell, + const struct ClearToken *ctok, + DATA_BLOB ticket) +{ + int ret; + struct { + char *in, *out; + uint16 in_size, out_size; + } iob; + + char buf[1024]; + char *p = buf; + int tmp; + + memcpy(p, &ticket.length, sizeof(uint32)); + p += sizeof(uint32); + memcpy(p, ticket.data, ticket.length); + p += ticket.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; + } + + strncpy(p, 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); +} + +BOOL afs_settoken_str(const char *token_string) +{ + DATA_BLOB ticket; + struct ClearToken ct; + BOOL result; + char *cell; + + if (!afs_decode_token(token_string, &cell, &ticket, &ct)) + return False; + + if (geteuid() != 0) + ct.ViceId = getuid(); + + result = afs_settoken(cell, &ct, ticket); + + SAFE_FREE(cell); + data_blob_free(&ticket); + + return result; +} + +#else + +BOOL afs_settoken_str(const char *token_string) +{ + return False; +} + +#endif diff --git a/source3/modules/vfs_afsacl.c b/source3/modules/vfs_afsacl.c new file mode 100644 index 0000000000..01b3fcb2b9 --- /dev/null +++ b/source3/modules/vfs_afsacl.c @@ -0,0 +1,730 @@ +/* + * Convert AFS acls to NT acls and vice versa. + * + * 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" + +#undef DBGC_CLASS +#define DBGC_CLASS DBGC_VFS + +#include <afs/stds.h> +#include <afs/afs.h> +#include <afs/auth.h> +#include <afs/venus.h> +#include <afs/prs_fs.h> + +#define MAXSIZE 2048 + +extern DOM_SID global_sid_World; +extern DOM_SID global_sid_Builtin_Administrators; +extern DOM_SID global_sid_Builtin_Backup_Operators; +extern DOM_SID global_sid_Authenticated_Users; +extern DOM_SID global_sid_NULL; + +extern int afs_syscall(int, char *, int, char *, int); + +struct afs_ace { + BOOL positive; + char *name; + DOM_SID sid; + enum SID_NAME_USE type; + uint32 rights; + struct afs_ace *next; +}; + +struct afs_acl { + TALLOC_CTX *ctx; + int type; + int num_aces; + struct afs_ace *acelist; +}; + +struct afs_iob { + char *in, *out; + uint16 in_size, out_size; +}; + + +static BOOL init_afs_acl(struct afs_acl *acl) +{ + ZERO_STRUCT(*acl); + acl->ctx = talloc_init("afs_acl"); + if (acl->ctx == NULL) { + DEBUG(10, ("Could not init afs_acl")); + return False; + } + return True; +} + +static void free_afs_acl(struct afs_acl *acl) +{ + talloc_destroy(acl->ctx); +} + +static struct afs_ace *clone_afs_ace(TALLOC_CTX *mem_ctx, struct afs_ace *ace) +{ + struct afs_ace *result = talloc(mem_ctx, sizeof(struct afs_ace)); + + if (result == NULL) + return NULL; + + *result = *ace; + + result->next = NULL; + result->name = talloc_strdup(mem_ctx, ace->name); + + if (result->name == NULL) { + return NULL; + } + + return result; +} + + +/* Ok, this is sort-of a hack. We assume here that we have winbind users in + * AFS. And yet another copy of parse_domain_user.... */ + +static BOOL parse_domain_user(const char *domuser, fstring domain, + fstring user) +{ + char *p = strchr(domuser,*lp_winbind_separator()); + + if (p==NULL) { + return False; + } + + fstrcpy(user, p+1); + fstrcpy(domain, domuser); + domain[PTR_DIFF(p, domuser)] = 0; + strupper_m(domain); + + return True; +} + +static struct afs_ace *new_afs_ace(TALLOC_CTX *mem_ctx, + BOOL positive, + const char *name, uint32 rights) +{ + DOM_SID sid; + enum SID_NAME_USE type; + struct afs_ace *result; + + if (strcmp(name, "system:administrators") == 0) { + + sid_copy(&sid, &global_sid_Builtin_Administrators); + type = SID_NAME_ALIAS; + + } else if (strcmp(name, "system:anyuser") == 0) { + + sid_copy(&sid, &global_sid_World); + type = SID_NAME_ALIAS; + + } else if (strcmp(name, "system:authuser") == 0) { + + sid_copy(&sid, &global_sid_Authenticated_Users); + type = SID_NAME_WKN_GRP; + + } else if (strcmp(name, "system:backup") == 0) { + + sid_copy(&sid, &global_sid_Builtin_Backup_Operators); + type = SID_NAME_ALIAS; + + } else { + + fstring user, domain; + + if (!parse_domain_user(name, domain, user)) { + fstrcpy(user, name); + fstrcpy(domain, lp_workgroup()); + } + + if (!lookup_name(domain, user, &sid, &type)) { + DEBUG(10, ("Could not find AFS user %s\n", name)); + + sid_copy(&sid, &global_sid_NULL); + type = SID_NAME_UNKNOWN; + + } + } + + result = talloc(mem_ctx, sizeof(struct afs_ace)); + + if (result == NULL) { + DEBUG(0, ("Could not talloc AFS ace\n")); + return NULL; + } + + result->name = talloc_strdup(mem_ctx, name); + if (result->name == NULL) { + DEBUG(0, ("Could not talloc AFS ace name\n")); + return NULL; + } + + result->sid = sid; + result->type = type; + + result->positive = positive; + result->rights = rights; + + return result; +} + +static void add_afs_ace(struct afs_acl *acl, + BOOL positive, + const char *name, uint32 rights) +{ + struct afs_ace *ace; + + ace = new_afs_ace(acl->ctx, positive, name, rights); + + ace->next = acl->acelist; + acl->acelist = ace; + + acl->num_aces += 1; + + DEBUG(10, ("add_afs_ace: Added %s entry for %s with rights %d\n", + ace->positive?"positive":"negative", + ace->name, ace->rights)); + + return; +} + +/* AFS ACLs in string form are a long string of fields delimited with \n. + * + * First line: Number of positive entries + * Second line: Number of negative entries + * Third and following lines: The entries themselves + * + * An ACE is a line of two fields, delimited by \t. + * + * First field: Name + * Second field: Rights + */ + +static BOOL parse_afs_acl(struct afs_acl *acl, const char *acl_str) +{ + int nplus, nminus; + int aces; + + char str[MAXSIZE+1]; + char *p = str; + + strncpy(str, acl_str, MAXSIZE); + + if (sscanf(p, "%d", &nplus) != 1) + return False; + + DEBUG(10, ("Found %d positive entries\n", nplus)); + + if ((p = strchr(p, '\n')) == NULL) + return False; + p += 1; + + if (sscanf(p, "%d", &nminus) != 1) + return False; + + DEBUG(10, ("Found %d negative entries\n", nminus)); + + if ((p = strchr(p, '\n')) == NULL) + return False; + p += 1; + + for (aces = nplus+nminus; aces > 0; aces--) + { + + const char *name; + uint32 rights; + + name = p; + + if ((p = strchr(p, '\t')) == NULL) + return False; + *p = '\0'; + p += 1; + + if (sscanf(p, "%d", &rights) != 1) + return False; + + if ((p = strchr(p, '\n')) == NULL) + return False; + p += 1; + + add_afs_ace(acl, nplus>0, name, rights); + + nplus -= 1; + } + + return True; +} + +static BOOL unparse_afs_acl(struct afs_acl *acl, char *acl_str) +{ + /* TODO: String length checks!!!! */ + + int positives = 0; + int negatives = 0; + fstring line; + + *acl_str = 0; + + struct afs_ace *ace = acl->acelist; + + while (ace != NULL) { + if (ace->positive) + positives++; + else + negatives++; + ace = ace->next; + } + + fstr_sprintf(line, "%d\n", positives); + safe_strcat(acl_str, line, MAXSIZE); + + fstr_sprintf(line, "%d\n", negatives); + safe_strcat(acl_str, line, MAXSIZE); + + ace = acl->acelist; + + while (ace != NULL) { + fstr_sprintf(line, "%s\t%d\n", ace->name, ace->rights); + safe_strcat(acl_str, line, MAXSIZE); + ace = ace->next; + } + return True; +} + +static uint32 afs_to_nt_file_rights(uint32 rights) +{ + uint32 result = 0; + + if (rights & PRSFS_READ) + result |= FILE_READ_DATA | FILE_READ_EA | + FILE_EXECUTE | FILE_READ_ATTRIBUTES | + READ_CONTROL_ACCESS | SYNCHRONIZE_ACCESS; + + if (rights & PRSFS_WRITE) + result |= FILE_WRITE_DATA | FILE_WRITE_ATTRIBUTES | + FILE_WRITE_EA | FILE_APPEND_DATA; + + if (rights & PRSFS_LOCK) + result |= WRITE_OWNER_ACCESS; + + if (rights & PRSFS_DELETE) + result |= DELETE_ACCESS; + + return result; +} + +static uint32 afs_to_nt_dir_rights(uint32 rights) +{ + uint32 result = 0; + + if (rights & PRSFS_INSERT) + result |= FILE_ADD_FILE | FILE_ADD_SUBDIRECTORY; + + if (rights & PRSFS_LOOKUP) + result |= FILE_READ_DATA | FILE_READ_EA | + FILE_EXECUTE | FILE_READ_ATTRIBUTES | + READ_CONTROL_ACCESS | SYNCHRONIZE_ACCESS; + + if (rights & PRSFS_WRITE) + result |= FILE_WRITE_ATTRIBUTES | FILE_WRITE_DATA | + FILE_APPEND_DATA | FILE_WRITE_EA; + + if ((rights & (PRSFS_INSERT|PRSFS_LOOKUP|PRSFS_DELETE)) == + (PRSFS_INSERT|PRSFS_LOOKUP|PRSFS_DELETE)) + result |= FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | + GENERIC_WRITE_ACCESS; + + if (rights & PRSFS_DELETE) + result |= DELETE_ACCESS; + + if (rights & PRSFS_ADMINISTER) + result |= FILE_DELETE_CHILD | WRITE_DAC_ACCESS | + WRITE_OWNER_ACCESS; + + return result; +} + +static uint32 nt_to_afs_dir_rights(uint32 rights) +{ + uint32 result = 0; + + if (rights & (GENERIC_ALL_ACCESS|WRITE_DAC_ACCESS)) { + result |= PRSFS_READ | PRSFS_WRITE | PRSFS_INSERT | + PRSFS_LOOKUP | PRSFS_DELETE | PRSFS_LOCK | + PRSFS_ADMINISTER; + } + + if (rights & (GENERIC_READ_ACCESS|FILE_READ_DATA)) { + result |= PRSFS_READ | PRSFS_LOOKUP; + } + + if (rights & (GENERIC_WRITE_ACCESS|FILE_WRITE_DATA)) { + result |= PRSFS_WRITE | PRSFS_INSERT | PRSFS_DELETE | + PRSFS_LOCK; + } + + return result; +} + +static size_t afs_to_nt_acl(struct afs_acl *afs_acl, + struct files_struct *fsp, + uint32 security_info, + struct security_descriptor_info **ppdesc) +{ + SEC_ACE *nt_ace_list; + DOM_SID owner_sid, group_sid; + SEC_ACCESS mask; + SMB_STRUCT_STAT sbuf; + SEC_ACL *psa = NULL; + int good_aces; + size_t sd_size; + TALLOC_CTX *mem_ctx = main_loop_talloc_get(); + + struct afs_ace *afs_ace; + + if (fsp->is_directory || fsp->fd == -1) { + /* Get the stat struct for the owner info. */ + if(SMB_VFS_STAT(fsp->conn,fsp->fsp_name, &sbuf) != 0) { + return 0; + } + } else { + if(SMB_VFS_FSTAT(fsp,fsp->fd,&sbuf) != 0) { + return 0; + } + } + + uid_to_sid(&owner_sid, sbuf.st_uid); + gid_to_sid(&group_sid, sbuf.st_gid); + + nt_ace_list = (SEC_ACE *)malloc(afs_acl->num_aces * sizeof(SEC_ACE)); + + if (nt_ace_list == NULL) + return 0; + + afs_ace = afs_acl->acelist; + good_aces = 0; + + while (afs_ace != NULL) { + uint32 nt_rights; + + if (afs_ace->type == SID_NAME_UNKNOWN) { + DEBUG(10, ("Ignoring unknown name %s\n", + afs_ace->name)); + afs_ace = afs_ace->next; + continue; + } + + if (fsp->is_directory) + nt_rights = afs_to_nt_dir_rights(afs_ace->rights); + else + nt_rights = afs_to_nt_file_rights(afs_ace->rights); + + init_sec_access(&mask, nt_rights); + init_sec_ace(&nt_ace_list[good_aces++], &(afs_ace->sid), + SEC_ACE_TYPE_ACCESS_ALLOWED, mask, + SEC_ACE_FLAG_OBJECT_INHERIT | + SEC_ACE_FLAG_CONTAINER_INHERIT); + afs_ace = afs_ace->next; + } + + psa = make_sec_acl(mem_ctx, NT4_ACL_REVISION, + good_aces, nt_ace_list); + if (psa == NULL) + return 0; + + + *ppdesc = make_sec_desc(mem_ctx, SEC_DESC_REVISION, + SEC_DESC_SELF_RELATIVE, + (security_info & OWNER_SECURITY_INFORMATION) + ? &owner_sid : NULL, + (security_info & GROUP_SECURITY_INFORMATION) + ? &group_sid : NULL, + NULL, psa, &sd_size); + + return sd_size; +} + +static BOOL nt_to_afs_acl(uint32 security_info_sent, + struct security_descriptor_info *psd, + struct afs_acl *afs_acl) +{ + SEC_ACL *dacl; + int i; + + /* Currently we *only* look at the dacl */ + + if (((security_info_sent & DACL_SECURITY_INFORMATION) == 0) || + (psd->dacl == NULL)) + return True; + + if (!init_afs_acl(afs_acl)) + return False; + + dacl = psd->dacl; + + for (i = 0; i < dacl->num_aces; i++) { + SEC_ACE *ace = &(dacl->ace[i]); + fstring dom_name; + fstring name; + enum SID_NAME_USE name_type; + + if (ace->type != SEC_ACE_TYPE_ACCESS_ALLOWED) { + /* First cut: Only positive ACEs */ + return False; + } + + if (sid_compare(&ace->trustee, + &global_sid_Builtin_Administrators) == 0) { + + fstrcpy(name, "system:administrators"); + + } else if (sid_compare(&ace->trustee, + &global_sid_World) == 0) { + + fstrcpy(name, "system:anyuser"); + + } else if (sid_compare(&ace->trustee, + &global_sid_Authenticated_Users) == 0) { + + fstrcpy(name, "system:authuser"); + + } else if (sid_compare(&ace->trustee, + &global_sid_Builtin_Backup_Operators) + == 0) { + + fstrcpy(name, "system:backup"); + + } else { + + if (!lookup_sid(&ace->trustee, + dom_name, name, &name_type)) { + DEBUG(3, ("Could not lookup sid %s\n", + sid_string_static(&ace->trustee))); + return False; + } + + if (strcmp(dom_name, lp_workgroup()) != 0) { + DEBUG(3, ("Got SID for domain %s, not mine\n", + dom_name)); + return False; + } + + if ( (name_type == SID_NAME_USER) || + (name_type == SID_NAME_DOM_GRP) ) { + fstring only_username; + fstrcpy(only_username, name); + fstr_sprintf(name, "%s%s%s", + dom_name, lp_winbind_separator(), + only_username); + strlower_m(name); + } + } + + add_afs_ace(afs_acl, True, name, + nt_to_afs_dir_rights(ace->info.mask)); + } + + return True; +} + +static BOOL afs_get_afs_acl(char *filename, struct afs_acl *acl) +{ + struct afs_iob iob; + + int ret; + + char space[MAXSIZE]; + + DEBUG(5, ("afs_get_afs_acl: %s\n", filename)); + + iob.in_size = 0; + iob.out_size = MAXSIZE; + iob.in = iob.out = space; + + ret = afs_syscall(AFSCALL_PIOCTL, filename, VIOCGETAL, + (char *)&iob, 0); + + if (ret) { + DEBUG(1, ("got error from PIOCTL: %d\n", ret)); + return False; + } + + if (!init_afs_acl(acl)) + return False; + + if (!parse_afs_acl(acl, space)) { + DEBUG(1, ("Could not parse AFS acl\n")); + free_afs_acl(acl); + return False; + } + + return True; +} + +static size_t afs_get_nt_acl(struct files_struct *fsp, uint32 security_info, + struct security_descriptor_info **ppdesc) +{ + struct afs_acl acl; + size_t sd_size; + + DEBUG(5, ("afs_get_nt_acl: %s\n", fsp->fsp_name)); + + if (!afs_get_afs_acl(fsp->fsp_name, &acl)) { + return 0; + } + + sd_size = afs_to_nt_acl(&acl, fsp, security_info, ppdesc); + + free_afs_acl(&acl); + + return sd_size; +} + +/* For setting an AFS ACL we have to take care of the ACEs we could + * not properly map to SIDs. Merge all of them into the new ACL. */ + +static void merge_unknown_aces(struct afs_acl *src, struct afs_acl *dst) +{ + struct afs_ace *ace; + + for (ace = src->acelist; ace != NULL; ace = ace->next) + { + struct afs_ace *copy; + + if (ace->type != SID_NAME_UNKNOWN) { + DEBUG(10, ("Not merging known ACE for %s\n", + ace->name)); + continue; + } + + DEBUG(10, ("Merging unknown ACE for %s\n", ace->name)); + + copy = clone_afs_ace(dst->ctx, ace); + + if (copy == NULL) { + DEBUG(0, ("Could not clone ACE for %s\n", ace->name)); + continue; + } + + copy->next = dst->acelist; + dst->acelist = copy; + dst->num_aces += 1; + } +} + +static BOOL afs_set_nt_acl(files_struct *fsp, uint32 security_info_sent, + struct security_descriptor_info *psd) +{ + struct afs_acl old_afs_acl, new_afs_acl; + char acl_string[2049]; + struct afs_iob iob; + int ret; + + if (!fsp->is_directory) { + /* AFS only supports ACLs on directories... */ + return False; + } + + if (!afs_get_afs_acl(fsp->fsp_name, &old_afs_acl)) { + DEBUG(3, ("Could not get old ACL of %s\n", fsp->fsp_name)); + return False; + } + + if (!nt_to_afs_acl(security_info_sent, psd, &new_afs_acl)) { + free_afs_acl(&old_afs_acl); + return False; + } + + merge_unknown_aces(&old_afs_acl, &new_afs_acl); + + unparse_afs_acl(&new_afs_acl, acl_string); + + free_afs_acl(&old_afs_acl); + free_afs_acl(&new_afs_acl); + + iob.in = acl_string; + iob.in_size = 1+strlen(iob.in); + iob.out = NULL; + iob.out_size = 0; + + DEBUG(10, ("trying to set acl '%s' on file %s\n", + iob.in, fsp->fsp_name)); + + ret = afs_syscall(AFSCALL_PIOCTL, fsp->fsp_name, VIOCSETAL, + (char *)&iob, 0); + + if (ret != 0) { + DEBUG(10, ("VIOCSETAL returned %d\n", ret)); + } + + return (ret == 0); +} + +static size_t afsacl_fget_nt_acl(struct vfs_handle_struct *handle, + struct files_struct *fsp, + int fd, uint32 security_info, + struct security_descriptor_info **ppdesc) +{ + return afs_get_nt_acl(fsp, security_info, ppdesc); +} +static size_t afsacl_get_nt_acl(struct vfs_handle_struct *handle, + struct files_struct *fsp, + const char *name, uint32 security_info, + struct security_descriptor_info **ppdesc) +{ + return afs_get_nt_acl(fsp, security_info, ppdesc); +} + +BOOL afsacl_fset_nt_acl(vfs_handle_struct *handle, + files_struct *fsp, + int fd, uint32 security_info_sent, + SEC_DESC *psd) +{ + return afs_set_nt_acl(fsp, security_info_sent, psd); +} + +BOOL afsacl_set_nt_acl(vfs_handle_struct *handle, + files_struct *fsp, + const char *name, uint32 security_info_sent, + SEC_DESC *psd) +{ + return afs_set_nt_acl(fsp, security_info_sent, psd); +} + +/* VFS operations structure */ + +static vfs_op_tuple afsacl_ops[] = { + {SMB_VFS_OP(afsacl_fget_nt_acl), SMB_VFS_OP_FGET_NT_ACL, + SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(afsacl_get_nt_acl), SMB_VFS_OP_GET_NT_ACL, + SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(afsacl_fset_nt_acl), SMB_VFS_OP_FSET_NT_ACL, + SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(afsacl_set_nt_acl), SMB_VFS_OP_SET_NT_ACL, + SMB_VFS_LAYER_TRANSPARENT}, + {SMB_VFS_OP(NULL), SMB_VFS_OP_NOOP, SMB_VFS_LAYER_NOOP} +}; + +NTSTATUS vfs_afsacl_init(void) +{ + return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, "afsacl", + afsacl_ops); +} |