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