/* * Copyright (c) 2010 Your File System Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #ifdef HAVE_SYS_WAIT_H #include #endif #ifdef IGNORE_SOME_GCC_WARNINGS # pragma GCC diagnostic warning "-Wdeprecated-declarations" #endif #include #include #include #include #include #include #include #include "test.h" #include "common.h" #define TEST_PORT 1234 static void testOriginalIterator(struct afsconf_dir *dir, int num, char *user) { char buffer[256]; ok((afsconf_GetNthUser(dir, num, buffer, sizeof buffer) == 0), "User %d successfully returned as %s", num, buffer); ok(strcmp(user, buffer) == 0, "User %d matches", num); } static void testNewIterator(struct afsconf_dir *dir, int num, struct rx_identity *id) { struct rx_identity *fileId; ok((afsconf_GetNthIdentity(dir, num, &fileId) == 0), "Identity %d successfully returned", num); ok(rx_identity_match(fileId, id), "Identity %d matches", num); rx_identity_free(&fileId); } void startClient(char *configPath) { struct afsconf_dir *dir; struct rx_identity *testId, *anotherId, *extendedId, *dummy; struct rx_securityClass *class; struct rx_connection *conn; afs_uint32 startTime; char ubuffer[256]; afs_int32 classIndex; int code; struct hostent *he; afs_uint32 addr; afs_int32 result; char *string = NULL; plan(63); dir = afsconf_Open(configPath); ok(dir!=NULL, "Configuration directory opened sucessfully by client"); /* Add a normal user to the super user file */ ok(afsconf_AddUser(dir, "test") == 0, "Adding a simple user works"); testId = rx_identity_new(RX_ID_KRB4, "test", "test", strlen("test")); /* Check that they are a super user */ ok(afsconf_IsSuperIdentity(dir, testId), "User added with old i/face is identitifed as super user"); /* Check that nobody else is */ ok(!afsconf_IsSuperIdentity(dir, rx_identity_new(RX_ID_KRB4, "testy", "testy", strlen("testy"))), "Additional users are not super users"); ok(afsconf_AddUser(dir, "test") == EEXIST, "Adding a user that already exists fails"); ok(afsconf_AddIdentity(dir, testId) == EEXIST, "Adding an identity that already exists fails"); anotherId = rx_identity_new(RX_ID_KRB4, "another", "another", strlen("another")); /* Add another normal user, but using the extended interface */ ok(afsconf_AddIdentity(dir, anotherId) == 0, "Adding a KRB4 identity works"); /* Check that they are a super user */ ok(afsconf_IsSuperIdentity(dir, anotherId), "User added with new i/face is identitifed as super user"); ok(afsconf_AddIdentity(dir, anotherId) == EEXIST, "Adding a KRB4 identity that already exists fails"); /* Add an extended user to the super user file */ extendedId = rx_identity_new(RX_ID_GSS, "sxw@INF.ED.AC.UK", "\x04\x01\x00\x0B\x06\x09\x2A\x86\x48\x86\xF7\x12\x01\x02\x02\x00\x00\x00\x10sxw@INF.ED.AC.UK", 35); ok(afsconf_AddIdentity(dir, extendedId) == 0, "Adding a GSSAPI identity works"); /* Check that they are now special */ ok(afsconf_IsSuperIdentity(dir, extendedId), "Added GSSAPI identity is a super user"); /* Check that display name isn't used for matches */ ok(!afsconf_IsSuperIdentity(dir, rx_identity_new(RX_ID_GSS, "sxw@INF.ED.AC.UK", "abcdefghijklmnopqrstuvwxyz123456789", 35)), "Display name is not used for extended matches"); ok(afsconf_AddIdentity(dir, extendedId) == EEXIST, "Adding GSSAPI identity twice fails"); /* Add a final normal user, so we can check that iteration works */ /* Add a normal user to the super user file */ ok(afsconf_AddUser(dir, "test2") == 0, "Adding another simple user works"); testOriginalIterator(dir, 0, "test"); testOriginalIterator(dir, 1, "another"); testOriginalIterator(dir, 2, "test2"); ok(afsconf_GetNthUser(dir, 3, ubuffer, sizeof ubuffer) != 0, "Reading past the end of the superuser list fails"); testNewIterator(dir, 0, testId); testNewIterator(dir, 1, anotherId); testNewIterator(dir, 2, extendedId); testNewIterator(dir, 3, rx_identity_new(RX_ID_KRB4, "test2", "test2", strlen("test2"))); ok(afsconf_GetNthIdentity(dir, 4, &dummy) != 0, "Reading past the end of the superuser list fails"); ok(afsconf_DeleteUser(dir, "notthere") != 0, "Deleting a user that doesn't exist fails"); /* Delete the normal user */ ok(afsconf_DeleteUser(dir, "another") == 0, "Deleting normal user works"); ok(!afsconf_IsSuperIdentity(dir, anotherId), "Deleted user is no longer super user"); ok(afsconf_IsSuperIdentity(dir, testId) && afsconf_IsSuperIdentity(dir, extendedId), "Other identities still are"); ok(afsconf_DeleteIdentity(dir, extendedId) == 0, "Deleting identity works"); ok(!afsconf_IsSuperIdentity(dir, extendedId), "Deleted identity is no longer special"); /* Now, what happens if we're doing something over the network instead */ code = rx_Init(0); is_int(code, 0, "Initialised RX"); /* Fake up an rx ticket. Note that this will be for the magic 'superuser' */ code = afsconf_ClientAuth(dir, &class, &classIndex); is_int(code, 0, "Can successfully create superuser token"); /* Start a connection to our test service with it */ he = gethostbyname("localhost"); if (!he) { printf("Couldn't look up server hostname"); exit(1); } memcpy(&addr, he->h_addr, sizeof(afs_uint32)); conn = rx_NewConnection(addr, htons(TEST_PORT), TEST_SERVICE_ID, class, classIndex); /* There's nothing in the list, so this just succeeds because we can */ code = TEST_CanI(conn, &result); is_int(0, code, "Can run a simple RPC"); code = TEST_WhoAmI(conn, &string); is_int(0, code, "Can get identity back"); is_string("", string, "Forged token is super user"); xdr_free((xdrproc_t)xdr_string, &string); /* Throw away this connection and security class */ rx_DestroyConnection(conn); rxs_Release(class); /* Now fake an rx ticket for a normal user. We have to do more work by hand * here, sadly */ startTime = time(NULL); class = afstest_FakeRxkadClass(dir, "rpctest", "", "", startTime, startTime + 60* 60); conn = rx_NewConnection(addr, htons(TEST_PORT), TEST_SERVICE_ID, class, RX_SECIDX_KAD); code = TEST_CanI(conn, &result); is_int(EPERM, code, "Running RPC as non-super user fails as expected"); code = TEST_NewCanI(conn, &result); is_int(EPERM, code, "Running new interface RPC as non-super user fails as expected"); code = TEST_WhoAmI(conn, &string); xdr_free((xdrproc_t)xdr_string, &string); is_int(EPERM, code, "Running RPC returning string fails as expected"); code = TEST_NewWhoAmI(conn, &string); xdr_free((xdrproc_t)xdr_string, &string); is_int(EPERM, code, "Running new interface RPC returning string fails as expected"); ok(afsconf_AddUser(dir, "rpctest") == 0, "Adding %s user works", "rpctest"); code = TEST_CanI(conn, &result); is_int(0, code, "Running RPC as rpctest works"); code = TEST_NewCanI(conn, &result); is_int(0, code, "Running new interface RPC as rpctest works"); code = TEST_WhoAmI(conn, &string); is_int(0, code, "Running RPC returning string as %s works", "rpctest"); is_string("rpctest", string, "Returned user string matches"); xdr_free((xdrproc_t)xdr_string, &string); code = TEST_NewWhoAmI(conn, &string); is_int(0, code, "Running new RPC returning string as %s works", "rpctest"); is_string("rpctest", string, "Returned user string for new interface matches"); xdr_free((xdrproc_t)xdr_string, &string); rx_DestroyConnection(conn); rxs_Release(class); /* Now try with an admin principal */ startTime = time(NULL); class = afstest_FakeRxkadClass(dir, "rpctest", "admin", "", startTime, startTime + 60* 60); conn = rx_NewConnection(addr, htons(TEST_PORT), TEST_SERVICE_ID, class, RX_SECIDX_KAD); code = TEST_CanI(conn, &result); is_int(EPERM, code, "Running RPC as non-super user fails as expected"); code = TEST_NewCanI(conn, &result); is_int(EPERM, code, "Running new interface RPC as non-super user fails as expected"); code = TEST_WhoAmI(conn, &string); xdr_free((xdrproc_t)xdr_string, &string); is_int(EPERM, code, "Running RPC returning string fails as expected"); code = TEST_NewWhoAmI(conn, &string); xdr_free((xdrproc_t)xdr_string, &string); is_int(EPERM, code, "Running new interface RPC returning string fails as expected"); ok(afsconf_AddUser(dir, "rpctest.admin") == 0, "Adding %s user works", "rpctest.admin"); code = TEST_CanI(conn, &result); is_int(0, code, "Running RPC as %s works", "rpctest/admin"); code = TEST_NewCanI(conn, &result); is_int(0, code, "Running new interface RPC as %s works", "rpctest/admin"); code = TEST_WhoAmI(conn, &string); is_int(0, code, "Running RPC returning string as %s works", "rpctest/admin"); is_string("rpctest.admin", string, "Returned user string matches"); xdr_free((xdrproc_t)xdr_string, &string); code = TEST_NewWhoAmI(conn, &string); is_int(0, code, "Running new interface RPC returning string as %s works", "rpctest/admin"); is_string("rpctest.admin", string, "Returned user string from new interface matches"); xdr_free((xdrproc_t)xdr_string, &string); rx_DestroyConnection(conn); rxs_Release(class); } /********************************************************************** * Server **********************************************************************/ struct afsconf_dir *globalDir; int STEST_CanI(struct rx_call *call, afs_int32 *result) { *result = 0; if (!afsconf_SuperUser(globalDir, call, NULL)) { return EPERM; } return 0; } int STEST_NewCanI(struct rx_call *call, afs_int32 *result) { *result = 0; if (!afsconf_SuperIdentity(globalDir, call, NULL)) { return EPERM; } return 0; } int STEST_WhoAmI(struct rx_call *call, char **result) { char string[MAXKTCNAMELEN]; if (!afsconf_SuperUser(globalDir, call, string)) { *result = strdup(""); return EPERM; } *result = strdup(string); return 0; } int STEST_NewWhoAmI(struct rx_call *call, char **result) { struct rx_identity *id; if (!afsconf_SuperIdentity(globalDir, call, &id)) { *result = strdup(""); return EPERM; } *result = strdup(id->displayName); return 0; } int main(int argc, char **argv) { struct afsconf_dir *dir; char *dirname; int serverPid, clientPid, waited, stat; int code; int ret = 0; afstest_SkipTestsIfBadHostname(); /* Start the client and the server if requested */ if (argc == 3 ) { if (strcmp(argv[1], "-server") == 0) { globalDir = afsconf_Open(argv[2]); afstest_StartTestRPCService(argv[2], TEST_PORT, TEST_SERVICE_ID, TEST_ExecuteRequest); exit(0); } else if (strcmp(argv[1], "-client") == 0) { startClient(argv[2]); exit(0); } else { printf("Bad option %s\n", argv[1]); exit(1); } } /* Otherwise, do the basic configuration, then start the client and * server */ dirname = afstest_BuildTestConfig(); dir = afsconf_Open(dirname); if (dir == NULL) { fprintf(stderr, "Unable to configure directory.\n"); ret = 1; goto out; } code = afstest_AddDESKeyFile(dir); if (code) { afs_com_err("superuser-t", code, "while adding new key\n"); ret = 1; goto out; } printf("Config directory is %s\n", dirname); serverPid = fork(); if (serverPid == -1) { /* Bang */ } else if (serverPid == 0) { execl(argv[0], argv[0], "-server", dirname, NULL); ret = 1; goto out; } clientPid = fork(); if (clientPid == -1) { kill(serverPid, SIGTERM); waitpid(serverPid, &stat, 0); ret = 1; goto out; } else if (clientPid == 0) { execl(argv[0], argv[0], "-client", dirname, NULL); } do { waited = waitpid(0, &stat, 0); } while(waited == -1 && errno == EINTR); if (waited == serverPid) { kill(clientPid, SIGTERM); } else if (waited == clientPid) { kill(serverPid, SIGTERM); } waitpid(0, &stat, 0); out: /* Client and server are both done, so cleanup after everything */ afstest_UnlinkTestConfig(dirname); return ret; }