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