/* * 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 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 . */ #include "includes.h" #include "lib/afs/afs_settoken.h" #ifdef WITH_FAKE_KASERVER #define NO_ASN1_TYPEDEFS 1 #include "system/filesys.h" #include #include #include #include #include #include #include #include int afs_syscall(int subcall, const char *path, int cmd, char *cmarg, int follow) { /* return( syscall( SYS_afs_syscall, subcall, path, cmd, cmarg, follow)); */ int errcode; int proc_afs_file; struct afsprocdata afs_syscall_data; afs_syscall_data.syscall = subcall; afs_syscall_data.param1 = (long)path; afs_syscall_data.param2 = cmd; afs_syscall_data.param3 = (long)cmarg; afs_syscall_data.param4 = follow; proc_afs_file = open(PROC_SYSCALL_FNAME, O_RDWR); if (proc_afs_file < 0) proc_afs_file = open(PROC_SYSCALL_ARLA_FNAME, O_RDWR); if (proc_afs_file < 0) return -1; errcode = ioctl(proc_afs_file, VIOC_SYSCALL, &afs_syscall_data); close(proc_afs_file); return errcode; } 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 *saveptr; char *s = SMB_STRDUP(string); char *t; if ((t = strtok_r(s, "\n", &saveptr)) == NULL) { DEBUG(10, ("strtok_r failed\n")); return false; } *cell = SMB_STRDUP(t); if ((t = strtok_r(NULL, "\n", &saveptr)) == NULL) { DEBUG(10, ("strtok_r failed\n")); return false; } if (sscanf(t, "%u", &result_ct.AuthHandle) != 1) { DEBUG(10, ("sscanf AuthHandle failed\n")); return false; } if ((t = strtok_r(NULL, "\n", &saveptr)) == NULL) { DEBUG(10, ("strtok_r 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/%lu\n", (uint8_t)*blob.data, (unsigned long) blob.length)); return false; } memcpy(result_ct.HandShakeKey, blob.data, blob.length); data_blob_free(&blob); if ((t = strtok_r(NULL, "\n", &saveptr)) == NULL) { DEBUG(10, ("strtok_r failed\n")); return false; } if (sscanf(t, "%u", &result_ct.ViceId) != 1) { DEBUG(10, ("sscanf ViceId failed\n")); return false; } if ((t = strtok_r(NULL, "\n", &saveptr)) == NULL) { DEBUG(10, ("strtok_r failed\n")); return false; } if (sscanf(t, "%u", &result_ct.BeginTimestamp) != 1) { DEBUG(10, ("sscanf BeginTimestamp failed\n")); return false; } if ((t = strtok_r(NULL, "\n", &saveptr)) == NULL) { DEBUG(10, ("strtok_r failed\n")); return false; } if (sscanf(t, "%u", &result_ct.EndTimestamp) != 1) { DEBUG(10, ("sscanf EndTimestamp failed\n")); return false; } if ((t = strtok_r(NULL, "\n", &saveptr)) == NULL) { DEBUG(10, ("strtok_r 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 = geteuid(); } result = afs_settoken(cell, &ct, ticket); SAFE_FREE(cell); data_blob_free(&ticket); return result; } #else int afs_syscall(int subcall, const char *path, int cmd, char *cmarg, int follow) { errno = ENOSYS; return -1; } bool afs_settoken_str(const char *token_string) { return false; } #endif