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