death to register
[openafs.git] / src / kauth / test / test_rxkad_free.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 #include <afsconfig.h>
11 #include <afs/param.h>
12
13
14 #include <afs/stds.h>
15 #include <sys/types.h>
16 #include <sys/time.h>
17 #include <sys/resource.h>
18 #include <stdio.h>
19 #include <netinet/in.h>
20 #include <netdb.h>
21 #include <rx/rx.h>
22 #include <ubik.h>
23 #include <pwd.h>
24 #include <afs/auth.h>
25 #include <afs/cellconfig.h>
26 #include <afs/cmd.h>
27 #include <afs/com_err.h>
28
29 #include "kauth.h"
30 #include "kautils.h"
31
32
33 char *whoami = "test_rxkad_free";
34
35 static void
36 PrintRxkadStats()
37 {
38     printf("New Objects client %d, server %d.  Destroyed objects %d.\n",
39            rxkad_stats.clientObjects, rxkad_stats.serverObjects,
40            rxkad_stats.destroyObject);
41     printf("client conns: %d %d %d, destroyed client %d.\n",
42            rxkad_stats.connections[0], rxkad_stats.connections[1],
43            rxkad_stats.connections[2], rxkad_stats.destroyClient);
44     printf("server challenges %d, responses %d %d %d\n",
45            rxkad_stats.challengesSent, rxkad_stats.responses[0],
46            rxkad_stats.responses[1], rxkad_stats.responses[2]);
47     printf("server conns %d %d %d unused %d, unauth %d\n",
48            rxkad_stats.destroyConn[0], rxkad_stats.destroyConn[1],
49            rxkad_stats.destroyConn[2], rxkad_stats.destroyUnused,
50            rxkad_stats.destroyUnauth);
51 }
52
53 static int
54 Main(struct cmd_syndesc *as, void *arock)
55 {
56     int code;
57     char name[MAXKTCNAMELEN];
58     char instance[MAXKTCNAMELEN];
59     char newCell[MAXKTCREALMLEN];
60     char *cell;
61
62     long serverList[MAXSERVERS];
63     extern struct passwd *getpwuid();
64
65     struct passwd *pw;
66     struct ktc_encryptionKey key;
67
68     char passwd[BUFSIZ];
69
70     int cellSpecified;
71     int i;
72     int verbose = (as->parms[1].items != 0);
73     int hostUsage = (as->parms[2].items != 0);
74     int waitReap = (as->parms[4].items != 0);
75     int doAuth = (as->parms[5].items != 0);
76     int number;                 /* number of iterations */
77     int callsPerSecond;         /* to allow conn GC to run */
78
79     unsigned long lo, hi;       /* mem usage */
80     unsigned long highWater;    /* mem usage after reap period */
81     unsigned long lastWater;    /* mem usage after last msg */
82     int serversUse[MAXSERVERS]; /* usage of each server */
83     long serversHost[MAXSERVERS];       /* host addr */
84     unsigned long startTime;
85     unsigned long now;
86
87     lo = 0;
88     whoami = as->a0name;
89     newCell[0] = 0;
90
91     if (as->parms[0].items)
92         number = atoi(as->parms[0].items->data);
93     else
94         number = 100;
95     if (as->parms[3].items)
96         callsPerSecond = atoi(as->parms[3].items->data);
97     else
98         callsPerSecond = 1;
99     if (doAuth && hostUsage) {
100         fprintf(stderr,
101                 "Can't report host usage when calling UserAuthenticate\n");
102         return -1;
103     }
104
105     if (as->parms[12].items) {  /* if username specified */
106         code =
107             ka_ParseLoginName(as->parms[12].items->data, name, instance,
108                               newCell);
109         if (code) {
110             afs_com_err(whoami, code, "parsing user's name '%s'",
111                     as->parms[12].items->data);
112             return code;
113         }
114         if (strlen(newCell) > 0)
115             cellSpecified = 1;
116     } else {
117         /* No explicit name provided: use Unix uid. */
118         pw = getpwuid(getuid());
119         if (pw == 0) {
120             printf("Can't figure out your name from your user id.\n");
121             return KABADCMD;
122         }
123         strncpy(name, pw->pw_name, sizeof(name));
124         strcpy(instance, "");
125         strcpy(newCell, "");
126     }
127     if (strcmp(as->parms[14].name, "-cell") == 0) {
128         if (as->parms[14].items) {      /* if cell specified */
129             if (cellSpecified)
130                 printf("Duplicate cell specification not allowed\n");
131             else
132                 strncpy(newCell, as->parms[14].items->data, sizeof(newCell));
133         }
134     }
135
136     code = ka_ExpandCell(newCell, newCell, 0 /*local */ );
137     if (code) {
138         afs_com_err(whoami, code, "Can't expand cell name");
139         return code;
140     }
141     cell = newCell;
142
143     if (as->parms[13].items) {  /* if password specified */
144         strncpy(passwd, as->parms[13].items->data, sizeof(passwd));
145         memset(as->parms[13].items->data, 0,
146                strlen(as->parms[13].items->data));
147     } else {
148         char msg[sizeof(name) + 15];
149         if (as->parms[12].items)
150             strcpy(msg, "Admin Password: ");
151         else
152             sprintf(msg, "Password for %s: ", name);
153         code = read_pw_string(passwd, sizeof(passwd), msg, 0);
154         if (code)
155             code = KAREADPW;
156         else if (strlen(passwd) == 0)
157             code = KANULLPASSWORD;
158         if (code) {
159             afs_com_err(whoami, code, "reading password");
160             return code;
161         }
162     }
163     if (as->parms[15].items) {
164         struct cmd_item *ip;
165         char *ap[MAXSERVERS + 2];
166
167         for (ip = as->parms[15].items, i = 2; ip; ip = ip->next, i++)
168             ap[i] = ip->data;
169         ap[0] = "";
170         ap[1] = "-servers";
171         code = ubik_ParseClientList(i, ap, serverList);
172         if (code) {
173             afs_com_err(whoami, code, "could not parse server list");
174             return code;
175         }
176         ka_ExplicitCell(cell, serverList);
177     }
178
179     if (!doAuth) {
180         ka_StringToKey(passwd, cell, &key);
181         memset(passwd, 0, sizeof(passwd));
182     }
183     if (hostUsage) {
184         memset(serversUse, 0, sizeof(serversUse));
185         memset(serversHost, 0, sizeof(serversHost));
186     }
187
188     startTime = time(0);
189     for (i = 0; i < number; i++) {
190         if (doAuth) {
191             char *reason;
192             code =
193                 ka_UserAuthenticateLife(0, name, instance, cell, passwd, 0,
194                                         &reason);
195             if (code) {
196                 fprintf(stderr, "Unable to authenticate to AFS because %s.\n",
197                         reason);
198                 return code;
199             }
200         } else {
201             struct ktc_token token;
202             struct ktc_token *pToken;
203             struct ubik_client *ubikConn;
204             struct kaentryinfo tentry;
205             int c;
206
207             code =
208                 ka_GetAdminToken(name, instance, cell, &key, 3600, &token,
209                                  1 /*new */ );
210             if (code) {
211                 afs_com_err(whoami, code, "getting admin token");
212                 return code;
213             }
214             pToken = &token;
215             if (token.ticketLen == 0) {
216                 fprintf("Can't get admin token\n");
217                 return -1;
218             }
219
220             code =
221                 ka_AuthServerConn(cell, KA_MAINTENANCE_SERVICE, pToken,
222                                   &ubikConn);
223             if (code) {
224                 afs_com_err(whoami, code, "Getting AuthServer ubik conn");
225                 return code;
226             }
227
228             if (verbose)
229                 for (c = 0; c < MAXSERVERS; c++) {
230                     struct rx_connection *rxConn =
231                         ubik_GetRPCConn(ubikConn, c);
232                     struct rx_peer *peer;
233
234                     if (rxConn == 0)
235                         break;
236                     peer = rx_PeerOf(rxConn);
237                     printf("conn to %s:%d secObj:%x\n",
238                            inet_ntoa(rx_HostOf(peer)), ntohs(rx_PortOf(peer)),
239                            rxConn->securityObject);
240                 }
241
242             code =
243                 ubik_Call(KAM_GetEntry, ubikConn, 0, name, instance,
244                           KAMAJORVERSION, &tentry);
245             if (code) {
246                 afs_com_err(whoami, code, "getting information for %s.%s", name,
247                         instance);
248                 return code;
249             }
250
251             for (c = 0; c < MAXSERVERS; c++) {
252                 struct rx_connection *rxConn = ubik_GetRPCConn(ubikConn, c);
253                 int d;
254                 if (rxConn == 0)
255                     break;
256                 if (rxConn->serial > 0) {
257                     long host = rx_HostOf(rx_PeerOf(rxConn));
258                     for (d = 0; d < MAXSERVERS; d++) {
259                         if (serversHost[d] == 0)
260                             serversHost[d] = host;
261                         if (host == serversHost[d]) {
262                             serversUse[d]++;
263                             break;
264                         }
265                     }
266                 }
267                 if (verbose)
268                     printf("serial is %d\n", rxConn->serial);
269             }
270             ubik_ClientDestroy(ubikConn);
271         }
272
273         now = time(0);
274         if (!lo)
275             lo = sbrk(0);
276         if (i && ((i & 0x3f) == 0)) {
277             unsigned long this = sbrk(0);
278             printf("  mem after %d: lo=%x, cur=%x => %d (@ %d)\n", i, lo,
279                    this, this - lo, (this - lo) / i);
280             if (highWater && (lastWater != this)) {
281                 lastWater = this;
282                 printf("  core leaking (after %d) should be %x, is %x\n", i,
283                        highWater, this);
284             }
285         }
286         if ((highWater == 0) && ((now - startTime) > 61)) {
287             highWater = sbrk(0);
288             lastWater = highWater;
289             printf("  mem highWater mark (after %d) should be %x\n", i,
290                    highWater);
291         }
292         if (callsPerSecond) {
293             long target;
294             if (callsPerSecond > 0)
295                 target = i / callsPerSecond;
296             else                /* if negative interpret as seconds per call */
297                 target = i * (-callsPerSecond);
298             target = (startTime + target) - now;
299             if (target > 0)
300                 IOMGR_Sleep(target);
301         }
302     }
303     printf("calling finalize\n");
304     rx_Finalize();
305     hi = sbrk(0);
306     if (hostUsage) {
307         int total = 0;
308         for (i = 0; i < MAXSERVERS; i++) {
309             total += serversUse[i];
310             if (serversHost[i] == 0)
311                 break;
312             printf("host %s used %d times (%2g%%)\n",
313                    inet_ntoa(serversHost[i]), serversUse[i],
314                    100.0 * serversUse[i] / (double)number);
315         }
316         if (total > number)
317             printf("  %2g%% retries\n",
318                    100.0 * (total - number) / (double)number);
319     }
320     PrintRxkadStats();
321     printf("mem usage: lo=%x, hi=%x => %d (@ %d)\n", lo, hi, hi - lo,
322            (hi - lo) / number);
323     if (waitReap) {
324         unsigned long mediumHi;
325         printf("Waiting 61 seconds for all connections to be reaped\n");
326         IOMGR_Sleep(61);
327         PrintRxkadStats();
328         mediumHi = hi;
329         hi = sbrk(0);
330         if (mediumHi != hi)
331             printf("mem usage: lo=%x, hi=%x => %d (@ %d)\n", lo, hi, hi - lo,
332                    (hi - lo) / number);
333     }
334     /* most of these checks are sure to fail w/o waiting for reap */
335     if (waitReap
336         && ((rxkad_stats_clientObjects != rxkad_stats.destroyObject)
337             || (rxkad_stats.connections[0] + rxkad_stats.connections[1] +
338                 rxkad_stats.connections[2] != rxkad_stats.destroyClient)
339             || (rxkad_stats.responses[0] != rxkad_stats.destroyConn[0])
340             || (rxkad_stats.responses[1] != rxkad_stats.destroyConn[1])
341             || (rxkad_stats.responses[2] != rxkad_stats.destroyConn[2])
342             /* values of destroyUnused and destroyUnauth should be very small */
343         )) {
344         fprintf(stderr, "Some rxkad security storage not freed\n");
345         return 1;
346     }
347     if ((highWater != 0) && (highWater < hi)) {
348         /* We should reach steady state memory usage after 60 seconds (the Rx
349          * connection reap period).  If we are still using memory, there must
350          * be a core leak. */
351         fprintf(stderr, "Core leak\n");
352         return 1;
353     }
354     return 0;
355 }
356
357 int
358 main(argc, argv)
359      IN int argc;
360      IN char *argv[];
361 {
362     struct cmd_syndesc *ts;
363     long code;
364
365     initialize_U_error_table();
366     initialize_CMD_error_table();
367     initialize_RXK_error_table();
368     initialize_KTC_error_table();
369     initialize_ACFG_error_table();
370     initialize_KA_error_table();
371
372     ts = cmd_CreateSyntax(NULL, Main, NULL, "Main program");
373     /* 0 */ cmd_AddParm(ts, "-number", CMD_SINGLE, CMD_OPTIONAL,
374                         "number of iterations");
375     /* 1 */ cmd_AddParm(ts, "-long", CMD_FLAG, CMD_OPTIONAL,
376                         "long form of output");
377     /* 2 */ cmd_AddParm(ts, "-hostusage", CMD_FLAG, CMD_OPTIONAL,
378                         "report distribution of host usage");
379     /* 3 */ cmd_AddParm(ts, "-rate", CMD_SINGLE, CMD_OPTIONAL,
380                         "calls per second");
381     /* 4 */ cmd_AddParm(ts, "-waitforreap", CMD_FLAG, CMD_OPTIONAL,
382                         "wait one reap time before exit");
383     /* 5 */ cmd_AddParm(ts, "-doauth", CMD_FLAG, CMD_OPTIONAL,
384                         "call UserAuthenticate instead of GetEntry");
385     cmd_Seek(ts, 12);
386     /* 12 */ cmd_AddParm(ts, "-admin_username", CMD_SINGLE, CMD_OPTIONAL,
387                          "admin principal to use for authentication");
388     /* 13 */ cmd_AddParm(ts, "-password_for_admin", CMD_SINGLE, CMD_OPTIONAL,
389                          "admin password");
390     /* 14 */ cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cell name");
391     /* 15 */ cmd_AddParm(ts, "-servers", CMD_LIST, CMD_OPTIONAL,
392                          "explicit list of authentication servers");
393     code = cmd_Dispatch(argc, argv);
394     return (code != 0);
395 }