c2ebbc6f10fb5edbf5e13fdb22692026b29bfa6c
[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 <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 struct rx_securityClass *
75 fakeRXKADClass(struct afsconf_dir *dir,
76                char *name, char *instance, char *realm,
77                afs_uint32 startTime, afs_uint32 endTime)
78 {
79     int code;
80     char buffer[256];
81     struct ktc_encryptionKey key, session;
82     afs_int32 kvno;
83     afs_int32 ticketLen;
84     struct rx_securityClass *class = NULL;
85
86     code = afsconf_GetLatestKey(dir, &kvno, &key);
87     if (code)
88         goto out;
89
90     DES_init_random_number_generator((DES_cblock *) &key);
91     code = DES_new_random_key((DES_cblock *) &session);
92     if (code)
93         goto out;
94
95     ticketLen = sizeof(buffer);
96     memset(buffer, 0, sizeof(buffer));
97     startTime = time(NULL);
98     endTime = startTime + 60 * 60;
99
100     code = tkt_MakeTicket(buffer, &ticketLen, &key, name, instance, realm,
101                           startTime, endTime, &session, 0, "afs", "");
102     if (code)
103         goto out;
104
105     class = rxkad_NewClientSecurityObject(rxkad_clear, &session, kvno,
106                                           ticketLen, buffer);
107 out:
108     return class;
109 }
110
111
112 void
113 startClient(char *configPath)
114 {
115     struct afsconf_dir *dir;
116     struct rx_identity *testId, *anotherId, *extendedId, *dummy;
117     struct rx_securityClass *class;
118     struct rx_connection *conn;
119     afs_uint32 startTime;
120     char ubuffer[256];
121     afs_int32 classIndex;
122     int code;
123     struct hostent *he;
124     afs_uint32 addr;
125     afs_int32 result;
126     char *string = NULL;
127
128     plan(63);
129
130     dir = afsconf_Open(configPath);
131     ok(dir!=NULL,
132        "Configuration directory opened sucessfully by client");
133
134     /* Add a normal user to the super user file */
135     ok(afsconf_AddUser(dir, "test") == 0,
136        "Adding a simple user works");
137
138     testId = rx_identity_new(RX_ID_KRB4, "test", "test", strlen("test"));
139
140     /* Check that they are a super user */
141     ok(afsconf_IsSuperIdentity(dir, testId),
142        "User added with old i/face is identitifed as super user");
143
144     /* Check that nobody else is */
145     ok(!afsconf_IsSuperIdentity(dir,
146                                rx_identity_new(RX_ID_KRB4, "testy",
147                                                "testy", strlen("testy"))),
148        "Additional users are not super users");
149
150     ok(afsconf_AddUser(dir, "test") == EEXIST,
151        "Adding a user that already exists fails");
152
153     ok(afsconf_AddIdentity(dir, testId) == EEXIST,
154        "Adding an identity that already exists fails");
155
156     anotherId = rx_identity_new(RX_ID_KRB4, "another",
157                                             "another", strlen("another"));
158
159     /* Add another normal user, but using the extended interface */
160     ok(afsconf_AddIdentity(dir, anotherId) == 0,
161        "Adding a KRB4 identity works");
162
163     /* Check that they are a super user */
164     ok(afsconf_IsSuperIdentity(dir, anotherId),
165        "User added with new i/face is identitifed as super user");
166
167     ok(afsconf_AddIdentity(dir, anotherId) == EEXIST,
168        "Adding a KRB4 identity that already exists fails");
169
170     /* Add an extended user to the super user file */
171     extendedId = rx_identity_new(RX_ID_GSS, "sxw@INF.ED.AC.UK",
172                                  "\x04\x01\x00\x0B\x06\x09\x2A\x86\x48\x86\xF7\x12\x01\x02\x02\x00\x00\x00\x10sxw@INF.ED.AC.UK", 35);
173
174     ok(afsconf_AddIdentity(dir, extendedId) == 0,
175        "Adding a GSSAPI identity works");
176
177     /* Check that they are now special */
178     ok(afsconf_IsSuperIdentity(dir, extendedId),
179        "Added GSSAPI identity is a super user");
180
181     /* Check that display name isn't used for matches */
182     ok(!afsconf_IsSuperIdentity(dir,
183                                 rx_identity_new(RX_ID_GSS, "sxw@INF.ED.AC.UK",
184                                                 "abcdefghijklmnopqrstuvwxyz123456789", 35)),
185        "Display name is not used for extended matches");
186
187     ok(afsconf_AddIdentity(dir, extendedId) == EEXIST,
188        "Adding GSSAPI identity twice fails");
189
190     /* Add a final normal user, so we can check that iteration works */
191     /* Add a normal user to the super user file */
192     ok(afsconf_AddUser(dir, "test2") == 0,
193        "Adding another simple user works");
194
195     testOriginalIterator(dir, 0, "test");
196     testOriginalIterator(dir, 1, "another");
197     testOriginalIterator(dir, 2, "test2");
198     ok(afsconf_GetNthUser(dir, 3, ubuffer, sizeof ubuffer) != 0,
199        "Reading past the end of the superuser list fails");
200
201     testNewIterator(dir, 0, testId);
202     testNewIterator(dir, 1, anotherId);
203     testNewIterator(dir, 2, extendedId);
204     testNewIterator(dir, 3, rx_identity_new(RX_ID_KRB4, "test2",
205                                             "test2", strlen("test2")));
206     ok(afsconf_GetNthIdentity(dir, 4, &dummy) != 0,
207        "Reading past the end of the superuser list fails");
208
209     ok(afsconf_DeleteUser(dir, "notthere") != 0,
210        "Deleting a user that doesn't exist fails");
211
212     /* Delete the normal user */
213     ok(afsconf_DeleteUser(dir, "another") == 0,
214        "Deleting normal user works");
215
216     ok(!afsconf_IsSuperIdentity(dir, anotherId),
217        "Deleted user is no longer super user");
218
219     ok(afsconf_IsSuperIdentity(dir, testId) &&
220        afsconf_IsSuperIdentity(dir, extendedId),
221        "Other identities still are");
222
223     ok(afsconf_DeleteIdentity(dir, extendedId) == 0,
224        "Deleting identity works");
225
226     ok(!afsconf_IsSuperIdentity(dir, extendedId),
227        "Deleted identity is no longer special");
228
229     /* Now, what happens if we're doing something over the network instead */
230
231     code = rx_Init(0);
232     is_int(code, 0, "Initialised RX");
233
234     /* Fake up an rx ticket. Note that this will be for the magic 'superuser' */
235     code = afsconf_ClientAuth(dir, &class, &classIndex);
236     is_int(code, 0, "Can successfully create superuser token");
237
238     /* Start a connection to our test service with it */
239     he = gethostbyname("localhost");
240     if (!he) {
241         printf("Couldn't look up server hostname");
242         exit(1);
243     }
244
245     memcpy(&addr, he->h_addr, sizeof(afs_uint32));
246
247     conn = rx_NewConnection(addr, htons(TEST_PORT), TEST_SERVICE_ID,
248                             class, classIndex);
249
250     /* There's nothing in the list, so this just succeeds because we can */
251     code = TEST_CanI(conn, &result);
252     is_int(0, code, "Can run a simple RPC");
253
254     code = TEST_WhoAmI(conn, &string);
255     is_int(0, code, "Can get identity back");
256     is_string("<LocalAuth>", string, "Forged token is super user");
257
258     xdr_free((xdrproc_t)xdr_string, &string);
259
260     /* Throw away this connection and security class */
261     rx_DestroyConnection(conn);
262     rxs_Release(class);
263
264     /* Now fake an rx ticket for a normal user. We have to do more work by hand
265      * here, sadly */
266
267     startTime = time(NULL);
268     class = fakeRXKADClass(dir, "rpctest", "", "", startTime, startTime + 60* 60);
269
270     conn = rx_NewConnection(addr, htons(TEST_PORT), TEST_SERVICE_ID, class,
271                             RX_SECIDX_KAD);
272
273     code = TEST_CanI(conn, &result);
274     is_int(EPERM, code,
275            "Running RPC as non-super user fails as expected");
276     code = TEST_NewCanI(conn, &result);
277     is_int(EPERM, code,
278            "Running new interface RPC as non-super user fails as expected");
279     code = TEST_WhoAmI(conn, &string);
280     xdr_free((xdrproc_t)xdr_string, &string);
281     is_int(EPERM, code,
282            "Running RPC returning string fails as expected");
283     code = TEST_NewWhoAmI(conn, &string);
284     xdr_free((xdrproc_t)xdr_string, &string);
285     is_int(EPERM, code,
286            "Running new interface RPC returning string fails as expected");
287     ok(afsconf_AddUser(dir, "rpctest") == 0,
288        "Adding %s user works", "rpctest");
289     code = TEST_CanI(conn, &result);
290     is_int(0, code, "Running RPC as rpctest works");
291     code = TEST_NewCanI(conn, &result);
292     is_int(0, code, "Running new interface RPC as rpctest works");
293     code = TEST_WhoAmI(conn, &string);
294     is_int(0, code, "Running RPC returning string as %s works", "rpctest");
295     is_string("rpctest", string, "Returned user string matches");
296     xdr_free((xdrproc_t)xdr_string, &string);
297     code = TEST_NewWhoAmI(conn, &string);
298     is_int(0, code, "Running new RPC returning string as %s works", "rpctest");
299     is_string("rpctest", string, "Returned user string for new interface matches");
300     xdr_free((xdrproc_t)xdr_string, &string);
301     rx_DestroyConnection(conn);
302     rxs_Release(class);
303
304     /* Now try with an admin principal */
305     startTime = time(NULL);
306     class = fakeRXKADClass(dir, "rpctest", "admin", "", startTime,
307                       startTime + 60* 60);
308
309     conn = rx_NewConnection(addr, htons(TEST_PORT), TEST_SERVICE_ID, class,
310                             RX_SECIDX_KAD);
311
312     code = TEST_CanI(conn, &result);
313     is_int(EPERM, code,
314            "Running RPC as non-super user fails as expected");
315     code = TEST_NewCanI(conn, &result);
316     is_int(EPERM, code,
317            "Running new interface RPC as non-super user fails as expected");
318     code = TEST_WhoAmI(conn, &string);
319     xdr_free((xdrproc_t)xdr_string, &string);
320     is_int(EPERM, code,
321            "Running RPC returning string fails as expected");
322     code = TEST_NewWhoAmI(conn, &string);
323     xdr_free((xdrproc_t)xdr_string, &string);
324     is_int(EPERM, code,
325            "Running new interface RPC returning string fails as expected");
326
327     ok(afsconf_AddUser(dir, "rpctest.admin") == 0,
328        "Adding %s user works", "rpctest.admin");
329
330     code = TEST_CanI(conn, &result);
331     is_int(0, code, "Running RPC as %s works", "rpctest/admin");
332     code = TEST_NewCanI(conn, &result);
333     is_int(0, code, "Running new interface RPC as %s works", "rpctest/admin");
334     code = TEST_WhoAmI(conn, &string);
335     is_int(0, code, "Running RPC returning string as %s works", "rpctest/admin");
336     is_string("rpctest.admin", string, "Returned user string matches");
337     xdr_free((xdrproc_t)xdr_string, &string);
338     code = TEST_NewWhoAmI(conn, &string);
339     is_int(0, code, "Running new interface RPC returning string as %s works",
340            "rpctest/admin");
341     is_string("rpctest.admin", string,
342               "Returned user string from new interface matches");
343     xdr_free((xdrproc_t)xdr_string, &string);
344
345     rx_DestroyConnection(conn);
346     rxs_Release(class);
347 }
348
349 /**********************************************************************
350  * Server
351  **********************************************************************/
352
353 struct afsconf_dir *globalDir;
354
355 int
356 STEST_CanI(struct rx_call *call, afs_int32 *result)
357 {
358     *result = 0;
359     if (!afsconf_SuperUser(globalDir, call, NULL)) {
360         return EPERM;
361     }
362     return 0;
363 }
364
365 int
366 STEST_NewCanI(struct rx_call *call, afs_int32 *result)
367 {
368     *result = 0;
369     if (!afsconf_SuperIdentity(globalDir, call, NULL)) {
370         return EPERM;
371     }
372     return 0;
373 }
374
375 int
376 STEST_WhoAmI(struct rx_call *call, char **result)
377 {
378    char string[MAXKTCNAMELEN];
379
380    if (!afsconf_SuperUser(globalDir, call, string)) {
381         *result = strdup("");
382         return EPERM;
383    }
384    *result = strdup(string);
385
386    return 0;
387 }
388
389 int
390 STEST_NewWhoAmI(struct rx_call *call, char **result)
391 {
392    struct rx_identity *id;
393
394    if (!afsconf_SuperIdentity(globalDir, call, &id)) {
395         *result = strdup("");
396         return EPERM;
397    }
398    *result = strdup(id->displayName);
399
400    return 0;
401 }
402
403 void
404 startServer(char *configPath)
405 {
406     struct rx_securityClass **classes;
407     afs_int32 numClasses;
408     int code;
409     struct rx_service *service;
410
411     globalDir = afsconf_Open(configPath);
412     if (globalDir == NULL) {
413         fprintf(stderr, "Server: Unable to open config directory\n");
414         exit(1);
415     }
416
417     code = rx_Init(htons(TEST_PORT));
418     if (code != 0) {
419         fprintf(stderr, "Server: Unable to initialise RX\n");
420         exit(1);
421     }
422
423     afsconf_BuildServerSecurityObjects(globalDir, &classes, &numClasses);
424     service = rx_NewService(0, TEST_SERVICE_ID, "test", classes, numClasses,
425                             TEST_ExecuteRequest);
426     if (service == NULL) {
427         fprintf(stderr, "Server: Unable to start to test service\n");
428         exit(1);
429     }
430
431     rx_StartServer(1);
432 }
433
434 int main(int argc, char **argv)
435 {
436     struct afsconf_dir *dir;
437     char *dirname;
438     int serverPid, clientPid, waited, stat;
439     char keymaterial[]="\x19\x17\xff\xe6\xbb\x77\x2e\xfc";
440     int code;
441
442     /* Start the client and the server if requested */
443
444     if (argc == 3 ) {
445         if (strcmp(argv[1], "-server") == 0) {
446             startServer(argv[2]);
447             exit(0);
448         } else if (strcmp(argv[1], "-client") == 0) {
449             startClient(argv[2]);
450             exit(0);
451         } else {
452             printf("Bad option %s\n", argv[1]);
453             exit(1);
454         }
455     }
456
457     /* Otherwise, do the basic configuration, then start the client and
458      * server */
459
460     dirname = buildTestConfig();
461
462     dir = afsconf_Open(dirname);
463     if (dir == NULL) {
464         fprintf(stderr, "Unable to configure directory.\n");
465         exit(1);
466     }
467
468     DES_set_odd_parity((DES_cblock *)keymaterial);
469
470     /* Add a key to it so we can use it for connection tests */
471     code = afsconf_AddKey(dir, 1, keymaterial, 1);
472     if (code) {
473         afs_com_err("superuser-t", code, "while adding new key\n");
474         exit(1);
475     }
476
477     printf("Config directory is %s\n", dirname);
478     serverPid = fork();
479     if (serverPid == -1) {
480         /* Bang */
481     } else if (serverPid == 0) {
482         execl(argv[0], argv[0], "-server", dirname, NULL);
483         exit(1);
484     }
485     clientPid = fork();
486     if (clientPid == -1) {
487         kill(serverPid, SIGTERM);
488         waitpid(serverPid, &stat, 0);
489         exit(1);
490     } else if (clientPid == 0) {
491         execl(argv[0], argv[0], "-client", dirname, NULL);
492     }
493
494     do {
495         waited = waitpid(0, &stat, 0);
496     } while(waited == -1 && errno == EINTR);
497
498     if (waited == serverPid) {
499         kill(clientPid, SIGTERM);
500     } else if (waited == clientPid) {
501         kill(serverPid, SIGTERM);
502     }
503     waitpid(0, &stat, 0);
504
505     /* Client and server are both done, so cleanup after everything */
506
507     /* unlinkTestConfig(dirname); */
508
509     return 0;
510 }