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