1 /*
2  * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved.
3  *
4  * $Id$
5  *
6  */
7 
8 #include "autoconf.h"
9 #include <stdio.h>
10 #include <string.h>
11 #include <netdb.h>
12 #include <sys/socket.h>
13 #ifdef HAVE_UNISTD_H
14 #include <unistd.h>
15 #endif
16 #include <gssrpc/rpc.h>
17 #include <gssapi/gssapi.h>
18 #include <gssapi/gssapi_krb5.h>
19 #include <gssrpc/rpc.h>
20 #include <gssrpc/auth_gssapi.h>
21 #include "rpc_test.h"
22 
23 #define BIG_BUF 4096
24 /* copied from auth_gssapi.c for hackery */
25 struct auth_gssapi_data {
26      bool_t established;
27      CLIENT *clnt;
28      gss_ctx_id_t context;
29      gss_buffer_desc client_handle;
30      OM_uint32 seq_num;
31      int def_cred;
32 
33      /* pre-serialized ah_cred */
34      u_char cred_buf[MAX_AUTH_BYTES];
35      int32_t cred_len;
36 };
37 #define AUTH_PRIVATE(auth) ((struct auth_gssapi_data *)auth->ah_private)
38 
39 extern int auth_debug_gssapi;
40 char *whoami;
41 
42 #ifdef __GNUC__
43 __attribute__((noreturn))
44 #endif
usage()45 static void usage()
46 {
47      fprintf(stderr, "usage: %s {-t|-u} [-a] [-s num] [-m num] host service [count]\n",
48 	     whoami);
49      exit(1);
50 }
51 
52 int
main(argc,argv)53 main(argc, argv)
54    int argc;
55    char **argv;
56 {
57      char        *host, *port, *target, *echo_arg, **echo_resp, buf[BIG_BUF];
58      CLIENT      *clnt;
59      AUTH	 *tmp_auth;
60      struct rpc_err e;
61      int auth_once, sock, use_tcp;
62      unsigned int count, i;
63      extern int optind;
64      extern char *optarg;
65      extern int svc_debug_gssapi, misc_debug_gssapi, auth_debug_gssapi;
66      int c;
67      struct sockaddr_in sin;
68      struct hostent *h;
69      struct timeval tv;
70 
71      extern int krb5_gss_dbg_client_expcreds;
72      krb5_gss_dbg_client_expcreds = 1;
73 
74      whoami = argv[0];
75      count = 1026;
76      auth_once = 0;
77      use_tcp = -1;
78 
79      while ((c = getopt(argc, argv, "a:m:os:tu")) != -1) {
80 	  switch (c) {
81 	  case 'a':
82 	       auth_debug_gssapi = atoi(optarg);
83 	       break;
84 	  case 'm':
85 	       misc_debug_gssapi = atoi(optarg);
86 	       break;
87 	  case 'o':
88 	       auth_once++;
89 	       break;
90 	  case 's':
91 	       svc_debug_gssapi = atoi(optarg);
92 	       break;
93 	  case 't':
94 	       use_tcp = 1;
95 	       break;
96 	  case 'u':
97 	       use_tcp = 0;
98 	       break;
99 	  case '?':
100 	       usage();
101 	       break;
102 	  }
103      }
104      if (use_tcp == -1)
105 	  usage();
106 
107      argv += optind;
108      argc -= optind;
109 
110      switch (argc) {
111      case 4:
112 	  count = atoi(argv[3]);
113 	  if (count > BIG_BUF-1) {
114 	    fprintf(stderr, "Test count cannot exceed %d.\n", BIG_BUF-1);
115 	    usage();
116 	  }
117      case 3:
118 	  host = argv[0];
119 	  port = argv[1];
120 	  target = argv[2];
121 	  break;
122      default:
123 	  usage();
124      }
125 
126      /* get server address */
127      h = gethostbyname(host);
128      if (h == NULL) {
129 	 fprintf(stderr, "Can't resolve hostname %s\n", host);
130 	 exit(1);
131      }
132      memset(&sin, 0, sizeof(sin));
133      sin.sin_family = h->h_addrtype;
134      sin.sin_port = ntohs(atoi(port));
135      memmove(&sin.sin_addr, h->h_addr, sizeof(sin.sin_addr));
136 
137      /* client handle to rstat */
138      sock = RPC_ANYSOCK;
139      if (use_tcp) {
140 	 clnt = clnttcp_create(&sin, RPC_TEST_PROG, RPC_TEST_VERS_1, &sock, 0,
141 			       0);
142      } else {
143 	 tv.tv_sec = 5;
144 	 tv.tv_usec = 0;
145 	 clnt = clntudp_create(&sin, RPC_TEST_PROG, RPC_TEST_VERS_1, tv,
146 			       &sock);
147      }
148      if (clnt == NULL) {
149 	  clnt_pcreateerror(whoami);
150 	  exit(1);
151      }
152 
153      clnt->cl_auth = auth_gssapi_create_default(clnt, target);
154      if (clnt->cl_auth == NULL) {
155 	  clnt_pcreateerror(whoami);
156 	  exit(2);
157      }
158 
159      /*
160       * Call the echo service multiple times.
161       */
162      echo_arg = buf;
163      for (i = 0; i < 3; i++) {
164 	  snprintf(buf, sizeof(buf), "testing %d\n", i);
165 
166 	  echo_resp = rpc_test_echo_1(&echo_arg, clnt);
167 	  if (echo_resp == NULL) {
168 	       fprintf(stderr, "RPC_TEST_ECHO call %d%s", i,
169 		       clnt_sperror(clnt, ""));
170 	  }
171 	  if (strncmp(*echo_resp, "Echo: ", 6) &&
172 	      strcmp(echo_arg, (*echo_resp) + 6) != 0)
173 	       fprintf(stderr, "RPC_TEST_ECHO call %d response wrong: "
174 		       "arg = %s, resp = %s\n", i, echo_arg, *echo_resp);
175 	  gssrpc_xdr_free(xdr_wrapstring, echo_resp);
176      }
177 
178      /*
179       * Make a call with an invalid verifier and check for error;
180       * server should log error message.  It is important to
181       *increment* seq_num here, since a decrement would be fixed (see
182       * below).  Note that seq_num will be incremented (by
183       * authg_gssapi_refresh) twice, so we need to decrement by three
184       * to reset.
185       */
186      AUTH_PRIVATE(clnt->cl_auth)->seq_num++;
187 
188      echo_arg = "testing with bad verf";
189 
190      echo_resp = rpc_test_echo_1(&echo_arg, clnt);
191      if (echo_resp == NULL) {
192 	  CLNT_GETERR(clnt, &e);
193 	  if (e.re_status != RPC_AUTHERROR || e.re_why != AUTH_REJECTEDVERF)
194 	       clnt_perror(clnt, whoami);
195      } else {
196 	  fprintf(stderr, "bad seq didn't cause failure\n");
197 	  gssrpc_xdr_free(xdr_wrapstring, echo_resp);
198      }
199 
200      AUTH_PRIVATE(clnt->cl_auth)->seq_num -= 3;
201 
202      /*
203       * Make sure we're resyncronized.
204       */
205      echo_arg = "testing for reset";
206      echo_resp = rpc_test_echo_1(&echo_arg, clnt);
207      if (echo_resp == NULL)
208 	  clnt_perror(clnt, "Sequence number improperly reset");
209      else
210 	  gssrpc_xdr_free(xdr_wrapstring, echo_resp);
211 
212      /*
213       * Now simulate a lost server response, and see if
214       * auth_gssapi_refresh recovers.
215       */
216      AUTH_PRIVATE(clnt->cl_auth)->seq_num--;
217      echo_arg = "forcing auto-resynchronization";
218      echo_resp = rpc_test_echo_1(&echo_arg, clnt);
219      if (echo_resp == NULL)
220 	  clnt_perror(clnt, "Auto-resynchronization failed");
221      else
222 	  gssrpc_xdr_free(xdr_wrapstring, echo_resp);
223 
224      /*
225       * Now make sure auto-resyncrhonization actually worked
226       */
227      echo_arg = "testing for resynchronization";
228      echo_resp = rpc_test_echo_1(&echo_arg, clnt);
229      if (echo_resp == NULL)
230 	  clnt_perror(clnt, "Auto-resynchronization did not work");
231      else
232 	  gssrpc_xdr_free(xdr_wrapstring, echo_resp);
233 
234      /*
235       * Test fix for secure-rpc/586, part 1: btree keys must be
236       * unique.  Create another context from the same credentials; it
237       * should have the same expiration time and will cause the server
238       * to abort if the clients are not differentiated.
239       *
240       * Test fix for secure-rpc/586, part 2: btree keys cannot be
241       * mutated in place.  To test this: a second client, *with a
242       * later expiration time*, must be run.  The second client should
243       * destroy itself *after* the first one; if the key-mutating bug
244       * is not fixed, the second client_data will be in the btree
245       * before the first, but its key will be larger; thus, when the
246       * first client calls AUTH_DESTROY, the server won't find it in
247       * the btree and call abort.
248       *
249       * For unknown reasons, running just a second client didn't
250       * tickle the bug; the btree code seemed to guess which node to
251       * look at first.  Running a total of three clients does ticket
252       * the bug.  Thus, the full test sequence looks like this:
253       *
254       * 	kinit -l 20m user && client server test@ddn 200
255       * 	sleep 1
256       * 	kini -l 30m user && client server test@ddn 300
257       * 	sleep 1
258       * 	kinit -l 40m user && client server test@ddn 400
259       */
260      if (! auth_once) {
261 	  tmp_auth = clnt->cl_auth;
262 	  clnt->cl_auth = auth_gssapi_create_default(clnt, target);
263 	  if (clnt->cl_auth == NULL) {
264 	       clnt_pcreateerror(whoami);
265 	       exit(2);
266 	  }
267 	  AUTH_DESTROY(clnt->cl_auth);
268 	  clnt->cl_auth = tmp_auth;
269      }
270 
271      /*
272       * Try RPC calls with argument/result lengths [0, 1025].  Do
273       * this last, since it takes a while..
274       */
275      echo_arg = buf;
276      memset(buf, 0, count+1);
277      for (i = 0; i < count; i++) {
278 	  echo_resp = rpc_test_echo_1(&echo_arg, clnt);
279 	  if (echo_resp == NULL) {
280 	       fprintf(stderr, "RPC_TEST_LENGTHS call %d%s", i,
281 		       clnt_sperror(clnt, ""));
282 	       break;
283 	  } else {
284 	       if (strncmp(*echo_resp, "Echo: ", 6) &&
285 		   strcmp(echo_arg, (*echo_resp) + 6) != 0)
286 		    fprintf(stderr,
287 			    "RPC_TEST_LENGTHS call %d response wrong\n", i);
288 	       gssrpc_xdr_free(xdr_wrapstring, echo_resp);
289 	  }
290 
291 	  /* cycle from 1 to 255 */
292 	  buf[i] = (i % 255) + 1;
293 
294 	  if (i % 100 == 0) {
295 	       fputc('.', stdout);
296 	       fflush(stdout);
297 	  }
298      }
299      fputc('\n', stdout);
300 
301      AUTH_DESTROY(clnt->cl_auth);
302      CLNT_DESTROY(clnt);
303      exit(0);
304 }
305