mirror of
https://git.openafs.org/openafs.git
synced 2025-01-18 23:10:58 +00:00
22a66e7b7e
Commit "Build tests by default" 68f406436c
changes the build so tests are always built.
On Solaris 10 the build fails because nanosleep is in librt, which we do
not link against.
Replace nanosleep with usleep. This avoids introducing extra configure
tests just for Solaris 10.
Note that with Solaris 11 nanosleep was moved from librt to libc, the
standard C library.
Change-Id: I6639f32bb8c8ace438e0092a866f06561dad54f1
Reviewed-on: https://gerrit.openafs.org/14244
Reviewed-by: Andrew Deason <adeason@sinenomine.net>
Tested-by: BuildBot <buildbot@rampaginggeek.com>
Reviewed-by: Benjamin Kaduk <kaduk@mit.edu>
496 lines
15 KiB
C
496 lines
15 KiB
C
/*
|
|
* 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 <afsconfig.h>
|
|
#include <afs/param.h>
|
|
|
|
#include <roken.h>
|
|
|
|
#ifdef HAVE_SYS_WAIT_H
|
|
#include <sys/wait.h>
|
|
#endif
|
|
#include <signal.h>
|
|
#include <time.h>
|
|
|
|
#ifdef IGNORE_SOME_GCC_WARNINGS
|
|
# pragma GCC diagnostic warning "-Wdeprecated-declarations"
|
|
#endif
|
|
|
|
#include <afs/cellconfig.h>
|
|
#include <afs/afsutil.h>
|
|
#include <afs/com_err.h>
|
|
|
|
#include <rx/rxkad.h>
|
|
#include <rx/rx_identity.h>
|
|
|
|
#include <hcrypto/des.h>
|
|
#include <tests/tap/basic.h>
|
|
|
|
#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("<LocalAuth>", 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;
|
|
}
|
|
|
|
/*
|
|
* Primitive replacement for using sigtimedwait(). Just see if 'signo' is
|
|
* pending, and if it's not, wait 100ms and try again. Try this for
|
|
* approximately as many times as it takes to wait for 'nsecs' seconds.
|
|
*/
|
|
static int
|
|
waitforsig(int signo, int nsecs)
|
|
{
|
|
int nsleeps;
|
|
|
|
for (nsleeps = 0; nsleeps < nsecs * 10; nsleeps++) {
|
|
sigset_t set;
|
|
int code;
|
|
|
|
opr_Verify(sigpending(&set) == 0);
|
|
if (sigismember(&set, signo)) {
|
|
return 0;
|
|
}
|
|
|
|
/* Sleep for 100ms */
|
|
code = usleep(100000);
|
|
opr_Assert(code == 0 || errno == EINTR);
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
struct afsconf_dir *dir;
|
|
char *dirname;
|
|
int serverPid, clientPid, waited, stat;
|
|
int code;
|
|
int ret = 0;
|
|
sigset_t set;
|
|
char *argv0 = afstest_GetProgname(argv);
|
|
|
|
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], getppid(), 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 */
|
|
|
|
sigemptyset(&set);
|
|
sigaddset(&set, SIGUSR1);
|
|
opr_Verify(sigprocmask(SIG_BLOCK, &set, NULL) == 0);
|
|
|
|
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(argv0, 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;
|
|
}
|
|
|
|
/* Our server child pid will send us a SIGUSR1 when it's started listening
|
|
* on its port. Wait for up to 5 seconds to get the USR1. */
|
|
if (waitforsig(SIGUSR1, 5) != 0) {
|
|
fprintf(stderr, "%s: Timed out waiting for SIGUSR1 from server child\n",
|
|
argv0);
|
|
kill(serverPid, SIGTERM);
|
|
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;
|
|
}
|