tests: Start using the upstream C TAP harness
[openafs.git] / tests / auth / superuser-t.c
1 /*
2  * Copyright (c) 2010 Your File System Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23  */
24 #include <afsconfig.h>
25 #include <afs/param.h>
26
27 #include <roken.h>
28
29 #ifdef HAVE_SYS_WAIT_H
30 #include <sys/wait.h>
31 #endif
32
33 #ifdef IGNORE_SOME_GCC_WARNINGS
34 # pragma GCC diagnostic warning "-Wdeprecated-declarations"
35 #endif
36
37 #include <afs/cellconfig.h>
38 #include <afs/afsutil.h>
39 #include <afs/com_err.h>
40
41 #include <rx/rxkad.h>
42 #include <rx/rx_identity.h>
43
44 #include <tests/tap/basic.h>
45
46 #include "test.h"
47 #include "common.h"
48
49 #define TEST_PORT 1234
50
51 static void
52 testOriginalIterator(struct afsconf_dir *dir, int num, char *user) {
53     char buffer[256];
54
55     ok((afsconf_GetNthUser(dir, num, buffer, sizeof buffer) == 0),
56        "User %d successfully returned as %s", num, buffer);
57
58     ok(strcmp(user, buffer) == 0,
59        "User %d matches", num);
60 }
61
62 static void
63 testNewIterator(struct afsconf_dir *dir, int num, struct rx_identity *id) {
64     struct rx_identity *fileId;
65
66     ok((afsconf_GetNthIdentity(dir, num, &fileId) == 0),
67        "Identity %d successfully returned", num);
68
69     ok(rx_identity_match(fileId, id), "Identity %d matches", num);
70
71     rx_identity_free(&fileId);
72 }
73
74
75 void
76 startClient(char *configPath)
77 {
78     struct afsconf_dir *dir;
79     struct rx_identity *testId, *anotherId, *extendedId, *dummy;
80     struct rx_securityClass *class;
81     struct rx_connection *conn;
82     afs_uint32 startTime;
83     char ubuffer[256];
84     afs_int32 classIndex;
85     int code;
86     struct hostent *he;
87     afs_uint32 addr;
88     afs_int32 result;
89     char *string = NULL;
90
91     plan(63);
92
93     dir = afsconf_Open(configPath);
94     ok(dir!=NULL,
95        "Configuration directory opened sucessfully by client");
96
97     /* Add a normal user to the super user file */
98     ok(afsconf_AddUser(dir, "test") == 0,
99        "Adding a simple user works");
100
101     testId = rx_identity_new(RX_ID_KRB4, "test", "test", strlen("test"));
102
103     /* Check that they are a super user */
104     ok(afsconf_IsSuperIdentity(dir, testId),
105        "User added with old i/face is identitifed as super user");
106
107     /* Check that nobody else is */
108     ok(!afsconf_IsSuperIdentity(dir,
109                                rx_identity_new(RX_ID_KRB4, "testy",
110                                                "testy", strlen("testy"))),
111        "Additional users are not super users");
112
113     ok(afsconf_AddUser(dir, "test") == EEXIST,
114        "Adding a user that already exists fails");
115
116     ok(afsconf_AddIdentity(dir, testId) == EEXIST,
117        "Adding an identity that already exists fails");
118
119     anotherId = rx_identity_new(RX_ID_KRB4, "another",
120                                             "another", strlen("another"));
121
122     /* Add another normal user, but using the extended interface */
123     ok(afsconf_AddIdentity(dir, anotherId) == 0,
124        "Adding a KRB4 identity works");
125
126     /* Check that they are a super user */
127     ok(afsconf_IsSuperIdentity(dir, anotherId),
128        "User added with new i/face is identitifed as super user");
129
130     ok(afsconf_AddIdentity(dir, anotherId) == EEXIST,
131        "Adding a KRB4 identity that already exists fails");
132
133     /* Add an extended user to the super user file */
134     extendedId = rx_identity_new(RX_ID_GSS, "sxw@INF.ED.AC.UK",
135                                  "\x04\x01\x00\x0B\x06\x09\x2A\x86\x48\x86\xF7\x12\x01\x02\x02\x00\x00\x00\x10sxw@INF.ED.AC.UK", 35);
136
137     ok(afsconf_AddIdentity(dir, extendedId) == 0,
138        "Adding a GSSAPI identity works");
139
140     /* Check that they are now special */
141     ok(afsconf_IsSuperIdentity(dir, extendedId),
142        "Added GSSAPI identity is a super user");
143
144     /* Check that display name isn't used for matches */
145     ok(!afsconf_IsSuperIdentity(dir,
146                                 rx_identity_new(RX_ID_GSS, "sxw@INF.ED.AC.UK",
147                                                 "abcdefghijklmnopqrstuvwxyz123456789", 35)),
148        "Display name is not used for extended matches");
149
150     ok(afsconf_AddIdentity(dir, extendedId) == EEXIST,
151        "Adding GSSAPI identity twice fails");
152
153     /* Add a final normal user, so we can check that iteration works */
154     /* Add a normal user to the super user file */
155     ok(afsconf_AddUser(dir, "test2") == 0,
156        "Adding another simple user works");
157
158     testOriginalIterator(dir, 0, "test");
159     testOriginalIterator(dir, 1, "another");
160     testOriginalIterator(dir, 2, "test2");
161     ok(afsconf_GetNthUser(dir, 3, ubuffer, sizeof ubuffer) != 0,
162        "Reading past the end of the superuser list fails");
163
164     testNewIterator(dir, 0, testId);
165     testNewIterator(dir, 1, anotherId);
166     testNewIterator(dir, 2, extendedId);
167     testNewIterator(dir, 3, rx_identity_new(RX_ID_KRB4, "test2",
168                                             "test2", strlen("test2")));
169     ok(afsconf_GetNthIdentity(dir, 4, &dummy) != 0,
170        "Reading past the end of the superuser list fails");
171
172     ok(afsconf_DeleteUser(dir, "notthere") != 0,
173        "Deleting a user that doesn't exist fails");
174
175     /* Delete the normal user */
176     ok(afsconf_DeleteUser(dir, "another") == 0,
177        "Deleting normal user works");
178
179     ok(!afsconf_IsSuperIdentity(dir, anotherId),
180        "Deleted user is no longer super user");
181
182     ok(afsconf_IsSuperIdentity(dir, testId) &&
183        afsconf_IsSuperIdentity(dir, extendedId),
184        "Other identities still are");
185
186     ok(afsconf_DeleteIdentity(dir, extendedId) == 0,
187        "Deleting identity works");
188
189     ok(!afsconf_IsSuperIdentity(dir, extendedId),
190        "Deleted identity is no longer special");
191
192     /* Now, what happens if we're doing something over the network instead */
193
194     code = rx_Init(0);
195     is_int(code, 0, "Initialised RX");
196
197     /* Fake up an rx ticket. Note that this will be for the magic 'superuser' */
198     code = afsconf_ClientAuth(dir, &class, &classIndex);
199     is_int(code, 0, "Can successfully create superuser token");
200
201     /* Start a connection to our test service with it */
202     he = gethostbyname("localhost");
203     if (!he) {
204         printf("Couldn't look up server hostname");
205         exit(1);
206     }
207
208     memcpy(&addr, he->h_addr, sizeof(afs_uint32));
209
210     conn = rx_NewConnection(addr, htons(TEST_PORT), TEST_SERVICE_ID,
211                             class, classIndex);
212
213     /* There's nothing in the list, so this just succeeds because we can */
214     code = TEST_CanI(conn, &result);
215     is_int(0, code, "Can run a simple RPC");
216
217     code = TEST_WhoAmI(conn, &string);
218     is_int(0, code, "Can get identity back");
219     is_string("<LocalAuth>", string, "Forged token is super user");
220
221     xdr_free((xdrproc_t)xdr_string, &string);
222
223     /* Throw away this connection and security class */
224     rx_DestroyConnection(conn);
225     rxs_Release(class);
226
227     /* Now fake an rx ticket for a normal user. We have to do more work by hand
228      * here, sadly */
229
230     startTime = time(NULL);
231     class = afstest_FakeRxkadClass(dir, "rpctest", "", "", startTime,
232                                    startTime + 60* 60);
233
234     conn = rx_NewConnection(addr, htons(TEST_PORT), TEST_SERVICE_ID, class,
235                             RX_SECIDX_KAD);
236
237     code = TEST_CanI(conn, &result);
238     is_int(EPERM, code,
239            "Running RPC as non-super user fails as expected");
240     code = TEST_NewCanI(conn, &result);
241     is_int(EPERM, code,
242            "Running new interface RPC as non-super user fails as expected");
243     code = TEST_WhoAmI(conn, &string);
244     xdr_free((xdrproc_t)xdr_string, &string);
245     is_int(EPERM, code,
246            "Running RPC returning string fails as expected");
247     code = TEST_NewWhoAmI(conn, &string);
248     xdr_free((xdrproc_t)xdr_string, &string);
249     is_int(EPERM, code,
250            "Running new interface RPC returning string fails as expected");
251     ok(afsconf_AddUser(dir, "rpctest") == 0,
252        "Adding %s user works", "rpctest");
253     code = TEST_CanI(conn, &result);
254     is_int(0, code, "Running RPC as rpctest works");
255     code = TEST_NewCanI(conn, &result);
256     is_int(0, code, "Running new interface RPC as rpctest works");
257     code = TEST_WhoAmI(conn, &string);
258     is_int(0, code, "Running RPC returning string as %s works", "rpctest");
259     is_string("rpctest", string, "Returned user string matches");
260     xdr_free((xdrproc_t)xdr_string, &string);
261     code = TEST_NewWhoAmI(conn, &string);
262     is_int(0, code, "Running new RPC returning string as %s works", "rpctest");
263     is_string("rpctest", string, "Returned user string for new interface matches");
264     xdr_free((xdrproc_t)xdr_string, &string);
265     rx_DestroyConnection(conn);
266     rxs_Release(class);
267
268     /* Now try with an admin principal */
269     startTime = time(NULL);
270     class = afstest_FakeRxkadClass(dir, "rpctest", "admin", "", startTime,
271                                    startTime + 60* 60);
272
273     conn = rx_NewConnection(addr, htons(TEST_PORT), TEST_SERVICE_ID, class,
274                             RX_SECIDX_KAD);
275
276     code = TEST_CanI(conn, &result);
277     is_int(EPERM, code,
278            "Running RPC as non-super user fails as expected");
279     code = TEST_NewCanI(conn, &result);
280     is_int(EPERM, code,
281            "Running new interface RPC as non-super user fails as expected");
282     code = TEST_WhoAmI(conn, &string);
283     xdr_free((xdrproc_t)xdr_string, &string);
284     is_int(EPERM, code,
285            "Running RPC returning string fails as expected");
286     code = TEST_NewWhoAmI(conn, &string);
287     xdr_free((xdrproc_t)xdr_string, &string);
288     is_int(EPERM, code,
289            "Running new interface RPC returning string fails as expected");
290
291     ok(afsconf_AddUser(dir, "rpctest.admin") == 0,
292        "Adding %s user works", "rpctest.admin");
293
294     code = TEST_CanI(conn, &result);
295     is_int(0, code, "Running RPC as %s works", "rpctest/admin");
296     code = TEST_NewCanI(conn, &result);
297     is_int(0, code, "Running new interface RPC as %s works", "rpctest/admin");
298     code = TEST_WhoAmI(conn, &string);
299     is_int(0, code, "Running RPC returning string as %s works", "rpctest/admin");
300     is_string("rpctest.admin", string, "Returned user string matches");
301     xdr_free((xdrproc_t)xdr_string, &string);
302     code = TEST_NewWhoAmI(conn, &string);
303     is_int(0, code, "Running new interface RPC returning string as %s works",
304            "rpctest/admin");
305     is_string("rpctest.admin", string,
306               "Returned user string from new interface matches");
307     xdr_free((xdrproc_t)xdr_string, &string);
308
309     rx_DestroyConnection(conn);
310     rxs_Release(class);
311 }
312
313 /**********************************************************************
314  * Server
315  **********************************************************************/
316
317 struct afsconf_dir *globalDir;
318
319 int
320 STEST_CanI(struct rx_call *call, afs_int32 *result)
321 {
322     *result = 0;
323     if (!afsconf_SuperUser(globalDir, call, NULL)) {
324         return EPERM;
325     }
326     return 0;
327 }
328
329 int
330 STEST_NewCanI(struct rx_call *call, afs_int32 *result)
331 {
332     *result = 0;
333     if (!afsconf_SuperIdentity(globalDir, call, NULL)) {
334         return EPERM;
335     }
336     return 0;
337 }
338
339 int
340 STEST_WhoAmI(struct rx_call *call, char **result)
341 {
342    char string[MAXKTCNAMELEN];
343
344    if (!afsconf_SuperUser(globalDir, call, string)) {
345         *result = strdup("");
346         return EPERM;
347    }
348    *result = strdup(string);
349
350    return 0;
351 }
352
353 int
354 STEST_NewWhoAmI(struct rx_call *call, char **result)
355 {
356    struct rx_identity *id;
357
358    if (!afsconf_SuperIdentity(globalDir, call, &id)) {
359         *result = strdup("");
360         return EPERM;
361    }
362    *result = strdup(id->displayName);
363
364    return 0;
365 }
366
367 void
368 startServer(char *configPath)
369 {
370     struct rx_securityClass **classes;
371     afs_int32 numClasses;
372     int code;
373     struct rx_service *service;
374
375     globalDir = afsconf_Open(configPath);
376     if (globalDir == NULL) {
377         fprintf(stderr, "Server: Unable to open config directory\n");
378         exit(1);
379     }
380
381     code = rx_Init(htons(TEST_PORT));
382     if (code != 0) {
383         fprintf(stderr, "Server: Unable to initialise RX\n");
384         exit(1);
385     }
386
387     afsconf_BuildServerSecurityObjects(globalDir, &classes, &numClasses);
388     service = rx_NewService(0, TEST_SERVICE_ID, "test", classes, numClasses,
389                             TEST_ExecuteRequest);
390     if (service == NULL) {
391         fprintf(stderr, "Server: Unable to start to test service\n");
392         exit(1);
393     }
394
395     rx_StartServer(1);
396 }
397
398 int main(int argc, char **argv)
399 {
400     struct afsconf_dir *dir;
401     char *dirname;
402     int serverPid, clientPid, waited, stat;
403     int code;
404
405     /* Start the client and the server if requested */
406
407     if (argc == 3 ) {
408         if (strcmp(argv[1], "-server") == 0) {
409             startServer(argv[2]);
410             exit(0);
411         } else if (strcmp(argv[1], "-client") == 0) {
412             startClient(argv[2]);
413             exit(0);
414         } else {
415             printf("Bad option %s\n", argv[1]);
416             exit(1);
417         }
418     }
419
420     /* Otherwise, do the basic configuration, then start the client and
421      * server */
422
423     dirname = afstest_BuildTestConfig();
424
425     dir = afsconf_Open(dirname);
426     if (dir == NULL) {
427         fprintf(stderr, "Unable to configure directory.\n");
428         exit(1);
429     }
430
431     code = afstest_AddDESKeyFile(dir);
432     if (code) {
433         afs_com_err("superuser-t", code, "while adding new key\n");
434         exit(1);
435     }
436
437     printf("Config directory is %s\n", dirname);
438     serverPid = fork();
439     if (serverPid == -1) {
440         /* Bang */
441     } else if (serverPid == 0) {
442         execl(argv[0], argv[0], "-server", dirname, NULL);
443         exit(1);
444     }
445     clientPid = fork();
446     if (clientPid == -1) {
447         kill(serverPid, SIGTERM);
448         waitpid(serverPid, &stat, 0);
449         exit(1);
450     } else if (clientPid == 0) {
451         execl(argv[0], argv[0], "-client", dirname, NULL);
452     }
453
454     do {
455         waited = waitpid(0, &stat, 0);
456     } while(waited == -1 && errno == EINTR);
457
458     if (waited == serverPid) {
459         kill(clientPid, SIGTERM);
460     } else if (waited == clientPid) {
461         kill(serverPid, SIGTERM);
462     }
463     waitpid(0, &stat, 0);
464
465     /* Client and server are both done, so cleanup after everything */
466
467     /* unlinkTestConfig(dirname); */
468
469     return 0;
470 }